blob: 08c69af43dd8210be8cb4a6ffd796d7c35619a33 [file] [log] [blame]
Jiri Simsab04fbb22014-06-27 17:38:04 -07001package impl
2
3import (
4 "bytes"
5 "crypto/md5"
6 "encoding/hex"
7 "io"
8 "io/ioutil"
Jiri Simsab04fbb22014-06-27 17:38:04 -07009 "os"
10 "path/filepath"
Jiri Simsab04fbb22014-06-27 17:38:04 -070011 "testing"
Jiri Simsa01cf9372014-06-30 09:49:55 -070012
13 "veyron/lib/testutil"
Jiri Simsab04fbb22014-06-27 17:38:04 -070014
15 "veyron2/naming"
16 "veyron2/rt"
17 "veyron2/services/mgmt/repository"
18 "veyron2/vlog"
19)
20
21const (
Jiri Simsab04fbb22014-06-27 17:38:04 -070022 veyronPrefix = "veyron_binary_repository"
23)
24
Jiri Simsab04fbb22014-06-27 17:38:04 -070025func init() {
26 rt.Init()
Jiri Simsab04fbb22014-06-27 17:38:04 -070027}
28
29// invokeUpload invokes the Upload RPC using the given client binary
30// <binary> and streams the given binary <binary> to it.
31func invokeUpload(t *testing.T, binary repository.Binary, data []byte, part int32) error {
32 stream, err := binary.Upload(rt.R().NewContext(), part)
33 if err != nil {
34 t.Errorf("Upload() failed: %v", err)
35 return err
36 }
37 if err := stream.Send(data); err != nil {
38 if err := stream.Finish(); err != nil {
39 t.Logf("Finish() failed: %v", err)
40 }
41 t.Logf("Send() failed: %v", err)
42 return err
43 }
44 if err := stream.CloseSend(); err != nil {
45 if err := stream.Finish(); err != nil {
46 t.Logf("Finish() failed: %v", err)
47 }
48 t.Logf("CloseSend() failed: %v", err)
49 return err
50 }
51 if err := stream.Finish(); err != nil {
52 t.Logf("Finish() failed: %v", err)
53 return err
54 }
55 return nil
56}
57
58// invokeDownload invokes the Download RPC using the given client binary
59// <binary> and streams binary from to it.
60func invokeDownload(t *testing.T, binary repository.Binary, part int32) ([]byte, error) {
61 stream, err := binary.Download(rt.R().NewContext(), part)
62 if err != nil {
63 t.Errorf("Download() failed: %v", err)
64 return nil, err
65 }
66 output := make([]byte, 0)
67 for {
68 bytes, err := stream.Recv()
69 if err != nil && err != io.EOF {
70 if err := stream.Finish(); err != nil {
71 t.Logf("Finish() failed: %v", err)
72 }
73 t.Logf("Recv() failed: %v", err)
74 return nil, err
75 }
76 if err == io.EOF {
77 break
78 }
79 output = append(output, bytes...)
80 }
81 if err := stream.Finish(); err != nil {
82 t.Logf("Finish() failed: %v", err)
83 return nil, err
84 }
85 return output, nil
86}
87
Jiri Simsab04fbb22014-06-27 17:38:04 -070088// startServer starts the binary repository server.
89func startServer(t *testing.T, depth int) (repository.Binary, func()) {
90 // Setup the root of the binary repository.
91 root, err := ioutil.TempDir("", veyronPrefix)
92 if err != nil {
93 t.Fatalf("TempDir() failed: %v", err)
94 }
95 path, perm := filepath.Join(root, VersionFile), os.FileMode(0600)
96 if err := ioutil.WriteFile(path, []byte(Version), perm); err != nil {
97 vlog.Fatalf("WriteFile(%v, %v, %v) failed: %v", path, Version, perm, err)
98 }
99 // Setup and start the binary repository server.
100 server, err := rt.R().NewServer()
101 if err != nil {
102 t.Fatalf("NewServer() failed: %v", err)
103 }
104 dispatcher, err := NewDispatcher(root, depth, nil)
105 if err != nil {
106 t.Fatalf("NewDispatcher(%v, %v, %v) failed: %v", root, depth, nil, err)
107 }
108 suffix := ""
109 if err := server.Register(suffix, dispatcher); err != nil {
110 t.Fatalf("Register(%v, %v) failed: %v", suffix, dispatcher, err)
111 }
112 protocol, hostname := "tcp", "localhost:0"
113 endpoint, err := server.Listen(protocol, hostname)
114 if err != nil {
115 t.Fatalf("Listen(%v, %v) failed: %v", protocol, hostname, err)
116 }
117 name := naming.JoinAddressName(endpoint.String(), "//test")
118 binary, err := repository.BindBinary(name)
119 if err != nil {
120 t.Fatalf("BindRepository() failed: %v", err)
121 }
122 return binary, func() {
123 // Shutdown the binary repository server.
124 if err := server.Stop(); err != nil {
125 t.Fatalf("Stop() failed: %v", err)
126 }
127 if err := os.Remove(path); err != nil {
128 t.Fatalf("Remove(%v) failed: %v", path, err)
129 }
130 // Check that any directories and files that were created to
131 // represent the binary objects have been garbage collected.
132 if err := os.Remove(root); err != nil {
133 t.Fatalf("Remove(%v) failed: %v", root, err)
134 }
135 }
136}
137
138// TestHierarchy checks that the binary repository works correctly for
139// all possible valid values of the depth used for the directory
140// hierarchy that stores binary objects in the local file system.
141func TestHierarchy(t *testing.T) {
142 for i := 0; i < md5.Size; i++ {
143 binary, cleanup := startServer(t, i)
144 defer cleanup()
145 // Create up to 4MB of random bytes.
Jiri Simsa01cf9372014-06-30 09:49:55 -0700146 size := testutil.Rand.Intn(1000 * bufferLength)
147 data := testutil.RandomBytes(size)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700148 // Test the binary repository interface.
149 if err := binary.Create(rt.R().NewContext(), 1); err != nil {
150 t.Fatalf("Create() failed: %v", err)
151 }
152 if err := invokeUpload(t, binary, data, 0); err != nil {
153 t.FailNow()
154 }
155 parts, err := binary.Stat(rt.R().NewContext())
156 if err != nil {
157 t.Fatalf("Stat() failed: %v", err)
158 }
159 h := md5.New()
160 h.Write(data)
161 checksum := hex.EncodeToString(h.Sum(nil))
162 if expected, got := checksum, parts[0].Checksum; expected != got {
163 t.Fatalf("Unexpected checksum: expected %v, got %v", expected, got)
164 }
165 if expected, got := len(data), int(parts[0].Size); expected != got {
166 t.Fatalf("Unexpected size: expected %v, got %v", expected, got)
167 }
168 output, err := invokeDownload(t, binary, 0)
169 if err != nil {
170 t.FailNow()
171 }
172 if bytes.Compare(output, data) != 0 {
173 t.Fatalf("Unexpected output: expected %v, got %v", data, output)
174 }
175 if err := binary.Delete(rt.R().NewContext()); err != nil {
176 t.Fatalf("Delete() failed: %v", err)
177 }
178 }
179}
180
181// TestMultiPart checks that the binary repository supports multi-part
182// uploads and downloads ranging the number of parts the test binary
183// consists of.
184func TestMultiPart(t *testing.T) {
185 for length := 2; length < 5; length++ {
186 binary, cleanup := startServer(t, 2)
187 defer cleanup()
188 // Create <length> chunks of up to 4MB of random bytes.
189 data := make([][]byte, length)
190 for i := 0; i < length; i++ {
Jiri Simsa01cf9372014-06-30 09:49:55 -0700191 size := testutil.Rand.Intn(1000 * bufferLength)
192 data[i] = testutil.RandomBytes(size)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700193 }
194 // Test the binary repository interface.
195 if err := binary.Create(rt.R().NewContext(), int32(length)); err != nil {
196 t.Fatalf("Create() failed: %v", err)
197 }
198 for i := 0; i < length; i++ {
199 if err := invokeUpload(t, binary, data[i], int32(i)); err != nil {
200 t.FailNow()
201 }
202 }
203 parts, err := binary.Stat(rt.R().NewContext())
204 if err != nil {
205 t.Fatalf("Stat() failed: %v", err)
206 }
207 h := md5.New()
208 for i := 0; i < length; i++ {
209 hpart := md5.New()
210 output, err := invokeDownload(t, binary, int32(i))
211 if err != nil {
212 t.FailNow()
213 }
214 if bytes.Compare(output, data[i]) != 0 {
215 t.Fatalf("Unexpected output: expected %v, got %v", data[i], output)
216 }
217 h.Write(data[i])
218 hpart.Write(data[i])
219 checksum := hex.EncodeToString(hpart.Sum(nil))
220 if expected, got := checksum, parts[i].Checksum; expected != got {
221 t.Fatalf("Unexpected checksum: expected %v, got %v", expected, got)
222 }
223 if expected, got := len(data[i]), int(parts[i].Size); expected != got {
224 t.Fatalf("Unexpected size: expected %v, got %v", expected, got)
225 }
226 }
227 if err := binary.Delete(rt.R().NewContext()); err != nil {
228 t.Fatalf("Delete() failed: %v", err)
229 }
230 }
231}
232
233// TestResumption checks that the binary interface supports upload
234// resumption ranging the number of parts the uploaded binary consists
235// of.
236func TestResumption(t *testing.T) {
237 for length := 2; length < 5; length++ {
238 binary, cleanup := startServer(t, 2)
239 defer cleanup()
240 // Create <length> chunks of up to 4MB of random bytes.
241 data := make([][]byte, length)
242 for i := 0; i < length; i++ {
Jiri Simsa01cf9372014-06-30 09:49:55 -0700243 size := testutil.Rand.Intn(1000 * bufferLength)
244 data[i] = testutil.RandomBytes(size)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700245 }
246 if err := binary.Create(rt.R().NewContext(), int32(length)); err != nil {
247 t.Fatalf("Create() failed: %v", err)
248 }
249 // Simulate a flaky upload client that keeps uploading parts until
250 // finished.
251 for {
252 parts, err := binary.Stat(rt.R().NewContext())
253 if err != nil {
254 t.Fatalf("Stat() failed: %v", err)
255 }
256 finished := true
257 for _, part := range parts {
258 finished = finished && (part != MissingPart)
259 }
260 if finished {
261 break
262 }
263 for i := 0; i < length; i++ {
Jiri Simsa01cf9372014-06-30 09:49:55 -0700264 fail := testutil.Rand.Intn(2)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700265 if parts[i] == MissingPart && fail != 0 {
266 if err := invokeUpload(t, binary, data[i], int32(i)); err != nil {
267 t.FailNow()
268 }
269 }
270 }
271 }
272 if err := binary.Delete(rt.R().NewContext()); err != nil {
273 t.Fatalf("Delete() failed: %v", err)
274 }
275 }
276}
277
278// TestErrors checks that the binary interface correctly reports errors.
279func TestErrors(t *testing.T) {
280 binary, cleanup := startServer(t, 2)
281 defer cleanup()
282 length := 2
283 data := make([][]byte, length)
284 for i := 0; i < length; i++ {
Jiri Simsa01cf9372014-06-30 09:49:55 -0700285 size := testutil.Rand.Intn(1000 * bufferLength)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700286 data[i] = make([]byte, size)
287 for j := 0; j < size; j++ {
Jiri Simsa01cf9372014-06-30 09:49:55 -0700288 data[i][j] = byte(testutil.Rand.Int())
Jiri Simsab04fbb22014-06-27 17:38:04 -0700289 }
290 }
291 if err := binary.Create(rt.R().NewContext(), int32(length)); err != nil {
292 t.Fatalf("Create() failed: %v", err)
293 }
294 if err := binary.Create(rt.R().NewContext(), int32(length)); err == nil {
295 t.Fatalf("Create() did not fail when it should have")
296 }
297 if err := invokeUpload(t, binary, data[0], 0); err != nil {
298 t.Fatalf("Upload() failed: %v", err)
299 }
300 if err := invokeUpload(t, binary, data[0], 0); err == nil {
301 t.Fatalf("Upload() did not fail when it should have")
302 }
303 if _, err := invokeDownload(t, binary, 1); err == nil {
304 t.Fatalf("Download() did not fail when it should have")
305 }
306 if err := invokeUpload(t, binary, data[1], 1); err != nil {
307 t.Fatalf("Upload() failed: %v", err)
308 }
309 if _, err := invokeDownload(t, binary, 0); err != nil {
310 t.Fatalf("Download() failed: %v", err)
311 }
312 if err := binary.Delete(rt.R().NewContext()); err != nil {
313 t.Fatalf("Delete() failed: %v", err)
314 }
315 if err := binary.Delete(rt.R().NewContext()); err == nil {
316 t.Fatalf("Delete() did not fail when it should have")
317 }
318}