17 "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
18 "git.curoverse.com/arvados.git/sdk/go/arvadostest"
19 "git.curoverse.com/arvados.git/sdk/go/streamer"
23 // Gocheck boilerplate
24 func Test(t *testing.T) {
28 // Gocheck boilerplate
29 var _ = Suite(&ServerRequiredSuite{})
30 var _ = Suite(&StandaloneSuite{})
32 // Tests that require the Keep server running
33 type ServerRequiredSuite struct{}
36 type StandaloneSuite struct{}
38 func pythonDir() string {
40 return fmt.Sprintf("%s/../../python/tests", cwd)
43 func (s *ServerRequiredSuite) SetUpSuite(c *C) {
44 arvadostest.StartAPI()
45 arvadostest.StartKeep(2, false)
48 func (s *ServerRequiredSuite) TearDownSuite(c *C) {
49 arvadostest.StopKeep(2)
53 func (s *ServerRequiredSuite) TestMakeKeepClient(c *C) {
54 arv, err := arvadosclient.MakeArvadosClient()
55 c.Assert(err, Equals, nil)
57 kc, err := MakeKeepClient(arv)
59 c.Assert(err, Equals, nil)
60 c.Check(len(kc.LocalRoots()), Equals, 2)
61 for _, root := range kc.LocalRoots() {
62 c.Check(root, Matches, "http://localhost:\\d+")
66 func (s *ServerRequiredSuite) TestDefaultReplications(c *C) {
67 arv, err := arvadosclient.MakeArvadosClient()
68 c.Assert(err, Equals, nil)
70 kc, err := MakeKeepClient(arv)
71 c.Assert(kc.Want_replicas, Equals, 2)
73 arv.DiscoveryDoc["defaultCollectionReplication"] = 3.0
74 kc, err = MakeKeepClient(arv)
75 c.Assert(kc.Want_replicas, Equals, 3)
77 arv.DiscoveryDoc["defaultCollectionReplication"] = 1.0
78 kc, err = MakeKeepClient(arv)
79 c.Assert(kc.Want_replicas, Equals, 1)
82 type StubPutHandler struct {
90 func (sph StubPutHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
91 sph.c.Check(req.URL.Path, Equals, "/"+sph.expectPath)
92 sph.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", sph.expectApiToken))
93 body, err := ioutil.ReadAll(req.Body)
94 sph.c.Check(err, Equals, nil)
95 sph.c.Check(body, DeepEquals, []byte(sph.expectBody))
97 sph.handled <- fmt.Sprintf("http://%s", req.Host)
100 func RunFakeKeepServer(st http.Handler) (ks KeepServer) {
102 ks.listener, err = net.ListenTCP("tcp", &net.TCPAddr{Port: 0})
104 panic(fmt.Sprintf("Could not listen on any port"))
106 ks.url = fmt.Sprintf("http://%s", ks.listener.Addr().String())
107 go http.Serve(ks.listener, st)
111 func UploadToStubHelper(c *C, st http.Handler, f func(*KeepClient, string,
112 io.ReadCloser, io.WriteCloser, chan uploadStatus)) {
114 ks := RunFakeKeepServer(st)
115 defer ks.listener.Close()
117 arv, _ := arvadosclient.MakeArvadosClient()
118 arv.ApiToken = "abc123"
120 kc, _ := MakeKeepClient(arv)
122 reader, writer := io.Pipe()
123 upload_status := make(chan uploadStatus)
125 f(kc, ks.url, reader, writer, upload_status)
128 func (s *StandaloneSuite) TestUploadToStubKeepServer(c *C) {
129 log.Printf("TestUploadToStubKeepServer")
131 st := StubPutHandler{
133 "acbd18db4cc2f85cedef654fccc4a4d8",
138 UploadToStubHelper(c, st,
139 func(kc *KeepClient, url string, reader io.ReadCloser, writer io.WriteCloser, upload_status chan uploadStatus) {
141 go kc.uploadToKeepServer(url, st.expectPath, reader, upload_status, int64(len("foo")), 0)
143 writer.Write([]byte("foo"))
147 status := <-upload_status
148 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, ""})
152 func (s *StandaloneSuite) TestUploadToStubKeepServerBufferReader(c *C) {
153 st := StubPutHandler{
155 "acbd18db4cc2f85cedef654fccc4a4d8",
160 UploadToStubHelper(c, st,
161 func(kc *KeepClient, url string, reader io.ReadCloser,
162 writer io.WriteCloser, upload_status chan uploadStatus) {
164 tr := streamer.AsyncStreamFromReader(512, reader)
167 br1 := tr.MakeStreamReader()
169 go kc.uploadToKeepServer(url, st.expectPath, br1, upload_status, 3, 0)
171 writer.Write([]byte("foo"))
176 status := <-upload_status
177 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, ""})
181 type FailHandler struct {
185 func (fh FailHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
186 resp.WriteHeader(500)
187 fh.handled <- fmt.Sprintf("http://%s", req.Host)
190 type FailThenSucceedHandler struct {
193 successhandler StubGetHandler
196 func (fh *FailThenSucceedHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
198 resp.WriteHeader(500)
200 fh.handled <- fmt.Sprintf("http://%s", req.Host)
202 fh.successhandler.ServeHTTP(resp, req)
206 type Error404Handler struct {
210 func (fh Error404Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
211 resp.WriteHeader(404)
212 fh.handled <- fmt.Sprintf("http://%s", req.Host)
215 func (s *StandaloneSuite) TestFailedUploadToStubKeepServer(c *C) {
219 hash := "acbd18db4cc2f85cedef654fccc4a4d8"
221 UploadToStubHelper(c, st,
222 func(kc *KeepClient, url string, reader io.ReadCloser,
223 writer io.WriteCloser, upload_status chan uploadStatus) {
225 go kc.uploadToKeepServer(url, hash, reader, upload_status, 3, 0)
227 writer.Write([]byte("foo"))
232 status := <-upload_status
233 c.Check(status.url, Equals, fmt.Sprintf("%s/%s", url, hash))
234 c.Check(status.statusCode, Equals, 500)
238 type KeepServer struct {
239 listener net.Listener
243 func RunSomeFakeKeepServers(st http.Handler, n int) (ks []KeepServer) {
244 ks = make([]KeepServer, n)
246 for i := 0; i < n; i += 1 {
247 ks[i] = RunFakeKeepServer(st)
253 func (s *StandaloneSuite) TestPutB(c *C) {
254 hash := Md5String("foo")
256 st := StubPutHandler{
261 make(chan string, 5)}
263 arv, _ := arvadosclient.MakeArvadosClient()
264 kc, _ := MakeKeepClient(arv)
267 arv.ApiToken = "abc123"
268 localRoots := make(map[string]string)
269 writableLocalRoots := make(map[string]string)
271 ks := RunSomeFakeKeepServers(st, 5)
273 for i, k := range ks {
274 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
275 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
276 defer k.listener.Close()
279 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
281 kc.PutB([]byte("foo"))
283 shuff := NewRootSorter(
284 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
288 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
289 (s1 == shuff[1] && s2 == shuff[0]),
294 func (s *StandaloneSuite) TestPutHR(c *C) {
295 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
297 st := StubPutHandler{
302 make(chan string, 5)}
304 arv, _ := arvadosclient.MakeArvadosClient()
305 kc, _ := MakeKeepClient(arv)
308 arv.ApiToken = "abc123"
309 localRoots := make(map[string]string)
310 writableLocalRoots := make(map[string]string)
312 ks := RunSomeFakeKeepServers(st, 5)
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()
320 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
322 reader, writer := io.Pipe()
325 writer.Write([]byte("foo"))
329 kc.PutHR(hash, reader, 3)
331 shuff := NewRootSorter(kc.LocalRoots(), hash).GetSortedRoots()
336 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
337 (s1 == shuff[1] && s2 == shuff[0]),
342 func (s *StandaloneSuite) TestPutWithFail(c *C) {
343 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
345 st := StubPutHandler{
350 make(chan string, 4)}
353 make(chan string, 1)}
355 arv, err := arvadosclient.MakeArvadosClient()
356 kc, _ := MakeKeepClient(arv)
359 arv.ApiToken = "abc123"
360 localRoots := make(map[string]string)
361 writableLocalRoots := make(map[string]string)
363 ks1 := RunSomeFakeKeepServers(st, 4)
364 ks2 := RunSomeFakeKeepServers(fh, 1)
366 for i, k := range ks1 {
367 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
368 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
369 defer k.listener.Close()
371 for i, k := range ks2 {
372 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
373 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
374 defer k.listener.Close()
377 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
379 shuff := NewRootSorter(
380 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
383 phash, replicas, err := kc.PutB([]byte("foo"))
387 c.Check(err, Equals, nil)
388 c.Check(phash, Equals, "")
389 c.Check(replicas, Equals, 2)
394 c.Check((s1 == shuff[1] && s2 == shuff[2]) ||
395 (s1 == shuff[2] && s2 == shuff[1]),
400 func (s *StandaloneSuite) TestPutWithTooManyFail(c *C) {
401 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
403 st := StubPutHandler{
408 make(chan string, 1)}
411 make(chan string, 4)}
413 arv, err := arvadosclient.MakeArvadosClient()
414 kc, _ := MakeKeepClient(arv)
418 arv.ApiToken = "abc123"
419 localRoots := make(map[string]string)
420 writableLocalRoots := make(map[string]string)
422 ks1 := RunSomeFakeKeepServers(st, 1)
423 ks2 := RunSomeFakeKeepServers(fh, 4)
425 for i, k := range ks1 {
426 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
427 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
428 defer k.listener.Close()
430 for i, k := range ks2 {
431 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
432 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
433 defer k.listener.Close()
436 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
438 _, replicas, err := kc.PutB([]byte("foo"))
440 c.Check(err, FitsTypeOf, InsufficientReplicasError(errors.New("")))
441 c.Check(replicas, Equals, 1)
442 c.Check(<-st.handled, Equals, ks1[0].url)
445 type StubGetHandler struct {
448 expectApiToken string
453 func (sgh StubGetHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
454 sgh.c.Check(req.URL.Path, Equals, "/"+sgh.expectPath)
455 sgh.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", sgh.expectApiToken))
456 resp.WriteHeader(sgh.httpStatus)
457 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(sgh.body)))
461 func (s *StandaloneSuite) TestGet(c *C) {
462 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
464 st := StubGetHandler{
471 ks := RunFakeKeepServer(st)
472 defer ks.listener.Close()
474 arv, err := arvadosclient.MakeArvadosClient()
475 kc, _ := MakeKeepClient(arv)
476 arv.ApiToken = "abc123"
477 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
479 r, n, url2, err := kc.Get(hash)
481 c.Check(err, Equals, nil)
482 c.Check(n, Equals, int64(3))
483 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks.url, hash))
485 content, err2 := ioutil.ReadAll(r)
486 c.Check(err2, Equals, nil)
487 c.Check(content, DeepEquals, []byte("foo"))
490 func (s *StandaloneSuite) TestGet404(c *C) {
491 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
493 st := Error404Handler{make(chan string, 1)}
495 ks := RunFakeKeepServer(st)
496 defer ks.listener.Close()
498 arv, err := arvadosclient.MakeArvadosClient()
499 kc, _ := MakeKeepClient(arv)
500 arv.ApiToken = "abc123"
501 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
503 r, n, url2, err := kc.Get(hash)
504 c.Check(err, Equals, BlockNotFound)
505 c.Check(n, Equals, int64(0))
506 c.Check(url2, Equals, "")
507 c.Check(r, Equals, nil)
510 func (s *StandaloneSuite) TestGetEmptyBlock(c *C) {
511 st := Error404Handler{make(chan string, 1)}
513 ks := RunFakeKeepServer(st)
514 defer ks.listener.Close()
516 arv, err := arvadosclient.MakeArvadosClient()
517 kc, _ := MakeKeepClient(arv)
518 arv.ApiToken = "abc123"
519 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
521 r, n, url2, err := kc.Get("d41d8cd98f00b204e9800998ecf8427e+0")
523 c.Check(n, Equals, int64(0))
524 c.Check(url2, Equals, "")
526 buf, err := ioutil.ReadAll(r)
528 c.Check(buf, DeepEquals, []byte{})
531 func (s *StandaloneSuite) TestGetFail(c *C) {
532 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
534 st := FailHandler{make(chan string, 1)}
536 ks := RunFakeKeepServer(st)
537 defer ks.listener.Close()
539 arv, err := arvadosclient.MakeArvadosClient()
540 kc, _ := MakeKeepClient(arv)
541 arv.ApiToken = "abc123"
542 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
545 r, n, url2, err := kc.Get(hash)
546 errNotFound, _ := err.(*ErrNotFound)
547 c.Check(errNotFound, NotNil)
548 c.Check(strings.Contains(errNotFound.Error(), "HTTP 500"), Equals, true)
549 c.Check(errNotFound.Temporary(), Equals, true)
550 c.Check(n, Equals, int64(0))
551 c.Check(url2, Equals, "")
552 c.Check(r, Equals, nil)
555 func (s *StandaloneSuite) TestGetFailRetry(c *C) {
556 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
558 st := &FailThenSucceedHandler{make(chan string, 1), 0,
566 ks := RunFakeKeepServer(st)
567 defer ks.listener.Close()
569 arv, err := arvadosclient.MakeArvadosClient()
570 kc, _ := MakeKeepClient(arv)
571 arv.ApiToken = "abc123"
572 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
574 r, n, url2, err := kc.Get(hash)
576 c.Check(err, Equals, nil)
577 c.Check(n, Equals, int64(3))
578 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks.url, hash))
580 content, err2 := ioutil.ReadAll(r)
581 c.Check(err2, Equals, nil)
582 c.Check(content, DeepEquals, []byte("foo"))
585 func (s *StandaloneSuite) TestGetNetError(c *C) {
586 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
588 arv, err := arvadosclient.MakeArvadosClient()
589 kc, _ := MakeKeepClient(arv)
590 arv.ApiToken = "abc123"
591 kc.SetServiceRoots(map[string]string{"x": "http://localhost:62222"}, nil, nil)
593 r, n, url2, err := kc.Get(hash)
594 errNotFound, _ := err.(*ErrNotFound)
595 c.Check(errNotFound, NotNil)
596 c.Check(strings.Contains(errNotFound.Error(), "connection refused"), Equals, true)
597 c.Check(errNotFound.Temporary(), Equals, true)
598 c.Check(n, Equals, int64(0))
599 c.Check(url2, Equals, "")
600 c.Check(r, Equals, nil)
603 func (s *StandaloneSuite) TestGetWithServiceHint(c *C) {
604 uuid := "zzzzz-bi6l4-123451234512345"
605 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
607 // This one shouldn't be used:
608 ks0 := RunFakeKeepServer(StubGetHandler{
614 defer ks0.listener.Close()
615 // This one should be used:
616 ks := RunFakeKeepServer(StubGetHandler{
622 defer ks.listener.Close()
624 arv, err := arvadosclient.MakeArvadosClient()
625 kc, _ := MakeKeepClient(arv)
626 arv.ApiToken = "abc123"
628 map[string]string{"x": ks0.url},
630 map[string]string{uuid: ks.url})
632 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
634 c.Check(err, Equals, nil)
635 c.Check(n, Equals, int64(3))
636 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ks.url, hash+"+K@"+uuid))
638 content, err := ioutil.ReadAll(r)
639 c.Check(err, Equals, nil)
640 c.Check(content, DeepEquals, []byte("foo"))
643 // Use a service hint to fetch from a local disk service, overriding
644 // rendezvous probe order.
645 func (s *StandaloneSuite) TestGetWithLocalServiceHint(c *C) {
646 uuid := "zzzzz-bi6l4-zzzzzzzzzzzzzzz"
647 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
649 // This one shouldn't be used, although it appears first in
650 // rendezvous probe order:
651 ks0 := RunFakeKeepServer(StubGetHandler{
657 defer ks0.listener.Close()
658 // This one should be used:
659 ks := RunFakeKeepServer(StubGetHandler{
665 defer ks.listener.Close()
667 arv, err := arvadosclient.MakeArvadosClient()
668 kc, _ := MakeKeepClient(arv)
669 arv.ApiToken = "abc123"
672 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
673 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
674 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
678 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
679 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
680 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
684 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
686 c.Check(err, Equals, nil)
687 c.Check(n, Equals, int64(3))
688 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ks.url, hash+"+K@"+uuid))
690 content, err := ioutil.ReadAll(r)
691 c.Check(err, Equals, nil)
692 c.Check(content, DeepEquals, []byte("foo"))
695 func (s *StandaloneSuite) TestGetWithServiceHintFailoverToLocals(c *C) {
696 uuid := "zzzzz-bi6l4-123451234512345"
697 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
699 ksLocal := RunFakeKeepServer(StubGetHandler{
705 defer ksLocal.listener.Close()
706 ksGateway := RunFakeKeepServer(StubGetHandler{
710 http.StatusInternalServerError,
712 defer ksGateway.listener.Close()
714 arv, err := arvadosclient.MakeArvadosClient()
715 kc, _ := MakeKeepClient(arv)
716 arv.ApiToken = "abc123"
718 map[string]string{"zzzzz-bi6l4-keepdisk0000000": ksLocal.url},
720 map[string]string{uuid: ksGateway.url})
722 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
723 c.Assert(err, Equals, nil)
725 c.Check(n, Equals, int64(3))
726 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ksLocal.url, hash+"+K@"+uuid))
728 content, err := ioutil.ReadAll(r)
729 c.Check(err, Equals, nil)
730 c.Check(content, DeepEquals, []byte("foo"))
733 type BarHandler struct {
737 func (this BarHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
738 resp.Write([]byte("bar"))
739 this.handled <- fmt.Sprintf("http://%s", req.Host)
742 func (s *StandaloneSuite) TestChecksum(c *C) {
743 foohash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
744 barhash := fmt.Sprintf("%x", md5.Sum([]byte("bar")))
746 st := BarHandler{make(chan string, 1)}
748 ks := RunFakeKeepServer(st)
749 defer ks.listener.Close()
751 arv, err := arvadosclient.MakeArvadosClient()
752 kc, _ := MakeKeepClient(arv)
753 arv.ApiToken = "abc123"
754 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
756 r, n, _, err := kc.Get(barhash)
757 _, err = ioutil.ReadAll(r)
758 c.Check(n, Equals, int64(3))
759 c.Check(err, Equals, nil)
763 r, n, _, err = kc.Get(foohash)
764 _, err = ioutil.ReadAll(r)
765 c.Check(n, Equals, int64(3))
766 c.Check(err, Equals, BadChecksum)
771 func (s *StandaloneSuite) TestGetWithFailures(c *C) {
772 content := []byte("waz")
773 hash := fmt.Sprintf("%x", md5.Sum(content))
775 fh := Error404Handler{
776 make(chan string, 4)}
778 st := StubGetHandler{
785 arv, err := arvadosclient.MakeArvadosClient()
786 kc, _ := MakeKeepClient(arv)
787 arv.ApiToken = "abc123"
788 localRoots := make(map[string]string)
789 writableLocalRoots := make(map[string]string)
791 ks1 := RunSomeFakeKeepServers(st, 1)
792 ks2 := RunSomeFakeKeepServers(fh, 4)
794 for i, k := range ks1 {
795 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
796 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
797 defer k.listener.Close()
799 for i, k := range ks2 {
800 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
801 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
802 defer k.listener.Close()
805 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
808 // This test works only if one of the failing services is
809 // attempted before the succeeding service. Otherwise,
810 // <-fh.handled below will just hang! (Probe order depends on
811 // the choice of block content "waz" and the UUIDs of the fake
812 // servers, so we just tried different strings until we found
813 // an example that passes this Assert.)
814 c.Assert(NewRootSorter(localRoots, hash).GetSortedRoots()[0], Not(Equals), ks1[0].url)
816 r, n, url2, err := kc.Get(hash)
819 c.Check(err, Equals, nil)
820 c.Check(n, Equals, int64(3))
821 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks1[0].url, hash))
823 read_content, err2 := ioutil.ReadAll(r)
824 c.Check(err2, Equals, nil)
825 c.Check(read_content, DeepEquals, content)
828 func (s *ServerRequiredSuite) TestPutGetHead(c *C) {
829 content := []byte("TestPutGetHead")
831 arv, err := arvadosclient.MakeArvadosClient()
832 kc, err := MakeKeepClient(arv)
833 c.Assert(err, Equals, nil)
835 hash := fmt.Sprintf("%x", md5.Sum(content))
838 n, _, err := kc.Ask(hash)
839 c.Check(err, Equals, BlockNotFound)
840 c.Check(n, Equals, int64(0))
843 hash2, replicas, err := kc.PutB(content)
844 c.Check(hash2, Matches, fmt.Sprintf(`%s\+%d\b.*`, hash, len(content)))
845 c.Check(replicas, Equals, 2)
846 c.Check(err, Equals, nil)
849 r, n, url2, err := kc.Get(hash)
850 c.Check(err, Equals, nil)
851 c.Check(n, Equals, int64(len(content)))
852 c.Check(url2, Matches, fmt.Sprintf("http://localhost:\\d+/%s", hash))
854 read_content, err2 := ioutil.ReadAll(r)
855 c.Check(err2, Equals, nil)
856 c.Check(read_content, DeepEquals, content)
859 n, url2, err := kc.Ask(hash)
860 c.Check(err, Equals, nil)
861 c.Check(n, Equals, int64(len(content)))
862 c.Check(url2, Matches, fmt.Sprintf("http://localhost:\\d+/%s", hash))
866 type StubProxyHandler struct {
870 func (this StubProxyHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
871 resp.Header().Set("X-Keep-Replicas-Stored", "2")
872 this.handled <- fmt.Sprintf("http://%s", req.Host)
875 func (s *StandaloneSuite) TestPutProxy(c *C) {
876 st := StubProxyHandler{make(chan string, 1)}
878 arv, err := arvadosclient.MakeArvadosClient()
879 kc, _ := MakeKeepClient(arv)
882 arv.ApiToken = "abc123"
883 localRoots := make(map[string]string)
884 writableLocalRoots := make(map[string]string)
886 ks1 := RunSomeFakeKeepServers(st, 1)
888 for i, k := range ks1 {
889 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
890 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
891 defer k.listener.Close()
894 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
896 _, replicas, err := kc.PutB([]byte("foo"))
899 c.Check(err, Equals, nil)
900 c.Check(replicas, Equals, 2)
903 func (s *StandaloneSuite) TestPutProxyInsufficientReplicas(c *C) {
904 st := StubProxyHandler{make(chan string, 1)}
906 arv, err := arvadosclient.MakeArvadosClient()
907 kc, _ := MakeKeepClient(arv)
910 arv.ApiToken = "abc123"
911 localRoots := make(map[string]string)
912 writableLocalRoots := make(map[string]string)
914 ks1 := RunSomeFakeKeepServers(st, 1)
916 for i, k := range ks1 {
917 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
918 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
919 defer k.listener.Close()
921 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
923 _, replicas, err := kc.PutB([]byte("foo"))
926 c.Check(err, FitsTypeOf, InsufficientReplicasError(errors.New("")))
927 c.Check(replicas, Equals, 2)
930 func (s *StandaloneSuite) TestMakeLocator(c *C) {
931 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+3+Aabcde@12345678")
932 c.Check(err, Equals, nil)
933 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
934 c.Check(l.Size, Equals, 3)
935 c.Check(l.Hints, DeepEquals, []string{"3", "Aabcde@12345678"})
938 func (s *StandaloneSuite) TestMakeLocatorNoHints(c *C) {
939 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce")
940 c.Check(err, Equals, nil)
941 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
942 c.Check(l.Size, Equals, -1)
943 c.Check(l.Hints, DeepEquals, []string{})
946 func (s *StandaloneSuite) TestMakeLocatorNoSizeHint(c *C) {
947 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+Aabcde@12345678")
948 c.Check(err, Equals, nil)
949 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
950 c.Check(l.Size, Equals, -1)
951 c.Check(l.Hints, DeepEquals, []string{"Aabcde@12345678"})
954 func (s *StandaloneSuite) TestMakeLocatorPreservesUnrecognizedHints(c *C) {
955 str := "91f372a266fe2bf2823cb8ec7fda31ce+3+Unknown+Kzzzzz+Afoobar"
956 l, err := MakeLocator(str)
957 c.Check(err, Equals, nil)
958 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
959 c.Check(l.Size, Equals, 3)
960 c.Check(l.Hints, DeepEquals, []string{"3", "Unknown", "Kzzzzz", "Afoobar"})
961 c.Check(l.String(), Equals, str)
964 func (s *StandaloneSuite) TestMakeLocatorInvalidInput(c *C) {
965 _, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31c")
966 c.Check(err, Equals, InvalidLocatorError)
969 func (s *StandaloneSuite) TestPutBWant2ReplicasWithOnlyOneWritableLocalRoot(c *C) {
970 hash := Md5String("foo")
972 st := StubPutHandler{
977 make(chan string, 5)}
979 arv, _ := arvadosclient.MakeArvadosClient()
980 kc, _ := MakeKeepClient(arv)
983 arv.ApiToken = "abc123"
984 localRoots := make(map[string]string)
985 writableLocalRoots := make(map[string]string)
987 ks := RunSomeFakeKeepServers(st, 5)
989 for i, k := range ks {
990 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
992 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
994 defer k.listener.Close()
997 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
999 _, replicas, err := kc.PutB([]byte("foo"))
1001 c.Check(err, FitsTypeOf, InsufficientReplicasError(errors.New("")))
1002 c.Check(replicas, Equals, 1)
1004 c.Check(<-st.handled, Equals, localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", 0)])
1007 func (s *StandaloneSuite) TestPutBWithNoWritableLocalRoots(c *C) {
1008 hash := Md5String("foo")
1010 st := StubPutHandler{
1015 make(chan string, 5)}
1017 arv, _ := arvadosclient.MakeArvadosClient()
1018 kc, _ := MakeKeepClient(arv)
1020 kc.Want_replicas = 2
1021 arv.ApiToken = "abc123"
1022 localRoots := make(map[string]string)
1023 writableLocalRoots := make(map[string]string)
1025 ks := RunSomeFakeKeepServers(st, 5)
1027 for i, k := range ks {
1028 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1029 defer k.listener.Close()
1032 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1034 _, replicas, err := kc.PutB([]byte("foo"))
1036 c.Check(err, FitsTypeOf, InsufficientReplicasError(errors.New("")))
1037 c.Check(replicas, Equals, 0)
1040 type StubGetIndexHandler struct {
1043 expectAPIToken string
1048 func (h StubGetIndexHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1049 h.c.Check(req.URL.Path, Equals, h.expectPath)
1050 h.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", h.expectAPIToken))
1051 resp.WriteHeader(h.httpStatus)
1052 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(h.body)))
1056 func (s *StandaloneSuite) TestGetIndexWithNoPrefix(c *C) {
1057 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1059 st := StubGetIndexHandler{
1064 []byte(hash + "+3 1443559274\n\n")}
1066 ks := RunFakeKeepServer(st)
1067 defer ks.listener.Close()
1069 arv, err := arvadosclient.MakeArvadosClient()
1070 kc, _ := MakeKeepClient(arv)
1071 arv.ApiToken = "abc123"
1072 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1074 r, err := kc.GetIndex("x", "")
1075 c.Check(err, Equals, nil)
1077 content, err2 := ioutil.ReadAll(r)
1078 c.Check(err2, Equals, nil)
1079 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1082 func (s *StandaloneSuite) TestGetIndexWithPrefix(c *C) {
1083 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1085 st := StubGetIndexHandler{
1087 "/index/" + hash[0:3],
1090 []byte(hash + "+3 1443559274\n\n")}
1092 ks := RunFakeKeepServer(st)
1093 defer ks.listener.Close()
1095 arv, err := arvadosclient.MakeArvadosClient()
1096 kc, _ := MakeKeepClient(arv)
1097 arv.ApiToken = "abc123"
1098 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1100 r, err := kc.GetIndex("x", hash[0:3])
1101 c.Check(err, Equals, nil)
1103 content, err2 := ioutil.ReadAll(r)
1104 c.Check(err2, Equals, nil)
1105 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1108 func (s *StandaloneSuite) TestGetIndexIncomplete(c *C) {
1109 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1111 st := StubGetIndexHandler{
1113 "/index/" + hash[0:3],
1118 ks := RunFakeKeepServer(st)
1119 defer ks.listener.Close()
1121 arv, err := arvadosclient.MakeArvadosClient()
1122 kc, _ := MakeKeepClient(arv)
1123 arv.ApiToken = "abc123"
1124 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1126 _, err = kc.GetIndex("x", hash[0:3])
1127 c.Check(err, Equals, ErrIncompleteIndex)
1130 func (s *StandaloneSuite) TestGetIndexWithNoSuchServer(c *C) {
1131 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1133 st := StubGetIndexHandler{
1135 "/index/" + hash[0:3],
1140 ks := RunFakeKeepServer(st)
1141 defer ks.listener.Close()
1143 arv, err := arvadosclient.MakeArvadosClient()
1144 kc, _ := MakeKeepClient(arv)
1145 arv.ApiToken = "abc123"
1146 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1148 _, err = kc.GetIndex("y", hash[0:3])
1149 c.Check(err, Equals, ErrNoSuchKeepServer)
1152 func (s *StandaloneSuite) TestGetIndexWithNoSuchPrefix(c *C) {
1153 st := StubGetIndexHandler{
1160 ks := RunFakeKeepServer(st)
1161 defer ks.listener.Close()
1163 arv, err := arvadosclient.MakeArvadosClient()
1164 kc, _ := MakeKeepClient(arv)
1165 arv.ApiToken = "abc123"
1166 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1168 r, err := kc.GetIndex("x", "abcd")
1169 c.Check(err, Equals, nil)
1171 content, err2 := ioutil.ReadAll(r)
1172 c.Check(err2, Equals, nil)
1173 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1176 type FailThenSucceedPutHandler struct {
1179 successhandler StubPutHandler
1182 func (h *FailThenSucceedPutHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1184 resp.WriteHeader(500)
1186 h.handled <- fmt.Sprintf("http://%s", req.Host)
1188 h.successhandler.ServeHTTP(resp, req)
1192 func (s *StandaloneSuite) TestPutBRetry(c *C) {
1193 st := &FailThenSucceedPutHandler{make(chan string, 1), 0,
1199 make(chan string, 5)}}
1201 arv, _ := arvadosclient.MakeArvadosClient()
1202 kc, _ := MakeKeepClient(arv)
1204 kc.Want_replicas = 2
1205 arv.ApiToken = "abc123"
1206 localRoots := make(map[string]string)
1207 writableLocalRoots := make(map[string]string)
1209 ks := RunSomeFakeKeepServers(st, 2)
1211 for i, k := range ks {
1212 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1213 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1214 defer k.listener.Close()
1217 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1219 hash, replicas, err := kc.PutB([]byte("foo"))
1221 c.Check(err, Equals, nil)
1222 c.Check(hash, Equals, "")
1223 c.Check(replicas, Equals, 2)
1226 func (s *ServerRequiredSuite) TestMakeKeepClientWithNonDiskTypeService(c *C) {
1227 arv, err := arvadosclient.MakeArvadosClient()
1228 c.Assert(err, Equals, nil)
1230 // Add an additional "testblobstore" keepservice
1231 blobKeepService := make(arvadosclient.Dict)
1232 err = arv.Create("keep_services",
1233 arvadosclient.Dict{"keep_service": arvadosclient.Dict{
1234 "service_host": "localhost",
1235 "service_port": "21321",
1236 "service_type": "testblobstore"}},
1238 c.Assert(err, Equals, nil)
1239 defer func() { arv.Delete("keep_services", blobKeepService["uuid"].(string), nil, nil) }()
1241 // Make a keepclient and ensure that the testblobstore is included
1242 kc, err := MakeKeepClient(arv)
1243 c.Assert(err, Equals, nil)
1245 // verify kc.LocalRoots
1246 c.Check(len(kc.LocalRoots()), Equals, 3)
1247 for _, root := range kc.LocalRoots() {
1248 c.Check(root, Matches, "http://localhost:\\d+")
1250 c.Assert(kc.LocalRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1252 // verify kc.GatewayRoots
1253 c.Check(len(kc.GatewayRoots()), Equals, 3)
1254 for _, root := range kc.GatewayRoots() {
1255 c.Check(root, Matches, "http://localhost:\\d+")
1257 c.Assert(kc.GatewayRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1259 // verify kc.WritableLocalRoots
1260 c.Check(len(kc.WritableLocalRoots()), Equals, 3)
1261 for _, root := range kc.WritableLocalRoots() {
1262 c.Check(root, Matches, "http://localhost:\\d+")
1264 c.Assert(kc.WritableLocalRoots()[blobKeepService["uuid"].(string)], Not(Equals), "")
1266 c.Assert(kc.replicasPerService, Equals, 0)
1267 c.Assert(kc.foundNonDiskSvc, Equals, true)
1268 c.Assert(kc.httpClient().(*http.Client).Timeout, Equals, 300*time.Second)