"crypto/sha256"
"fmt"
"io/ioutil"
+ "mime"
"net/http"
"net/http/httptest"
"net/url"
"group": map[string]interface{}{
"group_class": "project",
"name": "keep-web s3 test",
+ "properties": map[string]interface{}{
+ "project-properties-key": "project properties value",
+ },
},
"ensure_unique_name": true,
})
"name": "keep-web s3 test collection",
"manifest_text": ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:emptyfile\n./emptydir d41d8cd98f00b204e9800998ecf8427e+0 0:0:.\n",
"properties": map[string]interface{}{
- "string": "string value",
- "array": []string{"element1", "element2"},
- "object": map[string]interface{}{"key": map[string]interface{}{"key2": "value"}},
+ "string": "string value",
+ "array": []string{"element1", "element2"},
+ "object": map[string]interface{}{"key": map[string]interface{}{"key2": "value⛵"}},
+ "nonascii": "⛵",
+ "newline": "foo\r\nX-Bad: header",
+ // This key cannot be expressed as a MIME
+ // header key, so it will be silently skipped
+ // (see "Inject" in PropertiesAsMetadata test)
+ "a: a\r\nInject": "bogus",
},
}})
c.Assert(err, check.IsNil)
c.Check(exists, check.Equals, true)
}
-func (s *IntegrationSuite) checkMetaEquals(c *check.C, resp *http.Response, expect map[string]string) {
+func (s *IntegrationSuite) checkMetaEquals(c *check.C, hdr http.Header, expect map[string]string) {
got := map[string]string{}
- for hk, hv := range resp.Header {
+ for hk, hv := range hdr {
if k := strings.TrimPrefix(hk, "X-Amz-Meta-"); k != hk && len(hv) == 1 {
got[k] = hv[0]
}
defer stage.teardown(c)
expectCollectionTags := map[string]string{
- "String": "string value",
- "Array": `["element1","element2"]`,
- "Object": `{"key":{"key2":"value"}}`,
+ "String": "string value",
+ "Array": `["element1","element2"]`,
+ "Object": mime.BEncoding.Encode("UTF-8", `{"key":{"key2":"value⛵"}}`),
+ "Nonascii": "=?UTF-8?b?4pu1?=",
+ "Newline": mime.BEncoding.Encode("UTF-8", "foo\r\nX-Bad: header"),
}
expectSubprojectTags := map[string]string{
"Subproject_properties_key": "subproject properties value",
}
+ expectProjectTags := map[string]string{
+ "Project-Properties-Key": "project properties value",
+ }
+ c.Log("HEAD object with metadata from collection")
resp, err := stage.collbucket.Head("sailboat.txt", nil)
c.Assert(err, check.IsNil)
- s.checkMetaEquals(c, resp, expectCollectionTags)
+ s.checkMetaEquals(c, resp.Header, expectCollectionTags)
+ c.Log("GET object with metadata from collection")
+ rdr, hdr, err := stage.collbucket.GetReaderWithHeaders("sailboat.txt")
+ c.Assert(err, check.IsNil)
+ content, err := ioutil.ReadAll(rdr)
+ c.Check(err, check.IsNil)
+ rdr.Close()
+ c.Check(content, check.HasLen, 4)
+ s.checkMetaEquals(c, hdr, expectCollectionTags)
+ c.Check(hdr["Inject"], check.IsNil)
+
+ c.Log("HEAD bucket with metadata from collection")
+ resp, err = stage.collbucket.Head("/", nil)
+ c.Assert(err, check.IsNil)
+ s.checkMetaEquals(c, resp.Header, expectCollectionTags)
+
+ c.Log("HEAD directory placeholder with metadata from collection")
resp, err = stage.projbucket.Head("keep-web s3 test collection/", nil)
c.Assert(err, check.IsNil)
- s.checkMetaEquals(c, resp, expectCollectionTags)
+ s.checkMetaEquals(c, resp.Header, expectCollectionTags)
+ c.Log("HEAD file with metadata from collection")
resp, err = stage.projbucket.Head("keep-web s3 test collection/sailboat.txt", nil)
c.Assert(err, check.IsNil)
- s.checkMetaEquals(c, resp, expectCollectionTags)
+ s.checkMetaEquals(c, resp.Header, expectCollectionTags)
+ c.Log("HEAD directory placeholder with metadata from subproject")
resp, err = stage.projbucket.Head("keep-web s3 test subproject/", nil)
c.Assert(err, check.IsNil)
- s.checkMetaEquals(c, resp, expectSubprojectTags)
+ s.checkMetaEquals(c, resp.Header, expectSubprojectTags)
+
+ c.Log("HEAD bucket with metadata from project")
+ resp, err = stage.projbucket.Head("/", nil)
+ c.Assert(err, check.IsNil)
+ s.checkMetaEquals(c, resp.Header, expectProjectTags)
}
func (s *IntegrationSuite) TestS3CollectionPutObjectSuccess(c *check.C) {
stage := s.s3setup(c)
defer stage.teardown(c)
- s.testS3PutObjectSuccess(c, stage.collbucket, "")
+ s.testS3PutObjectSuccess(c, stage.collbucket, "", stage.coll.UUID)
}
func (s *IntegrationSuite) TestS3ProjectPutObjectSuccess(c *check.C) {
stage := s.s3setup(c)
defer stage.teardown(c)
- s.testS3PutObjectSuccess(c, stage.projbucket, stage.coll.Name+"/")
+ s.testS3PutObjectSuccess(c, stage.projbucket, stage.coll.Name+"/", stage.coll.UUID)
}
-func (s *IntegrationSuite) testS3PutObjectSuccess(c *check.C, bucket *s3.Bucket, prefix string) {
+func (s *IntegrationSuite) testS3PutObjectSuccess(c *check.C, bucket *s3.Bucket, prefix string, collUUID string) {
for _, trial := range []struct {
path string
size int
if !c.Check(err, check.NotNil) {
continue
}
- c.Check(err.(*s3.Error).StatusCode, check.Equals, 404)
+ c.Check(err.(*s3.Error).StatusCode, check.Equals, http.StatusNotFound)
c.Check(err.(*s3.Error).Code, check.Equals, `NoSuchKey`)
if !c.Check(err, check.ErrorMatches, `The specified key does not exist.`) {
continue
c.Check(err, check.IsNil)
c.Check(buf2, check.HasLen, len(buf))
c.Check(bytes.Equal(buf, buf2), check.Equals, true)
+
+ // Check that the change is immediately visible via
+ // (non-S3) webdav request.
+ _, resp := s.do("GET", "http://"+collUUID+".keep-web.example/"+trial.path, arvadostest.ActiveTokenV2, nil)
+ c.Check(resp.Code, check.Equals, http.StatusOK)
+ if !strings.HasSuffix(trial.path, "/") {
+ c.Check(resp.Body.Len(), check.Equals, trial.size)
+ }
}
}