summaryrefslogtreecommitdiff
path: root/xdelta3/go
diff options
context:
space:
mode:
Diffstat (limited to 'xdelta3/go')
-rw-r--r--xdelta3/go/src/regtest.go105
-rw-r--r--xdelta3/go/src/xdelta/rstream.go60
-rw-r--r--xdelta3/go/src/xdelta/test.go205
3 files changed, 370 insertions, 0 deletions
diff --git a/xdelta3/go/src/regtest.go b/xdelta3/go/src/regtest.go
new file mode 100644
index 0000000..6497166
--- /dev/null
+++ b/xdelta3/go/src/regtest.go
@@ -0,0 +1,105 @@
1package main
2
3import (
4 "errors"
5 "fmt"
6 "io"
7
8 "xdelta"
9)
10
11const (
12 blocksize = 1<<16
13 winsize = 1<<26
14 xdelta3 = "/volume/home/jmacd/src/xdelta-64bithash/xdelta3/build/x86_64-pc-linux-gnu-m64/usize64/xoff64/xdelta3"
15 seed = 1422253499919909358
16)
17
18func smokeTest(r *xdelta.Runner, t *xdelta.TestGroup, p *xdelta.Program) {
19 t.Add(1)
20 target := "Hello world!"
21 source := "Hello world, nice to meet you!"
22
23 run, err := r.Exec(p, true, []string{"-evv"})
24 if err != nil {
25 t.Panic(err)
26 }
27 encodeout := t.Drain(run.Stdout, "encode.stdout")
28 t.Empty(run.Stderr, "encode")
29
30 t.Write("encode.stdin", run.Stdin, []byte(target))
31 t.Write("encode.srcin", run.Srcin, []byte(source))
32
33 if err := run.Cmd.Wait(); err != nil {
34 t.Panic(err)
35 }
36
37 run, err = r.Exec(p, true, []string{"-dvv"})
38 if err != nil {
39 t.Panic(err)
40 }
41
42 decodeout := t.Drain(run.Stdout, "decode.stdout")
43 t.Empty(run.Stderr, "decode")
44
45 t.Write("decode.stdin", run.Stdin, <-encodeout)
46 t.Write("decode.srcin", run.Srcin, []byte(source))
47 decoded := string(<-decodeout)
48 if err := run.Cmd.Wait(); err != nil {
49 t.Panic(err)
50 }
51 if decoded != target {
52 t.Panic(errors.New("It's not working!!!"))
53 }
54 t.Done()
55 fmt.Println("Smoketest pass")
56}
57
58func offsetTest(r *xdelta.Runner, t *xdelta.TestGroup, p *xdelta.Program, offset, bufsize, length int64) {
59 t.Add(1)
60 eargs := []string{"-e", "-1", "-N", fmt.Sprint("-B", bufsize), "-vv", fmt.Sprint("-W", winsize)}
61 enc, err := r.Exec(p, true, eargs)
62 if err != nil {
63 t.Panic(err)
64 }
65 dargs := []string{"-d", fmt.Sprint("-B", bufsize), "-vv", fmt.Sprint("-W", winsize)}
66 dec, err := r.Exec(p, true, dargs)
67 if err != nil {
68 t.Panic(err)
69 }
70
71 read, write := io.Pipe()
72
73 t.Empty(enc.Stderr, "encode")
74 t.Empty(dec.Stderr, "decode")
75
76 t.CopyStreams(enc.Stdout, dec.Stdin)
77 t.CompareStreams(dec.Stdout, read, length)
78
79 // TODO: seems possible to use one WriteRstreams call to generate
80 // the source and target for both encoder and decoder. Why not?
81 xdelta.WriteRstreams(t, seed, offset, length, enc.Srcin, enc. Stdin)
82 xdelta.WriteRstreams(t, seed, offset, length, dec.Srcin, write)
83
84 if err := enc.Cmd.Wait(); err != nil {
85 t.Panic(err)
86 }
87 if err := dec.Cmd.Wait(); err != nil {
88 t.Panic(err)
89 }
90 t.Done()
91}
92
93func main() {
94 r, err := xdelta.NewRunner()
95 if err != nil {
96 panic(err)
97 }
98 defer r.Cleanup()
99
100 prog := &xdelta.Program{xdelta3}
101
102 smokeTest(r, xdelta.NewTestGroup(), prog)
103
104 offsetTest(r, xdelta.NewTestGroup(), prog, 1 << 31, 1 << 32, 1 << 33)
105}
diff --git a/xdelta3/go/src/xdelta/rstream.go b/xdelta3/go/src/xdelta/rstream.go
new file mode 100644
index 0000000..3e7265f
--- /dev/null
+++ b/xdelta3/go/src/xdelta/rstream.go
@@ -0,0 +1,60 @@
1package xdelta
2
3
4import (
5 "io"
6 "math/rand"
7)
8
9const (
10 blocksize = 16380
11)
12
13func WriteRstreams(t *TestGroup, seed, offset, len int64,
14 first, second io.WriteCloser) {
15 go writeOne(t, seed, 0, len, first)
16 go writeOne(t, seed, offset, len, second)
17}
18
19func writeOne(t *TestGroup, seed, offset, len int64, stream io.WriteCloser) error {
20 t.WaitGroup.Add(1)
21 if offset != 0 {
22 // Fill with other random data until the offset
23 if err := writeRand(rand.New(rand.NewSource(^seed)), offset, stream); err != nil {
24 return err
25 }
26 }
27 if err := writeRand(rand.New(rand.NewSource(seed)),
28 len - offset, stream); err != nil {
29 return err
30 }
31 t.WaitGroup.Done()
32 return stream.Close()
33}
34
35func writeRand(r *rand.Rand, len int64, s io.Writer) error {
36 blk := make([]byte, blocksize)
37 for len > 0 {
38 fillRand(r, blk)
39 c := blocksize
40 if len < blocksize {
41 c = int(len)
42 }
43 if _, err := s.Write(blk[0:c]); err != nil {
44 return err
45 }
46 len -= int64(c)
47 }
48 return nil
49}
50
51func fillRand(r *rand.Rand, blk []byte) {
52 for p := 0; p < blocksize; {
53 v := r.Int63()
54 for i := 7; i != 0; i-- {
55 blk[p] = byte(v)
56 p++
57 v >>= 8
58 }
59 }
60}
diff --git a/xdelta3/go/src/xdelta/test.go b/xdelta3/go/src/xdelta/test.go
new file mode 100644
index 0000000..9eb47f6
--- /dev/null
+++ b/xdelta3/go/src/xdelta/test.go
@@ -0,0 +1,205 @@
1package xdelta
2
3import (
4 "bufio"
5 "bytes"
6 "errors"
7 "fmt"
8 "io"
9 "io/ioutil"
10 "os"
11 "os/exec"
12 "path"
13 "sync/atomic"
14 "sync"
15
16 "golang.org/x/sys/unix"
17)
18
19var (
20 tmpDir = "/tmp"
21 srcSeq int64
22)
23
24type Program struct {
25 Path string
26}
27
28type Runner struct {
29 Testdir string
30}
31
32type TestGroup struct {
33 sync.WaitGroup
34}
35
36type Run struct {
37 Cmd exec.Cmd
38 Srcfile string
39 Stdin io.WriteCloser
40 Srcin io.WriteCloser
41 Stdout io.ReadCloser
42 Stderr io.ReadCloser
43}
44
45func (t *TestGroup) Panic(err error) {
46 t.Done() // For the caller
47 t.Wait()
48 panic(err)
49}
50
51func NewTestGroup() *TestGroup {
52 return &TestGroup{}
53}
54
55func (t *TestGroup) Drain(f io.ReadCloser, desc string) <-chan []byte {
56 c := make(chan []byte)
57 go func() {
58 t.Add(1)
59 //fmt.Println("Draining", desc)
60 if b, err := ioutil.ReadAll(f); err != nil {
61 t.Panic(err)
62 } else {
63 //fmt.Println("Draining", desc, "--got it")
64 c <- b
65 }
66 t.Done()
67 }()
68 return c
69}
70
71func (t *TestGroup) Empty(f io.ReadCloser, desc string) {
72 go func() {
73 t.Add(1)
74 s := bufio.NewScanner(f)
75 for s.Scan() {
76 os.Stderr.Write([]byte(fmt.Sprint(desc, ": ", s.Text(), "\n")))
77 }
78 if err := s.Err(); err != nil {
79 t.Panic(err)
80 }
81 t.Done()
82 }()
83}
84
85func (t *TestGroup) Write(what string, f io.WriteCloser, b []byte) {
86 //fmt.Println("Write (", what, ") ", len(b), "bytes")
87 if _, err := f.Write(b); err != nil {
88 t.Panic(errors.New(fmt.Sprint(what, ":", err)))
89 }
90 //fmt.Println("Write (", what, ") closing")
91 if err := f.Close(); err != nil {
92 t.Panic(errors.New(fmt.Sprint(what, ":", err)))
93 }
94}
95
96func (t *TestGroup) CopyStreams(r io.ReadCloser, w io.WriteCloser) {
97 go func() {
98 t.Add(1)
99 _, err := io.Copy(w, r)
100 if err != nil {
101 t.Panic(err)
102 }
103 err = r.Close()
104 if err != nil {
105 t.Panic(err)
106 }
107 err = w.Close()
108 if err != nil {
109 t.Panic(err)
110 }
111 t.Done()
112 }()
113}
114
115func (t *TestGroup) CompareStreams(r1 io.ReadCloser, r2 io.ReadCloser, length int64) {
116 go func() {
117 t.Add(1)
118 b1 := make([]byte, blocksize)
119 b2 := make([]byte, blocksize)
120 var idx int64
121 for length > 0 {
122 c := blocksize
123 if length < blocksize {
124 c = int(length)
125 }
126 if _, err := io.ReadFull(r1, b1[0:c]); err != nil {
127 t.Panic(err)
128 }
129 if _, err := io.ReadFull(r2, b2[0:c]); err != nil {
130 t.Panic(err)
131 }
132 if bytes.Compare(b1[0:c], b2[0:c]) != 0 {
133 fmt.Println("B1 is", string(b1[0:c]))
134 fmt.Println("B2 is", string(b2[0:c]))
135 t.Panic(errors.New(fmt.Sprint("Bytes do not compare at ", idx)))
136 }
137 length -= int64(c)
138 idx += int64(c)
139 }
140 t.Done()
141 }()
142}
143
144func NewRunner() (*Runner, error) {
145 if dir, err := ioutil.TempDir(tmpDir, "xrt"); err != nil {
146 return nil, err
147 } else {
148 return &Runner{dir}, nil
149 }
150}
151
152func (r *Runner) Cleanup() {
153 os.RemoveAll(r.Testdir)
154}
155
156func (r *Runner) Exec(p *Program, srcfifo bool, flags []string) (*Run, error) {
157 var err error
158 run := &Run{}
159 args := []string{p.Path}
160 if srcfifo {
161 num := atomic.AddInt64(&srcSeq, 1)
162 run.Srcfile = path.Join(r.Testdir, fmt.Sprint("source", num))
163 if err = unix.Mkfifo(run.Srcfile, 0600); err != nil {
164 return nil, err
165 }
166 // Because OpenFile blocks on the Fifo until the reader
167 // arrives, a pipe to defer open
168 read, write := io.Pipe()
169 run.Srcin = write
170
171 go writeFifo(run.Srcfile, read)
172 args = append(args, "-s")
173 args = append(args, run.Srcfile)
174 }
175 if run.Stdin, err = run.Cmd.StdinPipe(); err != nil {
176 return nil, err
177 }
178 if run.Stdout, err = run.Cmd.StdoutPipe(); err != nil {
179 return nil, err
180 }
181 if run.Stderr, err = run.Cmd.StderrPipe(); err != nil {
182 return nil, err
183 }
184
185 run.Cmd.Path = p.Path
186 run.Cmd.Args = append(args, flags...)
187 run.Cmd.Dir = r.Testdir
188 run.Cmd.Start()
189
190 return run, nil
191}
192
193func writeFifo(srcfile string, read io.Reader) error {
194 fifo, err := os.OpenFile(srcfile, os.O_WRONLY, 0600)
195 if err != nil {
196 return err
197 }
198 if _, err := io.Copy(fifo, read); err != nil {
199 return err
200 }
201 if err := fifo.Close(); err != nil {
202 return err
203 }
204 return nil
205}