Merge branch '2800-python-global-state' into 2800-pgs
[arvados.git] / sdk / go / keepclient / keepclient_test.go
1 package keepclient
2
3 import (
4         "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
5         "git.curoverse.com/arvados.git/sdk/go/streamer"
6         "crypto/md5"
7         "flag"
8         "fmt"
9         . "gopkg.in/check.v1"
10         "io"
11         "io/ioutil"
12         "log"
13         "net"
14         "net/http"
15         "os"
16         "os/exec"
17         "testing"
18 )
19
20 // Gocheck boilerplate
21 func Test(t *testing.T) {
22         TestingT(t)
23 }
24
25 // Gocheck boilerplate
26 var _ = Suite(&ServerRequiredSuite{})
27 var _ = Suite(&StandaloneSuite{})
28
29 var no_server = flag.Bool("no-server", false, "Skip 'ServerRequireSuite'")
30
31 // Tests that require the Keep server running
32 type ServerRequiredSuite struct{}
33
34 // Standalone tests
35 type StandaloneSuite struct{}
36
37 func pythonDir() string {
38         cwd, _ := os.Getwd()
39         return fmt.Sprintf("%s/../../python/tests", cwd)
40 }
41
42 func (s *ServerRequiredSuite) SetUpSuite(c *C) {
43         if *no_server {
44                 c.Skip("Skipping tests that require server")
45                 return
46         }
47         os.Chdir(pythonDir())
48         {
49                 cmd := exec.Command("python", "run_test_server.py", "start")
50                 stderr, err := cmd.StderrPipe()
51                 if err != nil {
52                         log.Fatalf("Setting up stderr pipe: %s", err)
53                 }
54                 go io.Copy(os.Stderr, stderr)
55                 if err := cmd.Run(); err != nil {
56                         panic(fmt.Sprintf("'python run_test_server.py start' returned error %s", err))
57                 }
58         }
59         {
60                 cmd := exec.Command("python", "run_test_server.py", "start_keep")
61                 stderr, err := cmd.StderrPipe()
62                 if err != nil {
63                         log.Fatalf("Setting up stderr pipe: %s", err)
64                 }
65                 go io.Copy(os.Stderr, stderr)
66                 if err := cmd.Run(); err != nil {
67                         panic(fmt.Sprintf("'python run_test_server.py start_keep' returned error %s", err))
68                 }
69         }
70 }
71
72 func (s *ServerRequiredSuite) TearDownSuite(c *C) {
73         os.Chdir(pythonDir())
74         exec.Command("python", "run_test_server.py", "stop_keep").Run()
75         exec.Command("python", "run_test_server.py", "stop").Run()
76 }
77
78 func (s *ServerRequiredSuite) TestMakeKeepClient(c *C) {
79         os.Setenv("ARVADOS_API_HOST", "localhost:3001")
80         os.Setenv("ARVADOS_API_TOKEN", "4axaw8zxe0qm22wa6urpp5nskcne8z88cvbupv653y1njyi05h")
81         os.Setenv("ARVADOS_API_HOST_INSECURE", "true")
82
83         arv, err := arvadosclient.MakeArvadosClient()
84         c.Assert(err, Equals, nil)
85
86         kc, err := MakeKeepClient(&arv)
87
88         c.Assert(err, Equals, nil)
89         c.Check(len(kc.ServiceRoots()), Equals, 2)
90         c.Check(kc.ServiceRoots()[0], Equals, "http://localhost:25107")
91         c.Check(kc.ServiceRoots()[1], Equals, "http://localhost:25108")
92 }
93
94 func (s *StandaloneSuite) TestShuffleServiceRoots(c *C) {
95         kc := KeepClient{}
96         kc.SetServiceRoots([]string{"http://localhost:25107", "http://localhost:25108", "http://localhost:25109", "http://localhost:25110", "http://localhost:25111", "http://localhost:25112", "http://localhost:25113", "http://localhost:25114", "http://localhost:25115", "http://localhost:25116", "http://localhost:25117", "http://localhost:25118", "http://localhost:25119", "http://localhost:25120", "http://localhost:25121", "http://localhost:25122", "http://localhost:25123"})
97
98         // "foo" acbd18db4cc2f85cedef654fccc4a4d8
99         foo_shuffle := []string{"http://localhost:25116", "http://localhost:25120", "http://localhost:25119", "http://localhost:25122", "http://localhost:25108", "http://localhost:25114", "http://localhost:25112", "http://localhost:25107", "http://localhost:25118", "http://localhost:25111", "http://localhost:25113", "http://localhost:25121", "http://localhost:25110", "http://localhost:25117", "http://localhost:25109", "http://localhost:25115", "http://localhost:25123"}
100         c.Check(kc.shuffledServiceRoots("acbd18db4cc2f85cedef654fccc4a4d8"), DeepEquals, foo_shuffle)
101
102         // "bar" 37b51d194a7513e45b56f6524f2d51f2
103         bar_shuffle := []string{"http://localhost:25108", "http://localhost:25112", "http://localhost:25119", "http://localhost:25107", "http://localhost:25110", "http://localhost:25116", "http://localhost:25122", "http://localhost:25120", "http://localhost:25121", "http://localhost:25117", "http://localhost:25111", "http://localhost:25123", "http://localhost:25118", "http://localhost:25113", "http://localhost:25114", "http://localhost:25115", "http://localhost:25109"}
104         c.Check(kc.shuffledServiceRoots("37b51d194a7513e45b56f6524f2d51f2"), DeepEquals, bar_shuffle)
105 }
106
107 type StubPutHandler struct {
108         c              *C
109         expectPath     string
110         expectApiToken string
111         expectBody     string
112         handled        chan string
113 }
114
115 func (this StubPutHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
116         this.c.Check(req.URL.Path, Equals, "/"+this.expectPath)
117         this.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", this.expectApiToken))
118         body, err := ioutil.ReadAll(req.Body)
119         this.c.Check(err, Equals, nil)
120         this.c.Check(body, DeepEquals, []byte(this.expectBody))
121         resp.WriteHeader(200)
122         this.handled <- fmt.Sprintf("http://%s", req.Host)
123 }
124
125 func RunBogusKeepServer(st http.Handler, port int) (listener net.Listener, url string) {
126         var err error
127         listener, err = net.ListenTCP("tcp", &net.TCPAddr{Port: port})
128         if err != nil {
129                 panic(fmt.Sprintf("Could not listen on tcp port %v", port))
130         }
131
132         url = fmt.Sprintf("http://localhost:%d", port)
133
134         go http.Serve(listener, st)
135         return listener, url
136 }
137
138 func UploadToStubHelper(c *C, st http.Handler, f func(KeepClient, string,
139         io.ReadCloser, io.WriteCloser, chan uploadStatus)) {
140
141         listener, url := RunBogusKeepServer(st, 2990)
142         defer listener.Close()
143
144         arv, _ := arvadosclient.MakeArvadosClient()
145         arv.ApiToken = "abc123"
146
147         kc, _ := MakeKeepClient(&arv)
148
149         reader, writer := io.Pipe()
150         upload_status := make(chan uploadStatus)
151
152         f(kc, url, reader, writer, upload_status)
153 }
154
155 func (s *StandaloneSuite) TestUploadToStubKeepServer(c *C) {
156         log.Printf("TestUploadToStubKeepServer")
157
158         st := StubPutHandler{
159                 c,
160                 "acbd18db4cc2f85cedef654fccc4a4d8",
161                 "abc123",
162                 "foo",
163                 make(chan string)}
164
165         UploadToStubHelper(c, st,
166                 func(kc KeepClient, url string, reader io.ReadCloser,
167                         writer io.WriteCloser, upload_status chan uploadStatus) {
168
169                         go kc.uploadToKeepServer(url, st.expectPath, reader, upload_status, int64(len("foo")))
170
171                         writer.Write([]byte("foo"))
172                         writer.Close()
173
174                         <-st.handled
175                         status := <-upload_status
176                         c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, ""})
177                 })
178
179         log.Printf("TestUploadToStubKeepServer done")
180 }
181
182 func (s *StandaloneSuite) TestUploadToStubKeepServerBufferReader(c *C) {
183         log.Printf("TestUploadToStubKeepServerBufferReader")
184
185         st := StubPutHandler{
186                 c,
187                 "acbd18db4cc2f85cedef654fccc4a4d8",
188                 "abc123",
189                 "foo",
190                 make(chan string)}
191
192         UploadToStubHelper(c, st,
193                 func(kc KeepClient, url string, reader io.ReadCloser,
194                         writer io.WriteCloser, upload_status chan uploadStatus) {
195
196                         tr := streamer.AsyncStreamFromReader(512, reader)
197                         defer tr.Close()
198
199                         br1 := tr.MakeStreamReader()
200
201                         go kc.uploadToKeepServer(url, st.expectPath, br1, upload_status, 3)
202
203                         writer.Write([]byte("foo"))
204                         writer.Close()
205
206                         <-st.handled
207
208                         status := <-upload_status
209                         c.Check(status, DeepEquals, uploadStatus{nil, fmt.Sprintf("%s/%s", url, st.expectPath), 200, 1, ""})
210                 })
211
212         log.Printf("TestUploadToStubKeepServerBufferReader done")
213 }
214
215 type FailHandler struct {
216         handled chan string
217 }
218
219 func (this FailHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
220         resp.WriteHeader(500)
221         this.handled <- fmt.Sprintf("http://%s", req.Host)
222 }
223
224 func (s *StandaloneSuite) TestFailedUploadToStubKeepServer(c *C) {
225         log.Printf("TestFailedUploadToStubKeepServer")
226
227         st := FailHandler{
228                 make(chan string)}
229
230         hash := "acbd18db4cc2f85cedef654fccc4a4d8"
231
232         UploadToStubHelper(c, st,
233                 func(kc KeepClient, url string, reader io.ReadCloser,
234                         writer io.WriteCloser, upload_status chan uploadStatus) {
235
236                         go kc.uploadToKeepServer(url, hash, reader, upload_status, 3)
237
238                         writer.Write([]byte("foo"))
239                         writer.Close()
240
241                         <-st.handled
242
243                         status := <-upload_status
244                         c.Check(status.url, Equals, fmt.Sprintf("%s/%s", url, hash))
245                         c.Check(status.statusCode, Equals, 500)
246                 })
247         log.Printf("TestFailedUploadToStubKeepServer done")
248 }
249
250 type KeepServer struct {
251         listener net.Listener
252         url      string
253 }
254
255 func RunSomeFakeKeepServers(st http.Handler, n int, port int) (ks []KeepServer) {
256         ks = make([]KeepServer, n)
257
258         for i := 0; i < n; i += 1 {
259                 boguslistener, bogusurl := RunBogusKeepServer(st, port+i)
260                 ks[i] = KeepServer{boguslistener, bogusurl}
261         }
262
263         return ks
264 }
265
266 func (s *StandaloneSuite) TestPutB(c *C) {
267         log.Printf("TestPutB")
268
269         hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
270
271         st := StubPutHandler{
272                 c,
273                 hash,
274                 "abc123",
275                 "foo",
276                 make(chan string, 2)}
277
278         arv, _ := arvadosclient.MakeArvadosClient()
279         kc, _ := MakeKeepClient(&arv)
280
281         kc.Want_replicas = 2
282         arv.ApiToken = "abc123"
283         service_roots := make([]string, 5)
284
285         ks := RunSomeFakeKeepServers(st, 5, 2990)
286
287         for i := 0; i < len(ks); i += 1 {
288                 service_roots[i] = ks[i].url
289                 defer ks[i].listener.Close()
290         }
291
292         kc.SetServiceRoots(service_roots)
293
294         kc.PutB([]byte("foo"))
295
296         shuff := kc.shuffledServiceRoots(fmt.Sprintf("%x", md5.Sum([]byte("foo"))))
297
298         s1 := <-st.handled
299         s2 := <-st.handled
300         c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
301                 (s1 == shuff[1] && s2 == shuff[0]),
302                 Equals,
303                 true)
304
305         log.Printf("TestPutB done")
306 }
307
308 func (s *StandaloneSuite) TestPutHR(c *C) {
309         log.Printf("TestPutHR")
310
311         hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
312
313         st := StubPutHandler{
314                 c,
315                 hash,
316                 "abc123",
317                 "foo",
318                 make(chan string, 2)}
319
320         arv, _ := arvadosclient.MakeArvadosClient()
321         kc, _ := MakeKeepClient(&arv)
322
323         kc.Want_replicas = 2
324         arv.ApiToken = "abc123"
325         service_roots := make([]string, 5)
326
327         ks := RunSomeFakeKeepServers(st, 5, 2990)
328
329         for i := 0; i < len(ks); i += 1 {
330                 service_roots[i] = ks[i].url
331                 defer ks[i].listener.Close()
332         }
333
334         kc.SetServiceRoots(service_roots)
335
336         reader, writer := io.Pipe()
337
338         go func() {
339                 writer.Write([]byte("foo"))
340                 writer.Close()
341         }()
342
343         kc.PutHR(hash, reader, 3)
344
345         shuff := kc.shuffledServiceRoots(hash)
346         log.Print(shuff)
347
348         s1 := <-st.handled
349         s2 := <-st.handled
350
351         c.Check((s1 == shuff[0] && s2 == shuff[1]) ||
352                 (s1 == shuff[1] && s2 == shuff[0]),
353                 Equals,
354                 true)
355
356         log.Printf("TestPutHR done")
357 }
358
359 func (s *StandaloneSuite) TestPutWithFail(c *C) {
360         log.Printf("TestPutWithFail")
361
362         hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
363
364         st := StubPutHandler{
365                 c,
366                 hash,
367                 "abc123",
368                 "foo",
369                 make(chan string, 2)}
370
371         fh := FailHandler{
372                 make(chan string, 1)}
373
374         arv, err := arvadosclient.MakeArvadosClient()
375         kc, _ := MakeKeepClient(&arv)
376
377         kc.Want_replicas = 2
378         arv.ApiToken = "abc123"
379         service_roots := make([]string, 5)
380
381         ks1 := RunSomeFakeKeepServers(st, 4, 2990)
382         ks2 := RunSomeFakeKeepServers(fh, 1, 2995)
383
384         for i, k := range ks1 {
385                 service_roots[i] = k.url
386                 defer k.listener.Close()
387         }
388         for i, k := range ks2 {
389                 service_roots[len(ks1)+i] = k.url
390                 defer k.listener.Close()
391         }
392
393         kc.SetServiceRoots(service_roots)
394
395         shuff := kc.shuffledServiceRoots(fmt.Sprintf("%x", md5.Sum([]byte("foo"))))
396
397         phash, replicas, err := kc.PutB([]byte("foo"))
398
399         <-fh.handled
400
401         c.Check(err, Equals, nil)
402         c.Check(phash, Equals, "")
403         c.Check(replicas, Equals, 2)
404         c.Check(<-st.handled, Equals, shuff[1])
405         c.Check(<-st.handled, Equals, shuff[2])
406 }
407
408 func (s *StandaloneSuite) TestPutWithTooManyFail(c *C) {
409         log.Printf("TestPutWithTooManyFail")
410
411         hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
412
413         st := StubPutHandler{
414                 c,
415                 hash,
416                 "abc123",
417                 "foo",
418                 make(chan string, 1)}
419
420         fh := FailHandler{
421                 make(chan string, 4)}
422
423         arv, err := arvadosclient.MakeArvadosClient()
424         kc, _ := MakeKeepClient(&arv)
425
426         kc.Want_replicas = 2
427         arv.ApiToken = "abc123"
428         service_roots := make([]string, 5)
429
430         ks1 := RunSomeFakeKeepServers(st, 1, 2990)
431         ks2 := RunSomeFakeKeepServers(fh, 4, 2991)
432
433         for i, k := range ks1 {
434                 service_roots[i] = k.url
435                 defer k.listener.Close()
436         }
437         for i, k := range ks2 {
438                 service_roots[len(ks1)+i] = k.url
439                 defer k.listener.Close()
440         }
441
442         kc.SetServiceRoots(service_roots)
443
444         shuff := kc.shuffledServiceRoots(fmt.Sprintf("%x", md5.Sum([]byte("foo"))))
445
446         _, replicas, err := kc.PutB([]byte("foo"))
447
448         c.Check(err, Equals, InsufficientReplicasError)
449         c.Check(replicas, Equals, 1)
450         c.Check(<-st.handled, Equals, shuff[1])
451
452         log.Printf("TestPutWithTooManyFail done")
453 }
454
455 type StubGetHandler struct {
456         c              *C
457         expectPath     string
458         expectApiToken string
459         returnBody     []byte
460 }
461
462 func (this StubGetHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
463         this.c.Check(req.URL.Path, Equals, "/"+this.expectPath)
464         this.c.Check(req.Header.Get("Authorization"), Equals, fmt.Sprintf("OAuth2 %s", this.expectApiToken))
465         resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(this.returnBody)))
466         resp.Write(this.returnBody)
467 }
468
469 func (s *StandaloneSuite) TestGet(c *C) {
470         log.Printf("TestGet")
471
472         hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
473
474         st := StubGetHandler{
475                 c,
476                 hash,
477                 "abc123",
478                 []byte("foo")}
479
480         listener, url := RunBogusKeepServer(st, 2990)
481         defer listener.Close()
482
483         arv, err := arvadosclient.MakeArvadosClient()
484         kc, _ := MakeKeepClient(&arv)
485         arv.ApiToken = "abc123"
486         kc.SetServiceRoots([]string{url})
487
488         r, n, url2, err := kc.Get(hash)
489         defer r.Close()
490         c.Check(err, Equals, nil)
491         c.Check(n, Equals, int64(3))
492         c.Check(url2, Equals, fmt.Sprintf("%s/%s", url, hash))
493
494         content, err2 := ioutil.ReadAll(r)
495         c.Check(err2, Equals, nil)
496         c.Check(content, DeepEquals, []byte("foo"))
497
498         log.Printf("TestGet done")
499 }
500
501 func (s *StandaloneSuite) TestGetFail(c *C) {
502         hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
503
504         st := FailHandler{make(chan string, 1)}
505
506         listener, url := RunBogusKeepServer(st, 2990)
507         defer listener.Close()
508
509         arv, err := arvadosclient.MakeArvadosClient()
510         kc, _ := MakeKeepClient(&arv)
511         arv.ApiToken = "abc123"
512         kc.SetServiceRoots([]string{url})
513
514         r, n, url2, err := kc.Get(hash)
515         c.Check(err, Equals, BlockNotFound)
516         c.Check(n, Equals, int64(0))
517         c.Check(url2, Equals, "")
518         c.Check(r, Equals, nil)
519 }
520
521 type BarHandler struct {
522         handled chan string
523 }
524
525 func (this BarHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
526         resp.Write([]byte("bar"))
527         this.handled <- fmt.Sprintf("http://%s", req.Host)
528 }
529
530 func (s *StandaloneSuite) TestChecksum(c *C) {
531         foohash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
532         barhash := fmt.Sprintf("%x", md5.Sum([]byte("bar")))
533
534         st := BarHandler{make(chan string, 1)}
535
536         listener, url := RunBogusKeepServer(st, 2990)
537         defer listener.Close()
538
539         arv, err := arvadosclient.MakeArvadosClient()
540         kc, _ := MakeKeepClient(&arv)
541         arv.ApiToken = "abc123"
542         kc.SetServiceRoots([]string{url})
543
544         r, n, _, err := kc.Get(barhash)
545         _, err = ioutil.ReadAll(r)
546         c.Check(n, Equals, int64(3))
547         c.Check(err, Equals, nil)
548
549         <-st.handled
550
551         r, n, _, err = kc.Get(foohash)
552         _, err = ioutil.ReadAll(r)
553         c.Check(n, Equals, int64(3))
554         c.Check(err, Equals, BadChecksum)
555
556         <-st.handled
557 }
558
559 func (s *StandaloneSuite) TestGetWithFailures(c *C) {
560
561         hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
562
563         fh := FailHandler{
564                 make(chan string, 1)}
565
566         st := StubGetHandler{
567                 c,
568                 hash,
569                 "abc123",
570                 []byte("foo")}
571
572         arv, err := arvadosclient.MakeArvadosClient()
573         kc, _ := MakeKeepClient(&arv)
574         arv.ApiToken = "abc123"
575         service_roots := make([]string, 5)
576
577         ks1 := RunSomeFakeKeepServers(st, 1, 2990)
578         ks2 := RunSomeFakeKeepServers(fh, 4, 2991)
579
580         for i, k := range ks1 {
581                 service_roots[i] = k.url
582                 defer k.listener.Close()
583         }
584         for i, k := range ks2 {
585                 service_roots[len(ks1)+i] = k.url
586                 defer k.listener.Close()
587         }
588
589         kc.SetServiceRoots(service_roots)
590
591         r, n, url2, err := kc.Get(hash)
592         <-fh.handled
593         c.Check(err, Equals, nil)
594         c.Check(n, Equals, int64(3))
595         c.Check(url2, Equals, fmt.Sprintf("%s/%s", ks1[0].url, hash))
596
597         content, err2 := ioutil.ReadAll(r)
598         c.Check(err2, Equals, nil)
599         c.Check(content, DeepEquals, []byte("foo"))
600 }
601
602 func (s *ServerRequiredSuite) TestPutGetHead(c *C) {
603         os.Setenv("ARVADOS_API_HOST", "localhost:3001")
604         os.Setenv("ARVADOS_API_TOKEN", "4axaw8zxe0qm22wa6urpp5nskcne8z88cvbupv653y1njyi05h")
605         os.Setenv("ARVADOS_API_HOST_INSECURE", "true")
606
607         arv, err := arvadosclient.MakeArvadosClient()
608         kc, err := MakeKeepClient(&arv)
609         c.Assert(err, Equals, nil)
610
611         hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
612
613         {
614                 n, _, err := kc.Ask(hash)
615                 c.Check(err, Equals, BlockNotFound)
616                 c.Check(n, Equals, int64(0))
617         }
618         {
619                 hash2, replicas, err := kc.PutB([]byte("foo"))
620                 c.Check(hash2, Equals, fmt.Sprintf("%s+%v", hash, 3))
621                 c.Check(replicas, Equals, 2)
622                 c.Check(err, Equals, nil)
623         }
624         {
625                 r, n, url2, err := kc.Get(hash)
626                 c.Check(err, Equals, nil)
627                 c.Check(n, Equals, int64(3))
628                 c.Check(url2, Equals, fmt.Sprintf("http://localhost:25108/%s", hash))
629
630                 content, err2 := ioutil.ReadAll(r)
631                 c.Check(err2, Equals, nil)
632                 c.Check(content, DeepEquals, []byte("foo"))
633         }
634         {
635                 n, url2, err := kc.Ask(hash)
636                 c.Check(err, Equals, nil)
637                 c.Check(n, Equals, int64(3))
638                 c.Check(url2, Equals, fmt.Sprintf("http://localhost:25108/%s", hash))
639         }
640 }
641
642 type StubProxyHandler struct {
643         handled chan string
644 }
645
646 func (this StubProxyHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
647         resp.Header().Set("X-Keep-Replicas-Stored", "2")
648         this.handled <- fmt.Sprintf("http://%s", req.Host)
649 }
650
651 func (s *StandaloneSuite) TestPutProxy(c *C) {
652         log.Printf("TestPutProxy")
653
654         st := StubProxyHandler{make(chan string, 1)}
655
656         arv, err := arvadosclient.MakeArvadosClient()
657         kc, _ := MakeKeepClient(&arv)
658
659         kc.Want_replicas = 2
660         kc.Using_proxy = true
661         arv.ApiToken = "abc123"
662         service_roots := make([]string, 1)
663
664         ks1 := RunSomeFakeKeepServers(st, 1, 2990)
665
666         for i, k := range ks1 {
667                 service_roots[i] = k.url
668                 defer k.listener.Close()
669         }
670
671         kc.SetServiceRoots(service_roots)
672
673         _, replicas, err := kc.PutB([]byte("foo"))
674         <-st.handled
675
676         c.Check(err, Equals, nil)
677         c.Check(replicas, Equals, 2)
678
679         log.Printf("TestPutProxy done")
680 }
681
682 func (s *StandaloneSuite) TestPutProxyInsufficientReplicas(c *C) {
683         log.Printf("TestPutProxy")
684
685         st := StubProxyHandler{make(chan string, 1)}
686
687         arv, err := arvadosclient.MakeArvadosClient()
688         kc, _ := MakeKeepClient(&arv)
689
690         kc.Want_replicas = 3
691         kc.Using_proxy = true
692         arv.ApiToken = "abc123"
693         service_roots := make([]string, 1)
694
695         ks1 := RunSomeFakeKeepServers(st, 1, 2990)
696
697         for i, k := range ks1 {
698                 service_roots[i] = k.url
699                 defer k.listener.Close()
700         }
701         kc.SetServiceRoots(service_roots)
702
703         _, replicas, err := kc.PutB([]byte("foo"))
704         <-st.handled
705
706         c.Check(err, Equals, InsufficientReplicasError)
707         c.Check(replicas, Equals, 2)
708
709         log.Printf("TestPutProxy done")
710 }
711
712 func (s *StandaloneSuite) TestMakeLocator(c *C) {
713         l := MakeLocator("91f372a266fe2bf2823cb8ec7fda31ce+3+Aabcde@12345678")
714
715         c.Check(l.Hash, Equals, "91f372a266fe2bf2823cb8ec7fda31ce")
716         c.Check(l.Size, Equals, 3)
717         c.Check(l.Signature, Equals, "abcde")
718         c.Check(l.Timestamp, Equals, "12345678")
719 }