summaryrefslogtreecommitdiff
path: root/xdelta3
diff options
context:
space:
mode:
authorJoshua MacDonald <josh.macdonald@gmail.com>2015-12-07 22:53:32 -0800
committerJoshua MacDonald <josh.macdonald@gmail.com>2015-12-07 22:53:32 -0800
commitb65269806e9b4c01f22614e93782ff4686eea72d (patch)
tree1c52878f144280027a2a4da0d574aa68b908ba58 /xdelta3
parent6d9ad86987f926068d0d4d503c4c23efa7af511f (diff)
Run offset tests up to the 31bit source window (see
Diffstat (limited to 'xdelta3')
-rw-r--r--xdelta3/go/src/regtest.go40
-rw-r--r--xdelta3/go/src/xdelta/rstream.go7
-rw-r--r--xdelta3/go/src/xdelta/run.go49
-rw-r--r--xdelta3/go/src/xdelta/test.go55
-rw-r--r--xdelta3/go/src/xdelta/tgroup.go17
5 files changed, 100 insertions, 68 deletions
diff --git a/xdelta3/go/src/regtest.go b/xdelta3/go/src/regtest.go
index adb4ae4..d762235 100644
--- a/xdelta3/go/src/regtest.go
+++ b/xdelta3/go/src/regtest.go
@@ -15,8 +15,8 @@ const (
15 seed = 1422253499919909358 15 seed = 1422253499919909358
16) 16)
17 17
18func smokeTest(r *xdelta.Runner, p *xdelta.Program) { 18func smokeTest(t *xdelta.TestGroup, p *xdelta.Program) {
19 t, g := xdelta.NewTestGroup(r) 19 g := t.Main()
20 target := "Hello world!" 20 target := "Hello world!"
21 source := "Hello world, nice to meet you!" 21 source := "Hello world, nice to meet you!"
22 22
@@ -55,32 +55,29 @@ func smokeTest(r *xdelta.Runner, p *xdelta.Program) {
55 t.Wait(g, enc, dec) 55 t.Wait(g, enc, dec)
56} 56}
57 57
58func offsetTest(r *xdelta.Runner, p *xdelta.Program, bufsize, offset, length int64) { 58func offsetTest(t *xdelta.TestGroup, p *xdelta.Program, offset, bufsize, length int64) {
59 // Note there is a strong potential to deadlock or fail due to 59 g := t.Main()
60 // a broken test in this test for several reasons: 60 eargs := []string{"-e", "-0", fmt.Sprint("-B", bufsize), "-q", fmt.Sprint("-W", winsize)}
61 // (a) decoder is not required to read the entire source file
62 // (b) decoder defers open to source file until first window received
63 // (c) open on a fifo blocks until a reader opens
64 // (d) sub-process Wait can invalidate busy file descriptors
65 t, g := xdelta.NewTestGroup(r)
66 eargs := []string{"-e", "-0", fmt.Sprint("-B", bufsize), "-vv", fmt.Sprint("-W", winsize)}
67 enc, err := t.Exec("encode", p, true, eargs) 61 enc, err := t.Exec("encode", p, true, eargs)
68 if err != nil { 62 if err != nil {
69 g.Panic(err) 63 g.Panic(err)
70 } 64 }
71 65
72 dargs := []string{"-d", fmt.Sprint("-B", bufsize), "-vv", fmt.Sprint("-W", winsize)} 66 dargs := []string{"-d", fmt.Sprint("-B", bufsize), "-q", fmt.Sprint("-W", winsize)}
73 dec, err := t.Exec("decode", p, true, dargs) 67 dec, err := t.Exec("decode", p, true, dargs)
74 if err != nil { 68 if err != nil {
75 g.Panic(err) 69 g.Panic(err)
76 } 70 }
77 71
72 // The pipe used to read the decoder output and compare
73 // against the target.
78 read, write := io.Pipe() 74 read, write := io.Pipe()
79 75
80 t.Empty(enc.Stderr, "encode") 76 t.Empty(enc.Stderr, "encode")
81 t.Empty(dec.Stderr, "decode") 77 t.Empty(dec.Stderr, "decode")
82 78
83 t.CopyStreams(enc.Stdout, dec.Stdin) 79 var encoded_size int64
80 t.CopyStreams(enc.Stdout, dec.Stdin, &encoded_size)
84 t.CompareStreams(dec.Stdout, read, length) 81 t.CompareStreams(dec.Stdout, read, length)
85 82
86 // The decoder output ("read", above) is compared with the 83 // The decoder output ("read", above) is compared with the
@@ -89,6 +86,12 @@ func offsetTest(r *xdelta.Runner, p *xdelta.Program, bufsize, offset, length int
89 t.WriteRstreams("encode", seed, offset, length, enc.Srcin, enc.Stdin) 86 t.WriteRstreams("encode", seed, offset, length, enc.Srcin, enc.Stdin)
90 t.WriteRstreams("decode", seed, offset, length, dec.Srcin, write) 87 t.WriteRstreams("decode", seed, offset, length, dec.Srcin, write)
91 t.Wait(g, enc, dec) 88 t.Wait(g, enc, dec)
89
90 expect := bufsize - offset
91 if float64(encoded_size) < (0.95 * float64(expect)) ||
92 float64(encoded_size) > (1.05 * float64(expect)) {
93 t.Fail("encoded size should be ~=", expect, ", actual ", encoded_size)
94 }
92} 95}
93 96
94func main() { 97func main() {
@@ -100,11 +103,10 @@ func main() {
100 103
101 prog := &xdelta.Program{xdelta3} 104 prog := &xdelta.Program{xdelta3}
102 105
103 smokeTest(r, prog) 106 r.RunTest("smoketest", func(tg *xdelta.TestGroup) { smokeTest(tg, prog) })
104 fmt.Println("Smoke-test pass")
105 107
106 offsetTest(r, prog, 4 << 20, 3 << 20, 5 << 20) 108 for i := uint(20); i <= 30; i += 1 {
107 fmt.Println("Offset-test pass") 109 r.RunTest(fmt.Sprint("offset", i), func(t *xdelta.TestGroup) {
108 110 offsetTest(t, prog, 1 << i, 2 << i, 3 << i) })
109 //offsetTest(r, xdelta.NewTestGroup(), prog, 1 << 31, 1 << 32, 1 << 33) 111 }
110} 112}
diff --git a/xdelta3/go/src/xdelta/rstream.go b/xdelta3/go/src/xdelta/rstream.go
index 9481f22..99c3d17 100644
--- a/xdelta3/go/src/xdelta/rstream.go
+++ b/xdelta3/go/src/xdelta/rstream.go
@@ -3,7 +3,6 @@ package xdelta
3 3
4import ( 4import (
5 "io" 5 "io"
6 "fmt"
7 "math/rand" 6 "math/rand"
8) 7)
9 8
@@ -14,10 +13,10 @@ const (
14func (t *TestGroup) WriteRstreams(desc string, seed, offset, len int64, 13func (t *TestGroup) WriteRstreams(desc string, seed, offset, len int64,
15 src, tgt io.WriteCloser) { 14 src, tgt io.WriteCloser) {
16 t.Go("src-write:"+desc, func (g *Goroutine) { 15 t.Go("src-write:"+desc, func (g *Goroutine) {
17 writeOne(g, seed, 0, len, src, false) 16 writeOne(g, seed, 0, len, tgt, false)
18 }) 17 })
19 t.Go("tgt-write:"+desc, func (g *Goroutine) { 18 t.Go("tgt-write:"+desc, func (g *Goroutine) {
20 writeOne(g, seed, offset, len, tgt, true) 19 writeOne(g, seed, offset, len, src, true)
21 }) 20 })
22} 21}
23 22
@@ -30,12 +29,10 @@ func writeOne(g *Goroutine, seed, offset, len int64, stream io.WriteCloser, read
30 } 29 }
31 if offset != 0 { 30 if offset != 0 {
32 // Fill with other random data until the offset 31 // Fill with other random data until the offset
33 fmt.Println(g, "pre-offset case", offset)
34 if err := writeRand(g, rand.New(rand.NewSource(^seed)), offset, stream); err != nil { 32 if err := writeRand(g, rand.New(rand.NewSource(^seed)), offset, stream); err != nil {
35 g.Panic(err) 33 g.Panic(err)
36 } 34 }
37 } 35 }
38 fmt.Println(g, "offset case", len - offset)
39 if err := writeRand(g, rand.New(rand.NewSource(seed)), 36 if err := writeRand(g, rand.New(rand.NewSource(seed)),
40 len - offset, stream); err != nil { 37 len - offset, stream); err != nil {
41 g.Panic(err) 38 g.Panic(err)
diff --git a/xdelta3/go/src/xdelta/run.go b/xdelta3/go/src/xdelta/run.go
index f9b4185..3b07178 100644
--- a/xdelta3/go/src/xdelta/run.go
+++ b/xdelta3/go/src/xdelta/run.go
@@ -1,14 +1,34 @@
1package xdelta 1package xdelta
2 2
3import ( 3import (
4 "fmt"
5 "io"
4 "io/ioutil" 6 "io/ioutil"
5 "os" 7 "os"
8 "os/exec"
6) 9)
7 10
11type Program struct {
12 Path string
13}
14
15type Run struct {
16 Cmd exec.Cmd
17 Srcfile string
18 Stdin io.WriteCloser
19 Srcin io.WriteCloser
20 Stdout io.ReadCloser
21 Stderr io.ReadCloser
22}
23
8type Runner struct { 24type Runner struct {
9 Testdir string 25 Testdir string
10} 26}
11 27
28func (r *Run) Wait() error {
29 return r.Cmd.Wait()
30}
31
12func NewRunner() (*Runner, error) { 32func NewRunner() (*Runner, error) {
13 if dir, err := ioutil.TempDir(tmpDir, "xrt"); err != nil { 33 if dir, err := ioutil.TempDir(tmpDir, "xrt"); err != nil {
14 return nil, err 34 return nil, err
@@ -17,6 +37,35 @@ func NewRunner() (*Runner, error) {
17 } 37 }
18} 38}
19 39
40func (r *Runner) newTestGroup(name string) (*TestGroup) {
41 tg := &TestGroup{Runner: r}
42 tg.WaitGroup.Add(1)
43 g0 := &Goroutine{tg, name, false}
44 tg.running = append(tg.running, g0)
45 tg.main = g0
46 return tg
47}
48
20func (r *Runner) Cleanup() { 49func (r *Runner) Cleanup() {
21 os.RemoveAll(r.Testdir) 50 os.RemoveAll(r.Testdir)
22} 51}
52
53func (r *Runner) RunTest(name string, f func (t *TestGroup)) {
54 t := r.newTestGroup(name)
55 var rec interface{}
56 defer func() {
57 if r := recover(); r != nil {
58 fmt.Println("PANIC in ", name, ": ", r)
59 rec = r
60 } else {
61 // Goexit
62 }
63 }()
64 fmt.Println("Testing", name, "...")
65 f(t)
66 if t.errors == nil && rec == nil {
67 fmt.Println("Success:", name)
68 } else {
69 fmt.Println("FAILED:", name, t.errors, rec)
70 }
71}
diff --git a/xdelta3/go/src/xdelta/test.go b/xdelta3/go/src/xdelta/test.go
index 00f3dd7..bab66f3 100644
--- a/xdelta3/go/src/xdelta/test.go
+++ b/xdelta3/go/src/xdelta/test.go
@@ -8,7 +8,6 @@ import (
8 "io" 8 "io"
9 "io/ioutil" 9 "io/ioutil"
10 "os" 10 "os"
11 "os/exec"
12 "path" 11 "path"
13 "sync/atomic" 12 "sync/atomic"
14 13
@@ -20,19 +19,6 @@ var (
20 srcSeq int64 19 srcSeq int64
21) 20)
22 21
23type Program struct {
24 Path string
25}
26
27type Run struct {
28 Cmd exec.Cmd
29 Srcfile string
30 Stdin io.WriteCloser
31 Srcin io.WriteCloser
32 Stdout io.ReadCloser
33 Stderr io.ReadCloser
34}
35
36func (t *TestGroup) Drain(f io.ReadCloser, desc string) <-chan []byte { 22func (t *TestGroup) Drain(f io.ReadCloser, desc string) <-chan []byte {
37 c := make(chan []byte) 23 c := make(chan []byte)
38 t.Go(desc, func(g *Goroutine) { 24 t.Go(desc, func(g *Goroutine) {
@@ -71,9 +57,9 @@ func TestWrite(what string, f io.WriteCloser, b []byte) error {
71 return nil 57 return nil
72} 58}
73 59
74func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser) *Goroutine { 60func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser, written *int64) *Goroutine {
75 return t.Go("copy", func(g *Goroutine) { 61 return t.Go("copy", func(g *Goroutine) {
76 _, err := io.Copy(w, r) 62 nwrite, err := io.Copy(w, r)
77 if err != nil { 63 if err != nil {
78 g.Panic(err) 64 g.Panic(err)
79 } 65 }
@@ -86,6 +72,7 @@ func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser) *Goroutine {
86 g.Panic(err) 72 g.Panic(err)
87 } 73 }
88 g.OK() 74 g.OK()
75 *written = nwrite
89 }) 76 })
90} 77}
91 78
@@ -127,12 +114,9 @@ func (t *TestGroup) Exec(desc string, p *Program, srcfifo bool, flags []string)
127 if err = unix.Mkfifo(run.Srcfile, 0600); err != nil { 114 if err = unix.Mkfifo(run.Srcfile, 0600); err != nil {
128 return nil, err 115 return nil, err
129 } 116 }
130 // Because OpenFile blocks on the Fifo until the reader
131 // arrives, a pipe to defer open
132 read, write := io.Pipe() 117 read, write := io.Pipe()
118 t.writeFifo(run.Srcfile, read)
133 run.Srcin = write 119 run.Srcin = write
134
135 go writeFifo(run.Srcfile, read)
136 args = append(args, "-s") 120 args = append(args, "-s")
137 args = append(args, run.Srcfile) 121 args = append(args, run.Srcfile)
138 } 122 }
@@ -156,19 +140,24 @@ func (t *TestGroup) Exec(desc string, p *Program, srcfifo bool, flags []string)
156 return run, nil 140 return run, nil
157} 141}
158 142
159func (r *Run) Wait() error { 143func (t *TestGroup) Fail(v ...interface{}) {
160 return r.Cmd.Wait() 144 panic(fmt.Sprintln(v...))
161} 145}
162 146
163func writeFifo(srcfile string, read io.Reader) error { 147func (t *TestGroup) writeFifo(srcfile string, read io.Reader) *Goroutine {
164 fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600) 148 return t.Go("compare", func(g *Goroutine) {
165 if err != nil { 149 fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600)
166 fifo.Close() 150 if err != nil {
167 return err 151 fifo.Close()
168 } 152 g.Panic(err)
169 if _, err := io.Copy(fifo, read); err != nil { 153 }
170 fifo.Close() 154 if _, err := io.Copy(fifo, read); err != nil {
171 return err 155 fifo.Close()
172 } 156 g.Panic(err)
173 return fifo.Close() 157 }
158 if err := fifo.Close(); err != nil {
159 g.Panic(err)
160 }
161 g.OK()
162 })
174} 163}
diff --git a/xdelta3/go/src/xdelta/tgroup.go b/xdelta3/go/src/xdelta/tgroup.go
index 7f6c875..0a3b41b 100644
--- a/xdelta3/go/src/xdelta/tgroup.go
+++ b/xdelta3/go/src/xdelta/tgroup.go
@@ -2,11 +2,13 @@ package xdelta
2 2
3import ( 3import (
4 "fmt" 4 "fmt"
5 "runtime"
5 "sync" 6 "sync"
6) 7)
7 8
8type TestGroup struct { 9type TestGroup struct {
9 *Runner 10 *Runner
11 main *Goroutine
10 sync.Mutex 12 sync.Mutex
11 sync.WaitGroup 13 sync.WaitGroup
12 running []*Goroutine 14 running []*Goroutine
@@ -20,14 +22,6 @@ type Goroutine struct {
20 done bool 22 done bool
21} 23}
22 24
23func NewTestGroup(r *Runner) (*TestGroup, *Goroutine) {
24 tg := &TestGroup{Runner: r}
25 tg.WaitGroup.Add(1)
26 g0 := &Goroutine{tg, "main", false}
27 tg.running = append(tg.running, g0)
28 return tg, g0
29}
30
31func (g *Goroutine) String() string { 25func (g *Goroutine) String() string {
32 return fmt.Sprint("[", g.name, "]") 26 return fmt.Sprint("[", g.name, "]")
33} 27}
@@ -59,9 +53,11 @@ func (g *Goroutine) OK() {
59 53
60func (g *Goroutine) Panic(err error) { 54func (g *Goroutine) Panic(err error) {
61 g.finish(err) 55 g.finish(err)
62 select {} 56 runtime.Goexit()
63} 57}
64 58
59func (t *TestGroup) Main() *Goroutine { return t.main }
60
65func (t *TestGroup) Go(name string, f func(*Goroutine)) *Goroutine { 61func (t *TestGroup) Go(name string, f func(*Goroutine)) *Goroutine {
66 g := &Goroutine{t, name, false} 62 g := &Goroutine{t, name, false}
67 t.Lock() 63 t.Lock()
@@ -87,7 +83,6 @@ func (t *TestGroup) Wait(self *Goroutine, procs... *Run) {
87 fmt.Println("(ERROR)", err) 83 fmt.Println("(ERROR)", err)
88 } 84 }
89 if len(t.errors) != 0 { 85 if len(t.errors) != 0 {
90 panic(fmt.Sprintf("Test failed with", len(t.errors), "errors")) 86 t.Fail("Test failed with", len(t.errors), "errors")
91 } 87 }
92} 88}
93