1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
22 "git.arvados.org/arvados.git/lib/config"
23 "git.arvados.org/arvados.git/sdk/go/arvados"
24 "git.arvados.org/arvados.git/sdk/go/arvadosclient"
25 "git.arvados.org/arvados.git/sdk/go/arvadostest"
26 "git.arvados.org/arvados.git/sdk/go/ctxlog"
27 "git.arvados.org/arvados.git/sdk/go/httpserver"
28 "git.arvados.org/arvados.git/sdk/go/keepclient"
29 log "github.com/sirupsen/logrus"
35 // Gocheck boilerplate
36 func Test(t *testing.T) {
40 // Gocheck boilerplate
41 var _ = Suite(&ServerRequiredSuite{})
43 // Tests that require the Keep server running
44 type ServerRequiredSuite struct{}
46 // Gocheck boilerplate
47 var _ = Suite(&ServerRequiredConfigYmlSuite{})
49 // Tests that require the Keep servers running as defined in config.yml
50 type ServerRequiredConfigYmlSuite struct{}
52 // Gocheck boilerplate
53 var _ = Suite(&NoKeepServerSuite{})
55 // Test with no keepserver to simulate errors
56 type NoKeepServerSuite struct{}
58 var TestProxyUUID = "zzzzz-bi6l4-lrixqc4fxofbmzz"
60 func (s *ServerRequiredSuite) SetUpSuite(c *C) {
61 arvadostest.StartKeep(2, false)
64 func (s *ServerRequiredSuite) SetUpTest(c *C) {
65 arvadostest.ResetEnv()
68 func (s *ServerRequiredSuite) TearDownSuite(c *C) {
69 arvadostest.StopKeep(2)
72 func (s *ServerRequiredConfigYmlSuite) SetUpSuite(c *C) {
73 // config.yml defines 4 keepstores
74 arvadostest.StartKeep(4, false)
77 func (s *ServerRequiredConfigYmlSuite) SetUpTest(c *C) {
78 arvadostest.ResetEnv()
81 func (s *ServerRequiredConfigYmlSuite) TearDownSuite(c *C) {
82 arvadostest.StopKeep(4)
85 func (s *NoKeepServerSuite) SetUpSuite(c *C) {
86 // We need API to have some keep services listed, but the
87 // services themselves should be unresponsive.
88 arvadostest.StartKeep(2, false)
89 arvadostest.StopKeep(2)
92 func (s *NoKeepServerSuite) SetUpTest(c *C) {
93 arvadostest.ResetEnv()
96 type testServer struct {
98 proxyHandler *proxyHandler
101 func runProxy(c *C, bogusClientToken bool, loadKeepstoresFromConfig bool, kp *arvados.UploadDownloadRolePermissions) (*testServer, *keepclient.KeepClient, *bytes.Buffer) {
102 cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load()
103 c.Assert(err, Equals, nil)
104 cluster, err := cfg.GetCluster("")
105 c.Assert(err, Equals, nil)
107 if !loadKeepstoresFromConfig {
108 // Do not load Keepstore InternalURLs from the config file
109 cluster.Services.Keepstore.InternalURLs = make(map[arvados.URL]arvados.ServiceInstance)
112 cluster.Services.Keepproxy.InternalURLs = map[arvados.URL]arvados.ServiceInstance{{Host: ":0"}: {}}
115 cluster.Collections.KeepproxyPermission = *kp
118 logbuf := &bytes.Buffer{}
121 ctx := ctxlog.Context(context.Background(), logger)
123 handler := newHandlerOrErrorHandler(ctx, cluster, cluster.SystemRootToken, nil).(*proxyHandler)
125 Server: &httpserver.Server{
127 BaseContext: func(net.Listener) context.Context { return ctx },
128 Handler: httpserver.AddRequestIDs(
129 httpserver.LogRequests(handler)),
133 proxyHandler: handler,
138 client := arvados.NewClientFromEnv()
139 arv, err := arvadosclient.New(client)
141 if bogusClientToken {
142 arv.ApiToken = "bogus-token"
144 kc := keepclient.New(arv)
145 sr := map[string]string{
146 TestProxyUUID: "http://" + srv.Addr,
148 kc.SetServiceRoots(sr, sr, sr)
149 return srv, kc, logbuf
152 func (s *ServerRequiredSuite) TestResponseViaHeader(c *C) {
153 srv, _, _ := runProxy(c, false, false, nil)
156 req, err := http.NewRequest("POST",
157 "http://"+srv.Addr+"/",
158 strings.NewReader("TestViaHeader"))
159 c.Assert(err, Equals, nil)
160 req.Header.Add("Authorization", "OAuth2 "+arvadostest.ActiveToken)
161 resp, err := (&http.Client{}).Do(req)
162 c.Assert(err, Equals, nil)
163 c.Check(resp.Header.Get("Via"), Equals, "HTTP/1.1 keepproxy")
164 c.Assert(resp.StatusCode, Equals, http.StatusOK)
165 locator, err := ioutil.ReadAll(resp.Body)
166 c.Assert(err, Equals, nil)
169 req, err = http.NewRequest("GET",
170 "http://"+srv.Addr+"/"+string(locator),
172 c.Assert(err, Equals, nil)
173 resp, err = (&http.Client{}).Do(req)
174 c.Assert(err, Equals, nil)
175 c.Check(resp.Header.Get("Via"), Equals, "HTTP/1.1 keepproxy")
179 func (s *ServerRequiredSuite) TestLoopDetection(c *C) {
180 srv, kc, _ := runProxy(c, false, false, nil)
183 sr := map[string]string{
184 TestProxyUUID: "http://" + srv.Addr,
186 srv.proxyHandler.KeepClient.SetServiceRoots(sr, sr, sr)
188 content := []byte("TestLoopDetection")
189 _, _, err := kc.PutB(content)
190 c.Check(err, ErrorMatches, `.*loop detected.*`)
192 hash := fmt.Sprintf("%x", md5.Sum(content))
193 _, _, _, err = kc.Get(hash)
194 c.Check(err, ErrorMatches, `.*loop detected.*`)
197 func (s *ServerRequiredSuite) TestStorageClassesHeader(c *C) {
198 srv, kc, _ := runProxy(c, false, false, nil)
201 // Set up fake keepstore to record request headers
203 ts := httptest.NewServer(http.HandlerFunc(
204 func(w http.ResponseWriter, r *http.Request) {
206 http.Error(w, "Error", http.StatusInternalServerError)
210 // Point keepproxy router's keepclient to the fake keepstore
211 sr := map[string]string{
212 TestProxyUUID: ts.URL,
214 srv.proxyHandler.KeepClient.SetServiceRoots(sr, sr, sr)
216 // Set up client to ask for storage classes to keepproxy
217 kc.StorageClasses = []string{"secure"}
218 content := []byte("Very important data")
219 _, _, err := kc.PutB(content)
221 c.Check(hdr.Get("X-Keep-Storage-Classes"), Equals, "secure")
224 func (s *ServerRequiredSuite) TestStorageClassesConfirmedHeader(c *C) {
225 srv, _, _ := runProxy(c, false, false, nil)
228 content := []byte("foo")
229 hash := fmt.Sprintf("%x", md5.Sum(content))
230 client := &http.Client{}
232 req, err := http.NewRequest("PUT",
233 fmt.Sprintf("http://%s/%s", srv.Addr, hash),
234 bytes.NewReader(content))
236 req.Header.Set("X-Keep-Storage-Classes", "default")
237 req.Header.Set("Authorization", "OAuth2 "+arvadostest.ActiveToken)
238 req.Header.Set("Content-Type", "application/octet-stream")
240 resp, err := client.Do(req)
242 c.Assert(resp.StatusCode, Equals, http.StatusOK)
243 c.Assert(resp.Header.Get("X-Keep-Storage-Classes-Confirmed"), Equals, "default=2")
246 func (s *ServerRequiredSuite) TestDesiredReplicas(c *C) {
247 srv, kc, _ := runProxy(c, false, false, nil)
250 content := []byte("TestDesiredReplicas")
251 hash := fmt.Sprintf("%x", md5.Sum(content))
253 for _, kc.Want_replicas = range []int{0, 1, 2, 3} {
254 locator, rep, err := kc.PutB(content)
255 if kc.Want_replicas < 3 {
256 c.Check(err, Equals, nil)
257 c.Check(rep, Equals, kc.Want_replicas)
259 c.Check(locator, Matches, fmt.Sprintf(`^%s\+%d(\+.+)?$`, hash, len(content)))
262 c.Check(err, ErrorMatches, ".*503.*")
267 func (s *ServerRequiredSuite) TestPutWrongContentLength(c *C) {
268 srv, kc, _ := runProxy(c, false, false, nil)
271 content := []byte("TestPutWrongContentLength")
272 hash := fmt.Sprintf("%x", md5.Sum(content))
274 // If we use http.Client to send these requests to the network
275 // server we just started, the Go http library automatically
276 // fixes the invalid Content-Length header. In order to test
277 // our server behavior, we have to call the handler directly
278 // using an httptest.ResponseRecorder.
279 rtr, err := newHandler(context.Background(), kc, 10*time.Second, &arvados.Cluster{})
280 c.Assert(err, check.IsNil)
282 type testcase struct {
287 for _, t := range []testcase{
288 {"1", http.StatusBadRequest},
289 {"", http.StatusLengthRequired},
290 {"-1", http.StatusLengthRequired},
291 {"abcdef", http.StatusLengthRequired},
293 req, err := http.NewRequest("PUT",
294 fmt.Sprintf("http://%s/%s+%d", srv.Addr, hash, len(content)),
295 bytes.NewReader(content))
297 req.Header.Set("Content-Length", t.sendLength)
298 req.Header.Set("Authorization", "OAuth2 "+arvadostest.ActiveToken)
299 req.Header.Set("Content-Type", "application/octet-stream")
301 resp := httptest.NewRecorder()
302 rtr.ServeHTTP(resp, req)
303 c.Check(resp.Code, Equals, t.expectStatus)
307 func (s *ServerRequiredSuite) TestManyFailedPuts(c *C) {
308 srv, kc, _ := runProxy(c, false, false, nil)
310 srv.proxyHandler.timeout = time.Nanosecond
312 buf := make([]byte, 1<<20)
314 var wg sync.WaitGroup
315 for i := 0; i < 128; i++ {
322 done := make(chan bool)
329 case <-time.After(10 * time.Second):
334 func (s *ServerRequiredSuite) TestPutAskGet(c *C) {
335 srv, kc, logbuf := runProxy(c, false, false, nil)
338 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
342 _, _, err := kc.Ask(hash)
343 c.Check(err, Equals, keepclient.BlockNotFound)
344 c.Log("Finished Ask (expected BlockNotFound)")
348 reader, _, _, err := kc.Get(hash)
349 c.Check(reader, Equals, nil)
350 c.Check(err, Equals, keepclient.BlockNotFound)
351 c.Log("Finished Get (expected BlockNotFound)")
354 // Note in bug #5309 among other errors keepproxy would set
355 // Content-Length incorrectly on the 404 BlockNotFound response, this
356 // would result in a protocol violation that would prevent reuse of the
357 // connection, which would manifest by the next attempt to use the
358 // connection (in this case the PutB below) failing. So to test for
359 // that bug it's necessary to trigger an error response (such as
360 // BlockNotFound) and then do something else with the same httpClient
366 hash2, rep, err = kc.PutB([]byte("foo"))
367 c.Check(hash2, Matches, fmt.Sprintf(`^%s\+3(\+.+)?$`, hash))
368 c.Check(rep, Equals, 2)
369 c.Check(err, Equals, nil)
370 c.Log("Finished PutB (expected success)")
372 c.Check(logbuf.String(), Matches, `(?ms).* locator=acbd18db4cc2f85cedef654fccc4a4d8\+3.* userFullName="TestCase Administrator".* userUUID=zzzzz-tpzed-d9tiejq69daie8f.*`)
377 blocklen, _, err := kc.Ask(hash2)
378 c.Assert(err, Equals, nil)
379 c.Check(blocklen, Equals, int64(3))
380 c.Log("Finished Ask (expected success)")
381 c.Check(logbuf.String(), Matches, `(?ms).* locator=acbd18db4cc2f85cedef654fccc4a4d8\+3.* userFullName="TestCase Administrator".* userUUID=zzzzz-tpzed-d9tiejq69daie8f.*`)
386 reader, blocklen, _, err := kc.Get(hash2)
387 c.Assert(err, Equals, nil)
388 all, err := ioutil.ReadAll(reader)
390 c.Check(all, DeepEquals, []byte("foo"))
391 c.Check(blocklen, Equals, int64(3))
392 c.Log("Finished Get (expected success)")
393 c.Check(logbuf.String(), Matches, `(?ms).* locator=acbd18db4cc2f85cedef654fccc4a4d8\+3.* userFullName="TestCase Administrator".* userUUID=zzzzz-tpzed-d9tiejq69daie8f.*`)
400 hash2, rep, err = kc.PutB([]byte(""))
401 c.Check(hash2, Matches, `^d41d8cd98f00b204e9800998ecf8427e\+0(\+.+)?$`)
402 c.Check(rep, Equals, 2)
403 c.Check(err, Equals, nil)
404 c.Log("Finished PutB zero block")
408 reader, blocklen, _, err := kc.Get("d41d8cd98f00b204e9800998ecf8427e")
409 c.Assert(err, Equals, nil)
410 all, err := ioutil.ReadAll(reader)
412 c.Check(all, DeepEquals, []byte(""))
413 c.Check(blocklen, Equals, int64(0))
414 c.Log("Finished Get zero block")
418 func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) {
419 srv, kc, _ := runProxy(c, true, false, nil)
422 hash := fmt.Sprintf("%x+3", md5.Sum([]byte("bar")))
424 _, _, err := kc.Ask(hash)
425 c.Check(err, FitsTypeOf, &keepclient.ErrNotFound{})
427 hash2, rep, err := kc.PutB([]byte("bar"))
428 c.Check(hash2, Equals, "")
429 c.Check(rep, Equals, 0)
430 c.Check(err, FitsTypeOf, keepclient.InsufficientReplicasError{})
432 blocklen, _, err := kc.Ask(hash)
433 c.Check(err, FitsTypeOf, &keepclient.ErrNotFound{})
434 c.Check(err, ErrorMatches, ".*HTTP 403.*")
435 c.Check(blocklen, Equals, int64(0))
437 _, blocklen, _, err = kc.Get(hash)
438 c.Check(err, FitsTypeOf, &keepclient.ErrNotFound{})
439 c.Check(err, ErrorMatches, ".*HTTP 403.*")
440 c.Check(blocklen, Equals, int64(0))
443 func testPermission(c *C, admin bool, perm arvados.UploadDownloadPermission) {
444 kp := arvados.UploadDownloadRolePermissions{}
447 kp.User = arvados.UploadDownloadPermission{Upload: true, Download: true}
449 kp.Admin = arvados.UploadDownloadPermission{Upload: true, Download: true}
453 srv, kc, logbuf := runProxy(c, false, false, &kp)
456 kc.Arvados.ApiToken = arvadostest.AdminToken
458 kc.Arvados.ApiToken = arvadostest.ActiveToken
461 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
467 hash2, rep, err = kc.PutB([]byte("foo"))
470 c.Check(hash2, Matches, fmt.Sprintf(`^%s\+3(\+.+)?$`, hash))
471 c.Check(rep, Equals, 2)
472 c.Check(err, Equals, nil)
473 c.Log("Finished PutB (expected success)")
475 c.Check(logbuf.String(), Matches, `(?ms).* locator=acbd18db4cc2f85cedef654fccc4a4d8\+3.* userFullName="TestCase Administrator".* userUUID=zzzzz-tpzed-d9tiejq69daie8f.*`)
478 c.Check(logbuf.String(), Matches, `(?ms).* locator=acbd18db4cc2f85cedef654fccc4a4d8\+3.* userFullName="Active User".* userUUID=zzzzz-tpzed-xurymjxw79nv3jz.*`)
481 c.Check(hash2, Equals, "")
482 c.Check(rep, Equals, 0)
483 c.Check(err, FitsTypeOf, keepclient.InsufficientReplicasError{})
488 // can't test download without upload.
490 reader, blocklen, _, err := kc.Get(hash2)
492 c.Assert(err, Equals, nil)
493 all, err := ioutil.ReadAll(reader)
495 c.Check(all, DeepEquals, []byte("foo"))
496 c.Check(blocklen, Equals, int64(3))
497 c.Log("Finished Get (expected success)")
499 c.Check(logbuf.String(), Matches, `(?ms).* locator=acbd18db4cc2f85cedef654fccc4a4d8\+3.* userFullName="TestCase Administrator".* userUUID=zzzzz-tpzed-d9tiejq69daie8f.*`)
501 c.Check(logbuf.String(), Matches, `(?ms).* locator=acbd18db4cc2f85cedef654fccc4a4d8\+3.* userFullName="Active User".* userUUID=zzzzz-tpzed-xurymjxw79nv3jz.*`)
504 c.Check(err, FitsTypeOf, &keepclient.ErrNotFound{})
505 c.Check(err, ErrorMatches, ".*Missing or invalid Authorization header, or method not allowed.*")
506 c.Check(blocklen, Equals, int64(0))
513 func (s *ServerRequiredSuite) TestPutGetPermission(c *C) {
515 for _, adminperm := range []bool{true, false} {
516 for _, userperm := range []bool{true, false} {
518 testPermission(c, true,
519 arvados.UploadDownloadPermission{
523 testPermission(c, true,
524 arvados.UploadDownloadPermission{
528 testPermission(c, false,
529 arvados.UploadDownloadPermission{
533 testPermission(c, false,
534 arvados.UploadDownloadPermission{
542 func (s *ServerRequiredSuite) TestCorsHeaders(c *C) {
543 srv, _, _ := runProxy(c, false, false, nil)
547 client := http.Client{}
548 req, err := http.NewRequest("OPTIONS",
549 fmt.Sprintf("http://%s/%x+3", srv.Addr, md5.Sum([]byte("foo"))),
552 req.Header.Add("Access-Control-Request-Method", "PUT")
553 req.Header.Add("Access-Control-Request-Headers", "Authorization, X-Keep-Desired-Replicas")
554 resp, err := client.Do(req)
555 c.Check(err, Equals, nil)
556 c.Check(resp.StatusCode, Equals, 200)
557 body, err := ioutil.ReadAll(resp.Body)
559 c.Check(string(body), Equals, "")
560 c.Check(resp.Header.Get("Access-Control-Allow-Methods"), Equals, "GET, HEAD, POST, PUT, OPTIONS")
561 c.Check(resp.Header.Get("Access-Control-Allow-Origin"), Equals, "*")
565 resp, err := http.Get(fmt.Sprintf("http://%s/%x+3", srv.Addr, md5.Sum([]byte("foo"))))
566 c.Check(err, Equals, nil)
567 c.Check(resp.Header.Get("Access-Control-Allow-Headers"), Equals, "Authorization, Content-Length, Content-Type, X-Keep-Desired-Replicas")
568 c.Check(resp.Header.Get("Access-Control-Allow-Origin"), Equals, "*")
572 func (s *ServerRequiredSuite) TestPostWithoutHash(c *C) {
573 srv, _, _ := runProxy(c, false, false, nil)
577 client := http.Client{}
578 req, err := http.NewRequest("POST",
579 "http://"+srv.Addr+"/",
580 strings.NewReader("qux"))
582 req.Header.Add("Authorization", "OAuth2 "+arvadostest.ActiveToken)
583 req.Header.Add("Content-Type", "application/octet-stream")
584 resp, err := client.Do(req)
585 c.Check(err, Equals, nil)
586 body, err := ioutil.ReadAll(resp.Body)
587 c.Check(err, Equals, nil)
588 c.Check(string(body), Matches,
589 fmt.Sprintf(`^%x\+3(\+.+)?$`, md5.Sum([]byte("qux"))))
593 func (s *ServerRequiredSuite) TestStripHint(c *C) {
594 c.Check(removeHint.ReplaceAllString("http://keep.zzzzz.arvadosapi.com:25107/2228819a18d3727630fa30c81853d23f+67108864+A37b6ab198qqqq28d903b975266b23ee711e1852c@55635f73+K@zzzzz", "$1"),
596 "http://keep.zzzzz.arvadosapi.com:25107/2228819a18d3727630fa30c81853d23f+67108864+A37b6ab198qqqq28d903b975266b23ee711e1852c@55635f73")
597 c.Check(removeHint.ReplaceAllString("http://keep.zzzzz.arvadosapi.com:25107/2228819a18d3727630fa30c81853d23f+67108864+K@zzzzz+A37b6ab198qqqq28d903b975266b23ee711e1852c@55635f73", "$1"),
599 "http://keep.zzzzz.arvadosapi.com:25107/2228819a18d3727630fa30c81853d23f+67108864+A37b6ab198qqqq28d903b975266b23ee711e1852c@55635f73")
600 c.Check(removeHint.ReplaceAllString("http://keep.zzzzz.arvadosapi.com:25107/2228819a18d3727630fa30c81853d23f+67108864+A37b6ab198qqqq28d903b975266b23ee711e1852c@55635f73+K@zzzzz-zzzzz-zzzzzzzzzzzzzzz", "$1"),
602 "http://keep.zzzzz.arvadosapi.com:25107/2228819a18d3727630fa30c81853d23f+67108864+A37b6ab198qqqq28d903b975266b23ee711e1852c@55635f73+K@zzzzz-zzzzz-zzzzzzzzzzzzzzz")
603 c.Check(removeHint.ReplaceAllString("http://keep.zzzzz.arvadosapi.com:25107/2228819a18d3727630fa30c81853d23f+67108864+K@zzzzz-zzzzz-zzzzzzzzzzzzzzz+A37b6ab198qqqq28d903b975266b23ee711e1852c@55635f73", "$1"),
605 "http://keep.zzzzz.arvadosapi.com:25107/2228819a18d3727630fa30c81853d23f+67108864+K@zzzzz-zzzzz-zzzzzzzzzzzzzzz+A37b6ab198qqqq28d903b975266b23ee711e1852c@55635f73")
610 // - Put one block, with 2 replicas
611 // - With no prefix (expect the block locator, twice)
612 // - With an existing prefix (expect the block locator, twice)
613 // - With a valid but non-existing prefix (expect "\n")
614 // - With an invalid prefix (expect error)
615 func (s *ServerRequiredSuite) TestGetIndex(c *C) {
616 getIndexWorker(c, false)
621 // - Put one block, with 2 replicas
622 // - With no prefix (expect the block locator, twice)
623 // - With an existing prefix (expect the block locator, twice)
624 // - With a valid but non-existing prefix (expect "\n")
625 // - With an invalid prefix (expect error)
626 func (s *ServerRequiredConfigYmlSuite) TestGetIndex(c *C) {
627 getIndexWorker(c, true)
630 func getIndexWorker(c *C, useConfig bool) {
631 srv, kc, _ := runProxy(c, false, useConfig, nil)
634 // Put "index-data" blocks
635 data := []byte("index-data")
636 hash := fmt.Sprintf("%x", md5.Sum(data))
638 hash2, rep, err := kc.PutB(data)
639 c.Check(hash2, Matches, fmt.Sprintf(`^%s\+10(\+.+)?$`, hash))
640 c.Check(rep, Equals, 2)
641 c.Check(err, Equals, nil)
643 reader, blocklen, _, err := kc.Get(hash)
645 c.Check(blocklen, Equals, int64(10))
646 all, err := ioutil.ReadAll(reader)
648 c.Check(all, DeepEquals, data)
650 // Put some more blocks
651 _, _, err = kc.PutB([]byte("some-more-index-data"))
654 kc.Arvados.ApiToken = arvadostest.SystemRootToken
657 for _, spec := range []struct {
662 {"", true, true}, // with no prefix
663 {hash[:3], true, false}, // with matching prefix
664 {"abcdef", false, false}, // with no such prefix
666 indexReader, err := kc.GetIndex(TestProxyUUID, spec.prefix)
667 c.Assert(err, Equals, nil)
668 indexResp, err := ioutil.ReadAll(indexReader)
669 c.Assert(err, Equals, nil)
670 locators := strings.Split(string(indexResp), "\n")
673 for _, locator := range locators {
677 c.Check(locator[:len(spec.prefix)], Equals, spec.prefix)
678 if locator[:32] == hash {
684 c.Check(gotTestHash == 2, Equals, spec.expectTestHash)
685 c.Check(gotOther > 0, Equals, spec.expectOther)
688 // GetIndex with invalid prefix
689 _, err = kc.GetIndex(TestProxyUUID, "xyz")
690 c.Assert((err != nil), Equals, true)
693 func (s *ServerRequiredSuite) TestCollectionSharingToken(c *C) {
694 srv, kc, _ := runProxy(c, false, false, nil)
696 hash, _, err := kc.PutB([]byte("shareddata"))
698 kc.Arvados.ApiToken = arvadostest.FooFileCollectionSharingToken
699 rdr, _, _, err := kc.Get(hash)
701 data, err := ioutil.ReadAll(rdr)
703 c.Check(data, DeepEquals, []byte("shareddata"))
706 func (s *ServerRequiredSuite) TestPutAskGetInvalidToken(c *C) {
707 srv, kc, _ := runProxy(c, false, false, nil)
711 hash, rep, err := kc.PutB([]byte("foo"))
713 c.Check(rep, Equals, 2)
715 for _, badToken := range []string{
717 "2ym314ysp27sk7h943q6vtc378srb06se3pq6ghurylyf3pdmx", // expired
719 kc.Arvados.ApiToken = badToken
721 // Ask and Get will fail only if the upstream
722 // keepstore server checks for valid signatures.
723 // Without knowing the blob signing key, there is no
724 // way for keepproxy to know whether a given token is
725 // permitted to read a block. So these tests fail:
727 _, _, err = kc.Ask(hash)
728 c.Assert(err, FitsTypeOf, &keepclient.ErrNotFound{})
729 c.Check(err.(*keepclient.ErrNotFound).Temporary(), Equals, false)
730 c.Check(err, ErrorMatches, ".*HTTP 403.*")
732 _, _, _, err = kc.Get(hash)
733 c.Assert(err, FitsTypeOf, &keepclient.ErrNotFound{})
734 c.Check(err.(*keepclient.ErrNotFound).Temporary(), Equals, false)
735 c.Check(err, ErrorMatches, ".*HTTP 403 \"Missing or invalid Authorization header, or method not allowed\".*")
738 _, _, err = kc.PutB([]byte("foo"))
739 c.Check(err, ErrorMatches, ".*403.*Missing or invalid Authorization header, or method not allowed")
743 func (s *ServerRequiredSuite) TestAskGetKeepProxyConnectionError(c *C) {
744 srv, kc, _ := runProxy(c, false, false, nil)
747 // Point keepproxy at a non-existent keepstore
748 locals := map[string]string{
749 TestProxyUUID: "http://localhost:12345",
751 srv.proxyHandler.KeepClient.SetServiceRoots(locals, nil, nil)
753 // Ask should result in temporary bad gateway error
754 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
755 _, _, err := kc.Ask(hash)
757 errNotFound, _ := err.(*keepclient.ErrNotFound)
758 c.Check(errNotFound.Temporary(), Equals, true)
759 c.Assert(err, ErrorMatches, ".*HTTP 502.*")
761 // Get should result in temporary bad gateway error
762 _, _, _, err = kc.Get(hash)
764 errNotFound, _ = err.(*keepclient.ErrNotFound)
765 c.Check(errNotFound.Temporary(), Equals, true)
766 c.Assert(err, ErrorMatches, ".*HTTP 502.*")
769 func (s *NoKeepServerSuite) TestAskGetNoKeepServerError(c *C) {
770 srv, kc, _ := runProxy(c, false, false, nil)
773 hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
774 for _, f := range []func() error{
776 _, _, err := kc.Ask(hash)
780 _, _, _, err := kc.Get(hash)
785 c.Assert(err, NotNil)
786 errNotFound, _ := err.(*keepclient.ErrNotFound)
787 c.Check(errNotFound.Temporary(), Equals, true)
788 c.Check(err, ErrorMatches, `.*HTTP 502.*`)
792 func (s *ServerRequiredSuite) TestPing(c *C) {
793 srv, kc, _ := runProxy(c, false, false, nil)
796 rtr, err := newHandler(context.Background(), kc, 10*time.Second, &arvados.Cluster{ManagementToken: arvadostest.ManagementToken})
797 c.Assert(err, check.IsNil)
799 req, err := http.NewRequest("GET",
800 "http://"+srv.Addr+"/_health/ping",
803 req.Header.Set("Authorization", "Bearer "+arvadostest.ManagementToken)
805 resp := httptest.NewRecorder()
806 rtr.ServeHTTP(resp, req)
807 c.Check(resp.Code, Equals, 200)
808 c.Assert(resp.Body.String(), Matches, `{"health":"OK"}\n?`)