Merge branch '12475-asyncbuf'
[arvados.git] / services / keepproxy / keepproxy_test.go
index 6a349dae216c54e81b309e7ecc52471549380146..23bb2bd216c1f1080d246e63a47252564e4d9bf4 100644 (file)
@@ -1,21 +1,29 @@
+// 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"
 )
 
@@ -111,6 +119,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 +191,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 +209,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 +218,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()
@@ -260,7 +338,7 @@ func (s *ServerRequiredSuite) TestPutAskGetForbidden(c *C) {
                hash2, rep, err := kc.PutB([]byte("bar"))
                c.Check(hash2, Equals, "")
                c.Check(rep, Equals, 0)
-               c.Check(err, Equals, keepclient.InsufficientReplicasError)
+               c.Check(err, FitsTypeOf, keepclient.InsufficientReplicasError(errors.New("")))
                log.Print("PutB")
        }
 
@@ -331,7 +409,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 +450,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 +626,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)
+}