1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
23 "git.arvados.org/arvados.git/sdk/go/arvados"
24 "git.arvados.org/arvados.git/sdk/go/arvadosclient"
25 "git.arvados.org/arvados.git/sdk/go/arvadostest"
29 // Gocheck boilerplate
30 func Test(t *testing.T) {
34 // Gocheck boilerplate
35 var _ = Suite(&ServerRequiredSuite{})
36 var _ = Suite(&StandaloneSuite{})
38 // Tests that require the Keep server running
39 type ServerRequiredSuite struct{}
42 type StandaloneSuite struct{}
44 var origHOME = os.Getenv("HOME")
46 func (s *StandaloneSuite) SetUpTest(c *C) {
47 RefreshServiceDiscovery()
48 // Prevent cache state from leaking between test cases
49 os.Setenv("HOME", c.MkDir())
52 func (s *StandaloneSuite) TearDownTest(c *C) {
53 os.Setenv("HOME", origHOME)
56 func pythonDir() string {
58 return fmt.Sprintf("%s/../../python/tests", cwd)
61 func (s *ServerRequiredSuite) SetUpSuite(c *C) {
62 arvadostest.StartKeep(2, false)
65 func (s *ServerRequiredSuite) TearDownSuite(c *C) {
66 arvadostest.StopKeep(2)
67 os.Setenv("HOME", origHOME)
70 func (s *ServerRequiredSuite) SetUpTest(c *C) {
71 RefreshServiceDiscovery()
72 // Prevent cache state from leaking between test cases
73 os.Setenv("HOME", c.MkDir())
76 func (s *ServerRequiredSuite) TestMakeKeepClient(c *C) {
77 arv, err := arvadosclient.MakeArvadosClient()
80 kc, err := MakeKeepClient(arv)
83 c.Check(len(kc.LocalRoots()), Equals, 2)
84 for _, root := range kc.LocalRoots() {
85 c.Check(root, Matches, "http://localhost:\\d+")
89 func (s *ServerRequiredSuite) TestDefaultStorageClasses(c *C) {
90 arv, err := arvadosclient.MakeArvadosClient()
93 cc, err := arv.ClusterConfig("StorageClasses")
96 c.Assert(cc.(map[string]interface{})["default"], NotNil)
99 c.Assert(kc.DefaultStorageClasses, DeepEquals, []string{"default"})
102 func (s *ServerRequiredSuite) TestDefaultReplications(c *C) {
103 arv, err := arvadosclient.MakeArvadosClient()
106 kc, err := MakeKeepClient(arv)
108 c.Assert(kc.Want_replicas, Equals, 2)
110 arv.DiscoveryDoc["defaultCollectionReplication"] = 3.0
111 kc, err = MakeKeepClient(arv)
113 c.Assert(kc.Want_replicas, Equals, 3)
115 arv.DiscoveryDoc["defaultCollectionReplication"] = 1.0
116 kc, err = MakeKeepClient(arv)
118 c.Assert(kc.Want_replicas, Equals, 1)
121 type StubPutHandler struct {
124 expectAPIToken string
126 expectStorageClass string
127 returnStorageClasses string
129 requests []*http.Request
133 func (sph *StubPutHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
135 sph.requests = append(sph.requests, req)
137 sph.c.Check(req.URL.Path, Equals, "/"+sph.expectPath)
138 sph.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", sph.expectAPIToken))
139 if sph.expectStorageClass != "*" {
140 sph.c.Check(req.Header.Get("X-Keep-Storage-Classes"), Equals, sph.expectStorageClass)
142 body, err := ioutil.ReadAll(req.Body)
143 sph.c.Check(err, IsNil)
144 sph.c.Check(body, DeepEquals, []byte(sph.expectBody))
145 resp.Header().Set("X-Keep-Replicas-Stored", "1")
146 if sph.returnStorageClasses != "" {
147 resp.Header().Set("X-Keep-Storage-Classes-Confirmed", sph.returnStorageClasses)
149 resp.WriteHeader(200)
150 sph.handled <- fmt.Sprintf("http://%s", req.Host)
153 func RunFakeKeepServer(st http.Handler) (ks KeepServer) {
155 // If we don't explicitly bind it to localhost, ks.listener.Addr() will
156 // bind to 0.0.0.0 or [::] which is not a valid address for Dial()
157 ks.listener, err = net.ListenTCP("tcp", &net.TCPAddr{IP: []byte{127, 0, 0, 1}, Port: 0})
159 panic("Could not listen on any port")
161 ks.url = fmt.Sprintf("http://%s", ks.listener.Addr().String())
162 go http.Serve(ks.listener, st)
166 func UploadToStubHelper(c *C, st http.Handler, f func(*KeepClient, string,
167 io.ReadCloser, io.WriteCloser, chan uploadStatus)) {
169 ks := RunFakeKeepServer(st)
170 defer ks.listener.Close()
172 arv, _ := arvadosclient.MakeArvadosClient()
173 arv.ApiToken = "abc123"
175 kc, _ := MakeKeepClient(arv)
177 reader, writer := io.Pipe()
178 uploadStatusChan := make(chan uploadStatus)
180 f(kc, ks.url, reader, writer, uploadStatusChan)
183 func (s *StandaloneSuite) TestUploadToStubKeepServer(c *C) {
184 log.Printf("TestUploadToStubKeepServer")
186 st := &StubPutHandler{
188 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
189 expectAPIToken: "abc123",
191 expectStorageClass: "",
192 returnStorageClasses: "default=1",
193 handled: make(chan string),
196 UploadToStubHelper(c, st,
197 func(kc *KeepClient, url string, reader io.ReadCloser, writer io.WriteCloser, uploadStatusChan chan uploadStatus) {
198 go kc.uploadToKeepServer(url, st.expectPath, nil, reader, uploadStatusChan, len("foo"), kc.getRequestID())
200 writer.Write([]byte("foo"))
204 status := <-uploadStatusChan
205 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, map[string]int{"default": 1}, ""})
209 func (s *StandaloneSuite) TestUploadToStubKeepServerBufferReader(c *C) {
210 st := &StubPutHandler{
212 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
213 expectAPIToken: "abc123",
215 expectStorageClass: "",
216 returnStorageClasses: "default=1",
217 handled: make(chan string),
220 UploadToStubHelper(c, st,
221 func(kc *KeepClient, url string, _ io.ReadCloser, _ io.WriteCloser, uploadStatusChan chan uploadStatus) {
222 go kc.uploadToKeepServer(url, st.expectPath, nil, bytes.NewBuffer([]byte("foo")), uploadStatusChan, 3, kc.getRequestID())
226 status := <-uploadStatusChan
227 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, map[string]int{"default": 1}, ""})
231 func (s *StandaloneSuite) TestUploadWithStorageClasses(c *C) {
232 for _, trial := range []struct {
234 expectMap map[string]int
237 {"foo=1", map[string]int{"foo": 1}},
238 {" foo=1 , bar=2 ", map[string]int{"foo": 1, "bar": 2}},
242 st := &StubPutHandler{
244 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
245 expectAPIToken: "abc123",
247 expectStorageClass: "",
248 returnStorageClasses: trial.respHeader,
249 handled: make(chan string),
252 UploadToStubHelper(c, st,
253 func(kc *KeepClient, url string, reader io.ReadCloser, writer io.WriteCloser, uploadStatusChan chan uploadStatus) {
254 go kc.uploadToKeepServer(url, st.expectPath, nil, reader, uploadStatusChan, len("foo"), kc.getRequestID())
256 writer.Write([]byte("foo"))
260 status := <-uploadStatusChan
261 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, trial.expectMap, ""})
266 func (s *StandaloneSuite) TestPutWithoutStorageClassesClusterSupport(c *C) {
268 for _, trial := range []struct {
270 clientClasses []string
276 // Talking to an older cluster (no default storage classes exported
277 // config) and no other additional storage classes requirements.
278 {1, nil, nil, 1, 1, true},
279 {2, nil, nil, 2, 2, true},
280 {3, nil, nil, 3, 3, true},
281 {nServers*2 + 1, nil, nil, nServers, nServers, false},
283 {1, []string{"class1"}, nil, 1, 1, true},
284 {2, []string{"class1"}, nil, 2, 2, true},
285 {3, []string{"class1"}, nil, 3, 3, true},
286 {1, []string{"class1", "class2"}, nil, 1, 1, true},
287 {nServers*2 + 1, []string{"class1"}, nil, nServers, nServers, false},
289 {1, nil, []string{"class1"}, 1, 1, true},
290 {2, nil, []string{"class1"}, 2, 2, true},
291 {3, nil, []string{"class1"}, 3, 3, true},
292 {1, nil, []string{"class1", "class2"}, 1, 1, true},
293 {nServers*2 + 1, nil, []string{"class1"}, nServers, nServers, false},
296 st := &StubPutHandler{
298 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
299 expectAPIToken: "abc123",
301 expectStorageClass: "*",
302 returnStorageClasses: "", // Simulate old cluster without SC keep support
303 handled: make(chan string, 100),
305 ks := RunSomeFakeKeepServers(st, nServers)
306 arv, _ := arvadosclient.MakeArvadosClient()
307 kc, _ := MakeKeepClient(arv)
308 kc.Want_replicas = trial.replicas
309 kc.StorageClasses = trial.clientClasses
310 kc.DefaultStorageClasses = nil // Simulate an old cluster without SC defaults
311 arv.ApiToken = "abc123"
312 localRoots := make(map[string]string)
313 writableLocalRoots := make(map[string]string)
314 for i, k := range ks {
315 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
316 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
317 defer k.listener.Close()
319 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
321 _, err := kc.BlockWrite(context.Background(), arvados.BlockWriteOptions{
323 StorageClasses: trial.putClasses,
330 c.Check(len(st.handled) >= trial.minRequests, Equals, true, Commentf("len(st.handled)==%d, trial.minRequests==%d", len(st.handled), trial.minRequests))
331 c.Check(len(st.handled) <= trial.maxRequests, Equals, true, Commentf("len(st.handled)==%d, trial.maxRequests==%d", len(st.handled), trial.maxRequests))
332 if trial.clientClasses == nil && trial.putClasses == nil {
333 c.Check(st.requests[0].Header.Get("X-Keep-Storage-Classes"), Equals, "")
338 func (s *StandaloneSuite) TestPutWithStorageClasses(c *C) {
340 for _, trial := range []struct {
342 defaultClasses []string
343 clientClasses []string // clientClasses takes precedence over defaultClasses
344 putClasses []string // putClasses takes precedence over clientClasses
349 {1, []string{"class1"}, nil, nil, 1, 1, true},
350 {2, []string{"class1"}, nil, nil, 1, 2, true},
351 {3, []string{"class1"}, nil, nil, 2, 3, true},
352 {1, []string{"class1", "class2"}, nil, nil, 1, 1, true},
354 // defaultClasses doesn't matter when any of the others is specified.
355 {1, []string{"class1"}, []string{"class1"}, nil, 1, 1, true},
356 {2, []string{"class1"}, []string{"class1"}, nil, 1, 2, true},
357 {3, []string{"class1"}, []string{"class1"}, nil, 2, 3, true},
358 {1, []string{"class1"}, []string{"class1", "class2"}, nil, 1, 1, true},
359 {3, []string{"class1"}, nil, []string{"class1"}, 2, 3, true},
360 {1, []string{"class1"}, nil, []string{"class1", "class2"}, 1, 1, true},
361 {1, []string{"class1"}, []string{"class404"}, []string{"class1", "class2"}, 1, 1, true},
362 {1, []string{"class1"}, []string{"class1"}, []string{"class404", "class2"}, nServers, nServers, false},
363 {nServers*2 + 1, []string{}, []string{"class1"}, nil, nServers, nServers, false},
364 {1, []string{"class1"}, []string{"class404"}, nil, nServers, nServers, false},
365 {1, []string{"class1"}, []string{"class1", "class404"}, nil, nServers, nServers, false},
366 {1, []string{"class1"}, nil, []string{"class1", "class404"}, nServers, nServers, false},
369 st := &StubPutHandler{
371 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
372 expectAPIToken: "abc123",
374 expectStorageClass: "*",
375 returnStorageClasses: "class1=2, class2=2",
376 handled: make(chan string, 100),
378 ks := RunSomeFakeKeepServers(st, nServers)
379 arv, _ := arvadosclient.MakeArvadosClient()
380 kc, _ := MakeKeepClient(arv)
381 kc.Want_replicas = trial.replicas
382 kc.StorageClasses = trial.clientClasses
383 kc.DefaultStorageClasses = trial.defaultClasses
384 arv.ApiToken = "abc123"
385 localRoots := make(map[string]string)
386 writableLocalRoots := make(map[string]string)
387 for i, k := range ks {
388 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
389 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
390 defer k.listener.Close()
392 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
394 _, err := kc.BlockWrite(context.Background(), arvados.BlockWriteOptions{
396 StorageClasses: trial.putClasses,
403 c.Check(len(st.handled) >= trial.minRequests, Equals, true, Commentf("len(st.handled)==%d, trial.minRequests==%d", len(st.handled), trial.minRequests))
404 c.Check(len(st.handled) <= trial.maxRequests, Equals, true, Commentf("len(st.handled)==%d, trial.maxRequests==%d", len(st.handled), trial.maxRequests))
405 if !trial.success && trial.replicas == 1 && c.Check(len(st.requests) >= 2, Equals, true) {
406 // Max concurrency should be 1. First request
407 // should have succeeded for class1. Second
408 // request should only ask for class404.
409 c.Check(st.requests[1].Header.Get("X-Keep-Storage-Classes"), Equals, "class404")
414 type FailHandler struct {
418 func (fh FailHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
419 resp.WriteHeader(500)
420 fh.handled <- fmt.Sprintf("http://%s", req.Host)
423 type FailThenSucceedHandler struct {
426 successhandler http.Handler
430 func (fh *FailThenSucceedHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
431 fh.reqIDs = append(fh.reqIDs, req.Header.Get("X-Request-Id"))
433 resp.WriteHeader(500)
435 fh.handled <- fmt.Sprintf("http://%s", req.Host)
437 fh.successhandler.ServeHTTP(resp, req)
441 type Error404Handler struct {
445 func (fh Error404Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
446 resp.WriteHeader(404)
447 fh.handled <- fmt.Sprintf("http://%s", req.Host)
450 func (s *StandaloneSuite) TestFailedUploadToStubKeepServer(c *C) {
454 hash := "acbd18db4cc2f85cedef654fccc4a4d8"
456 UploadToStubHelper(c, st,
457 func(kc *KeepClient, url string, reader io.ReadCloser,
458 writer io.WriteCloser, uploadStatusChan chan uploadStatus) {
460 go kc.uploadToKeepServer(url, hash, nil, reader, uploadStatusChan, 3, kc.getRequestID())
462 writer.Write([]byte("foo"))
467 status := <-uploadStatusChan
468 c.Check(status.url, Equals, fmt.Sprintf("%s/%s", url, hash))
469 c.Check(status.statusCode, Equals, 500)
473 type KeepServer struct {
474 listener net.Listener
478 func RunSomeFakeKeepServers(st http.Handler, n int) (ks []KeepServer) {
479 ks = make([]KeepServer, n)
481 for i := 0; i < n; i++ {
482 ks[i] = RunFakeKeepServer(st)
488 func (s *StandaloneSuite) TestPutB(c *C) {
489 hash := Md5String("foo")
491 st := &StubPutHandler{
494 expectAPIToken: "abc123",
496 expectStorageClass: "default",
497 returnStorageClasses: "",
498 handled: make(chan string, 5),
501 arv, _ := arvadosclient.MakeArvadosClient()
502 kc, _ := MakeKeepClient(arv)
505 arv.ApiToken = "abc123"
506 localRoots := make(map[string]string)
507 writableLocalRoots := make(map[string]string)
509 ks := RunSomeFakeKeepServers(st, 5)
511 for i, k := range ks {
512 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
513 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
514 defer k.listener.Close()
517 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
519 kc.PutB([]byte("foo"))
521 shuff := NewRootSorter(
522 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
526 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
527 (s1 == shuff[1] && s2 == shuff[0]),
532 func (s *StandaloneSuite) TestPutHR(c *C) {
533 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
535 st := &StubPutHandler{
538 expectAPIToken: "abc123",
540 expectStorageClass: "default",
541 returnStorageClasses: "",
542 handled: make(chan string, 5),
545 arv, _ := arvadosclient.MakeArvadosClient()
546 kc, _ := MakeKeepClient(arv)
549 arv.ApiToken = "abc123"
550 localRoots := make(map[string]string)
551 writableLocalRoots := make(map[string]string)
553 ks := RunSomeFakeKeepServers(st, 5)
555 for i, k := range ks {
556 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
557 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
558 defer k.listener.Close()
561 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
563 reader, writer := io.Pipe()
566 writer.Write([]byte("foo"))
570 kc.PutHR(hash, reader, 3)
572 shuff := NewRootSorter(kc.LocalRoots(), hash).GetSortedRoots()
577 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
578 (s1 == shuff[1] && s2 == shuff[0]),
583 func (s *StandaloneSuite) TestPutWithFail(c *C) {
584 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
586 st := &StubPutHandler{
589 expectAPIToken: "abc123",
591 expectStorageClass: "default",
592 returnStorageClasses: "",
593 handled: make(chan string, 4),
597 make(chan string, 1)}
599 arv, err := arvadosclient.MakeArvadosClient()
601 kc, _ := MakeKeepClient(arv)
604 arv.ApiToken = "abc123"
605 localRoots := make(map[string]string)
606 writableLocalRoots := make(map[string]string)
608 ks1 := RunSomeFakeKeepServers(st, 4)
609 ks2 := RunSomeFakeKeepServers(fh, 1)
611 for i, k := range ks1 {
612 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
613 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
614 defer k.listener.Close()
616 for i, k := range ks2 {
617 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
618 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
619 defer k.listener.Close()
622 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
624 shuff := NewRootSorter(
625 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
628 phash, replicas, err := kc.PutB([]byte("foo"))
633 c.Check(phash, Equals, "")
634 c.Check(replicas, Equals, 2)
639 c.Check((s1 == shuff[1] && s2 == shuff[2]) ||
640 (s1 == shuff[2] && s2 == shuff[1]),
645 func (s *StandaloneSuite) TestPutWithTooManyFail(c *C) {
646 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
648 st := &StubPutHandler{
651 expectAPIToken: "abc123",
653 expectStorageClass: "default",
654 returnStorageClasses: "",
655 handled: make(chan string, 1),
659 make(chan string, 4)}
661 arv, err := arvadosclient.MakeArvadosClient()
663 kc, _ := MakeKeepClient(arv)
667 arv.ApiToken = "abc123"
668 localRoots := make(map[string]string)
669 writableLocalRoots := make(map[string]string)
671 ks1 := RunSomeFakeKeepServers(st, 1)
672 ks2 := RunSomeFakeKeepServers(fh, 4)
674 for i, k := range ks1 {
675 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
676 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
677 defer k.listener.Close()
679 for i, k := range ks2 {
680 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
681 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
682 defer k.listener.Close()
685 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
687 _, replicas, err := kc.PutB([]byte("foo"))
689 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
690 c.Check(replicas, Equals, 1)
691 c.Check(<-st.handled, Equals, ks1[0].url)
694 type StubGetHandler struct {
697 expectAPIToken string
702 func (sgh StubGetHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
703 sgh.c.Check(req.URL.Path, Equals, "/"+sgh.expectPath)
704 sgh.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", sgh.expectAPIToken))
705 resp.WriteHeader(sgh.httpStatus)
706 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(sgh.body)))
710 func (s *StandaloneSuite) TestGet(c *C) {
711 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
713 st := StubGetHandler{
720 ks := RunFakeKeepServer(st)
721 defer ks.listener.Close()
723 arv, err := arvadosclient.MakeArvadosClient()
725 kc, _ := MakeKeepClient(arv)
726 arv.ApiToken = "abc123"
727 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
729 r, n, _, err := kc.Get(hash)
731 c.Check(n, Equals, int64(3))
733 content, err2 := ioutil.ReadAll(r)
735 c.Check(content, DeepEquals, []byte("foo"))
736 c.Check(r.Close(), IsNil)
739 func (s *StandaloneSuite) TestGet404(c *C) {
740 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
742 st := Error404Handler{make(chan string, 1)}
744 ks := RunFakeKeepServer(st)
745 defer ks.listener.Close()
747 arv, err := arvadosclient.MakeArvadosClient()
749 kc, _ := MakeKeepClient(arv)
750 arv.ApiToken = "abc123"
751 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
753 r, n, _, err := kc.Get(hash)
754 c.Check(err, Equals, BlockNotFound)
755 c.Check(n, Equals, int64(0))
759 func (s *StandaloneSuite) TestGetEmptyBlock(c *C) {
760 st := Error404Handler{make(chan string, 1)}
762 ks := RunFakeKeepServer(st)
763 defer ks.listener.Close()
765 arv, err := arvadosclient.MakeArvadosClient()
767 kc, _ := MakeKeepClient(arv)
768 arv.ApiToken = "abc123"
769 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
771 r, n, _, err := kc.Get("d41d8cd98f00b204e9800998ecf8427e+0")
773 c.Check(n, Equals, int64(0))
775 buf, err := ioutil.ReadAll(r)
777 c.Check(buf, DeepEquals, []byte{})
778 c.Check(r.Close(), IsNil)
781 func (s *StandaloneSuite) TestGetFail(c *C) {
782 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
784 st := FailHandler{make(chan string, 1)}
786 ks := RunFakeKeepServer(st)
787 defer ks.listener.Close()
789 arv, err := arvadosclient.MakeArvadosClient()
791 kc, _ := MakeKeepClient(arv)
792 arv.ApiToken = "abc123"
793 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
796 r, n, _, err := kc.Get(hash)
797 errNotFound, _ := err.(*ErrNotFound)
798 if c.Check(errNotFound, NotNil) {
799 c.Check(strings.Contains(errNotFound.Error(), "HTTP 500"), Equals, true)
800 c.Check(errNotFound.Temporary(), Equals, true)
802 c.Check(n, Equals, int64(0))
806 func (s *StandaloneSuite) TestGetFailRetry(c *C) {
807 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
809 st := &FailThenSucceedHandler{
810 handled: make(chan string, 1),
811 successhandler: StubGetHandler{
818 ks := RunFakeKeepServer(st)
819 defer ks.listener.Close()
821 arv, err := arvadosclient.MakeArvadosClient()
823 kc, _ := MakeKeepClient(arv)
824 arv.ApiToken = "abc123"
825 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
827 r, n, _, err := kc.Get(hash)
829 c.Check(n, Equals, int64(3))
831 content, err := ioutil.ReadAll(r)
833 c.Check(content, DeepEquals, []byte("foo"))
834 c.Check(r.Close(), IsNil)
836 c.Logf("%q", st.reqIDs)
837 c.Assert(len(st.reqIDs) > 1, Equals, true)
838 for _, reqid := range st.reqIDs {
839 c.Check(reqid, Not(Equals), "")
840 c.Check(reqid, Equals, st.reqIDs[0])
844 func (s *StandaloneSuite) TestGetNetError(c *C) {
845 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
847 arv, err := arvadosclient.MakeArvadosClient()
849 kc, _ := MakeKeepClient(arv)
850 arv.ApiToken = "abc123"
851 kc.SetServiceRoots(map[string]string{"x": "http://localhost:62222"}, nil, nil)
853 r, n, _, err := kc.Get(hash)
854 errNotFound, _ := err.(*ErrNotFound)
855 if c.Check(errNotFound, NotNil) {
856 c.Check(strings.Contains(errNotFound.Error(), "connection refused"), Equals, true)
857 c.Check(errNotFound.Temporary(), Equals, true)
859 c.Check(n, Equals, int64(0))
863 func (s *StandaloneSuite) TestGetWithServiceHint(c *C) {
864 uuid := "zzzzz-bi6l4-123451234512345"
865 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
867 // This one shouldn't be used:
868 ks0 := RunFakeKeepServer(StubGetHandler{
874 defer ks0.listener.Close()
875 // This one should be used:
876 ks := RunFakeKeepServer(StubGetHandler{
882 defer ks.listener.Close()
884 arv, err := arvadosclient.MakeArvadosClient()
886 kc, _ := MakeKeepClient(arv)
887 arv.ApiToken = "abc123"
889 map[string]string{"x": ks0.url},
891 map[string]string{uuid: ks.url})
893 r, n, _, err := kc.Get(hash + "+K@" + uuid)
895 c.Check(n, Equals, int64(3))
897 content, err := ioutil.ReadAll(r)
899 c.Check(content, DeepEquals, []byte("foo"))
900 c.Check(r.Close(), IsNil)
903 // Use a service hint to fetch from a local disk service, overriding
904 // rendezvous probe order.
905 func (s *StandaloneSuite) TestGetWithLocalServiceHint(c *C) {
906 uuid := "zzzzz-bi6l4-zzzzzzzzzzzzzzz"
907 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
909 // This one shouldn't be used, although it appears first in
910 // rendezvous probe order:
911 ks0 := RunFakeKeepServer(StubGetHandler{
915 http.StatusBadGateway,
917 defer ks0.listener.Close()
918 // This one should be used:
919 ks := RunFakeKeepServer(StubGetHandler{
925 defer ks.listener.Close()
927 arv, err := arvadosclient.MakeArvadosClient()
929 kc, _ := MakeKeepClient(arv)
930 arv.ApiToken = "abc123"
933 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
934 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
935 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
939 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
940 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
941 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
945 r, n, _, err := kc.Get(hash + "+K@" + uuid)
947 c.Check(n, Equals, int64(3))
949 content, err := ioutil.ReadAll(r)
951 c.Check(content, DeepEquals, []byte("foo"))
952 c.Check(r.Close(), IsNil)
955 func (s *StandaloneSuite) TestGetWithServiceHintFailoverToLocals(c *C) {
956 uuid := "zzzzz-bi6l4-123451234512345"
957 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
959 ksLocal := RunFakeKeepServer(StubGetHandler{
965 defer ksLocal.listener.Close()
966 ksGateway := RunFakeKeepServer(StubGetHandler{
970 http.StatusInternalServerError,
972 defer ksGateway.listener.Close()
974 arv, err := arvadosclient.MakeArvadosClient()
976 kc, _ := MakeKeepClient(arv)
977 arv.ApiToken = "abc123"
979 map[string]string{"zzzzz-bi6l4-keepdisk0000000": ksLocal.url},
981 map[string]string{uuid: ksGateway.url})
983 r, n, _, err := kc.Get(hash + "+K@" + uuid)
985 c.Check(n, Equals, int64(3))
987 content, err := ioutil.ReadAll(r)
989 c.Check(content, DeepEquals, []byte("foo"))
990 c.Check(r.Close(), IsNil)
993 type BarHandler struct {
997 func (h BarHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
998 resp.Write([]byte("bar"))
999 h.handled <- fmt.Sprintf("http://%s", req.Host)
1002 func (s *StandaloneSuite) TestChecksum(c *C) {
1003 foohash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
1004 barhash := fmt.Sprintf("%x+3", md5.Sum([]byte("bar")))
1006 st := BarHandler{make(chan string, 1)}
1008 ks := RunFakeKeepServer(st)
1009 defer ks.listener.Close()
1011 arv, err := arvadosclient.MakeArvadosClient()
1013 kc, _ := MakeKeepClient(arv)
1014 arv.ApiToken = "abc123"
1015 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1017 r, n, _, err := kc.Get(barhash)
1018 if c.Check(err, IsNil) {
1019 _, err = ioutil.ReadAll(r)
1020 c.Check(n, Equals, int64(3))
1026 case <-time.After(time.Second):
1027 c.Fatal("timed out")
1030 r, n, _, err = kc.Get(foohash)
1032 buf, readerr := ioutil.ReadAll(r)
1036 c.Check(err, Equals, BadChecksum)
1040 case <-time.After(time.Second):
1041 c.Fatal("timed out")
1045 func (s *StandaloneSuite) TestGetWithFailures(c *C) {
1046 content := []byte("waz")
1047 hash := fmt.Sprintf("%x+3", md5.Sum(content))
1049 fh := Error404Handler{
1050 make(chan string, 4)}
1052 st := StubGetHandler{
1059 arv, err := arvadosclient.MakeArvadosClient()
1061 kc, _ := MakeKeepClient(arv)
1062 arv.ApiToken = "abc123"
1063 localRoots := make(map[string]string)
1064 writableLocalRoots := make(map[string]string)
1066 ks1 := RunSomeFakeKeepServers(st, 1)
1067 ks2 := RunSomeFakeKeepServers(fh, 4)
1069 for i, k := range ks1 {
1070 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1071 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1072 defer k.listener.Close()
1074 for i, k := range ks2 {
1075 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
1076 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
1077 defer k.listener.Close()
1080 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1083 // This test works only if one of the failing services is
1084 // attempted before the succeeding service. Otherwise,
1085 // <-fh.handled below will just hang! (Probe order depends on
1086 // the choice of block content "waz" and the UUIDs of the fake
1087 // servers, so we just tried different strings until we found
1088 // an example that passes this Assert.)
1089 c.Assert(NewRootSorter(localRoots, hash).GetSortedRoots()[0], Not(Equals), ks1[0].url)
1091 r, n, _, err := kc.Get(hash)
1095 case <-time.After(time.Second):
1096 c.Fatal("timed out")
1098 c.Assert(err, IsNil)
1099 c.Check(n, Equals, int64(3))
1101 readContent, err2 := ioutil.ReadAll(r)
1102 c.Check(err2, IsNil)
1103 c.Check(readContent, DeepEquals, content)
1104 c.Check(r.Close(), IsNil)
1107 func (s *ServerRequiredSuite) TestPutGetHead(c *C) {
1108 content := []byte("TestPutGetHead")
1110 arv, err := arvadosclient.MakeArvadosClient()
1112 kc, err := MakeKeepClient(arv)
1113 c.Assert(err, IsNil)
1115 hash := fmt.Sprintf("%x+%d", md5.Sum(content), len(content))
1118 n, _, err := kc.Ask(hash)
1119 c.Check(err, Equals, BlockNotFound)
1120 c.Check(n, Equals, int64(0))
1123 hash2, replicas, err := kc.PutB(content)
1125 c.Check(hash2, Matches, `\Q`+hash+`\E\b.*`)
1126 c.Check(replicas, Equals, 2)
1129 r, n, _, err := kc.Get(hash)
1131 c.Check(n, Equals, int64(len(content)))
1132 if c.Check(r, NotNil) {
1133 readContent, err := ioutil.ReadAll(r)
1135 if c.Check(len(readContent), Equals, len(content)) {
1136 c.Check(readContent, DeepEquals, content)
1138 c.Check(r.Close(), IsNil)
1142 n, url2, err := kc.Ask(hash)
1144 c.Check(n, Equals, int64(len(content)))
1145 c.Check(url2, Matches, "http://localhost:\\d+/\\Q"+hash+"\\E")
1148 loc, err := kc.LocalLocator(hash)
1150 c.Assert(len(loc) >= 32, Equals, true)
1151 c.Check(loc[:32], Equals, hash[:32])
1154 content := []byte("the perth county conspiracy")
1155 loc, err := kc.LocalLocator(fmt.Sprintf("%x+%d+Rzaaaa-abcde@12345", md5.Sum(content), len(content)))
1156 c.Check(loc, Equals, "")
1157 c.Check(err, ErrorMatches, `.*HEAD .*\+R.*`)
1158 c.Check(err, ErrorMatches, `.*HTTP 400.*`)
1162 type StubProxyHandler struct {
1166 func (h StubProxyHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1167 resp.Header().Set("X-Keep-Replicas-Stored", "2")
1168 h.handled <- fmt.Sprintf("http://%s", req.Host)
1171 func (s *StandaloneSuite) TestPutProxy(c *C) {
1172 st := StubProxyHandler{make(chan string, 1)}
1174 arv, err := arvadosclient.MakeArvadosClient()
1176 kc, _ := MakeKeepClient(arv)
1178 kc.Want_replicas = 2
1179 arv.ApiToken = "abc123"
1180 localRoots := make(map[string]string)
1181 writableLocalRoots := make(map[string]string)
1183 ks1 := RunSomeFakeKeepServers(st, 1)
1185 for i, k := range ks1 {
1186 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1187 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1188 defer k.listener.Close()
1191 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1193 _, replicas, err := kc.PutB([]byte("foo"))
1197 c.Check(replicas, Equals, 2)
1200 func (s *StandaloneSuite) TestPutProxyInsufficientReplicas(c *C) {
1201 st := StubProxyHandler{make(chan string, 1)}
1203 arv, err := arvadosclient.MakeArvadosClient()
1205 kc, _ := MakeKeepClient(arv)
1207 kc.Want_replicas = 3
1208 arv.ApiToken = "abc123"
1209 localRoots := make(map[string]string)
1210 writableLocalRoots := make(map[string]string)
1212 ks1 := RunSomeFakeKeepServers(st, 1)
1214 for i, k := range ks1 {
1215 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1216 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1217 defer k.listener.Close()
1219 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1221 _, replicas, err := kc.PutB([]byte("foo"))
1224 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
1225 c.Check(replicas, Equals, 2)
1228 func (s *StandaloneSuite) TestMakeLocator(c *C) {
1229 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+3+Aabcde@12345678")
1231 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1232 c.Check(l.Size, Equals, 3)
1233 c.Check(l.Hints, DeepEquals, []string{"3", "Aabcde@12345678"})
1236 func (s *StandaloneSuite) TestMakeLocatorNoHints(c *C) {
1237 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce")
1239 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1240 c.Check(l.Size, Equals, -1)
1241 c.Check(l.Hints, DeepEquals, []string{})
1244 func (s *StandaloneSuite) TestMakeLocatorNoSizeHint(c *C) {
1245 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+Aabcde@12345678")
1247 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1248 c.Check(l.Size, Equals, -1)
1249 c.Check(l.Hints, DeepEquals, []string{"Aabcde@12345678"})
1252 func (s *StandaloneSuite) TestMakeLocatorPreservesUnrecognizedHints(c *C) {
1253 str := "91f372a266fe2bf2823cb8ec7fda31ce+3+Unknown+Kzzzzz+Afoobar"
1254 l, err := MakeLocator(str)
1256 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1257 c.Check(l.Size, Equals, 3)
1258 c.Check(l.Hints, DeepEquals, []string{"3", "Unknown", "Kzzzzz", "Afoobar"})
1259 c.Check(l.String(), Equals, str)
1262 func (s *StandaloneSuite) TestMakeLocatorInvalidInput(c *C) {
1263 _, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31c")
1264 c.Check(err, Equals, InvalidLocatorError)
1267 func (s *StandaloneSuite) TestPutBWant2ReplicasWithOnlyOneWritableLocalRoot(c *C) {
1268 hash := Md5String("foo")
1270 st := &StubPutHandler{
1273 expectAPIToken: "abc123",
1275 expectStorageClass: "default",
1276 returnStorageClasses: "",
1277 handled: make(chan string, 5),
1280 arv, _ := arvadosclient.MakeArvadosClient()
1281 kc, _ := MakeKeepClient(arv)
1283 kc.Want_replicas = 2
1284 arv.ApiToken = "abc123"
1285 localRoots := make(map[string]string)
1286 writableLocalRoots := make(map[string]string)
1288 ks := RunSomeFakeKeepServers(st, 5)
1290 for i, k := range ks {
1291 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1293 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1295 defer k.listener.Close()
1298 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1300 _, replicas, err := kc.PutB([]byte("foo"))
1302 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
1303 c.Check(replicas, Equals, 1)
1305 c.Check(<-st.handled, Equals, localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", 0)])
1308 func (s *StandaloneSuite) TestPutBWithNoWritableLocalRoots(c *C) {
1309 hash := Md5String("foo")
1311 st := &StubPutHandler{
1314 expectAPIToken: "abc123",
1316 expectStorageClass: "",
1317 returnStorageClasses: "",
1318 handled: make(chan string, 5),
1321 arv, _ := arvadosclient.MakeArvadosClient()
1322 kc, _ := MakeKeepClient(arv)
1324 kc.Want_replicas = 2
1325 arv.ApiToken = "abc123"
1326 localRoots := make(map[string]string)
1327 writableLocalRoots := make(map[string]string)
1329 ks := RunSomeFakeKeepServers(st, 5)
1331 for i, k := range ks {
1332 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1333 defer k.listener.Close()
1336 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1338 _, replicas, err := kc.PutB([]byte("foo"))
1340 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
1341 c.Check(replicas, Equals, 0)
1344 type StubGetIndexHandler struct {
1347 expectAPIToken string
1352 func (h StubGetIndexHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1353 h.c.Check(req.URL.Path, Equals, h.expectPath)
1354 h.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", h.expectAPIToken))
1355 resp.WriteHeader(h.httpStatus)
1356 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(h.body)))
1360 func (s *StandaloneSuite) TestGetIndexWithNoPrefix(c *C) {
1361 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
1363 st := StubGetIndexHandler{
1368 []byte(hash + " 1443559274\n\n")}
1370 ks := RunFakeKeepServer(st)
1371 defer ks.listener.Close()
1373 arv, err := arvadosclient.MakeArvadosClient()
1374 c.Assert(err, IsNil)
1375 kc, err := MakeKeepClient(arv)
1376 c.Assert(err, IsNil)
1377 arv.ApiToken = "abc123"
1378 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1380 r, err := kc.GetIndex("x", "")
1383 content, err2 := ioutil.ReadAll(r)
1384 c.Check(err2, IsNil)
1385 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1388 func (s *StandaloneSuite) TestGetIndexWithPrefix(c *C) {
1389 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
1391 st := StubGetIndexHandler{
1393 "/index/" + hash[0:3],
1396 []byte(hash + " 1443559274\n\n")}
1398 ks := RunFakeKeepServer(st)
1399 defer ks.listener.Close()
1401 arv, err := arvadosclient.MakeArvadosClient()
1403 kc, _ := MakeKeepClient(arv)
1404 arv.ApiToken = "abc123"
1405 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1407 r, err := kc.GetIndex("x", hash[0:3])
1408 c.Assert(err, IsNil)
1410 content, err2 := ioutil.ReadAll(r)
1411 c.Check(err2, IsNil)
1412 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1415 func (s *StandaloneSuite) TestGetIndexIncomplete(c *C) {
1416 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
1418 st := StubGetIndexHandler{
1420 "/index/" + hash[0:3],
1425 ks := RunFakeKeepServer(st)
1426 defer ks.listener.Close()
1428 arv, err := arvadosclient.MakeArvadosClient()
1430 kc, _ := MakeKeepClient(arv)
1431 arv.ApiToken = "abc123"
1432 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1434 _, err = kc.GetIndex("x", hash[0:3])
1435 c.Check(err, Equals, ErrIncompleteIndex)
1438 func (s *StandaloneSuite) TestGetIndexWithNoSuchServer(c *C) {
1439 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("foo")))
1441 st := StubGetIndexHandler{
1443 "/index/" + hash[0:3],
1448 ks := RunFakeKeepServer(st)
1449 defer ks.listener.Close()
1451 arv, err := arvadosclient.MakeArvadosClient()
1453 kc, _ := MakeKeepClient(arv)
1454 arv.ApiToken = "abc123"
1455 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1457 _, err = kc.GetIndex("y", hash[0:3])
1458 c.Check(err, Equals, ErrNoSuchKeepServer)
1461 func (s *StandaloneSuite) TestGetIndexWithNoSuchPrefix(c *C) {
1462 st := StubGetIndexHandler{
1469 ks := RunFakeKeepServer(st)
1470 defer ks.listener.Close()
1472 arv, err := arvadosclient.MakeArvadosClient()
1474 kc, _ := MakeKeepClient(arv)
1475 arv.ApiToken = "abc123"
1476 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1478 r, err := kc.GetIndex("x", "abcd")
1481 content, err2 := ioutil.ReadAll(r)
1482 c.Check(err2, IsNil)
1483 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1486 func (s *StandaloneSuite) TestPutBRetry(c *C) {
1487 st := &FailThenSucceedHandler{
1488 handled: make(chan string, 1),
1489 successhandler: &StubPutHandler{
1491 expectPath: Md5String("foo"),
1492 expectAPIToken: "abc123",
1494 expectStorageClass: "default",
1495 returnStorageClasses: "",
1496 handled: make(chan string, 5),
1500 arv, _ := arvadosclient.MakeArvadosClient()
1501 kc, _ := MakeKeepClient(arv)
1503 kc.Want_replicas = 2
1504 arv.ApiToken = "abc123"
1505 localRoots := make(map[string]string)
1506 writableLocalRoots := make(map[string]string)
1508 ks := RunSomeFakeKeepServers(st, 2)
1510 for i, k := range ks {
1511 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1512 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1513 defer k.listener.Close()
1516 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1518 hash, replicas, err := kc.PutB([]byte("foo"))
1521 c.Check(hash, Equals, "")
1522 c.Check(replicas, Equals, 2)
1525 func (s *ServerRequiredSuite) TestMakeKeepClientWithNonDiskTypeService(c *C) {
1526 arv, err := arvadosclient.MakeArvadosClient()
1527 c.Assert(err, IsNil)
1529 // Add an additional "testblobstore" keepservice
1530 blobKeepService := make(arvadosclient.Dict)
1531 err = arv.Create("keep_services",
1532 arvadosclient.Dict{"keep_service": arvadosclient.Dict{
1533 "service_host": "localhost",
1534 "service_port": "21321",
1535 "service_type": "testblobstore"}},
1537 c.Assert(err, IsNil)
1538 defer func() { arv.Delete("keep_services", blobKeepService["uuid"].(string), nil, nil) }()
1539 RefreshServiceDiscovery()
1541 // Make a keepclient and ensure that the testblobstore is included
1542 kc, err := MakeKeepClient(arv)
1543 c.Assert(err, IsNil)
1545 // verify kc.LocalRoots
1546 c.Check(len(kc.LocalRoots()), Equals, 3)
1547 for _, root := range kc.LocalRoots() {
1548 c.Check(root, Matches, "http://localhost:\\d+")
1550 c.Assert(kc.LocalRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1552 // verify kc.GatewayRoots
1553 c.Check(len(kc.GatewayRoots()), Equals, 3)
1554 for _, root := range kc.GatewayRoots() {
1555 c.Check(root, Matches, "http://localhost:\\d+")
1557 c.Assert(kc.GatewayRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1559 // verify kc.WritableLocalRoots
1560 c.Check(len(kc.WritableLocalRoots()), Equals, 3)
1561 for _, root := range kc.WritableLocalRoots() {
1562 c.Check(root, Matches, "http://localhost:\\d+")
1564 c.Assert(kc.WritableLocalRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1566 c.Assert(kc.replicasPerService, Equals, 0)
1567 c.Assert(kc.foundNonDiskSvc, Equals, true)
1568 c.Assert(kc.httpClient().(*http.Client).Timeout, Equals, 300*time.Second)