X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/0821f5481edd016a3744bb50d97a9e5b99cd1a0f..82b6440aaa9f265509770150d80e44319dc66fc7:/services/keepproxy/keepproxy_test.go diff --git a/services/keepproxy/keepproxy_test.go b/services/keepproxy/keepproxy_test.go index 6a349dae21..a7b608b69c 100644 --- a/services/keepproxy/keepproxy_test.go +++ b/services/keepproxy/keepproxy_test.go @@ -1,21 +1,28 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + package main import ( "bytes" "crypto/md5" + "errors" "fmt" - "git.curoverse.com/arvados.git/sdk/go/arvadosclient" - "git.curoverse.com/arvados.git/sdk/go/arvadostest" - "git.curoverse.com/arvados.git/sdk/go/keepclient" "io/ioutil" - "log" + "math/rand" "net/http" "net/http/httptest" "os" "strings" + "sync" "testing" "time" + "git.curoverse.com/arvados.git/sdk/go/arvadosclient" + "git.curoverse.com/arvados.git/sdk/go/arvadostest" + "git.curoverse.com/arvados.git/sdk/go/keepclient" + . "gopkg.in/check.v1" ) @@ -49,7 +56,7 @@ func waitForListener() { time.Sleep(ms * time.Millisecond) } if listener == nil { - log.Fatalf("Timed out waiting for listener to start") + panic("Timed out waiting for listener to start") } } @@ -111,6 +118,49 @@ func runProxy(c *C, args []string, bogusClientToken bool) *keepclient.KeepClient return kc } +func (s *ServerRequiredSuite) TestResponseViaHeader(c *C) { + runProxy(c, nil, false) + defer closeListener() + + req, err := http.NewRequest("POST", + "http://"+listener.Addr().String()+"/", + strings.NewReader("TestViaHeader")) + req.Header.Add("Authorization", "OAuth2 "+arvadostest.ActiveToken) + resp, err := (&http.Client{}).Do(req) + c.Assert(err, Equals, nil) + c.Check(resp.Header.Get("Via"), Equals, "HTTP/1.1 keepproxy") + locator, err := ioutil.ReadAll(resp.Body) + c.Assert(err, Equals, nil) + resp.Body.Close() + + req, err = http.NewRequest("GET", + "http://"+listener.Addr().String()+"/"+string(locator), + nil) + c.Assert(err, Equals, nil) + resp, err = (&http.Client{}).Do(req) + c.Assert(err, Equals, nil) + c.Check(resp.Header.Get("Via"), Equals, "HTTP/1.1 keepproxy") + resp.Body.Close() +} + +func (s *ServerRequiredSuite) TestLoopDetection(c *C) { + kc := runProxy(c, nil, false) + defer closeListener() + + sr := map[string]string{ + TestProxyUUID: "http://" + listener.Addr().String(), + } + router.(*proxyHandler).KeepClient.SetServiceRoots(sr, sr, sr) + + content := []byte("TestLoopDetection") + _, _, err := kc.PutB(content) + c.Check(err, ErrorMatches, `.*loop detected.*`) + + hash := fmt.Sprintf("%x", md5.Sum(content)) + _, _, _, err = kc.Get(hash) + c.Check(err, ErrorMatches, `.*loop detected.*`) +} + func (s *ServerRequiredSuite) TestDesiredReplicas(c *C) { kc := runProxy(c, nil, false) defer closeListener() @@ -140,7 +190,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) + rtr := MakeRESTRouter(true, true, kc, 10*time.Second, "") type testcase struct { sendLength string @@ -158,7 +208,7 @@ func (s *ServerRequiredSuite) TestPutWrongContentLength(c *C) { bytes.NewReader(content)) c.Assert(err, IsNil) req.Header.Set("Content-Length", t.sendLength) - req.Header.Set("Authorization", "OAuth2 4axaw8zxe0qm22wa6urpp5nskcne8z88cvbupv653y1njyi05h") + req.Header.Set("Authorization", "OAuth2 "+arvadostest.ActiveToken) req.Header.Set("Content-Type", "application/octet-stream") resp := httptest.NewRecorder() @@ -167,6 +217,33 @@ func (s *ServerRequiredSuite) TestPutWrongContentLength(c *C) { } } +func (s *ServerRequiredSuite) TestManyFailedPuts(c *C) { + kc := runProxy(c, nil, false) + defer closeListener() + router.(*proxyHandler).timeout = time.Nanosecond + + buf := make([]byte, 1<<20) + rand.Read(buf) + var wg sync.WaitGroup + for i := 0; i < 128; i++ { + wg.Add(1) + go func() { + defer wg.Done() + kc.PutB(buf) + }() + } + done := make(chan bool) + go func() { + wg.Wait() + close(done) + }() + select { + case <-done: + case <-time.After(10 * time.Second): + c.Error("timeout") + } +} + func (s *ServerRequiredSuite) TestPutAskGet(c *C) { kc := runProxy(c, nil, false) defer closeListener() @@ -177,14 +254,14 @@ func (s *ServerRequiredSuite) TestPutAskGet(c *C) { { _, _, err := kc.Ask(hash) c.Check(err, Equals, keepclient.BlockNotFound) - log.Print("Finished Ask (expected BlockNotFound)") + c.Log("Finished Ask (expected BlockNotFound)") } { reader, _, _, err := kc.Get(hash) c.Check(reader, Equals, nil) c.Check(err, Equals, keepclient.BlockNotFound) - log.Print("Finished Get (expected BlockNotFound)") + c.Log("Finished Get (expected BlockNotFound)") } // Note in bug #5309 among other errors keepproxy would set @@ -203,14 +280,14 @@ func (s *ServerRequiredSuite) TestPutAskGet(c *C) { c.Check(hash2, Matches, fmt.Sprintf(`^%s\+3(\+.+)?$`, hash)) c.Check(rep, Equals, 2) c.Check(err, Equals, nil) - log.Print("Finished PutB (expected success)") + c.Log("Finished PutB (expected success)") } { blocklen, _, err := kc.Ask(hash2) c.Assert(err, Equals, nil) c.Check(blocklen, Equals, int64(3)) - log.Print("Finished Ask (expected success)") + c.Log("Finished Ask (expected success)") } { @@ -219,7 +296,7 @@ func (s *ServerRequiredSuite) TestPutAskGet(c *C) { all, err := ioutil.ReadAll(reader) c.Check(all, DeepEquals, []byte("foo")) c.Check(blocklen, Equals, int64(3)) - log.Print("Finished Get (expected success)") + c.Log("Finished Get (expected success)") } { @@ -229,7 +306,7 @@ func (s *ServerRequiredSuite) TestPutAskGet(c *C) { c.Check(hash2, Matches, `^d41d8cd98f00b204e9800998ecf8427e\+0(\+.+)?$`) c.Check(rep, Equals, 2) c.Check(err, Equals, nil) - log.Print("Finished PutB zero block") + c.Log("Finished PutB zero block") } { @@ -238,7 +315,7 @@ func (s *ServerRequiredSuite) TestPutAskGet(c *C) { all, err := ioutil.ReadAll(reader) c.Check(all, DeepEquals, []byte("")) c.Check(blocklen, Equals, int64(0)) - log.Print("Finished Get zero block") + c.Log("Finished Get zero block") } } @@ -253,15 +330,15 @@ func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) { errNotFound, _ := err.(keepclient.ErrNotFound) c.Check(errNotFound, NotNil) c.Assert(strings.Contains(err.Error(), "HTTP 403"), Equals, true) - log.Print("Ask 1") + c.Log("Ask 1") } { hash2, rep, err := kc.PutB([]byte("bar")) c.Check(hash2, Equals, "") c.Check(rep, Equals, 0) - c.Check(err, Equals, keepclient.InsufficientReplicasError) - log.Print("PutB") + c.Check(err, FitsTypeOf, keepclient.InsufficientReplicasError(errors.New(""))) + c.Log("PutB") } { @@ -270,7 +347,7 @@ func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) { c.Check(errNotFound, NotNil) c.Assert(strings.Contains(err.Error(), "HTTP 403"), Equals, true) c.Check(blocklen, Equals, int64(0)) - log.Print("Ask 2") + c.Log("Ask 2") } { @@ -279,7 +356,7 @@ func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) { c.Check(errNotFound, NotNil) c.Assert(strings.Contains(err.Error(), "HTTP 403"), Equals, true) c.Check(blocklen, Equals, int64(0)) - log.Print("Get") + c.Log("Get") } } @@ -294,7 +371,7 @@ func (s *ServerRequiredSuite) TestGetDisabled(c *C) { errNotFound, _ := err.(keepclient.ErrNotFound) c.Check(errNotFound, NotNil) c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true) - log.Print("Ask 1") + c.Log("Ask 1") } { @@ -302,7 +379,7 @@ func (s *ServerRequiredSuite) TestGetDisabled(c *C) { c.Check(hash2, Matches, fmt.Sprintf(`^%s\+3(\+.+)?$`, hash)) c.Check(rep, Equals, 2) c.Check(err, Equals, nil) - log.Print("PutB") + c.Log("PutB") } { @@ -311,7 +388,7 @@ func (s *ServerRequiredSuite) TestGetDisabled(c *C) { c.Check(errNotFound, NotNil) c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true) c.Check(blocklen, Equals, int64(0)) - log.Print("Ask 2") + c.Log("Ask 2") } { @@ -320,7 +397,7 @@ func (s *ServerRequiredSuite) TestGetDisabled(c *C) { c.Check(errNotFound, NotNil) c.Assert(strings.Contains(err.Error(), "HTTP 400"), Equals, true) c.Check(blocklen, Equals, int64(0)) - log.Print("Get") + c.Log("Get") } } @@ -331,7 +408,7 @@ func (s *ServerRequiredSuite) TestPutDisabled(c *C) { hash2, rep, err := kc.PutB([]byte("quux")) c.Check(hash2, Equals, "") c.Check(rep, Equals, 0) - c.Check(err, Equals, keepclient.InsufficientReplicasError) + c.Check(err, FitsTypeOf, keepclient.InsufficientReplicasError(errors.New(""))) } func (s *ServerRequiredSuite) TestCorsHeaders(c *C) { @@ -372,7 +449,7 @@ func (s *ServerRequiredSuite) TestPostWithoutHash(c *C) { req, err := http.NewRequest("POST", "http://"+listener.Addr().String()+"/", strings.NewReader("qux")) - req.Header.Add("Authorization", "OAuth2 4axaw8zxe0qm22wa6urpp5nskcne8z88cvbupv653y1njyi05h") + req.Header.Add("Authorization", "OAuth2 "+arvadostest.ActiveToken) req.Header.Add("Content-Type", "application/octet-stream") resp, err := client.Do(req) c.Check(err, Equals, nil) @@ -548,3 +625,21 @@ func (s *NoKeepServerSuite) TestAskGetNoKeepServerError(c *C) { c.Check(err, ErrorMatches, `.*HTTP 502.*`) } } + +func (s *ServerRequiredSuite) TestPing(c *C) { + kc := runProxy(c, nil, false) + defer closeListener() + + rtr := MakeRESTRouter(true, true, kc, 10*time.Second, arvadostest.ManagementToken) + + req, err := http.NewRequest("GET", + "http://"+listener.Addr().String()+"/_health/ping", + nil) + c.Assert(err, IsNil) + req.Header.Set("Authorization", "Bearer "+arvadostest.ManagementToken) + + resp := httptest.NewRecorder() + rtr.ServeHTTP(resp, req) + c.Check(resp.Code, Equals, 200) + c.Assert(strings.Contains(resp.Body.String(), `{"health":"OK"}`), Equals, true) +}