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