7 "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
8 "git.curoverse.com/arvados.git/sdk/go/arvadostest"
9 "git.curoverse.com/arvados.git/sdk/go/streamer"
21 // Gocheck boilerplate
22 func Test(t *testing.T) {
26 // Gocheck boilerplate
27 var _ = Suite(&ServerRequiredSuite{})
28 var _ = Suite(&StandaloneSuite{})
30 var no_server = flag.Bool("no-server", false, "Skip 'ServerRequireSuite'")
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) {
45 c.Skip("Skipping tests that require server")
48 arvadostest.StartAPI()
49 arvadostest.StartKeep(2, false)
52 func (s *ServerRequiredSuite) TearDownSuite(c *C) {
56 arvadostest.StopKeep(2)
60 func (s *ServerRequiredSuite) TestMakeKeepClient(c *C) {
61 arv, err := arvadosclient.MakeArvadosClient()
62 c.Assert(err, Equals, nil)
64 kc, err := MakeKeepClient(&arv)
66 c.Assert(err, Equals, nil)
67 c.Check(len(kc.LocalRoots()), Equals, 2)
68 for _, root := range kc.LocalRoots() {
69 c.Check(root, Matches, "http://localhost:\\d+")
73 func (s *ServerRequiredSuite) TestDefaultReplications(c *C) {
74 arv, err := arvadosclient.MakeArvadosClient()
75 c.Assert(err, Equals, nil)
77 kc, err := MakeKeepClient(&arv)
78 c.Assert(kc.Want_replicas, Equals, 2)
80 arv.DiscoveryDoc["defaultCollectionReplication"] = 3.0
81 kc, err = MakeKeepClient(&arv)
82 c.Assert(kc.Want_replicas, Equals, 3)
84 arv.DiscoveryDoc["defaultCollectionReplication"] = 1.0
85 kc, err = MakeKeepClient(&arv)
86 c.Assert(kc.Want_replicas, Equals, 1)
89 type StubPutHandler struct {
97 func (sph StubPutHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
98 sph.c.Check(req.URL.Path, Equals, "/"+sph.expectPath)
99 sph.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", sph.expectApiToken))
100 body, err := ioutil.ReadAll(req.Body)
101 sph.c.Check(err, Equals, nil)
102 sph.c.Check(body, DeepEquals, []byte(sph.expectBody))
103 resp.WriteHeader(200)
104 sph.handled <- fmt.Sprintf("http://%s", req.Host)
107 func RunFakeKeepServer(st http.Handler) (ks KeepServer) {
109 ks.listener, err = net.ListenTCP("tcp", &net.TCPAddr{Port: 0})
111 panic(fmt.Sprintf("Could not listen on any port"))
113 ks.url = fmt.Sprintf("http://%s", ks.listener.Addr().String())
114 go http.Serve(ks.listener, st)
118 func UploadToStubHelper(c *C, st http.Handler, f func(*KeepClient, string,
119 io.ReadCloser, io.WriteCloser, chan uploadStatus)) {
121 ks := RunFakeKeepServer(st)
122 defer ks.listener.Close()
124 arv, _ := arvadosclient.MakeArvadosClient()
125 arv.ApiToken = "abc123"
127 kc, _ := MakeKeepClient(&arv)
129 reader, writer := io.Pipe()
130 upload_status := make(chan uploadStatus)
132 f(kc, ks.url, reader, writer, upload_status)
135 func (s *StandaloneSuite) TestUploadToStubKeepServer(c *C) {
136 log.Printf("TestUploadToStubKeepServer")
138 st := StubPutHandler{
140 "acbd18db4cc2f85cedef654fccc4a4d8",
145 UploadToStubHelper(c, st,
146 func(kc *KeepClient, url string, reader io.ReadCloser,
147 writer io.WriteCloser, upload_status chan uploadStatus) {
149 go kc.uploadToKeepServer(url, st.expectPath, reader, upload_status, int64(len("foo")), "TestUploadToStubKeepServer")
151 writer.Write([]byte("foo"))
155 status := <-upload_status
156 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, ""})
159 log.Printf("TestUploadToStubKeepServer done")
162 func (s *StandaloneSuite) TestUploadToStubKeepServerBufferReader(c *C) {
163 log.Printf("TestUploadToStubKeepServerBufferReader")
165 st := StubPutHandler{
167 "acbd18db4cc2f85cedef654fccc4a4d8",
172 UploadToStubHelper(c, st,
173 func(kc *KeepClient, url string, reader io.ReadCloser,
174 writer io.WriteCloser, upload_status chan uploadStatus) {
176 tr := streamer.AsyncStreamFromReader(512, reader)
179 br1 := tr.MakeStreamReader()
181 go kc.uploadToKeepServer(url, st.expectPath, br1, upload_status, 3, "TestUploadToStubKeepServerBufferReader")
183 writer.Write([]byte("foo"))
188 status := <-upload_status
189 c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, ""})
192 log.Printf("TestUploadToStubKeepServerBufferReader done")
195 type FailHandler struct {
199 func (fh FailHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
200 resp.WriteHeader(500)
201 fh.handled <- fmt.Sprintf("http://%s", req.Host)
204 type FailThenSucceedHandler struct {
207 successhandler StubGetHandler
210 func (fh *FailThenSucceedHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
212 resp.WriteHeader(500)
214 fh.handled <- fmt.Sprintf("http://%s", req.Host)
216 fh.successhandler.ServeHTTP(resp, req)
220 type Error404Handler struct {
224 func (fh Error404Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
225 resp.WriteHeader(404)
226 fh.handled <- fmt.Sprintf("http://%s", req.Host)
229 func (s *StandaloneSuite) TestFailedUploadToStubKeepServer(c *C) {
230 log.Printf("TestFailedUploadToStubKeepServer")
235 hash := "acbd18db4cc2f85cedef654fccc4a4d8"
237 UploadToStubHelper(c, st,
238 func(kc *KeepClient, url string, reader io.ReadCloser,
239 writer io.WriteCloser, upload_status chan uploadStatus) {
241 go kc.uploadToKeepServer(url, hash, reader, upload_status, 3, "TestFailedUploadToStubKeepServer")
243 writer.Write([]byte("foo"))
248 status := <-upload_status
249 c.Check(status.url, Equals, fmt.Sprintf("%s/%s", url, hash))
250 c.Check(status.statusCode, Equals, 500)
252 log.Printf("TestFailedUploadToStubKeepServer done")
255 type KeepServer struct {
256 listener net.Listener
260 func RunSomeFakeKeepServers(st http.Handler, n int) (ks []KeepServer) {
261 ks = make([]KeepServer, n)
263 for i := 0; i < n; i += 1 {
264 ks[i] = RunFakeKeepServer(st)
270 func (s *StandaloneSuite) TestPutB(c *C) {
271 log.Printf("TestPutB")
273 hash := Md5String("foo")
275 st := StubPutHandler{
280 make(chan string, 5)}
282 arv, _ := arvadosclient.MakeArvadosClient()
283 kc, _ := MakeKeepClient(&arv)
286 arv.ApiToken = "abc123"
287 localRoots := make(map[string]string)
288 writableLocalRoots := make(map[string]string)
290 ks := RunSomeFakeKeepServers(st, 5)
292 for i, k := range ks {
293 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
294 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
295 defer k.listener.Close()
298 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
300 kc.PutB([]byte("foo"))
302 shuff := NewRootSorter(
303 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
307 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
308 (s1 == shuff[1] && s2 == shuff[0]),
312 log.Printf("TestPutB done")
315 func (s *StandaloneSuite) TestPutHR(c *C) {
316 log.Printf("TestPutHR")
318 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
320 st := StubPutHandler{
325 make(chan string, 5)}
327 arv, _ := arvadosclient.MakeArvadosClient()
328 kc, _ := MakeKeepClient(&arv)
331 arv.ApiToken = "abc123"
332 localRoots := make(map[string]string)
333 writableLocalRoots := make(map[string]string)
335 ks := RunSomeFakeKeepServers(st, 5)
337 for i, k := range ks {
338 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
339 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
340 defer k.listener.Close()
343 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
345 reader, writer := io.Pipe()
348 writer.Write([]byte("foo"))
352 kc.PutHR(hash, reader, 3)
354 shuff := NewRootSorter(kc.LocalRoots(), hash).GetSortedRoots()
360 c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
361 (s1 == shuff[1] && s2 == shuff[0]),
365 log.Printf("TestPutHR done")
368 func (s *StandaloneSuite) TestPutWithFail(c *C) {
369 log.Printf("TestPutWithFail")
371 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
373 st := StubPutHandler{
378 make(chan string, 4)}
381 make(chan string, 1)}
383 arv, err := arvadosclient.MakeArvadosClient()
384 kc, _ := MakeKeepClient(&arv)
387 arv.ApiToken = "abc123"
388 localRoots := make(map[string]string)
389 writableLocalRoots := make(map[string]string)
391 ks1 := RunSomeFakeKeepServers(st, 4)
392 ks2 := RunSomeFakeKeepServers(fh, 1)
394 for i, k := range ks1 {
395 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
396 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
397 defer k.listener.Close()
399 for i, k := range ks2 {
400 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
401 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
402 defer k.listener.Close()
405 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
407 shuff := NewRootSorter(
408 kc.LocalRoots(), Md5String("foo")).GetSortedRoots()
410 phash, replicas, err := kc.PutB([]byte("foo"))
414 c.Check(err, Equals, nil)
415 c.Check(phash, Equals, "")
416 c.Check(replicas, Equals, 2)
421 c.Check((s1 == shuff[1] && s2 == shuff[2]) ||
422 (s1 == shuff[2] && s2 == shuff[1]),
427 func (s *StandaloneSuite) TestPutWithTooManyFail(c *C) {
428 log.Printf("TestPutWithTooManyFail")
430 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
432 st := StubPutHandler{
437 make(chan string, 1)}
440 make(chan string, 4)}
442 arv, err := arvadosclient.MakeArvadosClient()
443 kc, _ := MakeKeepClient(&arv)
447 arv.ApiToken = "abc123"
448 localRoots := make(map[string]string)
449 writableLocalRoots := make(map[string]string)
451 ks1 := RunSomeFakeKeepServers(st, 1)
452 ks2 := RunSomeFakeKeepServers(fh, 4)
454 for i, k := range ks1 {
455 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
456 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
457 defer k.listener.Close()
459 for i, k := range ks2 {
460 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
461 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
462 defer k.listener.Close()
465 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
467 _, replicas, err := kc.PutB([]byte("foo"))
469 c.Check(err, Equals, InsufficientReplicasError)
470 c.Check(replicas, Equals, 1)
471 c.Check(<-st.handled, Equals, ks1[0].url)
473 log.Printf("TestPutWithTooManyFail done")
476 type StubGetHandler struct {
479 expectApiToken string
484 func (sgh StubGetHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
485 sgh.c.Check(req.URL.Path, Equals, "/"+sgh.expectPath)
486 sgh.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", sgh.expectApiToken))
487 resp.WriteHeader(sgh.httpStatus)
488 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(sgh.body)))
492 func (s *StandaloneSuite) TestGet(c *C) {
493 log.Printf("TestGet")
495 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
497 st := StubGetHandler{
504 ks := RunFakeKeepServer(st)
505 defer ks.listener.Close()
507 arv, err := arvadosclient.MakeArvadosClient()
508 kc, _ := MakeKeepClient(&arv)
509 arv.ApiToken = "abc123"
510 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
512 r, n, url2, err := kc.Get(hash)
514 c.Check(err, Equals, nil)
515 c.Check(n, Equals, int64(3))
516 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks.url, hash))
518 content, err2 := ioutil.ReadAll(r)
519 c.Check(err2, Equals, nil)
520 c.Check(content, DeepEquals, []byte("foo"))
522 log.Printf("TestGet done")
525 func (s *StandaloneSuite) TestGet404(c *C) {
526 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
528 st := Error404Handler{make(chan string, 1)}
530 ks := RunFakeKeepServer(st)
531 defer ks.listener.Close()
533 arv, err := arvadosclient.MakeArvadosClient()
534 kc, _ := MakeKeepClient(&arv)
535 arv.ApiToken = "abc123"
536 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
538 r, n, url2, err := kc.Get(hash)
539 c.Check(err, Equals, BlockNotFound)
540 c.Check(n, Equals, int64(0))
541 c.Check(url2, Equals, "")
542 c.Check(r, Equals, nil)
545 func (s *StandaloneSuite) TestGetFail(c *C) {
546 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
548 st := FailHandler{make(chan string, 1)}
550 ks := RunFakeKeepServer(st)
551 defer ks.listener.Close()
553 arv, err := arvadosclient.MakeArvadosClient()
554 kc, _ := MakeKeepClient(&arv)
555 arv.ApiToken = "abc123"
556 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
559 r, n, url2, err := kc.Get(hash)
560 errNotFound, _ := err.(ErrNotFound)
561 c.Check(errNotFound, NotNil)
562 c.Check(n, Equals, int64(0))
563 c.Check(url2, Equals, "")
564 c.Check(r, Equals, nil)
567 func (s *StandaloneSuite) TestGetFailRetry(c *C) {
568 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
570 st := &FailThenSucceedHandler{make(chan string, 1), 0,
578 ks := RunFakeKeepServer(st)
579 defer ks.listener.Close()
581 arv, err := arvadosclient.MakeArvadosClient()
582 kc, _ := MakeKeepClient(&arv)
583 arv.ApiToken = "abc123"
584 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
586 r, n, url2, err := kc.Get(hash)
588 c.Check(err, Equals, nil)
589 c.Check(n, Equals, int64(3))
590 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks.url, hash))
592 content, err2 := ioutil.ReadAll(r)
593 c.Check(err2, Equals, nil)
594 c.Check(content, DeepEquals, []byte("foo"))
597 func (s *StandaloneSuite) TestGetNetError(c *C) {
598 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
600 arv, err := arvadosclient.MakeArvadosClient()
601 kc, _ := MakeKeepClient(&arv)
602 arv.ApiToken = "abc123"
603 kc.SetServiceRoots(map[string]string{"x": "http://localhost:62222"}, nil, nil)
605 r, n, url2, err := kc.Get(hash)
606 errNotFound, _ := err.(ErrNotFound)
607 c.Check(errNotFound, NotNil)
608 c.Check(strings.Contains(err.Error(), "connection refused"), Equals, true)
609 c.Check(n, Equals, int64(0))
610 c.Check(url2, Equals, "")
611 c.Check(r, Equals, nil)
614 func (s *StandaloneSuite) TestGetWithServiceHint(c *C) {
615 uuid := "zzzzz-bi6l4-123451234512345"
616 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
618 // This one shouldn't be used:
619 ks0 := RunFakeKeepServer(StubGetHandler{
625 defer ks0.listener.Close()
626 // This one should be used:
627 ks := RunFakeKeepServer(StubGetHandler{
633 defer ks.listener.Close()
635 arv, err := arvadosclient.MakeArvadosClient()
636 kc, _ := MakeKeepClient(&arv)
637 arv.ApiToken = "abc123"
639 map[string]string{"x": ks0.url},
641 map[string]string{uuid: ks.url})
643 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
645 c.Check(err, Equals, nil)
646 c.Check(n, Equals, int64(3))
647 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ks.url, hash+"+K@"+uuid))
649 content, err := ioutil.ReadAll(r)
650 c.Check(err, Equals, nil)
651 c.Check(content, DeepEquals, []byte("foo"))
654 // Use a service hint to fetch from a local disk service, overriding
655 // rendezvous probe order.
656 func (s *StandaloneSuite) TestGetWithLocalServiceHint(c *C) {
657 uuid := "zzzzz-bi6l4-zzzzzzzzzzzzzzz"
658 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
660 // This one shouldn't be used, although it appears first in
661 // rendezvous probe order:
662 ks0 := RunFakeKeepServer(StubGetHandler{
668 defer ks0.listener.Close()
669 // This one should be used:
670 ks := RunFakeKeepServer(StubGetHandler{
676 defer ks.listener.Close()
678 arv, err := arvadosclient.MakeArvadosClient()
679 kc, _ := MakeKeepClient(&arv)
680 arv.ApiToken = "abc123"
683 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
684 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
685 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
689 "zzzzz-bi6l4-yyyyyyyyyyyyyyy": ks0.url,
690 "zzzzz-bi6l4-xxxxxxxxxxxxxxx": ks0.url,
691 "zzzzz-bi6l4-wwwwwwwwwwwwwww": ks0.url,
695 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
697 c.Check(err, Equals, nil)
698 c.Check(n, Equals, int64(3))
699 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ks.url, hash+"+K@"+uuid))
701 content, err := ioutil.ReadAll(r)
702 c.Check(err, Equals, nil)
703 c.Check(content, DeepEquals, []byte("foo"))
706 func (s *StandaloneSuite) TestGetWithServiceHintFailoverToLocals(c *C) {
707 uuid := "zzzzz-bi6l4-123451234512345"
708 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
710 ksLocal := RunFakeKeepServer(StubGetHandler{
716 defer ksLocal.listener.Close()
717 ksGateway := RunFakeKeepServer(StubGetHandler{
721 http.StatusInternalServerError,
723 defer ksGateway.listener.Close()
725 arv, err := arvadosclient.MakeArvadosClient()
726 kc, _ := MakeKeepClient(&arv)
727 arv.ApiToken = "abc123"
729 map[string]string{"zzzzz-bi6l4-keepdisk0000000": ksLocal.url},
731 map[string]string{uuid: ksGateway.url})
733 r, n, uri, err := kc.Get(hash + "+K@" + uuid)
734 c.Assert(err, Equals, nil)
736 c.Check(n, Equals, int64(3))
737 c.Check(uri, Equals, fmt.Sprintf("%s/%s", ksLocal.url, hash+"+K@"+uuid))
739 content, err := ioutil.ReadAll(r)
740 c.Check(err, Equals, nil)
741 c.Check(content, DeepEquals, []byte("foo"))
744 type BarHandler struct {
748 func (this BarHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
749 resp.Write([]byte("bar"))
750 this.handled <- fmt.Sprintf("http://%s", req.Host)
753 func (s *StandaloneSuite) TestChecksum(c *C) {
754 foohash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
755 barhash := fmt.Sprintf("%x", md5.Sum([]byte("bar")))
757 st := BarHandler{make(chan string, 1)}
759 ks := RunFakeKeepServer(st)
760 defer ks.listener.Close()
762 arv, err := arvadosclient.MakeArvadosClient()
763 kc, _ := MakeKeepClient(&arv)
764 arv.ApiToken = "abc123"
765 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
767 r, n, _, err := kc.Get(barhash)
768 _, err = ioutil.ReadAll(r)
769 c.Check(n, Equals, int64(3))
770 c.Check(err, Equals, nil)
774 r, n, _, err = kc.Get(foohash)
775 _, err = ioutil.ReadAll(r)
776 c.Check(n, Equals, int64(3))
777 c.Check(err, Equals, BadChecksum)
782 func (s *StandaloneSuite) TestGetWithFailures(c *C) {
783 content := []byte("waz")
784 hash := fmt.Sprintf("%x", md5.Sum(content))
786 fh := Error404Handler{
787 make(chan string, 4)}
789 st := StubGetHandler{
796 arv, err := arvadosclient.MakeArvadosClient()
797 kc, _ := MakeKeepClient(&arv)
798 arv.ApiToken = "abc123"
799 localRoots := make(map[string]string)
800 writableLocalRoots := make(map[string]string)
802 ks1 := RunSomeFakeKeepServers(st, 1)
803 ks2 := RunSomeFakeKeepServers(fh, 4)
805 for i, k := range ks1 {
806 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
807 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
808 defer k.listener.Close()
810 for i, k := range ks2 {
811 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
812 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i+len(ks1))] = k.url
813 defer k.listener.Close()
816 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
819 // This test works only if one of the failing services is
820 // attempted before the succeeding service. Otherwise,
821 // <-fh.handled below will just hang! (Probe order depends on
822 // the choice of block content "waz" and the UUIDs of the fake
823 // servers, so we just tried different strings until we found
824 // an example that passes this Assert.)
825 c.Assert(NewRootSorter(localRoots, hash).GetSortedRoots()[0], Not(Equals), ks1[0].url)
827 r, n, url2, err := kc.Get(hash)
830 c.Check(err, Equals, nil)
831 c.Check(n, Equals, int64(3))
832 c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks1[0].url, hash))
834 read_content, err2 := ioutil.ReadAll(r)
835 c.Check(err2, Equals, nil)
836 c.Check(read_content, DeepEquals, content)
839 func (s *ServerRequiredSuite) TestPutGetHead(c *C) {
840 content := []byte("TestPutGetHead")
842 arv, err := arvadosclient.MakeArvadosClient()
843 kc, err := MakeKeepClient(&arv)
844 c.Assert(err, Equals, nil)
846 hash := fmt.Sprintf("%x", md5.Sum(content))
849 n, _, err := kc.Ask(hash)
850 c.Check(err, Equals, BlockNotFound)
851 c.Check(n, Equals, int64(0))
854 hash2, replicas, err := kc.PutB(content)
855 c.Check(hash2, Matches, fmt.Sprintf(`%s\+%d\b.*`, hash, len(content)))
856 c.Check(replicas, Equals, 2)
857 c.Check(err, Equals, nil)
860 r, n, url2, err := kc.Get(hash)
861 c.Check(err, Equals, nil)
862 c.Check(n, Equals, int64(len(content)))
863 c.Check(url2, Matches, fmt.Sprintf("http://localhost:\\d+/%s", hash))
865 read_content, err2 := ioutil.ReadAll(r)
866 c.Check(err2, Equals, nil)
867 c.Check(read_content, DeepEquals, content)
870 n, url2, err := kc.Ask(hash)
871 c.Check(err, Equals, nil)
872 c.Check(n, Equals, int64(len(content)))
873 c.Check(url2, Matches, fmt.Sprintf("http://localhost:\\d+/%s", hash))
877 type StubProxyHandler struct {
881 func (this StubProxyHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
882 resp.Header().Set("X-Keep-Replicas-Stored", "2")
883 this.handled <- fmt.Sprintf("http://%s", req.Host)
886 func (s *StandaloneSuite) TestPutProxy(c *C) {
887 log.Printf("TestPutProxy")
889 st := StubProxyHandler{make(chan string, 1)}
891 arv, err := arvadosclient.MakeArvadosClient()
892 kc, _ := MakeKeepClient(&arv)
895 kc.Using_proxy = true
896 arv.ApiToken = "abc123"
897 localRoots := make(map[string]string)
898 writableLocalRoots := make(map[string]string)
900 ks1 := RunSomeFakeKeepServers(st, 1)
902 for i, k := range ks1 {
903 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
904 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
905 defer k.listener.Close()
908 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
910 _, replicas, err := kc.PutB([]byte("foo"))
913 c.Check(err, Equals, nil)
914 c.Check(replicas, Equals, 2)
916 log.Printf("TestPutProxy done")
919 func (s *StandaloneSuite) TestPutProxyInsufficientReplicas(c *C) {
920 log.Printf("TestPutProxy")
922 st := StubProxyHandler{make(chan string, 1)}
924 arv, err := arvadosclient.MakeArvadosClient()
925 kc, _ := MakeKeepClient(&arv)
928 kc.Using_proxy = true
929 arv.ApiToken = "abc123"
930 localRoots := make(map[string]string)
931 writableLocalRoots := make(map[string]string)
933 ks1 := RunSomeFakeKeepServers(st, 1)
935 for i, k := range ks1 {
936 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
937 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
938 defer k.listener.Close()
940 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
942 _, replicas, err := kc.PutB([]byte("foo"))
945 c.Check(err, Equals, InsufficientReplicasError)
946 c.Check(replicas, Equals, 2)
948 log.Printf("TestPutProxy done")
951 func (s *StandaloneSuite) TestMakeLocator(c *C) {
952 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+3+Aabcde@12345678")
953 c.Check(err, Equals, nil)
954 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
955 c.Check(l.Size, Equals, 3)
956 c.Check(l.Hints, DeepEquals, []string{"3", "Aabcde@12345678"})
959 func (s *StandaloneSuite) TestMakeLocatorNoHints(c *C) {
960 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce")
961 c.Check(err, Equals, nil)
962 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
963 c.Check(l.Size, Equals, -1)
964 c.Check(l.Hints, DeepEquals, []string{})
967 func (s *StandaloneSuite) TestMakeLocatorNoSizeHint(c *C) {
968 l, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+Aabcde@12345678")
969 c.Check(err, Equals, nil)
970 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
971 c.Check(l.Size, Equals, -1)
972 c.Check(l.Hints, DeepEquals, []string{"Aabcde@12345678"})
975 func (s *StandaloneSuite) TestMakeLocatorPreservesUnrecognizedHints(c *C) {
976 str := "91f372a266fe2bf2823cb8ec7fda31ce+3+Unknown+Kzzzzz+Afoobar"
977 l, err := MakeLocator(str)
978 c.Check(err, Equals, nil)
979 c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
980 c.Check(l.Size, Equals, 3)
981 c.Check(l.Hints, DeepEquals, []string{"3", "Unknown", "Kzzzzz", "Afoobar"})
982 c.Check(l.String(), Equals, str)
985 func (s *StandaloneSuite) TestMakeLocatorInvalidInput(c *C) {
986 _, err := MakeLocator("91f372a266fe2bf2823cb8ec7fda31c")
987 c.Check(err, Equals, InvalidLocatorError)
990 func (s *StandaloneSuite) TestPutBWant2ReplicasWithOnlyOneWritableLocalRoot(c *C) {
991 hash := Md5String("foo")
993 st := StubPutHandler{
998 make(chan string, 5)}
1000 arv, _ := arvadosclient.MakeArvadosClient()
1001 kc, _ := MakeKeepClient(&arv)
1003 kc.Want_replicas = 2
1004 arv.ApiToken = "abc123"
1005 localRoots := make(map[string]string)
1006 writableLocalRoots := make(map[string]string)
1008 ks := RunSomeFakeKeepServers(st, 5)
1010 for i, k := range ks {
1011 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1013 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1015 defer k.listener.Close()
1018 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1020 _, replicas, err := kc.PutB([]byte("foo"))
1022 c.Check(err, Equals, InsufficientReplicasError)
1023 c.Check(replicas, Equals, 1)
1025 c.Check(<-st.handled, Equals, localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", 0)])
1028 func (s *StandaloneSuite) TestPutBWithNoWritableLocalRoots(c *C) {
1029 hash := Md5String("foo")
1031 st := StubPutHandler{
1036 make(chan string, 5)}
1038 arv, _ := arvadosclient.MakeArvadosClient()
1039 kc, _ := MakeKeepClient(&arv)
1041 kc.Want_replicas = 2
1042 arv.ApiToken = "abc123"
1043 localRoots := make(map[string]string)
1044 writableLocalRoots := make(map[string]string)
1046 ks := RunSomeFakeKeepServers(st, 5)
1048 for i, k := range ks {
1049 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1050 defer k.listener.Close()
1053 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1055 _, replicas, err := kc.PutB([]byte("foo"))
1057 c.Check(err, Equals, InsufficientReplicasError)
1058 c.Check(replicas, Equals, 0)
1061 type StubGetIndexHandler struct {
1064 expectAPIToken string
1069 func (h StubGetIndexHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1070 h.c.Check(req.URL.Path, Equals, h.expectPath)
1071 h.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", h.expectAPIToken))
1072 resp.WriteHeader(h.httpStatus)
1073 resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(h.body)))
1077 func (s *StandaloneSuite) TestGetIndexWithNoPrefix(c *C) {
1078 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1080 st := StubGetIndexHandler{
1085 []byte(hash + "+3 1443559274\n\n")}
1087 ks := RunFakeKeepServer(st)
1088 defer ks.listener.Close()
1090 arv, err := arvadosclient.MakeArvadosClient()
1091 kc, _ := MakeKeepClient(&arv)
1092 arv.ApiToken = "abc123"
1093 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1095 r, err := kc.GetIndex("x", "")
1096 c.Check(err, Equals, nil)
1098 content, err2 := ioutil.ReadAll(r)
1099 c.Check(err2, Equals, nil)
1100 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1103 func (s *StandaloneSuite) TestGetIndexWithPrefix(c *C) {
1104 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1106 st := StubGetIndexHandler{
1108 "/index/" + hash[0:3],
1111 []byte(hash + "+3 1443559274\n\n")}
1113 ks := RunFakeKeepServer(st)
1114 defer ks.listener.Close()
1116 arv, err := arvadosclient.MakeArvadosClient()
1117 kc, _ := MakeKeepClient(&arv)
1118 arv.ApiToken = "abc123"
1119 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1121 r, err := kc.GetIndex("x", hash[0:3])
1122 c.Check(err, Equals, nil)
1124 content, err2 := ioutil.ReadAll(r)
1125 c.Check(err2, Equals, nil)
1126 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1129 func (s *StandaloneSuite) TestGetIndexIncomplete(c *C) {
1130 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1132 st := StubGetIndexHandler{
1134 "/index/" + hash[0:3],
1139 ks := RunFakeKeepServer(st)
1140 defer ks.listener.Close()
1142 arv, err := arvadosclient.MakeArvadosClient()
1143 kc, _ := MakeKeepClient(&arv)
1144 arv.ApiToken = "abc123"
1145 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1147 _, err = kc.GetIndex("x", hash[0:3])
1148 c.Check(err, Equals, ErrIncompleteIndex)
1151 func (s *StandaloneSuite) TestGetIndexWithNoSuchServer(c *C) {
1152 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
1154 st := StubGetIndexHandler{
1156 "/index/" + hash[0:3],
1161 ks := RunFakeKeepServer(st)
1162 defer ks.listener.Close()
1164 arv, err := arvadosclient.MakeArvadosClient()
1165 kc, _ := MakeKeepClient(&arv)
1166 arv.ApiToken = "abc123"
1167 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1169 _, err = kc.GetIndex("y", hash[0:3])
1170 c.Check(err, Equals, ErrNoSuchKeepServer)
1173 func (s *StandaloneSuite) TestGetIndexWithNoSuchPrefix(c *C) {
1174 st := StubGetIndexHandler{
1181 ks := RunFakeKeepServer(st)
1182 defer ks.listener.Close()
1184 arv, err := arvadosclient.MakeArvadosClient()
1185 kc, _ := MakeKeepClient(&arv)
1186 arv.ApiToken = "abc123"
1187 kc.SetServiceRoots(map[string]string{"x": ks.url}, nil, nil)
1189 r, err := kc.GetIndex("x", "abcd")
1190 c.Check(err, Equals, nil)
1192 content, err2 := ioutil.ReadAll(r)
1193 c.Check(err2, Equals, nil)
1194 c.Check(content, DeepEquals, st.body[0:len(st.body)-1])
1197 type FailThenSucceedPutHandler struct {
1200 successhandler StubPutHandler
1203 func (h *FailThenSucceedPutHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
1205 resp.WriteHeader(500)
1207 h.handled <- fmt.Sprintf("http://%s", req.Host)
1209 h.successhandler.ServeHTTP(resp, req)
1213 func (s *StandaloneSuite) TestPutBRetry(c *C) {
1214 st := &FailThenSucceedPutHandler{make(chan string, 1), 0,
1220 make(chan string, 5)}}
1222 arv, _ := arvadosclient.MakeArvadosClient()
1223 kc, _ := MakeKeepClient(&arv)
1225 kc.Want_replicas = 2
1226 arv.ApiToken = "abc123"
1227 localRoots := make(map[string]string)
1228 writableLocalRoots := make(map[string]string)
1230 ks := RunSomeFakeKeepServers(st, 2)
1232 for i, k := range ks {
1233 localRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1234 writableLocalRoots[fmt.Sprintf("zzzzz-bi6l4-fakefakefake%03d", i)] = k.url
1235 defer k.listener.Close()
1238 kc.SetServiceRoots(localRoots, writableLocalRoots, nil)
1240 hash, replicas, err := kc.PutB([]byte("foo"))
1242 c.Check(err, Equals, nil)
1243 c.Check(hash, Equals, "")
1244 c.Check(replicas, Equals, 2)