diff options
author | Joshua MacDonald <josh.macdonald@gmail.com> | 2015-12-07 22:53:32 -0800 |
---|---|---|
committer | Joshua MacDonald <josh.macdonald@gmail.com> | 2015-12-07 22:53:32 -0800 |
commit | b65269806e9b4c01f22614e93782ff4686eea72d (patch) | |
tree | 1c52878f144280027a2a4da0d574aa68b908ba58 /xdelta3/go | |
parent | 6d9ad86987f926068d0d4d503c4c23efa7af511f (diff) |
Run offset tests up to the 31bit source window (see
Diffstat (limited to 'xdelta3/go')
-rw-r--r-- | xdelta3/go/src/regtest.go | 40 | ||||
-rw-r--r-- | xdelta3/go/src/xdelta/rstream.go | 7 | ||||
-rw-r--r-- | xdelta3/go/src/xdelta/run.go | 49 | ||||
-rw-r--r-- | xdelta3/go/src/xdelta/test.go | 55 | ||||
-rw-r--r-- | xdelta3/go/src/xdelta/tgroup.go | 17 |
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 | ||
18 | func smokeTest(r *xdelta.Runner, p *xdelta.Program) { | 18 | func 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 | ||
58 | func offsetTest(r *xdelta.Runner, p *xdelta.Program, bufsize, offset, length int64) { | 58 | func 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 | ||
94 | func main() { | 97 | func 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 | ||
4 | import ( | 4 | import ( |
5 | "io" | 5 | "io" |
6 | "fmt" | ||
7 | "math/rand" | 6 | "math/rand" |
8 | ) | 7 | ) |
9 | 8 | ||
@@ -14,10 +13,10 @@ const ( | |||
14 | func (t *TestGroup) WriteRstreams(desc string, seed, offset, len int64, | 13 | func (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 @@ | |||
1 | package xdelta | 1 | package xdelta |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "fmt" | ||
5 | "io" | ||
4 | "io/ioutil" | 6 | "io/ioutil" |
5 | "os" | 7 | "os" |
8 | "os/exec" | ||
6 | ) | 9 | ) |
7 | 10 | ||
11 | type Program struct { | ||
12 | Path string | ||
13 | } | ||
14 | |||
15 | type 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 | |||
8 | type Runner struct { | 24 | type Runner struct { |
9 | Testdir string | 25 | Testdir string |
10 | } | 26 | } |
11 | 27 | ||
28 | func (r *Run) Wait() error { | ||
29 | return r.Cmd.Wait() | ||
30 | } | ||
31 | |||
12 | func NewRunner() (*Runner, error) { | 32 | func 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 | ||
40 | func (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 | |||
20 | func (r *Runner) Cleanup() { | 49 | func (r *Runner) Cleanup() { |
21 | os.RemoveAll(r.Testdir) | 50 | os.RemoveAll(r.Testdir) |
22 | } | 51 | } |
52 | |||
53 | func (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 | ||
23 | type Program struct { | ||
24 | Path string | ||
25 | } | ||
26 | |||
27 | type 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 | |||
36 | func (t *TestGroup) Drain(f io.ReadCloser, desc string) <-chan []byte { | 22 | func (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 | ||
74 | func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser) *Goroutine { | 60 | func (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 | ||
159 | func (r *Run) Wait() error { | 143 | func (t *TestGroup) Fail(v ...interface{}) { |
160 | return r.Cmd.Wait() | 144 | panic(fmt.Sprintln(v...)) |
161 | } | 145 | } |
162 | 146 | ||
163 | func writeFifo(srcfile string, read io.Reader) error { | 147 | func (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 | ||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | "runtime" | ||
5 | "sync" | 6 | "sync" |
6 | ) | 7 | ) |
7 | 8 | ||
8 | type TestGroup struct { | 9 | type 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 | ||
23 | func 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 | |||
31 | func (g *Goroutine) String() string { | 25 | func (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 | ||
60 | func (g *Goroutine) Panic(err error) { | 54 | func (g *Goroutine) Panic(err error) { |
61 | g.finish(err) | 55 | g.finish(err) |
62 | select {} | 56 | runtime.Goexit() |
63 | } | 57 | } |
64 | 58 | ||
59 | func (t *TestGroup) Main() *Goroutine { return t.main } | ||
60 | |||
65 | func (t *TestGroup) Go(name string, f func(*Goroutine)) *Goroutine { | 61 | func (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 | |||