From b24969720ac9c92f3d7327250b3ee8e86acc6def Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Mon, 23 Nov 2015 20:28:05 -0800 Subject: Improve error handling; allow two routines to have errors in a successful test (Empty, which can get bad file descriptor after the process exits, and the Decode-Source writer, since the decoder is not required to read the full source) --- xdelta3/go/src/regtest.go | 18 +++++++++--------- xdelta3/go/src/xdelta/rstream.go | 15 +++++++++------ xdelta3/go/src/xdelta/test.go | 6 +++--- xdelta3/go/src/xdelta/tgroup.go | 41 +++++++++++++++++++++++++++------------- 4 files changed, 49 insertions(+), 31 deletions(-) (limited to 'xdelta3') diff --git a/xdelta3/go/src/regtest.go b/xdelta3/go/src/regtest.go index 793c9fc..385c936 100644 --- a/xdelta3/go/src/regtest.go +++ b/xdelta3/go/src/regtest.go @@ -20,7 +20,7 @@ func smokeTest(r *xdelta.Runner, p *xdelta.Program) { target := "Hello world!" source := "Hello world, nice to meet you!" - enc, err := t.Exec(p, true, []string{"-evv"}) + enc, err := t.Exec("encode", p, true, []string{"-evv"}) if err != nil { g.Panic(err) } @@ -34,7 +34,7 @@ func smokeTest(r *xdelta.Runner, p *xdelta.Program) { g.Panic(err) } - dec, err := t.Exec(p, true, []string{"-dvv"}) + dec, err := t.Exec("decode", p, true, []string{"-dvv"}) if err != nil { g.Panic(err) } @@ -59,13 +59,13 @@ func smokeTest(r *xdelta.Runner, p *xdelta.Program) { func offsetTest(r *xdelta.Runner, p *xdelta.Program, bufsize, offset, length int64) { t, g := xdelta.NewTestGroup(r) eargs := []string{"-e", "-0", fmt.Sprint("-B", bufsize), "-vv", fmt.Sprint("-W", winsize)} - enc, err := t.Exec(p, true, eargs) + enc, err := t.Exec("encode", p, true, eargs) if err != nil { g.Panic(err) } dargs := []string{"-d", fmt.Sprint("-B", bufsize), "-vv", fmt.Sprint("-W", winsize)} - dec, err := t.Exec(p, true, dargs) + dec, err := t.Exec("decode", p, true, dargs) if err != nil { g.Panic(err) } @@ -78,10 +78,8 @@ func offsetTest(r *xdelta.Runner, p *xdelta.Program, bufsize, offset, length int t.CopyStreams(enc.Stdout, dec.Stdin) t.CompareStreams(dec.Stdout, read, length) - // TODO: seems possible to use one WriteRstreams call to generate - // the source and target for both encoder and decoder. Why not? - xdelta.WriteRstreams(t, seed, offset, length, enc.Srcin, enc.Stdin) - xdelta.WriteRstreams(t, seed, offset, length, dec.Srcin, write) + xdelta.WriteRstreams(t, "encode", seed, offset, length, enc.Srcin, enc.Stdin) + xdelta.WriteRstreams(t, "decode", seed, offset, length, dec.Srcin, write) t.Wait(g) } @@ -96,7 +94,9 @@ func main() { prog := &xdelta.Program{xdelta3} smokeTest(r, prog) - offsetTest(r, prog, 4 << 20, 3 << 20, 5 << 20) + for { + offsetTest(r, prog, 4 << 20, 3 << 20, 5 << 20) + } //offsetTest(r, xdelta.NewTestGroup(), prog, 1 << 31, 1 << 32, 1 << 33) } diff --git a/xdelta3/go/src/xdelta/rstream.go b/xdelta3/go/src/xdelta/rstream.go index 3f520d7..e31b0b0 100644 --- a/xdelta3/go/src/xdelta/rstream.go +++ b/xdelta3/go/src/xdelta/rstream.go @@ -10,17 +10,20 @@ const ( blocksize = 16380 ) -func WriteRstreams(t *TestGroup, seed, offset, len int64, +func WriteRstreams(t *TestGroup, desc string, seed, offset, len int64, src, tgt io.WriteCloser) { - t.Go("src", func (g Goroutine) { - go writeOne(g, seed, 0, len, src) + t.Go("src-write:"+desc, func (g Goroutine) { + writeOne(g, seed, 0, len, src, false) }) - t.Go("tgt", func (g Goroutine) { - go writeOne(g, seed, offset, len, tgt) + t.Go("tgt-write:"+desc, func (g Goroutine) { + writeOne(g, seed, offset, len, tgt, true) }) } -func writeOne(g Goroutine, seed, offset, len int64, stream io.WriteCloser) { +func writeOne(g Goroutine, seed, offset, len int64, stream io.WriteCloser, readall bool) { + if !readall { + g.OK() + } if offset != 0 { // Fill with other random data until the offset if err := writeRand(rand.New(rand.NewSource(^seed)), offset, stream); err != nil { diff --git a/xdelta3/go/src/xdelta/test.go b/xdelta3/go/src/xdelta/test.go index d11ec29..ab4137c 100644 --- a/xdelta3/go/src/xdelta/test.go +++ b/xdelta3/go/src/xdelta/test.go @@ -49,6 +49,7 @@ func (t *TestGroup) Drain(f io.ReadCloser, desc string) <-chan []byte { func (t *TestGroup) Empty(f io.ReadCloser, desc string) { t.Go(desc, func (g Goroutine) { + g.OK() s := bufio.NewScanner(f) for s.Scan() { os.Stderr.Write([]byte(fmt.Sprint(desc, ": ", s.Text(), "\n"))) @@ -59,7 +60,6 @@ func (t *TestGroup) Empty(f io.ReadCloser, desc string) { fmt.Println("Empty", desc, err) g.Panic(err) } - g.OK() }) } @@ -126,7 +126,7 @@ func (t *TestGroup) CompareStreams(r1 io.ReadCloser, r2 io.ReadCloser, length in }) } -func (t *TestGroup) Exec(p *Program, srcfifo bool, flags []string) (*Run, error) { +func (t *TestGroup) Exec(desc string, p *Program, srcfifo bool, flags []string) (*Run, error) { var err error run := &Run{} args := []string{p.Path} @@ -162,7 +162,7 @@ func (t *TestGroup) Exec(p *Program, srcfifo bool, flags []string) (*Run, error) if serr := run.Cmd.Start(); serr != nil { return nil, serr } - t.Go("exec-wait", func (g Goroutine) { + t.Go("exec-wait:" + desc, func (g Goroutine) { if err := run.Cmd.Wait(); err != nil { g.Panic(err) } diff --git a/xdelta3/go/src/xdelta/tgroup.go b/xdelta3/go/src/xdelta/tgroup.go index bb34258..b64827c 100644 --- a/xdelta3/go/src/xdelta/tgroup.go +++ b/xdelta3/go/src/xdelta/tgroup.go @@ -10,6 +10,7 @@ type TestGroup struct { *Runner sync.Mutex running []Goroutine + errors []error waitChan <-chan bool } @@ -31,13 +32,19 @@ func (g *Goroutine) String() string { } func (g *Goroutine) OK() { - g.errChan <- nil - _ = <- g.errChan + if g.errChan != nil { + g.errChan <- nil + _ = <- g.errChan + g.errChan = nil + } } func (g *Goroutine) Panic(err error) { - g.errChan <- err - _ = <- g.errChan + fmt.Print("[", g.name, "] ", err, "\n") + if g.errChan != nil { + g.errChan <- err + _ = <- g.errChan + } select {} } @@ -52,15 +59,24 @@ func (t *TestGroup) Go(name string, f func(Goroutine)) { func (t *TestGroup) Wait(g Goroutine) { g.OK() t.Lock() - t.waitChan = nil wc := t.waitChan + t.waitChan = nil t.Unlock() _ = <- wc + t.Lock() + errs := t.errors + t.Unlock() + if len(errs) != 0 { + panic(fmt.Sprintln(len(errs), "errors in test")) + } } func waitAll(t *TestGroup, wc chan bool) { for { t.Lock() + // for _, x := range t.running { + // fmt.Println("RUNNING", x.name) + // } if len(t.running) == 0 { t.Unlock() break @@ -69,19 +85,18 @@ func waitAll(t *TestGroup, wc chan bool) { t.running = t.running[1:] t.Unlock() - timeout := make(chan bool, 1) - go func() { - time.Sleep(1 * time.Second) - timeout <- true - }() - fmt.Println("Waiting on", runner) + timeout := time.After(time.Second) + // fmt.Println("Waiting on", runner) select { case err := <- runner.errChan: runner.errChan <- err if err != nil { - fmt.Println("[G]", runner, err) + // fmt.Println("[G]", runner, err) + t.Lock() + t.errors = append(t.errors, err) + t.Unlock() } else { - fmt.Println("[G]", runner, "OK") + // fmt.Println("[G]", runner, "OK") } case <- timeout: t.Lock() -- cgit v1.2.3