summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua MacDonald <josh.macdonald@gmail.com>2015-11-29 23:14:04 -0800
committerJoshua MacDonald <josh.macdonald@gmail.com>2015-11-29 23:14:04 -0800
commitbdcbbc839ca7fd3e8edd1617bbf9bfdba4bf543d (patch)
treed2ed2ff8a4972c3e88db485f1d7c40d173eedd46
parent4b74451f9e9b976a2a0984130662f58bd39e1478 (diff)
Test this on Linux
-rw-r--r--xdelta3/go/src/regtest.go18
-rw-r--r--xdelta3/go/src/xdelta/rstream.go21
-rw-r--r--xdelta3/go/src/xdelta/test.go7
-rw-r--r--xdelta3/go/src/xdelta/tgroup.go62
4 files changed, 37 insertions, 71 deletions
diff --git a/xdelta3/go/src/regtest.go b/xdelta3/go/src/regtest.go
index 4507b8c..85bd43a 100644
--- a/xdelta3/go/src/regtest.go
+++ b/xdelta3/go/src/regtest.go
@@ -57,14 +57,20 @@ func smokeTest(r *xdelta.Runner, p *xdelta.Program) {
57} 57}
58 58
59func offsetTest(r *xdelta.Runner, p *xdelta.Program, bufsize, offset, length int64) { 59func offsetTest(r *xdelta.Runner, p *xdelta.Program, bufsize, offset, length int64) {
60 // Note there is a strong potential to deadlock or fail due to
61 // a broken test in this test for several reasons:
62 // (a) decoder is not required to read the entire source file
63 // (b) decoder defers open to source file until first window received
64 // (c) open on a fifo blocks until a reader opens
65 // (d) sub-process Wait can invalidate busy file descriptors
60 t, g := xdelta.NewTestGroup(r) 66 t, g := xdelta.NewTestGroup(r)
61 eargs := []string{"-e", "-0", fmt.Sprint("-B", bufsize), "-vv", fmt.Sprint("-W", winsize)} 67 eargs := []string{"-e", "-0", fmt.Sprint("-B", bufsize), "-vvvvvvv", fmt.Sprint("-W", winsize)}
62 enc, err := t.Exec("encode", p, true, eargs) 68 enc, err := t.Exec("encode", p, true, eargs)
63 if err != nil { 69 if err != nil {
64 g.Panic(err) 70 g.Panic(err)
65 } 71 }
66 72
67 dargs := []string{"-d", fmt.Sprint("-B", bufsize), "-vv", fmt.Sprint("-W", winsize)} 73 dargs := []string{"-d", fmt.Sprint("-B", bufsize), "-vvvvvvv", fmt.Sprint("-W", winsize)}
68 dec, err := t.Exec("decode", p, true, dargs) 74 dec, err := t.Exec("decode", p, true, dargs)
69 if err != nil { 75 if err != nil {
70 g.Panic(err) 76 g.Panic(err)
@@ -79,10 +85,10 @@ func offsetTest(r *xdelta.Runner, p *xdelta.Program, bufsize, offset, length int
79 t.CompareStreams(dec.Stdout, read, length) 85 t.CompareStreams(dec.Stdout, read, length)
80 86
81 // The decoder output ("read", above) is compared with the 87 // The decoder output ("read", above) is compared with the
82 // test-provided output ("write", below). 88 // test-provided output ("write", below). The following
83 xdelta.WriteRstreams(t, seed, offset, length, 89 // generates the input and output twice.
84 t.NewDualWriter(enc.Srcin, dec.Srcin), 90 t.WriteRstreams("encode", seed, offset, length, enc.Srcin, dec.Srcin)
85 t.NewDualWriter(dec.Srcin, write)) 91 t.WriteRstreams("decode", seed, offset, length, dec.Srcin, write)
86 t.Wait(g, enc, dec) 92 t.Wait(g, enc, dec)
87} 93}
88 94
diff --git a/xdelta3/go/src/xdelta/rstream.go b/xdelta3/go/src/xdelta/rstream.go
index eafcfeb..7d205c6 100644
--- a/xdelta3/go/src/xdelta/rstream.go
+++ b/xdelta3/go/src/xdelta/rstream.go
@@ -3,19 +3,20 @@ package xdelta
3 3
4import ( 4import (
5 "io" 5 "io"
6 "fmt"
6 "math/rand" 7 "math/rand"
7) 8)
8 9
9const ( 10const (
10 blocksize = 1<<20 11 blocksize = 1<<17
11) 12)
12 13
13func WriteRstreams(t *TestGroup, seed, offset, len int64, 14func (t *TestGroup) WriteRstreams(desc string, seed, offset, len int64,
14 src, tgt io.WriteCloser) { 15 src, tgt io.WriteCloser) {
15 t.Go("src-write", func (g Goroutine) { 16 t.Go("src-write:"+desc, func (g Goroutine) {
16 writeOne(g, seed, 0, len, src, false) 17 writeOne(g, seed, 0, len, src, false)
17 }) 18 })
18 t.Go("tgt-write", func (g Goroutine) { 19 t.Go("tgt-write:"+desc, func (g Goroutine) {
19 writeOne(g, seed, offset, len, tgt, true) 20 writeOne(g, seed, offset, len, tgt, true)
20 }) 21 })
21} 22}
@@ -29,31 +30,37 @@ func writeOne(g Goroutine, seed, offset, len int64, stream io.WriteCloser, reada
29 } 30 }
30 if offset != 0 { 31 if offset != 0 {
31 // Fill with other random data until the offset 32 // Fill with other random data until the offset
32 if err := writeRand(rand.New(rand.NewSource(^seed)), offset, stream); err != nil { 33 fmt.Println(g, "pre-offset case", offset)
34 if err := writeRand(g, rand.New(rand.NewSource(^seed)), offset, stream); err != nil {
33 g.Panic(err) 35 g.Panic(err)
34 } 36 }
35 } 37 }
36 if err := writeRand(rand.New(rand.NewSource(seed)), 38 fmt.Println(g, "offset case", len - offset)
39 if err := writeRand(g, rand.New(rand.NewSource(seed)),
37 len - offset, stream); err != nil { 40 len - offset, stream); err != nil {
38 g.Panic(err) 41 g.Panic(err)
39 } 42 }
43 fmt.Println(g, "closing", len)
40 if err := stream.Close(); err != nil { 44 if err := stream.Close(); err != nil {
41 g.Panic(err) 45 g.Panic(err)
42 } 46 }
43 g.OK() 47 g.OK()
44} 48}
45 49
46func writeRand(r *rand.Rand, len int64, s io.Writer) error { 50func writeRand(g Goroutine, r *rand.Rand, len int64, s io.Writer) error {
47 blk := make([]byte, blocksize) 51 blk := make([]byte, blocksize)
52 fmt.Println(g, "rstream", len)
48 for len > 0 { 53 for len > 0 {
49 fillRand(r, blk) 54 fillRand(r, blk)
50 c := blocksize 55 c := blocksize
51 if len < blocksize { 56 if len < blocksize {
52 c = int(len) 57 c = int(len)
53 } 58 }
59 fmt.Println(g, "writing...", c, s)
54 if _, err := s.Write(blk[0:c]); err != nil { 60 if _, err := s.Write(blk[0:c]); err != nil {
55 return err 61 return err
56 } 62 }
63 fmt.Println(g, "...written", c)
57 len -= int64(c) 64 len -= int64(c)
58 } 65 }
59 return nil 66 return nil
diff --git a/xdelta3/go/src/xdelta/test.go b/xdelta3/go/src/xdelta/test.go
index 05de487..427e4c7 100644
--- a/xdelta3/go/src/xdelta/test.go
+++ b/xdelta3/go/src/xdelta/test.go
@@ -78,17 +78,14 @@ func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser) Goroutine {
78 return t.Go("copy", func(g Goroutine) { 78 return t.Go("copy", func(g Goroutine) {
79 _, err := io.Copy(w, r) 79 _, err := io.Copy(w, r)
80 if err != nil { 80 if err != nil {
81 fmt.Println("CopyS", err)
82 g.Panic(err) 81 g.Panic(err)
83 } 82 }
84 err = r.Close() 83 err = r.Close()
85 if err != nil { 84 if err != nil {
86 fmt.Println("CloseS1", err)
87 g.Panic(err) 85 g.Panic(err)
88 } 86 }
89 err = w.Close() 87 err = w.Close()
90 if err != nil { 88 if err != nil {
91 fmt.Println("CloseS2", err)
92 g.Panic(err) 89 g.Panic(err)
93 } 90 }
94 g.OK() 91 g.OK()
@@ -157,7 +154,7 @@ func (t *TestGroup) Exec(desc string, p *Program, srcfifo bool, flags []string)
157 run.Cmd.Path = p.Path 154 run.Cmd.Path = p.Path
158 run.Cmd.Args = append(args, flags...) 155 run.Cmd.Args = append(args, flags...)
159 run.Cmd.Dir = t.Runner.Testdir 156 run.Cmd.Dir = t.Runner.Testdir
160 157 fmt.Println("Start command", run.Cmd.Args)
161 if serr := run.Cmd.Start(); serr != nil { 158 if serr := run.Cmd.Start(); serr != nil {
162 return nil, serr 159 return nil, serr
163 } 160 }
@@ -169,7 +166,9 @@ func (r *Run) Wait() error {
169} 166}
170 167
171func writeFifo(srcfile string, read io.Reader) error { 168func writeFifo(srcfile string, read io.Reader) error {
169 fmt.Println("About to open", srcfile)
172 fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600) 170 fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600)
171 fmt.Println("Opened!!!", srcfile)
173 if err != nil { 172 if err != nil {
174 fifo.Close() 173 fifo.Close()
175 return err 174 return err
diff --git a/xdelta3/go/src/xdelta/tgroup.go b/xdelta3/go/src/xdelta/tgroup.go
index 1852bac..f94c03e 100644
--- a/xdelta3/go/src/xdelta/tgroup.go
+++ b/xdelta3/go/src/xdelta/tgroup.go
@@ -2,7 +2,6 @@ package xdelta
2 2
3import ( 3import (
4 "fmt" 4 "fmt"
5 "io"
6 "sync" 5 "sync"
7 "time" 6 "time"
8) 7)
@@ -21,7 +20,7 @@ type Goroutine struct {
21} 20}
22 21
23func NewTestGroup(r *Runner) (*TestGroup, Goroutine) { 22func NewTestGroup(r *Runner) (*TestGroup, Goroutine) {
24 g := Goroutine{"main", make(chan error)} 23 g := Goroutine{"main", make(chan error, 1)}
25 wc := make(chan bool) 24 wc := make(chan bool)
26 tg := &TestGroup{Runner: r, running: []Goroutine{g}, waitChan: wc} 25 tg := &TestGroup{Runner: r, running: []Goroutine{g}, waitChan: wc}
27 go waitAll(tg, wc) 26 go waitAll(tg, wc)
@@ -33,6 +32,7 @@ func (g *Goroutine) String() string {
33} 32}
34 33
35func (g *Goroutine) OK() { 34func (g *Goroutine) OK() {
35 fmt.Println("OK", g)
36 if g.errChan != nil { 36 if g.errChan != nil {
37 g.errChan <- nil 37 g.errChan <- nil
38 _ = <- g.errChan 38 _ = <- g.errChan
@@ -41,7 +41,7 @@ func (g *Goroutine) OK() {
41} 41}
42 42
43func (g *Goroutine) Panic(err error) { 43func (g *Goroutine) Panic(err error) {
44 fmt.Println(g, err) 44 fmt.Println("PANIC", g, err)
45 if g.errChan != nil { 45 if g.errChan != nil {
46 g.errChan <- err 46 g.errChan <- err
47 _ = <- g.errChan 47 _ = <- g.errChan
@@ -50,7 +50,7 @@ func (g *Goroutine) Panic(err error) {
50} 50}
51 51
52func (t *TestGroup) Go(name string, f func(Goroutine)) Goroutine { 52func (t *TestGroup) Go(name string, f func(Goroutine)) Goroutine {
53 g := Goroutine{name, make(chan error)} 53 g := Goroutine{name, make(chan error, 1)}
54 t.Lock() 54 t.Lock()
55 t.running = append(t.running, g) 55 t.running = append(t.running, g)
56 t.Unlock() 56 t.Unlock()
@@ -88,6 +88,10 @@ func waitAll(t *TestGroup, wc chan bool) {
88 t.Unlock() 88 t.Unlock()
89 break 89 break
90 } 90 }
91 // fmt.Println("----------------------------------------------------------------------")
92 // for _, r := range t.running {
93 // fmt.Println("Waiting for", r)
94 // }
91 runner := t.running[0] 95 runner := t.running[0]
92 t.running = t.running[1:] 96 t.running = t.running[1:]
93 t.Unlock() 97 t.Unlock()
@@ -110,53 +114,3 @@ func waitAll(t *TestGroup, wc chan bool) {
110 } 114 }
111 wc <- true 115 wc <- true
112} 116}
113
114type dualWriter struct {
115 e, d chan []byte
116}
117
118func (d *dualWriter) Write(p []byte) (int, error) {
119 if len(p) != 0 {
120 d.e <- p
121 d.d <- p
122 }
123 return len(p), nil
124}
125
126func (d *dualWriter) Close() error {
127 d.e <- nil
128 d.d <- nil
129 _ = <- d.e
130 _ = <- d.d
131 return nil
132}
133
134func newWriter(c chan []byte, a io.WriteCloser) func (Goroutine) {
135 return func (g Goroutine) {
136 for {
137 d := <- c
138 if d == nil {
139 if err := a.Close(); err != nil {
140 g.Panic(err)
141 }
142 c <- nil
143 g.OK()
144 return
145 }
146 if num, err := a.Write(d); err != nil {
147 g.Panic(err)
148 } else if num != len(d) {
149 g.Panic(fmt.Errorf("Invalid write: %v != %v", num, len(d)))
150 }
151 }
152 }
153}
154
155func (t *TestGroup) NewDualWriter(a1, a2 io.WriteCloser) io.WriteCloser {
156 c1 := make(chan []byte)
157 c2 := make(chan []byte)
158 r := &dualWriter{c1, c2}
159 t.Go("writer0", newWriter(c1, a1))
160 t.Go("writer1", newWriter(c2, a2))
161 return r
162}