blob: 97ac9061c5d3bc2a86e1564864a4c7959a9deef5 [file] [log] [blame]
Robert Kroeger586bcb92015-01-14 17:56:21 -08001package impl_test
Jiri Simsab04fbb22014-06-27 17:38:04 -07002
3import (
4 "bytes"
5 "crypto/md5"
6 "encoding/hex"
Bogdan Capritae783dcc2014-11-04 14:16:55 -08007 "fmt"
Bogdan Capritae783dcc2014-11-04 14:16:55 -08008 "net"
9 "net/http"
Robin Thellendc5856f62014-11-17 10:30:54 -080010 "reflect"
Jiri Simsab04fbb22014-06-27 17:38:04 -070011 "testing"
Jiri Simsa01cf9372014-06-30 09:49:55 -070012
Robert Kroeger8d7a0ef2015-01-14 17:38:40 -080013 "v.io/core/veyron2"
Matt Rosencrantzf541b772015-01-13 07:58:59 -080014 "v.io/core/veyron2/context"
Jiri Simsa764efb72014-12-25 20:57:03 -080015 "v.io/core/veyron2/naming"
Jiri Simsa764efb72014-12-25 20:57:03 -080016 "v.io/core/veyron2/services/mgmt/repository"
17 verror "v.io/core/veyron2/verror2"
18 "v.io/core/veyron2/vlog"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070019
Jiri Simsa764efb72014-12-25 20:57:03 -080020 "v.io/core/veyron/lib/testutil"
Robert Kroeger586bcb92015-01-14 17:56:21 -080021 _ "v.io/core/veyron/profiles/static"
22 "v.io/core/veyron/services/mgmt/binary/impl"
23 mgmttest "v.io/core/veyron/services/mgmt/lib/testutil"
Jiri Simsab04fbb22014-06-27 17:38:04 -070024)
25
26const (
Jiri Simsab04fbb22014-06-27 17:38:04 -070027 veyronPrefix = "veyron_binary_repository"
28)
29
Matt Rosencrantzf541b772015-01-13 07:58:59 -080030var gctx *context.T
Robert Kroeger8d7a0ef2015-01-14 17:38:40 -080031var globalCancel context.CancelFunc
Jiri Simsab04fbb22014-06-27 17:38:04 -070032
Jiri Simsab04fbb22014-06-27 17:38:04 -070033// startServer starts the binary repository server.
Robin Thellendc5856f62014-11-17 10:30:54 -080034func startServer(t *testing.T, depth int) (repository.BinaryClientMethods, string, string, func()) {
Jiri Simsab04fbb22014-06-27 17:38:04 -070035 // Setup the root of the binary repository.
Robert Kroeger586bcb92015-01-14 17:56:21 -080036 rootDir, cleanup := mgmttest.SetupRootDir(t, "bindir")
37 prepDirectory(t, rootDir)
38
Jiri Simsab04fbb22014-06-27 17:38:04 -070039 // Setup and start the binary repository server.
Robert Kroeger586bcb92015-01-14 17:56:21 -080040 server, endpoint := mgmttest.NewServer(gctx)
41
Bogdan Capritae783dcc2014-11-04 14:16:55 -080042 listener, err := net.Listen("tcp", "127.0.0.1:0")
43 if err != nil {
44 t.Fatal(err)
45 }
Robert Kroeger586bcb92015-01-14 17:56:21 -080046 state, err := impl.NewState(rootDir, listener.Addr().String(), depth)
Jiri Simsa432cc2e2014-12-08 15:53:38 -080047 if err != nil {
48 t.Fatalf("NewState(%v, %v) failed: %v", rootDir, listener.Addr().String(), depth, err)
49 }
Bogdan Capritae783dcc2014-11-04 14:16:55 -080050 go func() {
Robert Kroeger586bcb92015-01-14 17:56:21 -080051 if err := http.Serve(listener, http.FileServer(impl.NewHTTPRoot(state))); err != nil {
Bogdan Capritae783dcc2014-11-04 14:16:55 -080052 vlog.Fatalf("Serve() failed: %v", err)
53 }
54 }()
Robert Kroeger8d7a0ef2015-01-14 17:38:40 -080055 dispatcher, err := impl.NewDispatcher(veyron2.GetPrincipal(gctx), state)
56 if err != nil {
57 t.Fatalf("NewDispatcher failed: %v", err)
58 }
Bogdan Capritaeed1c472014-07-02 14:44:54 -070059 dontPublishName := ""
Cosmos Nicolaou92dba582014-11-05 17:24:10 -080060 if err := server.ServeDispatcher(dontPublishName, dispatcher); err != nil {
Bogdan Capritaeed1c472014-07-02 14:44:54 -070061 t.Fatalf("Serve(%q) failed: %v", dontPublishName, err)
Jiri Simsa661ebbc2014-07-01 13:53:27 -070062 }
Robert Kroeger586bcb92015-01-14 17:56:21 -080063 name := naming.JoinAddressName(endpoint, "test")
Todd Wang702385a2014-11-07 01:54:08 -080064 binary := repository.BinaryClient(name)
Robert Kroeger586bcb92015-01-14 17:56:21 -080065 return binary, endpoint, fmt.Sprintf("http://%s/test", listener.Addr()), func() {
Jiri Simsab04fbb22014-06-27 17:38:04 -070066 // Shutdown the binary repository server.
67 if err := server.Stop(); err != nil {
68 t.Fatalf("Stop() failed: %v", err)
69 }
Robert Kroeger586bcb92015-01-14 17:56:21 -080070 cleanup()
Jiri Simsab04fbb22014-06-27 17:38:04 -070071 }
72}
73
74// TestHierarchy checks that the binary repository works correctly for
75// all possible valid values of the depth used for the directory
76// hierarchy that stores binary objects in the local file system.
77func TestHierarchy(t *testing.T) {
78 for i := 0; i < md5.Size; i++ {
Robin Thellendc5856f62014-11-17 10:30:54 -080079 binary, ep, _, cleanup := startServer(t, i)
Jiri Simsab04fbb22014-06-27 17:38:04 -070080 defer cleanup()
Robert Kroeger586bcb92015-01-14 17:56:21 -080081 data := testData()
82
Jiri Simsab04fbb22014-06-27 17:38:04 -070083 // Test the binary repository interface.
Matt Rosencrantzf541b772015-01-13 07:58:59 -080084 if err := binary.Create(gctx, 1, repository.MediaInfo{Type: "application/octet-stream"}); err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -070085 t.Fatalf("Create() failed: %v", err)
86 }
Robert Kroeger586bcb92015-01-14 17:56:21 -080087 if streamErr, err := invokeUpload(t, gctx, binary, data, 0); streamErr != nil || err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -070088 t.FailNow()
89 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -080090 parts, _, err := binary.Stat(gctx)
Jiri Simsab04fbb22014-06-27 17:38:04 -070091 if err != nil {
92 t.Fatalf("Stat() failed: %v", err)
93 }
94 h := md5.New()
95 h.Write(data)
96 checksum := hex.EncodeToString(h.Sum(nil))
97 if expected, got := checksum, parts[0].Checksum; expected != got {
98 t.Fatalf("Unexpected checksum: expected %v, got %v", expected, got)
99 }
100 if expected, got := len(data), int(parts[0].Size); expected != got {
101 t.Fatalf("Unexpected size: expected %v, got %v", expected, got)
102 }
Robert Kroeger586bcb92015-01-14 17:56:21 -0800103 output, streamErr, err := invokeDownload(t, gctx, binary, 0)
Jiri Simsa518ef152014-08-08 18:07:55 -0700104 if streamErr != nil || err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700105 t.FailNow()
106 }
107 if bytes.Compare(output, data) != 0 {
108 t.Fatalf("Unexpected output: expected %v, got %v", data, output)
109 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800110 results, err := testutil.GlobName(gctx, naming.JoinAddressName(ep, ""), "...")
Robin Thellendc5856f62014-11-17 10:30:54 -0800111 if err != nil {
112 t.Fatalf("GlobName failed: %v", err)
113 }
114 if expected := []string{"", "test"}; !reflect.DeepEqual(results, expected) {
115 t.Errorf("Unexpected results: expected %q, got %q", expected, results)
116 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800117 if err := binary.Delete(gctx); err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700118 t.Fatalf("Delete() failed: %v", err)
119 }
120 }
121}
122
123// TestMultiPart checks that the binary repository supports multi-part
124// uploads and downloads ranging the number of parts the test binary
125// consists of.
126func TestMultiPart(t *testing.T) {
127 for length := 2; length < 5; length++ {
Robin Thellendc5856f62014-11-17 10:30:54 -0800128 binary, _, _, cleanup := startServer(t, 2)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700129 defer cleanup()
130 // Create <length> chunks of up to 4MB of random bytes.
131 data := make([][]byte, length)
132 for i := 0; i < length; i++ {
Robert Kroeger586bcb92015-01-14 17:56:21 -0800133 data[i] = testData()
Jiri Simsab04fbb22014-06-27 17:38:04 -0700134 }
135 // Test the binary repository interface.
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800136 if err := binary.Create(gctx, int32(length), repository.MediaInfo{Type: "application/octet-stream"}); err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700137 t.Fatalf("Create() failed: %v", err)
138 }
139 for i := 0; i < length; i++ {
Robert Kroeger586bcb92015-01-14 17:56:21 -0800140 if streamErr, err := invokeUpload(t, gctx, binary, data[i], int32(i)); streamErr != nil || err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700141 t.FailNow()
142 }
143 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800144 parts, _, err := binary.Stat(gctx)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700145 if err != nil {
146 t.Fatalf("Stat() failed: %v", err)
147 }
Jiri Simsab04fbb22014-06-27 17:38:04 -0700148 for i := 0; i < length; i++ {
149 hpart := md5.New()
Robert Kroeger586bcb92015-01-14 17:56:21 -0800150 output, streamErr, err := invokeDownload(t, gctx, binary, int32(i))
Jiri Simsa518ef152014-08-08 18:07:55 -0700151 if streamErr != nil || err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700152 t.FailNow()
153 }
154 if bytes.Compare(output, data[i]) != 0 {
155 t.Fatalf("Unexpected output: expected %v, got %v", data[i], output)
156 }
Jiri Simsab04fbb22014-06-27 17:38:04 -0700157 hpart.Write(data[i])
158 checksum := hex.EncodeToString(hpart.Sum(nil))
159 if expected, got := checksum, parts[i].Checksum; expected != got {
160 t.Fatalf("Unexpected checksum: expected %v, got %v", expected, got)
161 }
162 if expected, got := len(data[i]), int(parts[i].Size); expected != got {
163 t.Fatalf("Unexpected size: expected %v, got %v", expected, got)
164 }
165 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800166 if err := binary.Delete(gctx); err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700167 t.Fatalf("Delete() failed: %v", err)
168 }
169 }
170}
171
172// TestResumption checks that the binary interface supports upload
173// resumption ranging the number of parts the uploaded binary consists
174// of.
175func TestResumption(t *testing.T) {
176 for length := 2; length < 5; length++ {
Robin Thellendc5856f62014-11-17 10:30:54 -0800177 binary, _, _, cleanup := startServer(t, 2)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700178 defer cleanup()
179 // Create <length> chunks of up to 4MB of random bytes.
180 data := make([][]byte, length)
181 for i := 0; i < length; i++ {
Robert Kroeger586bcb92015-01-14 17:56:21 -0800182 data[i] = testData()
Jiri Simsab04fbb22014-06-27 17:38:04 -0700183 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800184 if err := binary.Create(gctx, int32(length), repository.MediaInfo{Type: "application/octet-stream"}); err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700185 t.Fatalf("Create() failed: %v", err)
186 }
187 // Simulate a flaky upload client that keeps uploading parts until
188 // finished.
189 for {
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800190 parts, _, err := binary.Stat(gctx)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700191 if err != nil {
192 t.Fatalf("Stat() failed: %v", err)
193 }
194 finished := true
195 for _, part := range parts {
Robert Kroeger586bcb92015-01-14 17:56:21 -0800196 finished = finished && (part != impl.MissingPart)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700197 }
198 if finished {
199 break
200 }
201 for i := 0; i < length; i++ {
Jiri Simsa01cf9372014-06-30 09:49:55 -0700202 fail := testutil.Rand.Intn(2)
Robert Kroeger586bcb92015-01-14 17:56:21 -0800203 if parts[i] == impl.MissingPart && fail != 0 {
204 if streamErr, err := invokeUpload(t, gctx, binary, data[i], int32(i)); streamErr != nil || err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700205 t.FailNow()
206 }
207 }
208 }
209 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800210 if err := binary.Delete(gctx); err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700211 t.Fatalf("Delete() failed: %v", err)
212 }
213 }
214}
215
216// TestErrors checks that the binary interface correctly reports errors.
217func TestErrors(t *testing.T) {
Robin Thellendc5856f62014-11-17 10:30:54 -0800218 binary, _, _, cleanup := startServer(t, 2)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700219 defer cleanup()
Bogdan Capritae783dcc2014-11-04 14:16:55 -0800220 const length = 2
Jiri Simsab04fbb22014-06-27 17:38:04 -0700221 data := make([][]byte, length)
222 for i := 0; i < length; i++ {
Robert Kroeger586bcb92015-01-14 17:56:21 -0800223 data[i] = testData()
224 for j := 0; j < len(data[i]); j++ {
Jiri Simsa01cf9372014-06-30 09:49:55 -0700225 data[i][j] = byte(testutil.Rand.Int())
Jiri Simsab04fbb22014-06-27 17:38:04 -0700226 }
227 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800228 if err := binary.Create(gctx, int32(length), repository.MediaInfo{Type: "application/octet-stream"}); err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700229 t.Fatalf("Create() failed: %v", err)
230 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800231 if err := binary.Create(gctx, int32(length), repository.MediaInfo{Type: "application/octet-stream"}); err == nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700232 t.Fatalf("Create() did not fail when it should have")
Mike Burrowsd65df962014-12-17 10:01:19 -0800233 } else if want := verror.Exist.ID; !verror.Is(err, want) {
Jiri Simsa518ef152014-08-08 18:07:55 -0700234 t.Fatalf("Unexpected error: %v, expected error id %v", err, want)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700235 }
Robert Kroeger586bcb92015-01-14 17:56:21 -0800236 if streamErr, err := invokeUpload(t, gctx, binary, data[0], 0); streamErr != nil || err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700237 t.Fatalf("Upload() failed: %v", err)
238 }
Robert Kroeger586bcb92015-01-14 17:56:21 -0800239 if _, err := invokeUpload(t, gctx, binary, data[0], 0); err == nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700240 t.Fatalf("Upload() did not fail when it should have")
Mike Burrowsd65df962014-12-17 10:01:19 -0800241 } else if want := verror.Exist.ID; !verror.Is(err, want) {
Jiri Simsa518ef152014-08-08 18:07:55 -0700242 t.Fatalf("Unexpected error: %v, expected error id %v", err, want)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700243 }
Robert Kroeger586bcb92015-01-14 17:56:21 -0800244 if _, _, err := invokeDownload(t, gctx, binary, 1); err == nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700245 t.Fatalf("Download() did not fail when it should have")
Mike Burrowsd65df962014-12-17 10:01:19 -0800246 } else if want := verror.NoExist.ID; !verror.Is(err, want) {
Jiri Simsa518ef152014-08-08 18:07:55 -0700247 t.Fatalf("Unexpected error: %v, expected error id %v", err, want)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700248 }
Robert Kroeger586bcb92015-01-14 17:56:21 -0800249 if streamErr, err := invokeUpload(t, gctx, binary, data[1], 1); streamErr != nil || err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700250 t.Fatalf("Upload() failed: %v", err)
251 }
Robert Kroeger586bcb92015-01-14 17:56:21 -0800252 if _, streamErr, err := invokeDownload(t, gctx, binary, 0); streamErr != nil || err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700253 t.Fatalf("Download() failed: %v", err)
254 }
Bogdan Capritae783dcc2014-11-04 14:16:55 -0800255 // Upload/Download on a part number that's outside the range set forth in
256 // Create should fail.
257 for _, part := range []int32{-1, length} {
Robert Kroeger586bcb92015-01-14 17:56:21 -0800258 if _, err := invokeUpload(t, gctx, binary, []byte("dummy"), part); err == nil {
Bogdan Capritae783dcc2014-11-04 14:16:55 -0800259 t.Fatalf("Upload() did not fail when it should have")
Robert Kroeger586bcb92015-01-14 17:56:21 -0800260 } else if want := impl.ErrInvalidPart.ID; !verror.Is(err, want) {
Bogdan Capritae783dcc2014-11-04 14:16:55 -0800261 t.Fatalf("Unexpected error: %v, expected error id %v", err, want)
262 }
Robert Kroeger586bcb92015-01-14 17:56:21 -0800263 if _, _, err := invokeDownload(t, gctx, binary, part); err == nil {
Bogdan Capritae783dcc2014-11-04 14:16:55 -0800264 t.Fatalf("Download() did not fail when it should have")
Robert Kroeger586bcb92015-01-14 17:56:21 -0800265 } else if want := impl.ErrInvalidPart.ID; !verror.Is(err, want) {
Bogdan Capritae783dcc2014-11-04 14:16:55 -0800266 t.Fatalf("Unexpected error: %v, expected error id %v", err, want)
267 }
268 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800269 if err := binary.Delete(gctx); err != nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700270 t.Fatalf("Delete() failed: %v", err)
271 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800272 if err := binary.Delete(gctx); err == nil {
Jiri Simsab04fbb22014-06-27 17:38:04 -0700273 t.Fatalf("Delete() did not fail when it should have")
Mike Burrowsd65df962014-12-17 10:01:19 -0800274 } else if want := verror.NoExist.ID; !verror.Is(err, want) {
Jiri Simsa518ef152014-08-08 18:07:55 -0700275 t.Fatalf("Unexpected error: %v, expected error id %v", err, want)
Jiri Simsab04fbb22014-06-27 17:38:04 -0700276 }
277}
Robin Thellendc5856f62014-11-17 10:30:54 -0800278
279func TestGlob(t *testing.T) {
280 _, ep, _, cleanup := startServer(t, 2)
281 defer cleanup()
Robert Kroeger586bcb92015-01-14 17:56:21 -0800282 data := testData()
Robin Thellendc5856f62014-11-17 10:30:54 -0800283
284 objects := []string{"foo", "bar", "hello world", "a/b/c"}
285 for _, obj := range objects {
286 name := naming.JoinAddressName(ep, obj)
287 binary := repository.BinaryClient(name)
288
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800289 if err := binary.Create(gctx, 1, repository.MediaInfo{Type: "application/octet-stream"}); err != nil {
Robin Thellendc5856f62014-11-17 10:30:54 -0800290 t.Fatalf("Create() failed: %v", err)
291 }
Robert Kroeger586bcb92015-01-14 17:56:21 -0800292 if streamErr, err := invokeUpload(t, gctx, binary, data, 0); streamErr != nil || err != nil {
Robin Thellendc5856f62014-11-17 10:30:54 -0800293 t.FailNow()
294 }
295 }
Matt Rosencrantzf541b772015-01-13 07:58:59 -0800296 results, err := testutil.GlobName(gctx, naming.JoinAddressName(ep, ""), "...")
Robin Thellendc5856f62014-11-17 10:30:54 -0800297 if err != nil {
298 t.Fatalf("GlobName failed: %v", err)
299 }
300 expected := []string{"", "a", "a/b", "a/b/c", "bar", "foo", "hello world"}
301 if !reflect.DeepEqual(results, expected) {
302 t.Errorf("Unexpected results: expected %q, got %q", expected, results)
303 }
304}