summaryrefslogtreecommitdiff
path: root/xdelta3/go/src/xdelta
diff options
context:
space:
mode:
authorJoshua MacDonald <josh.macdonald@gmail.com>2015-11-21 23:36:51 -0800
committerJoshua MacDonald <josh.macdonald@gmail.com>2015-11-21 23:36:51 -0800
commitede482d8f3398262adcfb23095b6caad5872d8ba (patch)
tree89ea4cf3d61efbc82a9b342f3a9b6edc6edd8f69 /xdelta3/go/src/xdelta
parent6116f8879faff1a8145f55d9f537c33f39931678 (diff)
New TestGroup.Go method, improved error handling
Diffstat (limited to 'xdelta3/go/src/xdelta')
-rw-r--r--xdelta3/go/src/xdelta/rstream.go23
-rw-r--r--xdelta3/go/src/xdelta/run.go22
-rw-r--r--xdelta3/go/src/xdelta/test.go132
-rw-r--r--xdelta3/go/src/xdelta/tgroup.go93
4 files changed, 181 insertions, 89 deletions
diff --git a/xdelta3/go/src/xdelta/rstream.go b/xdelta3/go/src/xdelta/rstream.go
index 3e7265f..3f520d7 100644
--- a/xdelta3/go/src/xdelta/rstream.go
+++ b/xdelta3/go/src/xdelta/rstream.go
@@ -11,25 +11,30 @@ const (
11) 11)
12 12
13func WriteRstreams(t *TestGroup, seed, offset, len int64, 13func WriteRstreams(t *TestGroup, seed, offset, len int64,
14 first, second io.WriteCloser) { 14 src, tgt io.WriteCloser) {
15 go writeOne(t, seed, 0, len, first) 15 t.Go("src", func (g Goroutine) {
16 go writeOne(t, seed, offset, len, second) 16 go writeOne(g, seed, 0, len, src)
17 })
18 t.Go("tgt", func (g Goroutine) {
19 go writeOne(g, seed, offset, len, tgt)
20 })
17} 21}
18 22
19func writeOne(t *TestGroup, seed, offset, len int64, stream io.WriteCloser) error { 23func writeOne(g Goroutine, seed, offset, len int64, stream io.WriteCloser) {
20 t.WaitGroup.Add(1)
21 if offset != 0 { 24 if offset != 0 {
22 // Fill with other random data until the offset 25 // Fill with other random data until the offset
23 if err := writeRand(rand.New(rand.NewSource(^seed)), offset, stream); err != nil { 26 if err := writeRand(rand.New(rand.NewSource(^seed)), offset, stream); err != nil {
24 return err 27 g.Panic(err)
25 } 28 }
26 } 29 }
27 if err := writeRand(rand.New(rand.NewSource(seed)), 30 if err := writeRand(rand.New(rand.NewSource(seed)),
28 len - offset, stream); err != nil { 31 len - offset, stream); err != nil {
29 return err 32 g.Panic(err)
33 }
34 if err := stream.Close(); err != nil {
35 g.Panic(err)
30 } 36 }
31 t.WaitGroup.Done() 37 g.OK()
32 return stream.Close()
33} 38}
34 39
35func writeRand(r *rand.Rand, len int64, s io.Writer) error { 40func writeRand(r *rand.Rand, len int64, s io.Writer) error {
diff --git a/xdelta3/go/src/xdelta/run.go b/xdelta3/go/src/xdelta/run.go
new file mode 100644
index 0000000..f9b4185
--- /dev/null
+++ b/xdelta3/go/src/xdelta/run.go
@@ -0,0 +1,22 @@
1package xdelta
2
3import (
4 "io/ioutil"
5 "os"
6)
7
8type Runner struct {
9 Testdir string
10}
11
12func NewRunner() (*Runner, error) {
13 if dir, err := ioutil.TempDir(tmpDir, "xrt"); err != nil {
14 return nil, err
15 } else {
16 return &Runner{dir}, nil
17 }
18}
19
20func (r *Runner) Cleanup() {
21 os.RemoveAll(r.Testdir)
22}
diff --git a/xdelta3/go/src/xdelta/test.go b/xdelta3/go/src/xdelta/test.go
index e853554..d11ec29 100644
--- a/xdelta3/go/src/xdelta/test.go
+++ b/xdelta3/go/src/xdelta/test.go
@@ -11,7 +11,6 @@ import (
11 "os/exec" 11 "os/exec"
12 "path" 12 "path"
13 "sync/atomic" 13 "sync/atomic"
14 "sync"
15 14
16 "golang.org/x/sys/unix" 15 "golang.org/x/sys/unix"
17) 16)
@@ -25,16 +24,6 @@ type Program struct {
25 Path string 24 Path string
26} 25}
27 26
28type Runner struct {
29 Testdir string
30}
31
32type TestGroup struct {
33 sync.WaitGroup
34 sync.Mutex
35 errs []error
36}
37
38type Run struct { 27type Run struct {
39 Cmd exec.Cmd 28 Cmd exec.Cmd
40 Srcfile string 29 Srcfile string
@@ -44,86 +33,71 @@ type Run struct {
44 Stderr io.ReadCloser 33 Stderr io.ReadCloser
45} 34}
46 35
47
48func (t *TestGroup) Panic(err error) {
49 t.Lock()
50 t.errs = append(t.errs, err)
51 t.Unlock()
52 t.Done() // For the caller
53 t.Wait()
54 for _, e := range t.errs {
55 fmt.Println(e)
56 }
57 panic(fmt.Sprintf("%d errors", len(t.errs)))
58}
59
60func NewTestGroup() *TestGroup {
61 return &TestGroup{}
62}
63
64func (t *TestGroup) Drain(f io.ReadCloser, desc string) <-chan []byte { 36func (t *TestGroup) Drain(f io.ReadCloser, desc string) <-chan []byte {
65 c := make(chan []byte) 37 c := make(chan []byte)
66 go func() { 38 t.Go(desc, func(g Goroutine) {
67 t.Add(1)
68 //fmt.Println("Draining", desc)
69 if b, err := ioutil.ReadAll(f); err != nil { 39 if b, err := ioutil.ReadAll(f); err != nil {
70 t.Panic(err) 40 fmt.Println("Drain", err)
41 g.Panic(err)
71 } else { 42 } else {
72 //fmt.Println("Draining", desc, "--got it")
73 c <- b 43 c <- b
74 } 44 }
75 t.Done() 45 g.OK()
76 }() 46 })
77 return c 47 return c
78} 48}
79 49
80func (t *TestGroup) Empty(f io.ReadCloser, desc string) { 50func (t *TestGroup) Empty(f io.ReadCloser, desc string) {
81 go func() { 51 t.Go(desc, func (g Goroutine) {
82 t.Add(1)
83 s := bufio.NewScanner(f) 52 s := bufio.NewScanner(f)
84 for s.Scan() { 53 for s.Scan() {
85 os.Stderr.Write([]byte(fmt.Sprint(desc, ": ", s.Text(), "\n"))) 54 os.Stderr.Write([]byte(fmt.Sprint(desc, ": ", s.Text(), "\n")))
86 } 55 }
87 if err := s.Err(); err != nil { 56 err := s.Err()
88 t.Panic(err) 57 f.Close()
58 if err != nil {
59 fmt.Println("Empty", desc, err)
60 g.Panic(err)
89 } 61 }
90 t.Done() 62 g.OK()
91 }() 63 })
92} 64}
93 65
94func (t *TestGroup) Write(what string, f io.WriteCloser, b []byte) { 66func TestWrite(what string, f io.WriteCloser, b []byte) error {
95 //fmt.Println("Write (", what, ") ", len(b), "bytes")
96 if _, err := f.Write(b); err != nil { 67 if _, err := f.Write(b); err != nil {
97 t.Panic(errors.New(fmt.Sprint(what, ":", err))) 68 fmt.Println("Write", err)
69 return errors.New(fmt.Sprint(what, ":", err))
98 } 70 }
99 //fmt.Println("Write (", what, ") closing")
100 if err := f.Close(); err != nil { 71 if err := f.Close(); err != nil {
101 t.Panic(errors.New(fmt.Sprint(what, ":", err))) 72 fmt.Println("Close", err)
73 return errors.New(fmt.Sprint(what, ":", err))
102 } 74 }
75 return nil
103} 76}
104 77
105func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser) { 78func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser) {
106 go func() { 79 t.Go("copy", func(g Goroutine) {
107 t.Add(1)
108 _, err := io.Copy(w, r) 80 _, err := io.Copy(w, r)
109 if err != nil { 81 if err != nil {
110 t.Panic(err) 82 fmt.Println("CopyS", err)
83 g.Panic(err)
111 } 84 }
112 err = r.Close() 85 err = r.Close()
113 if err != nil { 86 if err != nil {
114 t.Panic(err) 87 fmt.Println("CloseS1", err)
88 g.Panic(err)
115 } 89 }
116 err = w.Close() 90 err = w.Close()
117 if err != nil { 91 if err != nil {
118 t.Panic(err) 92 fmt.Println("CloseS2", err)
93 g.Panic(err)
119 } 94 }
120 t.Done() 95 g.OK()
121 }() 96 })
122} 97}
123 98
124func (t *TestGroup) CompareStreams(r1 io.ReadCloser, r2 io.ReadCloser, length int64) { 99func (t *TestGroup) CompareStreams(r1 io.ReadCloser, r2 io.ReadCloser, length int64) {
125 go func() { 100 t.Go("compare", func(g Goroutine) {
126 t.Add(1)
127 b1 := make([]byte, blocksize) 101 b1 := make([]byte, blocksize)
128 b2 := make([]byte, blocksize) 102 b2 := make([]byte, blocksize)
129 var idx int64 103 var idx int64
@@ -133,42 +107,32 @@ func (t *TestGroup) CompareStreams(r1 io.ReadCloser, r2 io.ReadCloser, length in
133 c = int(length) 107 c = int(length)
134 } 108 }
135 if _, err := io.ReadFull(r1, b1[0:c]); err != nil { 109 if _, err := io.ReadFull(r1, b1[0:c]); err != nil {
136 t.Panic(err) 110 fmt.Println("ReadFull1", err)
111 g.Panic(err)
137 } 112 }
138 if _, err := io.ReadFull(r2, b2[0:c]); err != nil { 113 if _, err := io.ReadFull(r2, b2[0:c]); err != nil {
139 t.Panic(err) 114 fmt.Println("ReadFull2", err)
115 g.Panic(err)
140 } 116 }
141 if bytes.Compare(b1[0:c], b2[0:c]) != 0 { 117 if bytes.Compare(b1[0:c], b2[0:c]) != 0 {
142 fmt.Println("B1 is", string(b1[0:c])) 118 fmt.Println("B1 is", string(b1[0:c]))
143 fmt.Println("B2 is", string(b2[0:c])) 119 fmt.Println("B2 is", string(b2[0:c]))
144 t.Panic(errors.New(fmt.Sprint("Bytes do not compare at ", idx))) 120 g.Panic(errors.New(fmt.Sprint("Bytes do not compare at ", idx)))
145 } 121 }
146 length -= int64(c) 122 length -= int64(c)
147 idx += int64(c) 123 idx += int64(c)
148 } 124 }
149 t.Done() 125 g.OK()
150 }() 126 })
151} 127}
152 128
153func NewRunner() (*Runner, error) { 129func (t *TestGroup) Exec(p *Program, srcfifo bool, flags []string) (*Run, error) {
154 if dir, err := ioutil.TempDir(tmpDir, "xrt"); err != nil {
155 return nil, err
156 } else {
157 return &Runner{dir}, nil
158 }
159}
160
161func (r *Runner) Cleanup() {
162 os.RemoveAll(r.Testdir)
163}
164
165func (r *Runner) Exec(p *Program, srcfifo bool, flags []string) (*Run, error) {
166 var err error 130 var err error
167 run := &Run{} 131 run := &Run{}
168 args := []string{p.Path} 132 args := []string{p.Path}
169 if srcfifo { 133 if srcfifo {
170 num := atomic.AddInt64(&srcSeq, 1) 134 num := atomic.AddInt64(&srcSeq, 1)
171 run.Srcfile = path.Join(r.Testdir, fmt.Sprint("source", num)) 135 run.Srcfile = path.Join(t.Runner.Testdir, fmt.Sprint("source", num))
172 if err = unix.Mkfifo(run.Srcfile, 0600); err != nil { 136 if err = unix.Mkfifo(run.Srcfile, 0600); err != nil {
173 return nil, err 137 return nil, err
174 } 138 }
@@ -193,21 +157,29 @@ func (r *Runner) Exec(p *Program, srcfifo bool, flags []string) (*Run, error) {
193 157
194 run.Cmd.Path = p.Path 158 run.Cmd.Path = p.Path
195 run.Cmd.Args = append(args, flags...) 159 run.Cmd.Args = append(args, flags...)
196 run.Cmd.Dir = r.Testdir 160 run.Cmd.Dir = t.Runner.Testdir
197 161
198 return run, run.Cmd.Start() 162 if serr := run.Cmd.Start(); serr != nil {
163 return nil, serr
164 }
165 t.Go("exec-wait", func (g Goroutine) {
166 if err := run.Cmd.Wait(); err != nil {
167 g.Panic(err)
168 }
169 g.OK()
170 })
171 return run, nil
199} 172}
200 173
201func writeFifo(srcfile string, read io.Reader) error { 174func writeFifo(srcfile string, read io.Reader) error {
202 fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600) 175 fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600)
203 if err != nil { 176 if err != nil {
177 fifo.Close()
204 return err 178 return err
205 } 179 }
206 if _, err := io.Copy(fifo, read); err != nil { 180 if _, err := io.Copy(fifo, read); err != nil {
181 fifo.Close()
207 return err 182 return err
208 } 183 }
209 if err := fifo.Close(); err != nil { 184 return fifo.Close()
210 return err
211 }
212 return nil
213} 185}
diff --git a/xdelta3/go/src/xdelta/tgroup.go b/xdelta3/go/src/xdelta/tgroup.go
new file mode 100644
index 0000000..bb34258
--- /dev/null
+++ b/xdelta3/go/src/xdelta/tgroup.go
@@ -0,0 +1,93 @@
1package xdelta
2
3import (
4 "fmt"
5 "sync"
6 "time"
7)
8
9type TestGroup struct {
10 *Runner
11 sync.Mutex
12 running []Goroutine
13 waitChan <-chan bool
14}
15
16type Goroutine struct {
17 name string
18 errChan chan error
19}
20
21func NewTestGroup(r *Runner) (*TestGroup, Goroutine) {
22 g := Goroutine{"main", make(chan error)}
23 wc := make(chan bool)
24 tg := &TestGroup{Runner: r, running: []Goroutine{g}, waitChan: wc}
25 go waitAll(tg, wc)
26 return tg, g
27}
28
29func (g *Goroutine) String() string {
30 return fmt.Sprint("[", g.name, "]")
31}
32
33func (g *Goroutine) OK() {
34 g.errChan <- nil
35 _ = <- g.errChan
36}
37
38func (g *Goroutine) Panic(err error) {
39 g.errChan <- err
40 _ = <- g.errChan
41 select {}
42}
43
44func (t *TestGroup) Go(name string, f func(Goroutine)) {
45 g := Goroutine{name, make(chan error)}
46 t.Lock()
47 t.running = append(t.running, g)
48 t.Unlock()
49 go f(g)
50}
51
52func (t *TestGroup) Wait(g Goroutine) {
53 g.OK()
54 t.Lock()
55 t.waitChan = nil
56 wc := t.waitChan
57 t.Unlock()
58 _ = <- wc
59}
60
61func waitAll(t *TestGroup, wc chan bool) {
62 for {
63 t.Lock()
64 if len(t.running) == 0 {
65 t.Unlock()
66 break
67 }
68 runner := t.running[0]
69 t.running = t.running[1:]
70 t.Unlock()
71
72 timeout := make(chan bool, 1)
73 go func() {
74 time.Sleep(1 * time.Second)
75 timeout <- true
76 }()
77 fmt.Println("Waiting on", runner)
78 select {
79 case err := <- runner.errChan:
80 runner.errChan <- err
81 if err != nil {
82 fmt.Println("[G]", runner, err)
83 } else {
84 fmt.Println("[G]", runner, "OK")
85 }
86 case <- timeout:
87 t.Lock()
88 t.running = append(t.running, runner)
89 t.Unlock()
90 }
91 }
92 wc <- true
93}