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 func (s *StandaloneSuite) SetUpTest(c *C) {
45 RefreshServiceDiscovery()
48 func pythonDir() string {
50 return fmt.Sprintf("%s/../../python/tests", cwd)
53 func (s *ServerRequiredSuite) SetUpSuite(c *C) {
54 arvadostest.StartKeep(2, false)
57 func (s *ServerRequiredSuite) TearDownSuite(c *C) {
58 arvadostest.StopKeep(2)
61 func (s *ServerRequiredSuite) SetUpTest(c *C) {
62 RefreshServiceDiscovery()
65 func (s *ServerRequiredSuite) TestMakeKeepClient(c *C) {
66 arv, err := arvadosclient.MakeArvadosClient()
67 c.Assert(err, Equals, nil)
69 kc, err := MakeKeepClient(arv)
71 c.Assert(err, Equals, nil)
72 c.Check(len(kc.LocalRoots()), Equals, 2)
73 for _, root := range kc.LocalRoots() {
74 c.Check(root, Matches, "http://localhost:\\d+")
78 func (s *ServerRequiredSuite) TestDefaultStorageClasses(c *C) {
79 arv, err := arvadosclient.MakeArvadosClient()
82 cc, err := arv.ClusterConfig("StorageClasses")
85 c.Assert(cc.(map[string]interface{})["default"], NotNil)
88 c.Assert(kc.DefaultStorageClasses, DeepEquals, []string{"default"})
91 func (s *ServerRequiredSuite) TestDefaultReplications(c *C) {
92 arv, err := arvadosclient.MakeArvadosClient()
95 kc, err := MakeKeepClient(arv)
97 c.Assert(kc.Want_replicas, Equals, 2)
99 arv.DiscoveryDoc["defaultCollectionReplication"] = 3.0
100 kc, err = MakeKeepClient(arv)
102 c.Assert(kc.Want_replicas, Equals, 3)
104 arv.DiscoveryDoc["defaultCollectionReplication"] = 1.0
105 kc, err = MakeKeepClient(arv)
107 c.Assert(kc.Want_replicas, Equals, 1)
110 type StubPutHandler struct {
113 expectAPIToken string
115 expectStorageClass string
116 returnStorageClasses string
118 requests []*http.Request
122 func (sph *StubPutHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
124 sph.requests = append(sph.requests, req)
126 sph.c.Check(req.URL.Path, Equals, "/"+sph.expectPath)
127 sph.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", sph.expectAPIToken))
128 if sph.expectStorageClass != "*" {
129 sph.c.Check(req.Header.Get("X-Keep-Storage-Classes"), Equals, sph.expectStorageClass)
131 body, err := ioutil.ReadAll(req.Body)
132 sph.c.Check(err, Equals, nil)
133 sph.c.Check(body, DeepEquals, []byte(sph.expectBody))
134 resp.Header().Set("X-Keep-Replicas-Stored", "1")
135 if sph.returnStorageClasses != "" {
136 resp.Header().Set("X-Keep-Storage-Classes-Confirmed", sph.returnStorageClasses)
138 resp.WriteHeader(200)
139 sph.handled <- fmt.Sprintf("http://%s", req.Host)
142 func RunFakeKeepServer(st http.Handler) (ks KeepServer) {
144 // If we don't explicitly bind it to localhost, ks.listener.Addr() will
145 // bind to 0.0.0.0 or [::] which is not a valid address for Dial()
146 ks.listener, err = net.ListenTCP("tcp", &net.TCPAddr{IP: []byte{127, 0, 0, 1}, Port: 0})
148 panic("Could not listen on any port")
150 ks.url = fmt.Sprintf("http://%s", ks.listener.Addr().String())
151 go http.Serve(ks.listener, st)
155 func UploadToStubHelper(c *C, st http.Handler, f func(*KeepClient, string,
156 io.ReadCloser, io.WriteCloser, chan uploadStatus)) {
158 ks := RunFakeKeepServer(st)
159 defer ks.listener.Close()
161 arv, _ := arvadosclient.MakeArvadosClient()
162 arv.ApiToken = "abc123"
164 kc, _ := MakeKeepClient(arv)
166 reader, writer := io.Pipe()
167 uploadStatusChan := make(chan uploadStatus)
169 f(kc, ks.url, reader, writer, uploadStatusChan)
172 func (s *StandaloneSuite) TestUploadToStubKeepServer(c *C) {
173 log.Printf("TestUploadToStubKeepServer")
175 st := &StubPutHandler{
177 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
178 expectAPIToken: "abc123",
180 expectStorageClass: "",
181 returnStorageClasses: "default=1",
182 handled: make(chan string),
185 UploadToStubHelper(c, st,
186 func(kc *KeepClient, url string, reader io.ReadCloser, writer io.WriteCloser, uploadStatusChan chan uploadStatus) {
187 go kc.uploadToKeepServer(url, st.expectPath, nil, reader, uploadStatusChan, len("foo"), kc.getRequestID())
189 writer.Write([]byte("foo"))
193 status := <-uploadStatusChan
194 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, map[string]int{"default": 1}, ""})
198 func (s *StandaloneSuite) TestUploadToStubKeepServerBufferReader(c *C) {
199 st := &StubPutHandler{
201 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
202 expectAPIToken: "abc123",
204 expectStorageClass: "",
205 returnStorageClasses: "default=1",
206 handled: make(chan string),
209 UploadToStubHelper(c, st,
210 func(kc *KeepClient, url string, _ io.ReadCloser, _ io.WriteCloser, uploadStatusChan chan uploadStatus) {
211 go kc.uploadToKeepServer(url, st.expectPath, nil, bytes.NewBuffer([]byte("foo")), uploadStatusChan, 3, kc.getRequestID())
215 status := <-uploadStatusChan
216 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, map[string]int{"default": 1}, ""})
220 func (s *StandaloneSuite) TestUploadWithStorageClasses(c *C) {
221 for _, trial := range []struct {
223 expectMap map[string]int
226 {"foo=1", map[string]int{"foo": 1}},
227 {" foo=1 , bar=2 ", map[string]int{"foo": 1, "bar": 2}},
231 st := &StubPutHandler{
233 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
234 expectAPIToken: "abc123",
236 expectStorageClass: "",
237 returnStorageClasses: trial.respHeader,
238 handled: make(chan string),
241 UploadToStubHelper(c, st,
242 func(kc *KeepClient, url string, reader io.ReadCloser, writer io.WriteCloser, uploadStatusChan chan uploadStatus) {
243 go kc.uploadToKeepServer(url, st.expectPath, nil, reader, uploadStatusChan, len("foo"), kc.getRequestID())
245 writer.Write([]byte("foo"))
249 status := <-uploadStatusChan
250 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, trial.expectMap, ""})
255 func (s *StandaloneSuite) TestPutWithStorageClasses(c *C) {
257 for _, trial := range []struct {
259 defaultClasses []string
260 clientClasses []string // clientClasses takes precedence over defaultClasses
261 putClasses []string // putClasses takes precedence over clientClasses
266 {1, []string{"class1"}, nil, nil, 1, 1, true},
267 {2, []string{"class1"}, nil, nil, 1, 2, true},
268 {3, []string{"class1"}, nil, nil, 2, 3, true},
269 {1, []string{"class1", "class2"}, nil, nil, 1, 1, true},
271 // defaultClasses doesn't matter when any of the others is specified.
272 {1, []string{"class1"}, []string{"class1"}, nil, 1, 1, true},
273 {2, []string{"class1"}, []string{"class1"}, nil, 1, 2, true},
274 {3, []string{"class1"}, []string{"class1"}, nil, 2, 3, true},
275 {1, []string{"class1"}, []string{"class1", "class2"}, nil, 1, 1, true},
276 {3, []string{"class1"}, nil, []string{"class1"}, 2, 3, true},
277 {1, []string{"class1"}, nil, []string{"class1", "class2"}, 1, 1, true},
278 {1, []string{"class1"}, []string{"class404"}, []string{"class1", "class2"}, 1, 1, true},
279 {1, []string{"class1"}, []string{"class1"}, []string{"class404", "class2"}, nServers, nServers, false},
280 {nServers*2 + 1, []string{}, []string{"class1"}, nil, nServers, nServers, false},
281 {1, []string{"class1"}, []string{"class404"}, nil, nServers, nServers, false},
282 {1, []string{"class1"}, []string{"class1", "class404"}, nil, nServers, nServers, false},
283 {1, []string{"class1"}, nil, []string{"class1", "class404"}, nServers, nServers, false},
285 // Talking to an older cluster (with no default storage classes advertising)
286 {1, nil, []string{"class1"}, nil, 1, 1, true},
287 {2, nil, []string{"class1"}, nil, 1, 2, true},
288 {3, nil, []string{"class1"}, nil, 2, 3, true},
289 {1, nil, []string{"class1", "class2"}, nil, 1, 1, true},
290 {3, nil, nil, []string{"class1"}, 2, 3, true},
291 {1, nil, nil, []string{"class1", "class2"}, 1, 1, true},
292 {1, nil, []string{"class404"}, []string{"class1", "class2"}, 1, 1, true},
293 {1, nil, []string{"class1"}, []string{"class404", "class2"}, nServers, nServers, false},
294 {nServers*2 + 1, []string{}, []string{"class1"}, nil, nServers, nServers, false},
295 {1, nil, []string{"class404"}, nil, nServers, nServers, false},
296 {1, nil, []string{"class1", "class404"}, nil, nServers, nServers, false},
297 {1, nil, nil, []string{"class1", "class404"}, nServers, nServers, false},
300 st := &StubPutHandler{
302 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
303 expectAPIToken: "abc123",
305 expectStorageClass: "*",
306 returnStorageClasses: "class1=2, class2=2",
307 handled: make(chan string, 100),
309 ks := RunSomeFakeKeepServers(st, nServers)
310 arv, _ := arvadosclient.MakeArvadosClient()
311 kc, _ := MakeKeepClient(arv)
312 kc.Want_replicas = trial.replicas
313 kc.StorageClasses = trial.clientClasses
314 kc.DefaultStorageClasses = trial.defaultClasses
315 arv.ApiToken = "abc123"
316 localRoots := make(map[string]string)
317 writableLocalRoots := make(map[string]string)
318 for i, k := range ks {
319 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
320 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
321 defer k.listener.Close()
323 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
325 _, err := kc.BlockWrite(context.Background(), arvados.BlockWriteOptions{
327 StorageClasses: trial.putClasses,
334 c.Check(len(st.handled) >= trial.minRequests, Equals, true, Commentf("len(st.handled)==%d, trial.minRequests==%d", len(st.handled), trial.minRequests))
335 c.Check(len(st.handled) <= trial.maxRequests, Equals, true, Commentf("len(st.handled)==%d, trial.maxRequests==%d", len(st.handled), trial.maxRequests))
336 if !trial.success && trial.replicas == 1 && c.Check(len(st.requests) >= 2, Equals, true) {
337 // Max concurrency should be 1. First request
338 // should have succeeded for class1. Second
339 // request should only ask for class404.
340 c.Check(st.requests[1].Header.Get("X-Keep-Storage-Classes"), Equals, "class404")
345 type FailHandler struct {
349 func (fh FailHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
350 resp.WriteHeader(500)
351 fh.handled <- fmt.Sprintf("http://%s", req.Host)
354 type FailThenSucceedHandler struct {
357 successhandler http.Handler
361 func (fh *FailThenSucceedHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
362 fh.reqIDs = append(fh.reqIDs, req.Header.Get("X-Request-Id"))
364 resp.WriteHeader(500)
366 fh.handled <- fmt.Sprintf("http://%s", req.Host)
368 fh.successhandler.ServeHTTP(resp, req)
372 type Error404Handler struct {
376 func (fh Error404Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
377 resp.WriteHeader(404)
378 fh.handled <- fmt.Sprintf("http://%s", req.Host)
381 func (s *StandaloneSuite) TestFailedUploadToStubKeepServer(c *C) {
385 hash := "acbd18db4cc2f85cedef654fccc4a4d8"
387 UploadToStubHelper(c, st,
388 func(kc *KeepClient, url string, reader io.ReadCloser,
389 writer io.WriteCloser, uploadStatusChan chan uploadStatus) {
391 go kc.uploadToKeepServer(url, hash, nil, reader, uploadStatusChan, 3, kc.getRequestID())
393 writer.Write([]byte("foo"))
398 status := <-uploadStatusChan
399 c.Check(status.url, Equals, fmt.Sprintf("%s/%s", url, hash))
400 c.Check(status.statusCode, Equals, 500)
404 type KeepServer struct {
405 listener net.Listener
409 func RunSomeFakeKeepServers(st http.Handler, n int) (ks []KeepServer) {
410 ks = make([]KeepServer, n)
412 for i := 0; i < n; i++ {
413 ks[i] = RunFakeKeepServer(st)
419 func (s *StandaloneSuite) TestPutB(c *C) {
420 hash := Md5String("foo")
422 st := &StubPutHandler{
425 expectAPIToken: "abc123",
427 expectStorageClass: "default",
428 returnStorageClasses: "",
429 handled: make(chan string, 5),
432 arv, _ := arvadosclient.MakeArvadosClient()
433 kc, _ := MakeKeepClient(arv)
436 arv.ApiToken = "abc123"
437 localRoots := make(map[string]string)
438 writableLocalRoots := make(map[string]string)
440 ks := RunSomeFakeKeepServers(st, 5)
442 for i, k := range ks {
443 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
444 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
445 defer k.listener.Close()
448 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
450 kc.PutB([]byte("foo"))
452 shuff := NewRootSorter(
453 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
457 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
458 (s1 == shuff[1] && s2 == shuff[0]),
463 func (s *StandaloneSuite) TestPutHR(c *C) {
464 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
466 st := &StubPutHandler{
469 expectAPIToken: "abc123",
471 expectStorageClass: "default",
472 returnStorageClasses: "",
473 handled: make(chan string, 5),
476 arv, _ := arvadosclient.MakeArvadosClient()
477 kc, _ := MakeKeepClient(arv)
480 arv.ApiToken = "abc123"
481 localRoots := make(map[string]string)
482 writableLocalRoots := make(map[string]string)
484 ks := RunSomeFakeKeepServers(st, 5)
486 for i, k := range ks {
487 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
488 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
489 defer k.listener.Close()
492 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
494 reader, writer := io.Pipe()
497 writer.Write([]byte("foo"))
501 kc.PutHR(hash, reader, 3)
503 shuff := NewRootSorter(kc.LocalRoots(), hash).GetSortedRoots()
508 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
509 (s1 == shuff[1] && s2 == shuff[0]),
514 func (s *StandaloneSuite) TestPutWithFail(c *C) {
515 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
517 st := &StubPutHandler{
520 expectAPIToken: "abc123",
522 expectStorageClass: "default",
523 returnStorageClasses: "",
524 handled: make(chan string, 4),
528 make(chan string, 1)}
530 arv, err := arvadosclient.MakeArvadosClient()
532 kc, _ := MakeKeepClient(arv)
535 arv.ApiToken = "abc123"
536 localRoots := make(map[string]string)
537 writableLocalRoots := make(map[string]string)
539 ks1 := RunSomeFakeKeepServers(st, 4)
540 ks2 := RunSomeFakeKeepServers(fh, 1)
542 for i, k := range ks1 {
543 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
544 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
545 defer k.listener.Close()
547 for i, k := range ks2 {
548 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
549 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
550 defer k.listener.Close()
553 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
555 shuff := NewRootSorter(
556 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
559 phash, replicas, err := kc.PutB([]byte("foo"))
563 c.Check(err, Equals, nil)
564 c.Check(phash, Equals, "")
565 c.Check(replicas, Equals, 2)
570 c.Check((s1 == shuff[1] && s2 == shuff[2]) ||
571 (s1 == shuff[2] && s2 == shuff[1]),
576 func (s *StandaloneSuite) TestPutWithTooManyFail(c *C) {
577 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
579 st := &StubPutHandler{
582 expectAPIToken: "abc123",
584 expectStorageClass: "default",
585 returnStorageClasses: "",
586 handled: make(chan string, 1),
590 make(chan string, 4)}
592 arv, err := arvadosclient.MakeArvadosClient()
594 kc, _ := MakeKeepClient(arv)
598 arv.ApiToken = "abc123"
599 localRoots := make(map[string]string)
600 writableLocalRoots := make(map[string]string)
602 ks1 := RunSomeFakeKeepServers(st, 1)
603 ks2 := RunSomeFakeKeepServers(fh, 4)
605 for i, k := range ks1 {
606 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
607 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
608 defer k.listener.Close()
610 for i, k := range ks2 {
611 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
612 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
613 defer k.listener.Close()
616 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
618 _, replicas, err := kc.PutB([]byte("foo"))
620 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
621 c.Check(replicas, Equals, 1)
622 c.Check(<-st.handled, Equals, ks1[0].url)
625 type StubGetHandler struct {
628 expectAPIToken string
633 func (sgh StubGetHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
634 sgh.c.Check(req.URL.Path, Equals, "/"+sgh.expectPath)
635 sgh.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", sgh.expectAPIToken))
636 resp.WriteHeader(sgh.httpStatus)
637 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(sgh.body)))
641 func (s *StandaloneSuite) TestGet(c *C) {
642 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
644 st := StubGetHandler{
651 ks := RunFakeKeepServer(st)
652 defer ks.listener.Close()
654 arv, err := arvadosclient.MakeArvadosClient()
656 kc, _ := MakeKeepClient(arv)
657 arv.ApiToken = "abc123"
658 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
660 r, n, url2, err := kc.Get(hash)
662 c.Check(err, Equals, nil)
663 c.Check(n, Equals, int64(3))
664 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks.url, hash))
666 content, err2 := ioutil.ReadAll(r)
667 c.Check(err2, Equals, nil)
668 c.Check(content, DeepEquals, []byte("foo"))
671 func (s *StandaloneSuite) TestGet404(c *C) {
672 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
674 st := Error404Handler{make(chan string, 1)}
676 ks := RunFakeKeepServer(st)
677 defer ks.listener.Close()
679 arv, err := arvadosclient.MakeArvadosClient()
681 kc, _ := MakeKeepClient(arv)
682 arv.ApiToken = "abc123"
683 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
685 r, n, url2, err := kc.Get(hash)
686 c.Check(err, Equals, BlockNotFound)
687 c.Check(n, Equals, int64(0))
688 c.Check(url2, Equals, "")
689 c.Check(r, Equals, nil)
692 func (s *StandaloneSuite) TestGetEmptyBlock(c *C) {
693 st := Error404Handler{make(chan string, 1)}
695 ks := RunFakeKeepServer(st)
696 defer ks.listener.Close()
698 arv, err := arvadosclient.MakeArvadosClient()
700 kc, _ := MakeKeepClient(arv)
701 arv.ApiToken = "abc123"
702 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
704 r, n, url2, err := kc.Get("d41d8cd98f00b204e9800998ecf8427e+0")
706 c.Check(n, Equals, int64(0))
707 c.Check(url2, Equals, "")
709 buf, err := ioutil.ReadAll(r)
711 c.Check(buf, DeepEquals, []byte{})
714 func (s *StandaloneSuite) TestGetFail(c *C) {
715 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
717 st := FailHandler{make(chan string, 1)}
719 ks := RunFakeKeepServer(st)
720 defer ks.listener.Close()
722 arv, err := arvadosclient.MakeArvadosClient()
724 kc, _ := MakeKeepClient(arv)
725 arv.ApiToken = "abc123"
726 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
729 r, n, url2, err := kc.Get(hash)
730 errNotFound, _ := err.(*ErrNotFound)
731 c.Check(errNotFound, NotNil)
732 c.Check(strings.Contains(errNotFound.Error(), "HTTP 500"), Equals, true)
733 c.Check(errNotFound.Temporary(), Equals, true)
734 c.Check(n, Equals, int64(0))
735 c.Check(url2, Equals, "")
736 c.Check(r, Equals, nil)
739 func (s *StandaloneSuite) TestGetFailRetry(c *C) {
740 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
742 st := &FailThenSucceedHandler{
743 handled: make(chan string, 1),
744 successhandler: StubGetHandler{
751 ks := RunFakeKeepServer(st)
752 defer ks.listener.Close()
754 arv, err := arvadosclient.MakeArvadosClient()
756 kc, _ := MakeKeepClient(arv)
757 arv.ApiToken = "abc123"
758 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
760 r, n, url2, err := kc.Get(hash)
762 c.Check(err, Equals, nil)
763 c.Check(n, Equals, int64(3))
764 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks.url, hash))
766 content, err2 := ioutil.ReadAll(r)
767 c.Check(err2, Equals, nil)
768 c.Check(content, DeepEquals, []byte("foo"))
770 c.Logf("%q", st.reqIDs)
771 c.Assert(len(st.reqIDs) > 1, Equals, true)
772 for _, reqid := range st.reqIDs {
773 c.Check(reqid, Not(Equals), "")
774 c.Check(reqid, Equals, st.reqIDs[0])
778 func (s *StandaloneSuite) TestGetNetError(c *C) {
779 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
781 arv, err := arvadosclient.MakeArvadosClient()
783 kc, _ := MakeKeepClient(arv)
784 arv.ApiToken = "abc123"
785 kc.SetServiceRoots(map[string]string{"x": "http://localhost:62222"}, nil, nil)
787 r, n, url2, err := kc.Get(hash)
788 errNotFound, _ := err.(*ErrNotFound)
789 c.Check(errNotFound, NotNil)
790 c.Check(strings.Contains(errNotFound.Error(), "connection refused"), Equals, true)
791 c.Check(errNotFound.Temporary(), Equals, true)
792 c.Check(n, Equals, int64(0))
793 c.Check(url2, Equals, "")
794 c.Check(r, Equals, nil)
797 func (s *StandaloneSuite) TestGetWithServiceHint(c *C) {
798 uuid := "zzzzz-bi6l4-123451234512345"
799 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
801 // This one shouldn't be used:
802 ks0 := RunFakeKeepServer(StubGetHandler{
808 defer ks0.listener.Close()
809 // This one should be used:
810 ks := RunFakeKeepServer(StubGetHandler{
816 defer ks.listener.Close()
818 arv, err := arvadosclient.MakeArvadosClient()
820 kc, _ := MakeKeepClient(arv)
821 arv.ApiToken = "abc123"
823 map[string]string{"x": ks0.url},
825 map[string]string{uuid: ks.url})
827 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
829 c.Check(err, Equals, nil)
830 c.Check(n, Equals, int64(3))
831 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ks.url, hash+"+K@"+uuid))
833 content, err := ioutil.ReadAll(r)
834 c.Check(err, Equals, nil)
835 c.Check(content, DeepEquals, []byte("foo"))
838 // Use a service hint to fetch from a local disk service, overriding
839 // rendezvous probe order.
840 func (s *StandaloneSuite) TestGetWithLocalServiceHint(c *C) {
841 uuid := "zzzzz-bi6l4-zzzzzzzzzzzzzzz"
842 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
844 // This one shouldn't be used, although it appears first in
845 // rendezvous probe order:
846 ks0 := RunFakeKeepServer(StubGetHandler{
852 defer ks0.listener.Close()
853 // This one should be used:
854 ks := RunFakeKeepServer(StubGetHandler{
860 defer ks.listener.Close()
862 arv, err := arvadosclient.MakeArvadosClient()
864 kc, _ := MakeKeepClient(arv)
865 arv.ApiToken = "abc123"
868 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
869 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
870 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
874 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
875 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
876 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
880 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
882 c.Check(err, Equals, nil)
883 c.Check(n, Equals, int64(3))
884 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ks.url, hash+"+K@"+uuid))
886 content, err := ioutil.ReadAll(r)
887 c.Check(err, Equals, nil)
888 c.Check(content, DeepEquals, []byte("foo"))
891 func (s *StandaloneSuite) TestGetWithServiceHintFailoverToLocals(c *C) {
892 uuid := "zzzzz-bi6l4-123451234512345"
893 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
895 ksLocal := RunFakeKeepServer(StubGetHandler{
901 defer ksLocal.listener.Close()
902 ksGateway := RunFakeKeepServer(StubGetHandler{
906 http.StatusInternalServerError,
908 defer ksGateway.listener.Close()
910 arv, err := arvadosclient.MakeArvadosClient()
912 kc, _ := MakeKeepClient(arv)
913 arv.ApiToken = "abc123"
915 map[string]string{"zzzzz-bi6l4-keepdisk0000000": ksLocal.url},
917 map[string]string{uuid: ksGateway.url})
919 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
920 c.Assert(err, Equals, nil)
922 c.Check(n, Equals, int64(3))
923 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ksLocal.url, hash+"+K@"+uuid))
925 content, err := ioutil.ReadAll(r)
926 c.Check(err, Equals, nil)
927 c.Check(content, DeepEquals, []byte("foo"))
930 type BarHandler struct {
934 func (h BarHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
935 resp.Write([]byte("bar"))
936 h.handled <- fmt.Sprintf("http://%s", req.Host)
939 func (s *StandaloneSuite) TestChecksum(c *C) {
940 foohash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
941 barhash := fmt.Sprintf("%x", md5.Sum([]byte("bar")))
943 st := BarHandler{make(chan string, 1)}
945 ks := RunFakeKeepServer(st)
946 defer ks.listener.Close()
948 arv, err := arvadosclient.MakeArvadosClient()
950 kc, _ := MakeKeepClient(arv)
951 arv.ApiToken = "abc123"
952 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
954 r, n, _, err := kc.Get(barhash)
956 _, err = ioutil.ReadAll(r)
957 c.Check(n, Equals, int64(3))
958 c.Check(err, Equals, nil)
962 r, n, _, err = kc.Get(foohash)
964 _, err = ioutil.ReadAll(r)
965 c.Check(n, Equals, int64(3))
966 c.Check(err, Equals, BadChecksum)
971 func (s *StandaloneSuite) TestGetWithFailures(c *C) {
972 content := []byte("waz")
973 hash := fmt.Sprintf("%x", md5.Sum(content))
975 fh := Error404Handler{
976 make(chan string, 4)}
978 st := StubGetHandler{
985 arv, err := arvadosclient.MakeArvadosClient()
987 kc, _ := MakeKeepClient(arv)
988 arv.ApiToken = "abc123"
989 localRoots := make(map[string]string)
990 writableLocalRoots := make(map[string]string)
992 ks1 := RunSomeFakeKeepServers(st, 1)
993 ks2 := RunSomeFakeKeepServers(fh, 4)
995 for i, k := range ks1 {
996 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
997 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
998 defer k.listener.Close()
1000 for i, k := range ks2 {
1001 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
1002 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
1003 defer k.listener.Close()
1006 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1009 // This test works only if one of the failing services is
1010 // attempted before the succeeding service. Otherwise,
1011 // <-fh.handled below will just hang! (Probe order depends on
1012 // the choice of block content "waz" and the UUIDs of the fake
1013 // servers, so we just tried different strings until we found
1014 // an example that passes this Assert.)
1015 c.Assert(NewRootSorter(localRoots, hash).GetSortedRoots()[0], Not(Equals), ks1[0].url)
1017 r, n, url2, err := kc.Get(hash)
1020 c.Check(err, Equals, nil)
1021 c.Check(n, Equals, int64(3))
1022 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks1[0].url, hash))
1024 readContent, err2 := ioutil.ReadAll(r)
1025 c.Check(err2, Equals, nil)
1026 c.Check(readContent, DeepEquals, content)
1029 func (s *ServerRequiredSuite) TestPutGetHead(c *C) {
1030 content := []byte("TestPutGetHead")
1032 arv, err := arvadosclient.MakeArvadosClient()
1034 kc, err := MakeKeepClient(arv)
1035 c.Assert(err, Equals, nil)
1037 hash := fmt.Sprintf("%x", md5.Sum(content))
1040 n, _, err := kc.Ask(hash)
1041 c.Check(err, Equals, BlockNotFound)
1042 c.Check(n, Equals, int64(0))
1045 hash2, replicas, err := kc.PutB(content)
1046 c.Check(hash2, Matches, fmt.Sprintf(`%s\+%d\b.*`, hash, len(content)))
1047 c.Check(replicas, Equals, 2)
1048 c.Check(err, Equals, nil)
1051 r, n, url2, err := kc.Get(hash)
1052 c.Check(err, Equals, nil)
1053 c.Check(n, Equals, int64(len(content)))
1054 c.Check(url2, Matches, fmt.Sprintf("http://localhost:\\d+/%s", hash))
1056 readContent, err2 := ioutil.ReadAll(r)
1057 c.Check(err2, Equals, nil)
1058 c.Check(readContent, DeepEquals, content)
1061 n, url2, err := kc.Ask(hash)
1062 c.Check(err, Equals, nil)
1063 c.Check(n, Equals, int64(len(content)))
1064 c.Check(url2, Matches, fmt.Sprintf("http://localhost:\\d+/%s", hash))
1067 loc, err := kc.LocalLocator(hash)
1068 c.Check(err, Equals, nil)
1069 c.Assert(len(loc) >= 32, Equals, true)
1070 c.Check(loc[:32], Equals, hash[:32])
1073 content := []byte("the perth county conspiracy")
1074 loc, err := kc.LocalLocator(fmt.Sprintf("%x+%d+Rzaaaa-abcde@12345", md5.Sum(content), len(content)))
1075 c.Check(loc, Equals, "")
1076 c.Check(err, ErrorMatches, `.*HEAD .*\+R.*`)
1077 c.Check(err, ErrorMatches, `.*HTTP 400.*`)
1081 type StubProxyHandler struct {
1085 func (h StubProxyHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1086 resp.Header().Set("X-Keep-Replicas-Stored", "2")
1087 h.handled <- fmt.Sprintf("http://%s", req.Host)
1090 func (s *StandaloneSuite) TestPutProxy(c *C) {
1091 st := StubProxyHandler{make(chan string, 1)}
1093 arv, err := arvadosclient.MakeArvadosClient()
1095 kc, _ := MakeKeepClient(arv)
1097 kc.Want_replicas = 2
1098 arv.ApiToken = "abc123"
1099 localRoots := make(map[string]string)
1100 writableLocalRoots := make(map[string]string)
1102 ks1 := RunSomeFakeKeepServers(st, 1)
1104 for i, k := range ks1 {
1105 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1106 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1107 defer k.listener.Close()
1110 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1112 _, replicas, err := kc.PutB([]byte("foo"))
1115 c.Check(err, Equals, nil)
1116 c.Check(replicas, Equals, 2)
1119 func (s *StandaloneSuite) TestPutProxyInsufficientReplicas(c *C) {
1120 st := StubProxyHandler{make(chan string, 1)}
1122 arv, err := arvadosclient.MakeArvadosClient()
1124 kc, _ := MakeKeepClient(arv)
1126 kc.Want_replicas = 3
1127 arv.ApiToken = "abc123"
1128 localRoots := make(map[string]string)
1129 writableLocalRoots := make(map[string]string)
1131 ks1 := RunSomeFakeKeepServers(st, 1)
1133 for i, k := range ks1 {
1134 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1135 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1136 defer k.listener.Close()
1138 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1140 _, replicas, err := kc.PutB([]byte("foo"))
1143 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
1144 c.Check(replicas, Equals, 2)
1147 func (s *StandaloneSuite) TestMakeLocator(c *C) {
1148 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+3+Aabcde@12345678")
1149 c.Check(err, Equals, nil)
1150 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1151 c.Check(l.Size, Equals, 3)
1152 c.Check(l.Hints, DeepEquals, []string{"3", "Aabcde@12345678"})
1155 func (s *StandaloneSuite) TestMakeLocatorNoHints(c *C) {
1156 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce")
1157 c.Check(err, Equals, nil)
1158 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1159 c.Check(l.Size, Equals, -1)
1160 c.Check(l.Hints, DeepEquals, []string{})
1163 func (s *StandaloneSuite) TestMakeLocatorNoSizeHint(c *C) {
1164 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+Aabcde@12345678")
1165 c.Check(err, Equals, nil)
1166 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1167 c.Check(l.Size, Equals, -1)
1168 c.Check(l.Hints, DeepEquals, []string{"Aabcde@12345678"})
1171 func (s *StandaloneSuite) TestMakeLocatorPreservesUnrecognizedHints(c *C) {
1172 str := "91f372a266fe2bf2823cb8ec7fda31ce+3+Unknown+Kzzzzz+Afoobar"
1173 l, err := MakeLocator(str)
1174 c.Check(err, Equals, nil)
1175 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1176 c.Check(l.Size, Equals, 3)
1177 c.Check(l.Hints, DeepEquals, []string{"3", "Unknown", "Kzzzzz", "Afoobar"})
1178 c.Check(l.String(), Equals, str)
1181 func (s *StandaloneSuite) TestMakeLocatorInvalidInput(c *C) {
1182 _, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31c")
1183 c.Check(err, Equals, InvalidLocatorError)
1186 func (s *StandaloneSuite) TestPutBWant2ReplicasWithOnlyOneWritableLocalRoot(c *C) {
1187 hash := Md5String("foo")
1189 st := &StubPutHandler{
1192 expectAPIToken: "abc123",
1194 expectStorageClass: "default",
1195 returnStorageClasses: "",
1196 handled: make(chan string, 5),
1199 arv, _ := arvadosclient.MakeArvadosClient()
1200 kc, _ := MakeKeepClient(arv)
1202 kc.Want_replicas = 2
1203 arv.ApiToken = "abc123"
1204 localRoots := make(map[string]string)
1205 writableLocalRoots := make(map[string]string)
1207 ks := RunSomeFakeKeepServers(st, 5)
1209 for i, k := range ks {
1210 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1212 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1214 defer k.listener.Close()
1217 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1219 _, replicas, err := kc.PutB([]byte("foo"))
1221 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
1222 c.Check(replicas, Equals, 1)
1224 c.Check(<-st.handled, Equals, localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", 0)])
1227 func (s *StandaloneSuite) TestPutBWithNoWritableLocalRoots(c *C) {
1228 hash := Md5String("foo")
1230 st := &StubPutHandler{
1233 expectAPIToken: "abc123",
1235 expectStorageClass: "",
1236 returnStorageClasses: "",
1237 handled: make(chan string, 5),
1240 arv, _ := arvadosclient.MakeArvadosClient()
1241 kc, _ := MakeKeepClient(arv)
1243 kc.Want_replicas = 2
1244 arv.ApiToken = "abc123"
1245 localRoots := make(map[string]string)
1246 writableLocalRoots := make(map[string]string)
1248 ks := RunSomeFakeKeepServers(st, 5)
1250 for i, k := range ks {
1251 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1252 defer k.listener.Close()
1255 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1257 _, replicas, err := kc.PutB([]byte("foo"))
1259 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
1260 c.Check(replicas, Equals, 0)
1263 type StubGetIndexHandler struct {
1266 expectAPIToken string
1271 func (h StubGetIndexHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1272 h.c.Check(req.URL.Path, Equals, h.expectPath)
1273 h.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", h.expectAPIToken))
1274 resp.WriteHeader(h.httpStatus)
1275 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(h.body)))
1279 func (s *StandaloneSuite) TestGetIndexWithNoPrefix(c *C) {
1280 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1282 st := StubGetIndexHandler{
1287 []byte(hash + "+3 1443559274\n\n")}
1289 ks := RunFakeKeepServer(st)
1290 defer ks.listener.Close()
1292 arv, err := arvadosclient.MakeArvadosClient()
1293 c.Assert(err, IsNil)
1294 kc, err := MakeKeepClient(arv)
1295 c.Assert(err, IsNil)
1296 arv.ApiToken = "abc123"
1297 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1299 r, err := kc.GetIndex("x", "")
1302 content, err2 := ioutil.ReadAll(r)
1303 c.Check(err2, Equals, nil)
1304 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1307 func (s *StandaloneSuite) TestGetIndexWithPrefix(c *C) {
1308 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1310 st := StubGetIndexHandler{
1312 "/index/" + hash[0:3],
1315 []byte(hash + "+3 1443559274\n\n")}
1317 ks := RunFakeKeepServer(st)
1318 defer ks.listener.Close()
1320 arv, err := arvadosclient.MakeArvadosClient()
1322 kc, _ := MakeKeepClient(arv)
1323 arv.ApiToken = "abc123"
1324 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1326 r, err := kc.GetIndex("x", hash[0:3])
1327 c.Assert(err, Equals, nil)
1329 content, err2 := ioutil.ReadAll(r)
1330 c.Check(err2, Equals, nil)
1331 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1334 func (s *StandaloneSuite) TestGetIndexIncomplete(c *C) {
1335 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1337 st := StubGetIndexHandler{
1339 "/index/" + hash[0:3],
1344 ks := RunFakeKeepServer(st)
1345 defer ks.listener.Close()
1347 arv, err := arvadosclient.MakeArvadosClient()
1349 kc, _ := MakeKeepClient(arv)
1350 arv.ApiToken = "abc123"
1351 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1353 _, err = kc.GetIndex("x", hash[0:3])
1354 c.Check(err, Equals, ErrIncompleteIndex)
1357 func (s *StandaloneSuite) TestGetIndexWithNoSuchServer(c *C) {
1358 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1360 st := StubGetIndexHandler{
1362 "/index/" + hash[0:3],
1367 ks := RunFakeKeepServer(st)
1368 defer ks.listener.Close()
1370 arv, err := arvadosclient.MakeArvadosClient()
1372 kc, _ := MakeKeepClient(arv)
1373 arv.ApiToken = "abc123"
1374 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1376 _, err = kc.GetIndex("y", hash[0:3])
1377 c.Check(err, Equals, ErrNoSuchKeepServer)
1380 func (s *StandaloneSuite) TestGetIndexWithNoSuchPrefix(c *C) {
1381 st := StubGetIndexHandler{
1388 ks := RunFakeKeepServer(st)
1389 defer ks.listener.Close()
1391 arv, err := arvadosclient.MakeArvadosClient()
1393 kc, _ := MakeKeepClient(arv)
1394 arv.ApiToken = "abc123"
1395 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1397 r, err := kc.GetIndex("x", "abcd")
1398 c.Check(err, Equals, nil)
1400 content, err2 := ioutil.ReadAll(r)
1401 c.Check(err2, Equals, nil)
1402 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1405 func (s *StandaloneSuite) TestPutBRetry(c *C) {
1406 st := &FailThenSucceedHandler{
1407 handled: make(chan string, 1),
1408 successhandler: &StubPutHandler{
1410 expectPath: Md5String("foo"),
1411 expectAPIToken: "abc123",
1413 expectStorageClass: "default",
1414 returnStorageClasses: "",
1415 handled: make(chan string, 5),
1419 arv, _ := arvadosclient.MakeArvadosClient()
1420 kc, _ := MakeKeepClient(arv)
1422 kc.Want_replicas = 2
1423 arv.ApiToken = "abc123"
1424 localRoots := make(map[string]string)
1425 writableLocalRoots := make(map[string]string)
1427 ks := RunSomeFakeKeepServers(st, 2)
1429 for i, k := range ks {
1430 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1431 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1432 defer k.listener.Close()
1435 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1437 hash, replicas, err := kc.PutB([]byte("foo"))
1439 c.Check(err, Equals, nil)
1440 c.Check(hash, Equals, "")
1441 c.Check(replicas, Equals, 2)
1444 func (s *ServerRequiredSuite) TestMakeKeepClientWithNonDiskTypeService(c *C) {
1445 arv, err := arvadosclient.MakeArvadosClient()
1446 c.Assert(err, Equals, nil)
1448 // Add an additional "testblobstore" keepservice
1449 blobKeepService := make(arvadosclient.Dict)
1450 err = arv.Create("keep_services",
1451 arvadosclient.Dict{"keep_service": arvadosclient.Dict{
1452 "service_host": "localhost",
1453 "service_port": "21321",
1454 "service_type": "testblobstore"}},
1456 c.Assert(err, Equals, nil)
1457 defer func() { arv.Delete("keep_services", blobKeepService["uuid"].(string), nil, nil) }()
1458 RefreshServiceDiscovery()
1460 // Make a keepclient and ensure that the testblobstore is included
1461 kc, err := MakeKeepClient(arv)
1462 c.Assert(err, Equals, nil)
1464 // verify kc.LocalRoots
1465 c.Check(len(kc.LocalRoots()), Equals, 3)
1466 for _, root := range kc.LocalRoots() {
1467 c.Check(root, Matches, "http://localhost:\\d+")
1469 c.Assert(kc.LocalRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1471 // verify kc.GatewayRoots
1472 c.Check(len(kc.GatewayRoots()), Equals, 3)
1473 for _, root := range kc.GatewayRoots() {
1474 c.Check(root, Matches, "http://localhost:\\d+")
1476 c.Assert(kc.GatewayRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1478 // verify kc.WritableLocalRoots
1479 c.Check(len(kc.WritableLocalRoots()), Equals, 3)
1480 for _, root := range kc.WritableLocalRoots() {
1481 c.Check(root, Matches, "http://localhost:\\d+")
1483 c.Assert(kc.WritableLocalRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1485 c.Assert(kc.replicasPerService, Equals, 0)
1486 c.Assert(kc.foundNonDiskSvc, Equals, true)
1487 c.Assert(kc.httpClient().(*http.Client).Timeout, Equals, 300*time.Second)