X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/644f5de63e2b8b02e054fcbb3e9af39560cffae3..ee53a267ded17bc50eaf4dfebba5ff4a3273753c:/services/keepproxy/keepproxy_test.go diff --git a/services/keepproxy/keepproxy_test.go b/services/keepproxy/keepproxy_test.go index a7b608b69c..dc70d968e2 100644 --- a/services/keepproxy/keepproxy_test.go +++ b/services/keepproxy/keepproxy_test.go @@ -125,6 +125,7 @@ func (s *ServerRequiredSuite) TestResponseViaHeader(c *C) { req, err := http.NewRequest("POST", "http://"+listener.Addr().String()+"/", strings.NewReader("TestViaHeader")) + c.Assert(err, Equals, nil) req.Header.Add("Authorization", "OAuth2 "+arvadostest.ActiveToken) resp, err := (&http.Client{}).Do(req) c.Assert(err, Equals, nil) @@ -161,6 +162,33 @@ func (s *ServerRequiredSuite) TestLoopDetection(c *C) { c.Check(err, ErrorMatches, `.*loop detected.*`) } +func (s *ServerRequiredSuite) TestStorageClassesHeader(c *C) { + kc := runProxy(c, nil, false) + defer closeListener() + + // Set up fake keepstore to record request headers + var hdr http.Header + ts := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + hdr = r.Header + http.Error(w, "Error", http.StatusInternalServerError) + })) + defer ts.Close() + + // Point keepproxy router's keepclient to the fake keepstore + sr := map[string]string{ + TestProxyUUID: ts.URL, + } + router.(*proxyHandler).KeepClient.SetServiceRoots(sr, sr, sr) + + // Set up client to ask for storage classes to keepproxy + kc.StorageClasses = []string{"secure"} + content := []byte("Very important data") + _, _, err := kc.PutB(content) + c.Check(err, NotNil) + c.Check(hdr.Get("X-Keep-Storage-Classes"), Equals, "secure") +} + func (s *ServerRequiredSuite) TestDesiredReplicas(c *C) { kc := runProxy(c, nil, false) defer closeListener() @@ -294,6 +322,7 @@ func (s *ServerRequiredSuite) TestPutAskGet(c *C) { reader, blocklen, _, err := kc.Get(hash2) c.Assert(err, Equals, nil) all, err := ioutil.ReadAll(reader) + c.Check(err, IsNil) c.Check(all, DeepEquals, []byte("foo")) c.Check(blocklen, Equals, int64(3)) c.Log("Finished Get (expected success)") @@ -313,6 +342,7 @@ func (s *ServerRequiredSuite) TestPutAskGet(c *C) { reader, blocklen, _, err := kc.Get("d41d8cd98f00b204e9800998ecf8427e") c.Assert(err, Equals, nil) all, err := ioutil.ReadAll(reader) + c.Check(err, IsNil) c.Check(all, DeepEquals, []byte("")) c.Check(blocklen, Equals, int64(0)) c.Log("Finished Get zero block") @@ -323,41 +353,26 @@ func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) { kc := runProxy(c, nil, true) defer closeListener() - hash := fmt.Sprintf("%x", md5.Sum([]byte("bar"))) + hash := fmt.Sprintf("%x+3", md5.Sum([]byte("bar"))) - { - _, _, err := kc.Ask(hash) - errNotFound, _ := err.(keepclient.ErrNotFound) - c.Check(errNotFound, NotNil) - c.Assert(strings.Contains(err.Error(), "HTTP 403"), Equals, true) - c.Log("Ask 1") - } + _, _, err := kc.Ask(hash) + c.Check(err, FitsTypeOf, &keepclient.ErrNotFound{}) - { - hash2, rep, err := kc.PutB([]byte("bar")) - c.Check(hash2, Equals, "") - c.Check(rep, Equals, 0) - c.Check(err, FitsTypeOf, keepclient.InsufficientReplicasError(errors.New(""))) - c.Log("PutB") - } + hash2, rep, err := kc.PutB([]byte("bar")) + c.Check(hash2, Equals, "") + c.Check(rep, Equals, 0) + c.Check(err, FitsTypeOf, keepclient.InsufficientReplicasError(errors.New(""))) - { - blocklen, _, err := kc.Ask(hash) - errNotFound, _ := err.(keepclient.ErrNotFound) - c.Check(errNotFound, NotNil) - c.Assert(strings.Contains(err.Error(), "HTTP 403"), Equals, true) - c.Check(blocklen, Equals, int64(0)) - c.Log("Ask 2") - } + blocklen, _, err := kc.Ask(hash) + c.Check(err, FitsTypeOf, &keepclient.ErrNotFound{}) + c.Check(err, ErrorMatches, ".*not found.*") + c.Check(blocklen, Equals, int64(0)) + + _, blocklen, _, err = kc.Get(hash) + c.Check(err, FitsTypeOf, &keepclient.ErrNotFound{}) + c.Check(err, ErrorMatches, ".*not found.*") + c.Check(blocklen, Equals, int64(0)) - { - _, blocklen, _, err := kc.Get(hash) - errNotFound, _ := err.(keepclient.ErrNotFound) - c.Check(errNotFound, NotNil) - c.Assert(strings.Contains(err.Error(), "HTTP 403"), Equals, true) - c.Check(blocklen, Equals, int64(0)) - c.Log("Get") - } } func (s *ServerRequiredSuite) TestGetDisabled(c *C) { @@ -370,7 +385,7 @@ func (s *ServerRequiredSuite) TestGetDisabled(c *C) { _, _, err := kc.Ask(hash) errNotFound, _ := err.(keepclient.ErrNotFound) c.Check(errNotFound, NotNil) - c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true) + c.Assert(err, ErrorMatches, `.*HTTP 405.*`) c.Log("Ask 1") } @@ -386,7 +401,7 @@ func (s *ServerRequiredSuite) TestGetDisabled(c *C) { blocklen, _, err := kc.Ask(hash) errNotFound, _ := err.(keepclient.ErrNotFound) c.Check(errNotFound, NotNil) - c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true) + c.Assert(err, ErrorMatches, `.*HTTP 405.*`) c.Check(blocklen, Equals, int64(0)) c.Log("Ask 2") } @@ -395,7 +410,7 @@ func (s *ServerRequiredSuite) TestGetDisabled(c *C) { _, blocklen, _, err := kc.Get(hash) errNotFound, _ := err.(keepclient.ErrNotFound) c.Check(errNotFound, NotNil) - c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true) + c.Assert(err, ErrorMatches, `.*HTTP 405.*`) c.Check(blocklen, Equals, int64(0)) c.Log("Get") } @@ -420,12 +435,14 @@ func (s *ServerRequiredSuite) TestCorsHeaders(c *C) { req, err := http.NewRequest("OPTIONS", fmt.Sprintf("http://%s/%x+3", listener.Addr().String(), md5.Sum([]byte("foo"))), nil) + c.Assert(err, IsNil) req.Header.Add("Access-Control-Request-Method", "PUT") req.Header.Add("Access-Control-Request-Headers", "Authorization, X-Keep-Desired-Replicas") resp, err := client.Do(req) c.Check(err, Equals, nil) c.Check(resp.StatusCode, Equals, 200) body, err := ioutil.ReadAll(resp.Body) + c.Check(err, IsNil) c.Check(string(body), Equals, "") c.Check(resp.Header.Get("Access-Control-Allow-Methods"), Equals, "GET, HEAD, POST, PUT, OPTIONS") c.Check(resp.Header.Get("Access-Control-Allow-Origin"), Equals, "*") @@ -449,6 +466,7 @@ func (s *ServerRequiredSuite) TestPostWithoutHash(c *C) { req, err := http.NewRequest("POST", "http://"+listener.Addr().String()+"/", strings.NewReader("qux")) + c.Check(err, IsNil) req.Header.Add("Authorization", "OAuth2 "+arvadostest.ActiveToken) req.Header.Add("Content-Type", "application/octet-stream") resp, err := client.Do(req) @@ -496,14 +514,15 @@ func (s *ServerRequiredSuite) TestGetIndex(c *C) { c.Check(err, Equals, nil) reader, blocklen, _, err := kc.Get(hash) - c.Assert(err, Equals, nil) + c.Assert(err, IsNil) c.Check(blocklen, Equals, int64(10)) all, err := ioutil.ReadAll(reader) + c.Assert(err, IsNil) c.Check(all, DeepEquals, data) // Put some more blocks - _, rep, err = kc.PutB([]byte("some-more-index-data")) - c.Check(err, Equals, nil) + _, _, err = kc.PutB([]byte("some-more-index-data")) + c.Check(err, IsNil) kc.Arvados.ApiToken = arvadostest.DataManagerToken @@ -544,63 +563,80 @@ func (s *ServerRequiredSuite) TestGetIndex(c *C) { c.Assert((err != nil), Equals, true) } +func (s *ServerRequiredSuite) TestCollectionSharingToken(c *C) { + kc := runProxy(c, nil, false) + defer closeListener() + hash, _, err := kc.PutB([]byte("shareddata")) + c.Check(err, IsNil) + kc.Arvados.ApiToken = arvadostest.FooCollectionSharingToken + rdr, _, _, err := kc.Get(hash) + c.Assert(err, IsNil) + data, err := ioutil.ReadAll(rdr) + c.Check(err, IsNil) + c.Check(data, DeepEquals, []byte("shareddata")) +} + func (s *ServerRequiredSuite) TestPutAskGetInvalidToken(c *C) { kc := runProxy(c, nil, false) defer closeListener() // Put a test block hash, rep, err := kc.PutB([]byte("foo")) - c.Check(err, Equals, nil) + c.Check(err, IsNil) c.Check(rep, Equals, 2) - for _, token := range []string{ + for _, badToken := range []string{ "nosuchtoken", "2ym314ysp27sk7h943q6vtc378srb06se3pq6ghurylyf3pdmx", // expired } { - // Change token to given bad token - kc.Arvados.ApiToken = token + kc.Arvados.ApiToken = badToken + + // Ask and Get will fail only if the upstream + // keepstore server checks for valid signatures. + // Without knowing the blob signing key, there is no + // way for keepproxy to know whether a given token is + // permitted to read a block. So these tests fail: + if false { + _, _, err = kc.Ask(hash) + c.Assert(err, FitsTypeOf, &keepclient.ErrNotFound{}) + c.Check(err.(*keepclient.ErrNotFound).Temporary(), Equals, false) + c.Check(err, ErrorMatches, ".*HTTP 403.*") + + _, _, _, err = kc.Get(hash) + c.Assert(err, FitsTypeOf, &keepclient.ErrNotFound{}) + c.Check(err.(*keepclient.ErrNotFound).Temporary(), Equals, false) + c.Check(err, ErrorMatches, ".*HTTP 403 \"Missing or invalid Authorization header\".*") + } - // Ask should result in error - _, _, err = kc.Ask(hash) - c.Check(err, NotNil) - errNotFound, _ := err.(keepclient.ErrNotFound) - c.Check(errNotFound.Temporary(), Equals, false) - c.Assert(strings.Contains(err.Error(), "HTTP 403"), Equals, true) - - // Get should result in error - _, _, _, err = kc.Get(hash) - c.Check(err, NotNil) - errNotFound, _ = err.(keepclient.ErrNotFound) - c.Check(errNotFound.Temporary(), Equals, false) - c.Assert(strings.Contains(err.Error(), "HTTP 403 \"Missing or invalid Authorization header\""), Equals, true) + _, _, err = kc.PutB([]byte("foo")) + c.Check(err, ErrorMatches, ".*403.*Missing or invalid Authorization header") } } func (s *ServerRequiredSuite) TestAskGetKeepProxyConnectionError(c *C) { - arv, err := arvadosclient.MakeArvadosClient() - c.Assert(err, Equals, nil) + kc := runProxy(c, nil, false) + defer closeListener() - // keepclient with no such keep server - kc := keepclient.New(arv) + // Point keepproxy at a non-existent keepstore locals := map[string]string{ TestProxyUUID: "http://localhost:12345", } - kc.SetServiceRoots(locals, nil, nil) + router.(*proxyHandler).KeepClient.SetServiceRoots(locals, nil, nil) - // Ask should result in temporary connection refused error + // Ask should result in temporary bad gateway error hash := fmt.Sprintf("%x", md5.Sum([]byte("foo"))) - _, _, err = kc.Ask(hash) + _, _, err := kc.Ask(hash) c.Check(err, NotNil) errNotFound, _ := err.(*keepclient.ErrNotFound) c.Check(errNotFound.Temporary(), Equals, true) - c.Assert(strings.Contains(err.Error(), "connection refused"), Equals, true) + c.Assert(err, ErrorMatches, ".*HTTP 502.*") - // Get should result in temporary connection refused error + // Get should result in temporary bad gateway error _, _, _, err = kc.Get(hash) c.Check(err, NotNil) errNotFound, _ = err.(*keepclient.ErrNotFound) c.Check(errNotFound.Temporary(), Equals, true) - c.Assert(strings.Contains(err.Error(), "connection refused"), Equals, true) + c.Assert(err, ErrorMatches, ".*HTTP 502.*") } func (s *NoKeepServerSuite) TestAskGetNoKeepServerError(c *C) { @@ -641,5 +677,5 @@ func (s *ServerRequiredSuite) TestPing(c *C) { resp := httptest.NewRecorder() rtr.ServeHTTP(resp, req) c.Check(resp.Code, Equals, 200) - c.Assert(strings.Contains(resp.Body.String(), `{"health":"OK"}`), Equals, true) + c.Assert(resp.Body.String(), Matches, `{"health":"OK"}\n?`) }