X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/47e59a35d5ed9b2cdb052894d741972324058505..90d84d8578b760b493ac76b22c42bc284868bc0c:/services/keepproxy/keepproxy_test.go diff --git a/services/keepproxy/keepproxy_test.go b/services/keepproxy/keepproxy_test.go index bb0e9bbf68..d2758cc25f 100644 --- a/services/keepproxy/keepproxy_test.go +++ b/services/keepproxy/keepproxy_test.go @@ -13,15 +13,17 @@ import ( "math/rand" "net/http" "net/http/httptest" - "os" "strings" "sync" "testing" "time" + "git.curoverse.com/arvados.git/lib/config" + "git.curoverse.com/arvados.git/sdk/go/arvados" "git.curoverse.com/arvados.git/sdk/go/arvadosclient" "git.curoverse.com/arvados.git/sdk/go/arvadostest" "git.curoverse.com/arvados.git/sdk/go/keepclient" + log "github.com/sirupsen/logrus" . "gopkg.in/check.v1" ) @@ -96,14 +98,23 @@ func (s *NoKeepServerSuite) TearDownSuite(c *C) { arvadostest.StopAPI() } -func runProxy(c *C, args []string, bogusClientToken bool) *keepclient.KeepClient { - args = append([]string{"keepproxy"}, args...) - os.Args = append(args, "-listen=:0") +func runProxy(c *C, bogusClientToken bool) *keepclient.KeepClient { + cfg, err := config.NewLoader(nil, nil).Load() + c.Assert(err, Equals, nil) + cluster, err := cfg.GetCluster("") + c.Assert(err, Equals, nil) + + cluster.Services.Keepproxy.InternalURLs = map[arvados.URL]arvados.ServiceInstance{arvados.URL{Host: ":0"}: arvados.ServiceInstance{}} + listener = nil - go main() + go func() { + run(log.New(), cluster) + defer closeListener() + }() waitForListener() - arv, err := arvadosclient.MakeArvadosClient() + client := arvados.NewClientFromEnv() + arv, err := arvadosclient.New(client) c.Assert(err, Equals, nil) if bogusClientToken { arv.ApiToken = "bogus-token" @@ -119,12 +130,13 @@ func runProxy(c *C, args []string, bogusClientToken bool) *keepclient.KeepClient } func (s *ServerRequiredSuite) TestResponseViaHeader(c *C) { - runProxy(c, nil, false) + runProxy(c, false) defer closeListener() 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) @@ -144,7 +156,7 @@ func (s *ServerRequiredSuite) TestResponseViaHeader(c *C) { } func (s *ServerRequiredSuite) TestLoopDetection(c *C) { - kc := runProxy(c, nil, false) + kc := runProxy(c, false) defer closeListener() sr := map[string]string{ @@ -161,8 +173,35 @@ func (s *ServerRequiredSuite) TestLoopDetection(c *C) { c.Check(err, ErrorMatches, `.*loop detected.*`) } +func (s *ServerRequiredSuite) TestStorageClassesHeader(c *C) { + kc := runProxy(c, 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) + kc := runProxy(c, false) defer closeListener() content := []byte("TestDesiredReplicas") @@ -179,7 +218,7 @@ func (s *ServerRequiredSuite) TestDesiredReplicas(c *C) { } func (s *ServerRequiredSuite) TestPutWrongContentLength(c *C) { - kc := runProxy(c, nil, false) + kc := runProxy(c, false) defer closeListener() content := []byte("TestPutWrongContentLength") @@ -190,7 +229,7 @@ func (s *ServerRequiredSuite) TestPutWrongContentLength(c *C) { // fixes the invalid Content-Length header. In order to test // our server behavior, we have to call the handler directly // using an httptest.ResponseRecorder. - rtr := MakeRESTRouter(true, true, kc, 10*time.Second, "") + rtr := MakeRESTRouter(kc, 10*time.Second, "") type testcase struct { sendLength string @@ -218,7 +257,7 @@ func (s *ServerRequiredSuite) TestPutWrongContentLength(c *C) { } func (s *ServerRequiredSuite) TestManyFailedPuts(c *C) { - kc := runProxy(c, nil, false) + kc := runProxy(c, false) defer closeListener() router.(*proxyHandler).timeout = time.Nanosecond @@ -245,7 +284,7 @@ func (s *ServerRequiredSuite) TestManyFailedPuts(c *C) { } func (s *ServerRequiredSuite) TestPutAskGet(c *C) { - kc := runProxy(c, nil, false) + kc := runProxy(c, false) defer closeListener() hash := fmt.Sprintf("%x", md5.Sum([]byte("foo"))) @@ -294,6 +333,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 +353,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") @@ -320,7 +361,7 @@ func (s *ServerRequiredSuite) TestPutAskGet(c *C) { } func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) { - kc := runProxy(c, nil, true) + kc := runProxy(c, true) defer closeListener() hash := fmt.Sprintf("%x+3", md5.Sum([]byte("bar"))) @@ -345,59 +386,8 @@ func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) { } -func (s *ServerRequiredSuite) TestGetDisabled(c *C) { - kc := runProxy(c, []string{"-no-get"}, false) - defer closeListener() - - hash := fmt.Sprintf("%x", md5.Sum([]byte("baz"))) - - { - _, _, err := kc.Ask(hash) - errNotFound, _ := err.(keepclient.ErrNotFound) - c.Check(errNotFound, NotNil) - c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true) - c.Log("Ask 1") - } - - { - hash2, rep, err := kc.PutB([]byte("baz")) - c.Check(hash2, Matches, fmt.Sprintf(`^%s\+3(\+.+)?$`, hash)) - c.Check(rep, Equals, 2) - c.Check(err, Equals, nil) - c.Log("PutB") - } - - { - blocklen, _, err := kc.Ask(hash) - errNotFound, _ := err.(keepclient.ErrNotFound) - c.Check(errNotFound, NotNil) - c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true) - c.Check(blocklen, Equals, int64(0)) - c.Log("Ask 2") - } - - { - _, blocklen, _, err := kc.Get(hash) - errNotFound, _ := err.(keepclient.ErrNotFound) - c.Check(errNotFound, NotNil) - c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true) - c.Check(blocklen, Equals, int64(0)) - c.Log("Get") - } -} - -func (s *ServerRequiredSuite) TestPutDisabled(c *C) { - kc := runProxy(c, []string{"-no-put"}, false) - defer closeListener() - - hash2, rep, err := kc.PutB([]byte("quux")) - c.Check(hash2, Equals, "") - c.Check(rep, Equals, 0) - c.Check(err, FitsTypeOf, keepclient.InsufficientReplicasError(errors.New(""))) -} - func (s *ServerRequiredSuite) TestCorsHeaders(c *C) { - runProxy(c, nil, false) + runProxy(c, false) defer closeListener() { @@ -405,12 +395,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, "*") @@ -426,7 +418,7 @@ func (s *ServerRequiredSuite) TestCorsHeaders(c *C) { } func (s *ServerRequiredSuite) TestPostWithoutHash(c *C) { - runProxy(c, nil, false) + runProxy(c, false) defer closeListener() { @@ -434,6 +426,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) @@ -468,7 +461,7 @@ func (s *ServerRequiredSuite) TestStripHint(c *C) { // With a valid but non-existing prefix (expect "\n") // With an invalid prefix (expect error) func (s *ServerRequiredSuite) TestGetIndex(c *C) { - kc := runProxy(c, nil, false) + kc := runProxy(c, false) defer closeListener() // Put "index-data" blocks @@ -481,14 +474,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 @@ -530,7 +524,7 @@ func (s *ServerRequiredSuite) TestGetIndex(c *C) { } func (s *ServerRequiredSuite) TestCollectionSharingToken(c *C) { - kc := runProxy(c, nil, false) + kc := runProxy(c, false) defer closeListener() hash, _, err := kc.PutB([]byte("shareddata")) c.Check(err, IsNil) @@ -543,7 +537,7 @@ func (s *ServerRequiredSuite) TestCollectionSharingToken(c *C) { } func (s *ServerRequiredSuite) TestPutAskGetInvalidToken(c *C) { - kc := runProxy(c, nil, false) + kc := runProxy(c, false) defer closeListener() // Put a test block @@ -580,34 +574,33 @@ func (s *ServerRequiredSuite) TestPutAskGetInvalidToken(c *C) { } func (s *ServerRequiredSuite) TestAskGetKeepProxyConnectionError(c *C) { - arv, err := arvadosclient.MakeArvadosClient() - c.Assert(err, Equals, nil) + kc := runProxy(c, 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) { - kc := runProxy(c, nil, false) + kc := runProxy(c, false) defer closeListener() hash := fmt.Sprintf("%x", md5.Sum([]byte("foo"))) @@ -630,10 +623,10 @@ func (s *NoKeepServerSuite) TestAskGetNoKeepServerError(c *C) { } func (s *ServerRequiredSuite) TestPing(c *C) { - kc := runProxy(c, nil, false) + kc := runProxy(c, false) defer closeListener() - rtr := MakeRESTRouter(true, true, kc, 10*time.Second, arvadostest.ManagementToken) + rtr := MakeRESTRouter(kc, 10*time.Second, arvadostest.ManagementToken) req, err := http.NewRequest("GET", "http://"+listener.Addr().String()+"/_health/ping", @@ -644,5 +637,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?`) }