X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/eee302a3157296bccf40e9b83f52c2952294a04e..580d77ef4d6b244971bc26c649e017e912ca8737:/services/keep-web/s3_test.go diff --git a/services/keep-web/s3_test.go b/services/keep-web/s3_test.go index 73553ff4d3..5acc18e494 100644 --- a/services/keep-web/s3_test.go +++ b/services/keep-web/s3_test.go @@ -70,12 +70,13 @@ func (s *IntegrationSuite) s3setup(c *check.C) s3stage { err = arv.RequestAndDecode(&coll, "GET", "arvados/v1/collections/"+coll.UUID, nil, nil) c.Assert(err, check.IsNil) - auth := aws.NewAuth(arvadostest.ActiveTokenV2, arvadostest.ActiveTokenV2, "", time.Now().Add(time.Hour)) + auth := aws.NewAuth(arvadostest.ActiveTokenUUID, arvadostest.ActiveToken, "", time.Now().Add(time.Hour)) region := aws.Region{ Name: s.testServer.Addr, S3Endpoint: "http://" + s.testServer.Addr, } client := s3.New(*auth, region) + client.Signature = aws.V4Signature return s3stage{ arv: arv, ac: ac, @@ -104,6 +105,40 @@ func (stage s3stage) teardown(c *check.C) { } } +func (s *IntegrationSuite) TestS3Signatures(c *check.C) { + stage := s.s3setup(c) + defer stage.teardown(c) + + bucket := stage.collbucket + for _, trial := range []struct { + success bool + signature int + accesskey string + secretkey string + }{ + {true, aws.V2Signature, arvadostest.ActiveToken, "none"}, + {false, aws.V2Signature, "none", "none"}, + {false, aws.V2Signature, "none", arvadostest.ActiveToken}, + + {true, aws.V4Signature, arvadostest.ActiveTokenUUID, arvadostest.ActiveToken}, + {true, aws.V4Signature, arvadostest.ActiveToken, arvadostest.ActiveToken}, + {false, aws.V4Signature, arvadostest.ActiveToken, ""}, + {false, aws.V4Signature, arvadostest.ActiveToken, "none"}, + {false, aws.V4Signature, "none", arvadostest.ActiveToken}, + {false, aws.V4Signature, "none", "none"}, + } { + c.Logf("%#v", trial) + bucket.S3.Auth = *(aws.NewAuth(trial.accesskey, trial.secretkey, "", time.Now().Add(time.Hour))) + bucket.S3.Signature = trial.signature + _, err := bucket.GetReader("emptyfile") + if trial.success { + c.Check(err, check.IsNil) + } else { + c.Check(err, check.NotNil) + } + } +} + func (s *IntegrationSuite) TestS3HeadBucket(c *check.C) { stage := s.s3setup(c) defer stage.teardown(c) @@ -154,9 +189,10 @@ func (s *IntegrationSuite) testS3GetObject(c *check.C, bucket *s3.Bucket, prefix c.Check(err, check.IsNil) // HeadObject - exists, err = bucket.Exists(prefix + "sailboat.txt") + resp, err := bucket.Head(prefix+"sailboat.txt", nil) c.Check(err, check.IsNil) - c.Check(exists, check.Equals, true) + c.Check(resp.StatusCode, check.Equals, http.StatusOK) + c.Check(resp.ContentLength, check.Equals, int64(4)) } func (s *IntegrationSuite) TestS3CollectionPutObjectSuccess(c *check.C) { @@ -260,6 +296,43 @@ func (s *IntegrationSuite) TestS3ProjectPutObjectNotSupported(c *check.C) { } } +func (s *IntegrationSuite) TestS3CollectionDeleteObject(c *check.C) { + stage := s.s3setup(c) + defer stage.teardown(c) + s.testS3DeleteObject(c, stage.collbucket, "") +} +func (s *IntegrationSuite) TestS3ProjectDeleteObject(c *check.C) { + stage := s.s3setup(c) + defer stage.teardown(c) + s.testS3DeleteObject(c, stage.projbucket, stage.coll.Name+"/") +} +func (s *IntegrationSuite) testS3DeleteObject(c *check.C, bucket *s3.Bucket, prefix string) { + s.testServer.Config.cluster.Collections.S3FolderObjects = true + for _, trial := range []struct { + path string + }{ + {"/"}, + {"nonexistentfile"}, + {"emptyfile"}, + {"sailboat.txt"}, + {"sailboat.txt/"}, + {"emptydir"}, + {"emptydir/"}, + } { + objname := prefix + trial.path + comment := check.Commentf("objname %q", objname) + + err := bucket.Del(objname) + if trial.path == "/" { + c.Check(err, check.NotNil) + continue + } + c.Check(err, check.IsNil, comment) + _, err = bucket.GetReader(objname) + c.Check(err, check.NotNil, comment) + } +} + func (s *IntegrationSuite) TestS3CollectionPutObjectFailure(c *check.C) { stage := s.s3setup(c) defer stage.teardown(c) @@ -272,6 +345,15 @@ func (s *IntegrationSuite) TestS3ProjectPutObjectFailure(c *check.C) { } func (s *IntegrationSuite) testS3PutObjectFailure(c *check.C, bucket *s3.Bucket, prefix string) { s.testServer.Config.cluster.Collections.S3FolderObjects = false + + // Can't use V4 signature for these tests, because + // double-slash is incorrectly cleaned by the aws.V4Signature, + // resulting in a "bad signature" error. (Cleaning the path is + // appropriate for other services, but not in S3 where object + // names "foo//bar" and "foo/bar" are semantically different.) + bucket.S3.Auth = *(aws.NewAuth(arvadostest.ActiveToken, "none", "", time.Now().Add(time.Hour))) + bucket.S3.Signature = aws.V2Signature + var wg sync.WaitGroup for _, trial := range []struct { path string @@ -345,6 +427,7 @@ func (s *IntegrationSuite) TestS3GetBucketVersioning(c *check.C) { defer stage.teardown(c) for _, bucket := range []*s3.Bucket{stage.collbucket, stage.projbucket} { req, err := http.NewRequest("GET", bucket.URL("/"), nil) + c.Check(err, check.IsNil) req.Header.Set("Authorization", "AWS "+arvadostest.ActiveTokenV2+":none") req.URL.RawQuery = "versioning" resp, err := http.DefaultClient.Do(req) @@ -356,6 +439,43 @@ func (s *IntegrationSuite) TestS3GetBucketVersioning(c *check.C) { } } +// If there are no CommonPrefixes entries, the CommonPrefixes XML tag +// should not appear at all. +func (s *IntegrationSuite) TestS3ListNoCommonPrefixes(c *check.C) { + stage := s.s3setup(c) + defer stage.teardown(c) + + req, err := http.NewRequest("GET", stage.collbucket.URL("/"), nil) + c.Assert(err, check.IsNil) + req.Header.Set("Authorization", "AWS "+arvadostest.ActiveTokenV2+":none") + req.URL.RawQuery = "prefix=asdfasdfasdf&delimiter=/" + resp, err := http.DefaultClient.Do(req) + c.Assert(err, check.IsNil) + buf, err := ioutil.ReadAll(resp.Body) + c.Assert(err, check.IsNil) + c.Check(string(buf), check.Not(check.Matches), `(?ms).*CommonPrefixes.*`) +} + +// If there is no delimiter in the request, or the results are not +// truncated, the NextMarker XML tag should not appear in the response +// body. +func (s *IntegrationSuite) TestS3ListNoNextMarker(c *check.C) { + stage := s.s3setup(c) + defer stage.teardown(c) + + for _, query := range []string{"prefix=e&delimiter=/", ""} { + req, err := http.NewRequest("GET", stage.collbucket.URL("/"), nil) + c.Assert(err, check.IsNil) + req.Header.Set("Authorization", "AWS "+arvadostest.ActiveTokenV2+":none") + req.URL.RawQuery = query + resp, err := http.DefaultClient.Do(req) + c.Assert(err, check.IsNil) + buf, err := ioutil.ReadAll(resp.Body) + c.Assert(err, check.IsNil) + c.Check(string(buf), check.Not(check.Matches), `(?ms).*NextMarker.*`) + } +} + func (s *IntegrationSuite) TestS3CollectionList(c *check.C) { stage := s.s3setup(c) defer stage.teardown(c)