From b55fcf3dc4c775ef35dce116ab23d35a5f9ff326 Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Sun, 25 Jan 2015 23:17:17 -0800 Subject: regtest.go tests a random stream and an offset copy --- xdelta3/go/src/regtest.go | 100 +++++++++++++++++++++++++++++++++++---- xdelta3/go/src/xdelta/rstream.go | 56 ++++++++++++++++++++++ xdelta3/go/src/xdelta/test.go | 63 +++++++++++++++--------- 3 files changed, 189 insertions(+), 30 deletions(-) create mode 100644 xdelta3/go/src/xdelta/rstream.go (limited to 'xdelta3') diff --git a/xdelta3/go/src/regtest.go b/xdelta3/go/src/regtest.go index aee419d..d31e905 100644 --- a/xdelta3/go/src/regtest.go +++ b/xdelta3/go/src/regtest.go @@ -1,13 +1,17 @@ package main import ( + "bytes" + "fmt" "io" "io/ioutil" "xdelta" ) const ( + blocksize = 1<<20 prog = "/Users/jmacd/src/xdelta/xdelta3/xdelta3" + seed = 1422253499919909358 ) func drain(f io.ReadCloser) <-chan []byte { @@ -39,16 +43,11 @@ func write(f io.WriteCloser, b []byte) { } } -func main() { - x := xdelta.Program{prog} - smokeTest(x) -} - -func smokeTest(p xdelta.Program) { +func smokeTest(r *xdelta.Runner, p *xdelta.Program) { target := "Hello world!" source := "Hello world, nice to meet you!" - run, err := p.Exec(true, []string{"-e"}) + run, err := r.Exec(p, true, []string{"-e"}) if err != nil { panic(err) } @@ -62,7 +61,7 @@ func smokeTest(p xdelta.Program) { panic(err) } - run, err = p.Exec(true, []string{"-d"}) + run, err = r.Exec(p, true, []string{"-d"}) if err != nil { panic(err) } @@ -81,3 +80,88 @@ func smokeTest(p xdelta.Program) { panic("It's not working!!!") } } + +func copyStreams(r io.ReadCloser, w io.WriteCloser) { + _, err := io.Copy(w, r) + if err != nil { + panic(err) + } + err = r.Close() + if err != nil { + panic(err) + } + err = w.Close() + if err != nil { + panic(err) + } +} + +func compareStreams(r1 io.ReadCloser, r2 io.ReadCloser, length int64) { + b1 := make([]byte, blocksize) + b2 := make([]byte, blocksize) + var idx int64 + for length > 0 { + c := blocksize + if length < blocksize { + c = int(length) + } + if _, err := io.ReadFull(r1, b1[0:c]); err != nil { + panic(err) + } + if _, err := io.ReadFull(r2, b2[0:c]); err != nil { + panic(err) + } + if bytes.Compare(b1[0:c], b2[0:c]) != 0 { + fmt.Println("B1 is", string(b1[0:c])) + fmt.Println("B2 is", string(b2[0:c])) + panic(fmt.Sprint("Bytes do not compare at ", idx)) + } + length -= int64(c) + idx += int64(c) + } +} + +func offsetTest(r *xdelta.Runner, p *xdelta.Program, offset, length int64) { + enc, err := r.Exec(p, true, []string{"-e"}) + if err != nil { + panic(err) + } + dec, err := r.Exec(p, true, []string{"-d"}) + if err != nil { + panic(err) + } + + read, write := io.Pipe() + + go copyStreams(enc.Stdout, dec.Stdin) + go compareStreams(dec.Stdout, read, length) + + empty(enc.Stderr) // Use these? + empty(dec.Stderr) + + // TODO: seems possible to use one WriteRstreams call to generate + // the source and target for both encoder and decoder. Why not? + xdelta.WriteRstreams(seed, offset, length, enc.Srcin, enc.Stdin) + xdelta.WriteRstreams(seed, offset, length, dec.Srcin, write) + + if err := enc.Cmd.Wait(); err != nil { + panic(err) + } + if err := dec.Cmd.Wait(); err != nil { + panic(err) + } +} + +func main() { + r, err := xdelta.NewRunner() + if err != nil { + panic(err) + } + defer r.Cleanup() + + prog := &xdelta.Program{prog} + + smokeTest(r, prog) + + offsetTest(r, prog, 0, 1024 << 20) +} diff --git a/xdelta3/go/src/xdelta/rstream.go b/xdelta3/go/src/xdelta/rstream.go new file mode 100644 index 0000000..1666934 --- /dev/null +++ b/xdelta3/go/src/xdelta/rstream.go @@ -0,0 +1,56 @@ +package xdelta + + +import ( + "io" + "math/rand" +) + +const ( + blocksize = 16380 // A factor of 7 +) + +func WriteRstreams(seed, offset, len int64, + first, second io.WriteCloser) { + go writeOne(seed, 0, len, first) + go writeOne(seed, offset, len, second) +} + +func writeOne(seed, offset, len int64, stream io.WriteCloser) { + if offset != 0 { + // Fill with other random data until the offset + writeRand(rand.New(rand.NewSource(^seed)), + offset, stream) + } + writeRand(rand.New(rand.NewSource(seed)), + len - offset, stream) + if err := stream.Close(); err != nil { + panic(err) + } +} + +func writeRand(r *rand.Rand, len int64, s io.Writer) { + blk := make([]byte, blocksize) + for len > 0 { + fillRand(r, blk) + c := blocksize + if len < blocksize { + c = int(len) + } + if _, err := s.Write(blk[0:c]); err != nil { + panic(err) + } + len -= int64(c) + } +} + +func fillRand(r *rand.Rand, blk []byte) { + for p := 0; p < blocksize; { + v := r.Int63() + for i := 7; i != 0; i-- { + blk[p] = byte(v) + p++ + v >>= 8 + } + } +} diff --git a/xdelta3/go/src/xdelta/test.go b/xdelta3/go/src/xdelta/test.go index d586538..292f133 100644 --- a/xdelta3/go/src/xdelta/test.go +++ b/xdelta3/go/src/xdelta/test.go @@ -1,41 +1,58 @@ package xdelta import ( + "fmt" "io" "io/ioutil" "os" "os/exec" "path" + "sync/atomic" + "golang.org/x/sys/unix" ) var ( tmpDir = "/tmp" + srcSeq int64 ) type Program struct { Path string } +type Runner struct { + Testdir string +} + type Run struct { Cmd exec.Cmd - Testdir string Srcfile string Stdin io.WriteCloser Srcin io.WriteCloser Stdout io.ReadCloser Stderr io.ReadCloser -} +} -func (b *Program) Exec(srcfifo bool, flags []string) (*Run, error) { - var err error - run := &Run{} - if run.Testdir, err = ioutil.TempDir(tmpDir, "xrt"); err != nil { +func NewRunner() (*Runner, error) { + if dir, err := ioutil.TempDir(tmpDir, "xrt"); err != nil { return nil, err + } else { + return &Runner{dir}, nil } - args := []string{b.Path} +} + +func (r *Runner) Cleanup() { + os.RemoveAll(r.Testdir) +} + +func (r *Runner) Exec(p *Program, srcfifo bool, flags []string) (*Run, error) { + var err error + run := &Run{} + args := []string{p.Path} if srcfifo { - run.Srcfile = path.Join(run.Testdir, "source") + num := atomic.AddInt64(&srcSeq, 1) + run.Srcfile = path.Join(r.Testdir, fmt.Sprint("source", num)) if err = unix.Mkfifo(run.Srcfile, 0600); err != nil { return nil, err } @@ -44,18 +61,7 @@ func (b *Program) Exec(srcfifo bool, flags []string) (*Run, error) { read, write := io.Pipe() run.Srcin = write - go func() { - fifo, err := os.OpenFile(run.Srcfile, os.O_WRONLY, 0600) - if err != nil { - panic(err) - } - if _, err := io.Copy(fifo, read); err != nil { - panic(err) - } - if err := fifo.Close(); err != nil { - panic(err) - } - }() + go writeFifo(run.Srcfile, read) args = append(args, "-s") args = append(args, run.Srcfile) } @@ -69,10 +75,23 @@ func (b *Program) Exec(srcfifo bool, flags []string) (*Run, error) { return nil, err } - run.Cmd.Path = b.Path + run.Cmd.Path = p.Path run.Cmd.Args = append(args, flags...) - run.Cmd.Dir = run.Testdir + run.Cmd.Dir = r.Testdir run.Cmd.Start() return run, nil } + +func writeFifo(srcfile string, read io.Reader) { + fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600) + if err != nil { + panic(err) + } + if _, err := io.Copy(fifo, read); err != nil { + panic(err) + } + if err := fifo.Close(); err != nil { + panic(err) + } +} -- cgit v1.2.3