10473: Use fixed-point timestamps and more human-readable field ordering, hide "incom...
[arvados.git] / services / keepproxy / keepproxy_test.go
index e4f09b4e74a071b62797da22c3649ddd1f423938..6a349dae216c54e81b309e7ecc52471549380146 100644 (file)
@@ -1,6 +1,7 @@
 package main
 
 import (
+       "bytes"
        "crypto/md5"
        "fmt"
        "git.curoverse.com/arvados.git/sdk/go/arvadosclient"
@@ -9,6 +10,7 @@ import (
        "io/ioutil"
        "log"
        "net/http"
+       "net/http/httptest"
        "os"
        "strings"
        "testing"
@@ -43,7 +45,7 @@ func waitForListener() {
        const (
                ms = 5
        )
-       for i := 0; listener == nil && i < 1000; i += ms {
+       for i := 0; listener == nil && i < 10000; i += ms {
                time.Sleep(ms * time.Millisecond)
        }
        if listener == nil {
@@ -73,6 +75,10 @@ func (s *ServerRequiredSuite) TearDownSuite(c *C) {
 
 func (s *NoKeepServerSuite) SetUpSuite(c *C) {
        arvadostest.StartAPI()
+       // We need API to have some keep services listed, but the
+       // services themselves should be unresponsive.
+       arvadostest.StartKeep(2, false)
+       arvadostest.StopKeep(2)
 }
 
 func (s *NoKeepServerSuite) SetUpTest(c *C) {
@@ -95,15 +101,70 @@ func runProxy(c *C, args []string, bogusClientToken bool) *keepclient.KeepClient
        if bogusClientToken {
                arv.ApiToken = "bogus-token"
        }
-       kc := keepclient.New(&arv)
+       kc := keepclient.New(arv)
        sr := map[string]string{
                TestProxyUUID: "http://" + listener.Addr().String(),
        }
        kc.SetServiceRoots(sr, sr, sr)
        kc.Arvados.External = true
-       kc.Using_proxy = true
 
-       return &kc
+       return kc
+}
+
+func (s *ServerRequiredSuite) TestDesiredReplicas(c *C) {
+       kc := runProxy(c, nil, false)
+       defer closeListener()
+
+       content := []byte("TestDesiredReplicas")
+       hash := fmt.Sprintf("%x", md5.Sum(content))
+
+       for _, kc.Want_replicas = range []int{0, 1, 2} {
+               locator, rep, err := kc.PutB(content)
+               c.Check(err, Equals, nil)
+               c.Check(rep, Equals, kc.Want_replicas)
+               if rep > 0 {
+                       c.Check(locator, Matches, fmt.Sprintf(`^%s\+%d(\+.+)?$`, hash, len(content)))
+               }
+       }
+}
+
+func (s *ServerRequiredSuite) TestPutWrongContentLength(c *C) {
+       kc := runProxy(c, nil, false)
+       defer closeListener()
+
+       content := []byte("TestPutWrongContentLength")
+       hash := fmt.Sprintf("%x", md5.Sum(content))
+
+       // If we use http.Client to send these requests to the network
+       // server we just started, the Go http library automatically
+       // 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)
+
+       type testcase struct {
+               sendLength   string
+               expectStatus int
+       }
+
+       for _, t := range []testcase{
+               {"1", http.StatusBadRequest},
+               {"", http.StatusLengthRequired},
+               {"-1", http.StatusLengthRequired},
+               {"abcdef", http.StatusLengthRequired},
+       } {
+               req, err := http.NewRequest("PUT",
+                       fmt.Sprintf("http://%s/%s+%d", listener.Addr().String(), hash, len(content)),
+                       bytes.NewReader(content))
+               c.Assert(err, IsNil)
+               req.Header.Set("Content-Length", t.sendLength)
+               req.Header.Set("Authorization", "OAuth2 4axaw8zxe0qm22wa6urpp5nskcne8z88cvbupv653y1njyi05h")
+               req.Header.Set("Content-Type", "application/octet-stream")
+
+               resp := httptest.NewRecorder()
+               rtr.ServeHTTP(resp, req)
+               c.Check(resp.Code, Equals, t.expectStatus)
+       }
 }
 
 func (s *ServerRequiredSuite) TestPutAskGet(c *C) {
@@ -367,6 +428,8 @@ func (s *ServerRequiredSuite) TestGetIndex(c *C) {
        _, rep, err = kc.PutB([]byte("some-more-index-data"))
        c.Check(err, Equals, nil)
 
+       kc.Arvados.ApiToken = arvadostest.DataManagerToken
+
        // Invoke GetIndex
        for _, spec := range []struct {
                prefix         string
@@ -405,8 +468,7 @@ func (s *ServerRequiredSuite) TestGetIndex(c *C) {
 }
 
 func (s *ServerRequiredSuite) TestPutAskGetInvalidToken(c *C) {
-       kc := runProxy(c, []string{"keepproxy"}, 28852, false)
-       waitForListener()
+       kc := runProxy(c, nil, false)
        defer closeListener()
 
        // Put a test block
@@ -442,9 +504,9 @@ func (s *ServerRequiredSuite) TestAskGetKeepProxyConnectionError(c *C) {
        c.Assert(err, Equals, nil)
 
        // keepclient with no such keep server
-       kc := keepclient.New(&arv)
+       kc := keepclient.New(arv)
        locals := map[string]string{
-               "proxy": "http://localhost:12345",
+               TestProxyUUID: "http://localhost:12345",
        }
        kc.SetServiceRoots(locals, nil, nil)
 
@@ -465,22 +527,24 @@ func (s *ServerRequiredSuite) TestAskGetKeepProxyConnectionError(c *C) {
 }
 
 func (s *NoKeepServerSuite) TestAskGetNoKeepServerError(c *C) {
-       kc := runProxy(c, []string{"keepproxy"}, 29999, false)
-       waitForListener()
+       kc := runProxy(c, nil, false)
        defer closeListener()
 
-       // Ask should result in temporary connection refused error
        hash := fmt.Sprintf("%x", md5.Sum([]byte("foo")))
-       _, _, err := kc.Ask(hash)
-       c.Check(err, NotNil)
-       errNotFound, _ := err.(*keepclient.ErrNotFound)
-       c.Check(errNotFound.Temporary(), Equals, true)
-       c.Assert(strings.Contains(err.Error(), "HTTP 502"), Equals, true)
-
-       // Get should result in temporary connection refused 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(), "HTTP 502"), Equals, true)
+       for _, f := range []func() error{
+               func() error {
+                       _, _, err := kc.Ask(hash)
+                       return err
+               },
+               func() error {
+                       _, _, _, err := kc.Get(hash)
+                       return err
+               },
+       } {
+               err := f()
+               c.Assert(err, NotNil)
+               errNotFound, _ := err.(*keepclient.ErrNotFound)
+               c.Check(errNotFound.Temporary(), Equals, true)
+               c.Check(err, ErrorMatches, `.*HTTP 502.*`)
+       }
 }