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) TestPutWithoutStorageClassesClusterSupport(c *C) {
257 for _, trial := range []struct {
259 clientClasses []string
265 // Talking to an older cluster (no default storage classes exported
266 // config) and no other additional storage classes requirements.
267 {1, nil, nil, 1, 1, true},
268 {2, nil, nil, 2, 2, true},
269 {3, nil, nil, 3, 3, true},
270 {nServers*2 + 1, nil, nil, nServers, nServers, false},
272 {1, []string{"class1"}, nil, 1, 1, true},
273 {2, []string{"class1"}, nil, 2, 2, true},
274 {3, []string{"class1"}, nil, 3, 3, true},
275 {1, []string{"class1", "class2"}, nil, 1, 1, true},
276 {nServers*2 + 1, []string{"class1"}, nil, nServers, nServers, false},
278 {1, nil, []string{"class1"}, 1, 1, true},
279 {2, nil, []string{"class1"}, 2, 2, true},
280 {3, nil, []string{"class1"}, 3, 3, true},
281 {1, nil, []string{"class1", "class2"}, 1, 1, true},
282 {nServers*2 + 1, nil, []string{"class1"}, nServers, nServers, false},
285 st := &StubPutHandler{
287 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
288 expectAPIToken: "abc123",
290 expectStorageClass: "*",
291 returnStorageClasses: "", // Simulate old cluster without SC keep support
292 handled: make(chan string, 100),
294 ks := RunSomeFakeKeepServers(st, nServers)
295 arv, _ := arvadosclient.MakeArvadosClient()
296 kc, _ := MakeKeepClient(arv)
297 kc.Want_replicas = trial.replicas
298 kc.StorageClasses = trial.clientClasses
299 kc.DefaultStorageClasses = nil // Simulate an old cluster without SC defaults
300 arv.ApiToken = "abc123"
301 localRoots := make(map[string]string)
302 writableLocalRoots := make(map[string]string)
303 for i, k := range ks {
304 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
305 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
306 defer k.listener.Close()
308 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
310 _, err := kc.BlockWrite(context.Background(), arvados.BlockWriteOptions{
312 StorageClasses: trial.putClasses,
319 c.Check(len(st.handled) >= trial.minRequests, Equals, true, Commentf("len(st.handled)==%d, trial.minRequests==%d", len(st.handled), trial.minRequests))
320 c.Check(len(st.handled) <= trial.maxRequests, Equals, true, Commentf("len(st.handled)==%d, trial.maxRequests==%d", len(st.handled), trial.maxRequests))
321 if trial.clientClasses == nil && trial.putClasses == nil {
322 c.Check(st.requests[0].Header.Get("X-Keep-Storage-Classes"), Equals, "")
327 func (s *StandaloneSuite) TestPutWithStorageClasses(c *C) {
329 for _, trial := range []struct {
331 defaultClasses []string
332 clientClasses []string // clientClasses takes precedence over defaultClasses
333 putClasses []string // putClasses takes precedence over clientClasses
338 {1, []string{"class1"}, nil, nil, 1, 1, true},
339 {2, []string{"class1"}, nil, nil, 1, 2, true},
340 {3, []string{"class1"}, nil, nil, 2, 3, true},
341 {1, []string{"class1", "class2"}, nil, nil, 1, 1, true},
343 // defaultClasses doesn't matter when any of the others is specified.
344 {1, []string{"class1"}, []string{"class1"}, nil, 1, 1, true},
345 {2, []string{"class1"}, []string{"class1"}, nil, 1, 2, true},
346 {3, []string{"class1"}, []string{"class1"}, nil, 2, 3, true},
347 {1, []string{"class1"}, []string{"class1", "class2"}, nil, 1, 1, true},
348 {3, []string{"class1"}, nil, []string{"class1"}, 2, 3, true},
349 {1, []string{"class1"}, nil, []string{"class1", "class2"}, 1, 1, true},
350 {1, []string{"class1"}, []string{"class404"}, []string{"class1", "class2"}, 1, 1, true},
351 {1, []string{"class1"}, []string{"class1"}, []string{"class404", "class2"}, nServers, nServers, false},
352 {nServers*2 + 1, []string{}, []string{"class1"}, nil, nServers, nServers, false},
353 {1, []string{"class1"}, []string{"class404"}, nil, nServers, nServers, false},
354 {1, []string{"class1"}, []string{"class1", "class404"}, nil, nServers, nServers, false},
355 {1, []string{"class1"}, nil, []string{"class1", "class404"}, nServers, nServers, false},
358 st := &StubPutHandler{
360 expectPath: "acbd18db4cc2f85cedef654fccc4a4d8",
361 expectAPIToken: "abc123",
363 expectStorageClass: "*",
364 returnStorageClasses: "class1=2, class2=2",
365 handled: make(chan string, 100),
367 ks := RunSomeFakeKeepServers(st, nServers)
368 arv, _ := arvadosclient.MakeArvadosClient()
369 kc, _ := MakeKeepClient(arv)
370 kc.Want_replicas = trial.replicas
371 kc.StorageClasses = trial.clientClasses
372 kc.DefaultStorageClasses = trial.defaultClasses
373 arv.ApiToken = "abc123"
374 localRoots := make(map[string]string)
375 writableLocalRoots := make(map[string]string)
376 for i, k := range ks {
377 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
378 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
379 defer k.listener.Close()
381 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
383 _, err := kc.BlockWrite(context.Background(), arvados.BlockWriteOptions{
385 StorageClasses: trial.putClasses,
392 c.Check(len(st.handled) >= trial.minRequests, Equals, true, Commentf("len(st.handled)==%d, trial.minRequests==%d", len(st.handled), trial.minRequests))
393 c.Check(len(st.handled) <= trial.maxRequests, Equals, true, Commentf("len(st.handled)==%d, trial.maxRequests==%d", len(st.handled), trial.maxRequests))
394 if !trial.success && trial.replicas == 1 && c.Check(len(st.requests) >= 2, Equals, true) {
395 // Max concurrency should be 1. First request
396 // should have succeeded for class1. Second
397 // request should only ask for class404.
398 c.Check(st.requests[1].Header.Get("X-Keep-Storage-Classes"), Equals, "class404")
403 type FailHandler struct {
407 func (fh FailHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
408 resp.WriteHeader(500)
409 fh.handled <- fmt.Sprintf("http://%s", req.Host)
412 type FailThenSucceedHandler struct {
415 successhandler http.Handler
419 func (fh *FailThenSucceedHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
420 fh.reqIDs = append(fh.reqIDs, req.Header.Get("X-Request-Id"))
422 resp.WriteHeader(500)
424 fh.handled <- fmt.Sprintf("http://%s", req.Host)
426 fh.successhandler.ServeHTTP(resp, req)
430 type Error404Handler struct {
434 func (fh Error404Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
435 resp.WriteHeader(404)
436 fh.handled <- fmt.Sprintf("http://%s", req.Host)
439 func (s *StandaloneSuite) TestFailedUploadToStubKeepServer(c *C) {
443 hash := "acbd18db4cc2f85cedef654fccc4a4d8"
445 UploadToStubHelper(c, st,
446 func(kc *KeepClient, url string, reader io.ReadCloser,
447 writer io.WriteCloser, uploadStatusChan chan uploadStatus) {
449 go kc.uploadToKeepServer(url, hash, nil, reader, uploadStatusChan, 3, kc.getRequestID())
451 writer.Write([]byte("foo"))
456 status := <-uploadStatusChan
457 c.Check(status.url, Equals, fmt.Sprintf("%s/%s", url, hash))
458 c.Check(status.statusCode, Equals, 500)
462 type KeepServer struct {
463 listener net.Listener
467 func RunSomeFakeKeepServers(st http.Handler, n int) (ks []KeepServer) {
468 ks = make([]KeepServer, n)
470 for i := 0; i < n; i++ {
471 ks[i] = RunFakeKeepServer(st)
477 func (s *StandaloneSuite) TestPutB(c *C) {
478 hash := Md5String("foo")
480 st := &StubPutHandler{
483 expectAPIToken: "abc123",
485 expectStorageClass: "default",
486 returnStorageClasses: "",
487 handled: make(chan string, 5),
490 arv, _ := arvadosclient.MakeArvadosClient()
491 kc, _ := MakeKeepClient(arv)
494 arv.ApiToken = "abc123"
495 localRoots := make(map[string]string)
496 writableLocalRoots := make(map[string]string)
498 ks := RunSomeFakeKeepServers(st, 5)
500 for i, k := range ks {
501 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
502 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
503 defer k.listener.Close()
506 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
508 kc.PutB([]byte("foo"))
510 shuff := NewRootSorter(
511 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
515 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
516 (s1 == shuff[1] && s2 == shuff[0]),
521 func (s *StandaloneSuite) TestPutHR(c *C) {
522 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
524 st := &StubPutHandler{
527 expectAPIToken: "abc123",
529 expectStorageClass: "default",
530 returnStorageClasses: "",
531 handled: make(chan string, 5),
534 arv, _ := arvadosclient.MakeArvadosClient()
535 kc, _ := MakeKeepClient(arv)
538 arv.ApiToken = "abc123"
539 localRoots := make(map[string]string)
540 writableLocalRoots := make(map[string]string)
542 ks := RunSomeFakeKeepServers(st, 5)
544 for i, k := range ks {
545 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
546 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
547 defer k.listener.Close()
550 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
552 reader, writer := io.Pipe()
555 writer.Write([]byte("foo"))
559 kc.PutHR(hash, reader, 3)
561 shuff := NewRootSorter(kc.LocalRoots(), hash).GetSortedRoots()
566 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
567 (s1 == shuff[1] && s2 == shuff[0]),
572 func (s *StandaloneSuite) TestPutWithFail(c *C) {
573 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
575 st := &StubPutHandler{
578 expectAPIToken: "abc123",
580 expectStorageClass: "default",
581 returnStorageClasses: "",
582 handled: make(chan string, 4),
586 make(chan string, 1)}
588 arv, err := arvadosclient.MakeArvadosClient()
590 kc, _ := MakeKeepClient(arv)
593 arv.ApiToken = "abc123"
594 localRoots := make(map[string]string)
595 writableLocalRoots := make(map[string]string)
597 ks1 := RunSomeFakeKeepServers(st, 4)
598 ks2 := RunSomeFakeKeepServers(fh, 1)
600 for i, k := range ks1 {
601 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
602 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
603 defer k.listener.Close()
605 for i, k := range ks2 {
606 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
607 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
608 defer k.listener.Close()
611 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
613 shuff := NewRootSorter(
614 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
617 phash, replicas, err := kc.PutB([]byte("foo"))
621 c.Check(err, Equals, nil)
622 c.Check(phash, Equals, "")
623 c.Check(replicas, Equals, 2)
628 c.Check((s1 == shuff[1] && s2 == shuff[2]) ||
629 (s1 == shuff[2] && s2 == shuff[1]),
634 func (s *StandaloneSuite) TestPutWithTooManyFail(c *C) {
635 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
637 st := &StubPutHandler{
640 expectAPIToken: "abc123",
642 expectStorageClass: "default",
643 returnStorageClasses: "",
644 handled: make(chan string, 1),
648 make(chan string, 4)}
650 arv, err := arvadosclient.MakeArvadosClient()
652 kc, _ := MakeKeepClient(arv)
656 arv.ApiToken = "abc123"
657 localRoots := make(map[string]string)
658 writableLocalRoots := make(map[string]string)
660 ks1 := RunSomeFakeKeepServers(st, 1)
661 ks2 := RunSomeFakeKeepServers(fh, 4)
663 for i, k := range ks1 {
664 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
665 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
666 defer k.listener.Close()
668 for i, k := range ks2 {
669 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
670 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
671 defer k.listener.Close()
674 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
676 _, replicas, err := kc.PutB([]byte("foo"))
678 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
679 c.Check(replicas, Equals, 1)
680 c.Check(<-st.handled, Equals, ks1[0].url)
683 type StubGetHandler struct {
686 expectAPIToken string
691 func (sgh StubGetHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
692 sgh.c.Check(req.URL.Path, Equals, "/"+sgh.expectPath)
693 sgh.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", sgh.expectAPIToken))
694 resp.WriteHeader(sgh.httpStatus)
695 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(sgh.body)))
699 func (s *StandaloneSuite) TestGet(c *C) {
700 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
702 st := StubGetHandler{
709 ks := RunFakeKeepServer(st)
710 defer ks.listener.Close()
712 arv, err := arvadosclient.MakeArvadosClient()
714 kc, _ := MakeKeepClient(arv)
715 arv.ApiToken = "abc123"
716 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
718 r, n, url2, err := kc.Get(hash)
720 c.Check(err, Equals, nil)
721 c.Check(n, Equals, int64(3))
722 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks.url, hash))
724 content, err2 := ioutil.ReadAll(r)
725 c.Check(err2, Equals, nil)
726 c.Check(content, DeepEquals, []byte("foo"))
729 func (s *StandaloneSuite) TestGet404(c *C) {
730 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
732 st := Error404Handler{make(chan string, 1)}
734 ks := RunFakeKeepServer(st)
735 defer ks.listener.Close()
737 arv, err := arvadosclient.MakeArvadosClient()
739 kc, _ := MakeKeepClient(arv)
740 arv.ApiToken = "abc123"
741 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
743 r, n, url2, err := kc.Get(hash)
744 c.Check(err, Equals, BlockNotFound)
745 c.Check(n, Equals, int64(0))
746 c.Check(url2, Equals, "")
747 c.Check(r, Equals, nil)
750 func (s *StandaloneSuite) TestGetEmptyBlock(c *C) {
751 st := Error404Handler{make(chan string, 1)}
753 ks := RunFakeKeepServer(st)
754 defer ks.listener.Close()
756 arv, err := arvadosclient.MakeArvadosClient()
758 kc, _ := MakeKeepClient(arv)
759 arv.ApiToken = "abc123"
760 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
762 r, n, url2, err := kc.Get("d41d8cd98f00b204e9800998ecf8427e+0")
764 c.Check(n, Equals, int64(0))
765 c.Check(url2, Equals, "")
767 buf, err := ioutil.ReadAll(r)
769 c.Check(buf, DeepEquals, []byte{})
772 func (s *StandaloneSuite) TestGetFail(c *C) {
773 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
775 st := FailHandler{make(chan string, 1)}
777 ks := RunFakeKeepServer(st)
778 defer ks.listener.Close()
780 arv, err := arvadosclient.MakeArvadosClient()
782 kc, _ := MakeKeepClient(arv)
783 arv.ApiToken = "abc123"
784 kc.SetServiceRoots(map[string]string{"x": ks.url}, 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(), "HTTP 500"), 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) TestGetFailRetry(c *C) {
798 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
800 st := &FailThenSucceedHandler{
801 handled: make(chan string, 1),
802 successhandler: StubGetHandler{
809 ks := RunFakeKeepServer(st)
810 defer ks.listener.Close()
812 arv, err := arvadosclient.MakeArvadosClient()
814 kc, _ := MakeKeepClient(arv)
815 arv.ApiToken = "abc123"
816 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
818 r, n, url2, err := kc.Get(hash)
820 c.Check(err, Equals, nil)
821 c.Check(n, Equals, int64(3))
822 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks.url, hash))
824 content, err2 := ioutil.ReadAll(r)
825 c.Check(err2, Equals, nil)
826 c.Check(content, DeepEquals, []byte("foo"))
828 c.Logf("%q", st.reqIDs)
829 c.Assert(len(st.reqIDs) > 1, Equals, true)
830 for _, reqid := range st.reqIDs {
831 c.Check(reqid, Not(Equals), "")
832 c.Check(reqid, Equals, st.reqIDs[0])
836 func (s *StandaloneSuite) TestGetNetError(c *C) {
837 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
839 arv, err := arvadosclient.MakeArvadosClient()
841 kc, _ := MakeKeepClient(arv)
842 arv.ApiToken = "abc123"
843 kc.SetServiceRoots(map[string]string{"x": "http://localhost:62222"}, nil, nil)
845 r, n, url2, err := kc.Get(hash)
846 errNotFound, _ := err.(*ErrNotFound)
847 c.Check(errNotFound, NotNil)
848 c.Check(strings.Contains(errNotFound.Error(), "connection refused"), Equals, true)
849 c.Check(errNotFound.Temporary(), Equals, true)
850 c.Check(n, Equals, int64(0))
851 c.Check(url2, Equals, "")
852 c.Check(r, Equals, nil)
855 func (s *StandaloneSuite) TestGetWithServiceHint(c *C) {
856 uuid := "zzzzz-bi6l4-123451234512345"
857 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
859 // This one shouldn't be used:
860 ks0 := RunFakeKeepServer(StubGetHandler{
866 defer ks0.listener.Close()
867 // This one should be used:
868 ks := RunFakeKeepServer(StubGetHandler{
874 defer ks.listener.Close()
876 arv, err := arvadosclient.MakeArvadosClient()
878 kc, _ := MakeKeepClient(arv)
879 arv.ApiToken = "abc123"
881 map[string]string{"x": ks0.url},
883 map[string]string{uuid: ks.url})
885 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
887 c.Check(err, Equals, nil)
888 c.Check(n, Equals, int64(3))
889 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ks.url, hash+"+K@"+uuid))
891 content, err := ioutil.ReadAll(r)
892 c.Check(err, Equals, nil)
893 c.Check(content, DeepEquals, []byte("foo"))
896 // Use a service hint to fetch from a local disk service, overriding
897 // rendezvous probe order.
898 func (s *StandaloneSuite) TestGetWithLocalServiceHint(c *C) {
899 uuid := "zzzzz-bi6l4-zzzzzzzzzzzzzzz"
900 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
902 // This one shouldn't be used, although it appears first in
903 // rendezvous probe order:
904 ks0 := RunFakeKeepServer(StubGetHandler{
910 defer ks0.listener.Close()
911 // This one should be used:
912 ks := RunFakeKeepServer(StubGetHandler{
918 defer ks.listener.Close()
920 arv, err := arvadosclient.MakeArvadosClient()
922 kc, _ := MakeKeepClient(arv)
923 arv.ApiToken = "abc123"
926 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
927 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
928 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
932 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
933 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
934 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
938 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
940 c.Check(err, Equals, nil)
941 c.Check(n, Equals, int64(3))
942 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ks.url, hash+"+K@"+uuid))
944 content, err := ioutil.ReadAll(r)
945 c.Check(err, Equals, nil)
946 c.Check(content, DeepEquals, []byte("foo"))
949 func (s *StandaloneSuite) TestGetWithServiceHintFailoverToLocals(c *C) {
950 uuid := "zzzzz-bi6l4-123451234512345"
951 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
953 ksLocal := RunFakeKeepServer(StubGetHandler{
959 defer ksLocal.listener.Close()
960 ksGateway := RunFakeKeepServer(StubGetHandler{
964 http.StatusInternalServerError,
966 defer ksGateway.listener.Close()
968 arv, err := arvadosclient.MakeArvadosClient()
970 kc, _ := MakeKeepClient(arv)
971 arv.ApiToken = "abc123"
973 map[string]string{"zzzzz-bi6l4-keepdisk0000000": ksLocal.url},
975 map[string]string{uuid: ksGateway.url})
977 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
978 c.Assert(err, Equals, nil)
980 c.Check(n, Equals, int64(3))
981 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ksLocal.url, hash+"+K@"+uuid))
983 content, err := ioutil.ReadAll(r)
984 c.Check(err, Equals, nil)
985 c.Check(content, DeepEquals, []byte("foo"))
988 type BarHandler struct {
992 func (h BarHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
993 resp.Write([]byte("bar"))
994 h.handled <- fmt.Sprintf("http://%s", req.Host)
997 func (s *StandaloneSuite) TestChecksum(c *C) {
998 foohash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
999 barhash := fmt.Sprintf("%x", md5.Sum([]byte("bar")))
1001 st := BarHandler{make(chan string, 1)}
1003 ks := RunFakeKeepServer(st)
1004 defer ks.listener.Close()
1006 arv, err := arvadosclient.MakeArvadosClient()
1008 kc, _ := MakeKeepClient(arv)
1009 arv.ApiToken = "abc123"
1010 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1012 r, n, _, err := kc.Get(barhash)
1014 _, err = ioutil.ReadAll(r)
1015 c.Check(n, Equals, int64(3))
1016 c.Check(err, Equals, nil)
1020 r, n, _, err = kc.Get(foohash)
1022 _, err = ioutil.ReadAll(r)
1023 c.Check(n, Equals, int64(3))
1024 c.Check(err, Equals, BadChecksum)
1029 func (s *StandaloneSuite) TestGetWithFailures(c *C) {
1030 content := []byte("waz")
1031 hash := fmt.Sprintf("%x", md5.Sum(content))
1033 fh := Error404Handler{
1034 make(chan string, 4)}
1036 st := StubGetHandler{
1043 arv, err := arvadosclient.MakeArvadosClient()
1045 kc, _ := MakeKeepClient(arv)
1046 arv.ApiToken = "abc123"
1047 localRoots := make(map[string]string)
1048 writableLocalRoots := make(map[string]string)
1050 ks1 := RunSomeFakeKeepServers(st, 1)
1051 ks2 := RunSomeFakeKeepServers(fh, 4)
1053 for i, k := range ks1 {
1054 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1055 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1056 defer k.listener.Close()
1058 for i, k := range ks2 {
1059 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
1060 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
1061 defer k.listener.Close()
1064 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1067 // This test works only if one of the failing services is
1068 // attempted before the succeeding service. Otherwise,
1069 // <-fh.handled below will just hang! (Probe order depends on
1070 // the choice of block content "waz" and the UUIDs of the fake
1071 // servers, so we just tried different strings until we found
1072 // an example that passes this Assert.)
1073 c.Assert(NewRootSorter(localRoots, hash).GetSortedRoots()[0], Not(Equals), ks1[0].url)
1075 r, n, url2, err := kc.Get(hash)
1078 c.Check(err, Equals, nil)
1079 c.Check(n, Equals, int64(3))
1080 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks1[0].url, hash))
1082 readContent, err2 := ioutil.ReadAll(r)
1083 c.Check(err2, Equals, nil)
1084 c.Check(readContent, DeepEquals, content)
1087 func (s *ServerRequiredSuite) TestPutGetHead(c *C) {
1088 content := []byte("TestPutGetHead")
1090 arv, err := arvadosclient.MakeArvadosClient()
1092 kc, err := MakeKeepClient(arv)
1093 c.Assert(err, Equals, nil)
1095 hash := fmt.Sprintf("%x", md5.Sum(content))
1098 n, _, err := kc.Ask(hash)
1099 c.Check(err, Equals, BlockNotFound)
1100 c.Check(n, Equals, int64(0))
1103 hash2, replicas, err := kc.PutB(content)
1104 c.Check(hash2, Matches, fmt.Sprintf(`%s\+%d\b.*`, hash, len(content)))
1105 c.Check(replicas, Equals, 2)
1106 c.Check(err, Equals, nil)
1109 r, n, url2, err := kc.Get(hash)
1110 c.Check(err, Equals, nil)
1111 c.Check(n, Equals, int64(len(content)))
1112 c.Check(url2, Matches, fmt.Sprintf("http://localhost:\\d+/%s", hash))
1114 readContent, err2 := ioutil.ReadAll(r)
1115 c.Check(err2, Equals, nil)
1116 c.Check(readContent, DeepEquals, content)
1119 n, url2, err := kc.Ask(hash)
1120 c.Check(err, Equals, nil)
1121 c.Check(n, Equals, int64(len(content)))
1122 c.Check(url2, Matches, fmt.Sprintf("http://localhost:\\d+/%s", hash))
1125 loc, err := kc.LocalLocator(hash)
1126 c.Check(err, Equals, nil)
1127 c.Assert(len(loc) >= 32, Equals, true)
1128 c.Check(loc[:32], Equals, hash[:32])
1131 content := []byte("the perth county conspiracy")
1132 loc, err := kc.LocalLocator(fmt.Sprintf("%x+%d+Rzaaaa-abcde@12345", md5.Sum(content), len(content)))
1133 c.Check(loc, Equals, "")
1134 c.Check(err, ErrorMatches, `.*HEAD .*\+R.*`)
1135 c.Check(err, ErrorMatches, `.*HTTP 400.*`)
1139 type StubProxyHandler struct {
1143 func (h StubProxyHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1144 resp.Header().Set("X-Keep-Replicas-Stored", "2")
1145 h.handled <- fmt.Sprintf("http://%s", req.Host)
1148 func (s *StandaloneSuite) TestPutProxy(c *C) {
1149 st := StubProxyHandler{make(chan string, 1)}
1151 arv, err := arvadosclient.MakeArvadosClient()
1153 kc, _ := MakeKeepClient(arv)
1155 kc.Want_replicas = 2
1156 arv.ApiToken = "abc123"
1157 localRoots := make(map[string]string)
1158 writableLocalRoots := make(map[string]string)
1160 ks1 := RunSomeFakeKeepServers(st, 1)
1162 for i, k := range ks1 {
1163 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1164 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1165 defer k.listener.Close()
1168 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1170 _, replicas, err := kc.PutB([]byte("foo"))
1173 c.Check(err, Equals, nil)
1174 c.Check(replicas, Equals, 2)
1177 func (s *StandaloneSuite) TestPutProxyInsufficientReplicas(c *C) {
1178 st := StubProxyHandler{make(chan string, 1)}
1180 arv, err := arvadosclient.MakeArvadosClient()
1182 kc, _ := MakeKeepClient(arv)
1184 kc.Want_replicas = 3
1185 arv.ApiToken = "abc123"
1186 localRoots := make(map[string]string)
1187 writableLocalRoots := make(map[string]string)
1189 ks1 := RunSomeFakeKeepServers(st, 1)
1191 for i, k := range ks1 {
1192 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1193 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1194 defer k.listener.Close()
1196 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1198 _, replicas, err := kc.PutB([]byte("foo"))
1201 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
1202 c.Check(replicas, Equals, 2)
1205 func (s *StandaloneSuite) TestMakeLocator(c *C) {
1206 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+3+Aabcde@12345678")
1207 c.Check(err, Equals, nil)
1208 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1209 c.Check(l.Size, Equals, 3)
1210 c.Check(l.Hints, DeepEquals, []string{"3", "Aabcde@12345678"})
1213 func (s *StandaloneSuite) TestMakeLocatorNoHints(c *C) {
1214 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce")
1215 c.Check(err, Equals, nil)
1216 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1217 c.Check(l.Size, Equals, -1)
1218 c.Check(l.Hints, DeepEquals, []string{})
1221 func (s *StandaloneSuite) TestMakeLocatorNoSizeHint(c *C) {
1222 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+Aabcde@12345678")
1223 c.Check(err, Equals, nil)
1224 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1225 c.Check(l.Size, Equals, -1)
1226 c.Check(l.Hints, DeepEquals, []string{"Aabcde@12345678"})
1229 func (s *StandaloneSuite) TestMakeLocatorPreservesUnrecognizedHints(c *C) {
1230 str := "91f372a266fe2bf2823cb8ec7fda31ce+3+Unknown+Kzzzzz+Afoobar"
1231 l, err := MakeLocator(str)
1232 c.Check(err, Equals, nil)
1233 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
1234 c.Check(l.Size, Equals, 3)
1235 c.Check(l.Hints, DeepEquals, []string{"3", "Unknown", "Kzzzzz", "Afoobar"})
1236 c.Check(l.String(), Equals, str)
1239 func (s *StandaloneSuite) TestMakeLocatorInvalidInput(c *C) {
1240 _, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31c")
1241 c.Check(err, Equals, InvalidLocatorError)
1244 func (s *StandaloneSuite) TestPutBWant2ReplicasWithOnlyOneWritableLocalRoot(c *C) {
1245 hash := Md5String("foo")
1247 st := &StubPutHandler{
1250 expectAPIToken: "abc123",
1252 expectStorageClass: "default",
1253 returnStorageClasses: "",
1254 handled: make(chan string, 5),
1257 arv, _ := arvadosclient.MakeArvadosClient()
1258 kc, _ := MakeKeepClient(arv)
1260 kc.Want_replicas = 2
1261 arv.ApiToken = "abc123"
1262 localRoots := make(map[string]string)
1263 writableLocalRoots := make(map[string]string)
1265 ks := RunSomeFakeKeepServers(st, 5)
1267 for i, k := range ks {
1268 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1270 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1272 defer k.listener.Close()
1275 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1277 _, replicas, err := kc.PutB([]byte("foo"))
1279 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
1280 c.Check(replicas, Equals, 1)
1282 c.Check(<-st.handled, Equals, localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", 0)])
1285 func (s *StandaloneSuite) TestPutBWithNoWritableLocalRoots(c *C) {
1286 hash := Md5String("foo")
1288 st := &StubPutHandler{
1291 expectAPIToken: "abc123",
1293 expectStorageClass: "",
1294 returnStorageClasses: "",
1295 handled: make(chan string, 5),
1298 arv, _ := arvadosclient.MakeArvadosClient()
1299 kc, _ := MakeKeepClient(arv)
1301 kc.Want_replicas = 2
1302 arv.ApiToken = "abc123"
1303 localRoots := make(map[string]string)
1304 writableLocalRoots := make(map[string]string)
1306 ks := RunSomeFakeKeepServers(st, 5)
1308 for i, k := range ks {
1309 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1310 defer k.listener.Close()
1313 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1315 _, replicas, err := kc.PutB([]byte("foo"))
1317 c.Check(err, FitsTypeOf, InsufficientReplicasError{})
1318 c.Check(replicas, Equals, 0)
1321 type StubGetIndexHandler struct {
1324 expectAPIToken string
1329 func (h StubGetIndexHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1330 h.c.Check(req.URL.Path, Equals, h.expectPath)
1331 h.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", h.expectAPIToken))
1332 resp.WriteHeader(h.httpStatus)
1333 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(h.body)))
1337 func (s *StandaloneSuite) TestGetIndexWithNoPrefix(c *C) {
1338 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1340 st := StubGetIndexHandler{
1345 []byte(hash + "+3 1443559274\n\n")}
1347 ks := RunFakeKeepServer(st)
1348 defer ks.listener.Close()
1350 arv, err := arvadosclient.MakeArvadosClient()
1351 c.Assert(err, IsNil)
1352 kc, err := MakeKeepClient(arv)
1353 c.Assert(err, IsNil)
1354 arv.ApiToken = "abc123"
1355 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1357 r, err := kc.GetIndex("x", "")
1360 content, err2 := ioutil.ReadAll(r)
1361 c.Check(err2, Equals, nil)
1362 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1365 func (s *StandaloneSuite) TestGetIndexWithPrefix(c *C) {
1366 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1368 st := StubGetIndexHandler{
1370 "/index/" + hash[0:3],
1373 []byte(hash + "+3 1443559274\n\n")}
1375 ks := RunFakeKeepServer(st)
1376 defer ks.listener.Close()
1378 arv, err := arvadosclient.MakeArvadosClient()
1380 kc, _ := MakeKeepClient(arv)
1381 arv.ApiToken = "abc123"
1382 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1384 r, err := kc.GetIndex("x", hash[0:3])
1385 c.Assert(err, Equals, nil)
1387 content, err2 := ioutil.ReadAll(r)
1388 c.Check(err2, Equals, nil)
1389 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1392 func (s *StandaloneSuite) TestGetIndexIncomplete(c *C) {
1393 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1395 st := StubGetIndexHandler{
1397 "/index/" + hash[0:3],
1402 ks := RunFakeKeepServer(st)
1403 defer ks.listener.Close()
1405 arv, err := arvadosclient.MakeArvadosClient()
1407 kc, _ := MakeKeepClient(arv)
1408 arv.ApiToken = "abc123"
1409 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1411 _, err = kc.GetIndex("x", hash[0:3])
1412 c.Check(err, Equals, ErrIncompleteIndex)
1415 func (s *StandaloneSuite) TestGetIndexWithNoSuchServer(c *C) {
1416 hash := fmt.Sprintf("%x", 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("y", hash[0:3])
1435 c.Check(err, Equals, ErrNoSuchKeepServer)
1438 func (s *StandaloneSuite) TestGetIndexWithNoSuchPrefix(c *C) {
1439 st := StubGetIndexHandler{
1446 ks := RunFakeKeepServer(st)
1447 defer ks.listener.Close()
1449 arv, err := arvadosclient.MakeArvadosClient()
1451 kc, _ := MakeKeepClient(arv)
1452 arv.ApiToken = "abc123"
1453 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1455 r, err := kc.GetIndex("x", "abcd")
1456 c.Check(err, Equals, nil)
1458 content, err2 := ioutil.ReadAll(r)
1459 c.Check(err2, Equals, nil)
1460 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1463 func (s *StandaloneSuite) TestPutBRetry(c *C) {
1464 st := &FailThenSucceedHandler{
1465 handled: make(chan string, 1),
1466 successhandler: &StubPutHandler{
1468 expectPath: Md5String("foo"),
1469 expectAPIToken: "abc123",
1471 expectStorageClass: "default",
1472 returnStorageClasses: "",
1473 handled: make(chan string, 5),
1477 arv, _ := arvadosclient.MakeArvadosClient()
1478 kc, _ := MakeKeepClient(arv)
1480 kc.Want_replicas = 2
1481 arv.ApiToken = "abc123"
1482 localRoots := make(map[string]string)
1483 writableLocalRoots := make(map[string]string)
1485 ks := RunSomeFakeKeepServers(st, 2)
1487 for i, k := range ks {
1488 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1489 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1490 defer k.listener.Close()
1493 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1495 hash, replicas, err := kc.PutB([]byte("foo"))
1497 c.Check(err, Equals, nil)
1498 c.Check(hash, Equals, "")
1499 c.Check(replicas, Equals, 2)
1502 func (s *ServerRequiredSuite) TestMakeKeepClientWithNonDiskTypeService(c *C) {
1503 arv, err := arvadosclient.MakeArvadosClient()
1504 c.Assert(err, Equals, nil)
1506 // Add an additional "testblobstore" keepservice
1507 blobKeepService := make(arvadosclient.Dict)
1508 err = arv.Create("keep_services",
1509 arvadosclient.Dict{"keep_service": arvadosclient.Dict{
1510 "service_host": "localhost",
1511 "service_port": "21321",
1512 "service_type": "testblobstore"}},
1514 c.Assert(err, Equals, nil)
1515 defer func() { arv.Delete("keep_services", blobKeepService["uuid"].(string), nil, nil) }()
1516 RefreshServiceDiscovery()
1518 // Make a keepclient and ensure that the testblobstore is included
1519 kc, err := MakeKeepClient(arv)
1520 c.Assert(err, Equals, nil)
1522 // verify kc.LocalRoots
1523 c.Check(len(kc.LocalRoots()), Equals, 3)
1524 for _, root := range kc.LocalRoots() {
1525 c.Check(root, Matches, "http://localhost:\\d+")
1527 c.Assert(kc.LocalRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1529 // verify kc.GatewayRoots
1530 c.Check(len(kc.GatewayRoots()), Equals, 3)
1531 for _, root := range kc.GatewayRoots() {
1532 c.Check(root, Matches, "http://localhost:\\d+")
1534 c.Assert(kc.GatewayRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1536 // verify kc.WritableLocalRoots
1537 c.Check(len(kc.WritableLocalRoots()), Equals, 3)
1538 for _, root := range kc.WritableLocalRoots() {
1539 c.Check(root, Matches, "http://localhost:\\d+")
1541 c.Assert(kc.WritableLocalRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1543 c.Assert(kc.replicasPerService, Equals, 0)
1544 c.Assert(kc.foundNonDiskSvc, Equals, true)
1545 c.Assert(kc.httpClient().(*http.Client).Timeout, Equals, 300*time.Second)