Skip to content

Commit

Permalink
fakestorage: add support for ContentType
Browse files Browse the repository at this point in the history
Closes #52.
  • Loading branch information
fsouza committed Aug 2, 2019
1 parent f300899 commit 5e96638
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 71 deletions.
41 changes: 23 additions & 18 deletions fakestorage/object.go
Expand Up @@ -18,9 +18,10 @@ import (

// Object represents the object that is stored within the fake server.
type Object struct {
BucketName string `json:"-"`
Name string `json:"name"`
Content []byte `json:"-"`
BucketName string `json:"-"`
Name string `json:"name"`
ContentType string `json:"contentType"`
Content []byte `json:"-"`
// Crc32c checksum of Content. calculated by server when it's upload methods are used.
Crc32c string `json:"crc32c,omitempty"`
Md5Hash string `json:"md5hash,omitempty"`
Expand Down Expand Up @@ -95,11 +96,12 @@ func toBackendObjects(objects []Object) []backend.Object {
backendObjects := []backend.Object{}
for _, o := range objects {
backendObjects = append(backendObjects, backend.Object{
BucketName: o.BucketName,
Name: o.Name,
Content: o.Content,
Crc32c: o.Crc32c,
Md5Hash: o.Md5Hash,
BucketName: o.BucketName,
Name: o.Name,
Content: o.Content,
ContentType: o.ContentType,
Crc32c: o.Crc32c,
Md5Hash: o.Md5Hash,
})
}
return backendObjects
Expand All @@ -109,11 +111,12 @@ func fromBackendObjects(objects []backend.Object) []Object {
backendObjects := []Object{}
for _, o := range objects {
backendObjects = append(backendObjects, Object{
BucketName: o.BucketName,
Name: o.Name,
Content: o.Content,
Crc32c: o.Crc32c,
Md5Hash: o.Md5Hash,
BucketName: o.BucketName,
Name: o.Name,
Content: o.Content,
ContentType: o.ContentType,
Crc32c: o.Crc32c,
Md5Hash: o.Md5Hash,
})
}
return backendObjects
Expand Down Expand Up @@ -180,11 +183,12 @@ func (s *Server) rewriteObject(w http.ResponseWriter, r *http.Request) {
}
dstBucket := vars["destinationBucket"]
newObject := Object{
BucketName: dstBucket,
Name: vars["destinationObject"],
Content: append([]byte(nil), obj.Content...),
Crc32c: obj.Crc32c,
Md5Hash: obj.Md5Hash,
BucketName: dstBucket,
Name: vars["destinationObject"],
Content: append([]byte(nil), obj.Content...),
Crc32c: obj.Crc32c,
Md5Hash: obj.Md5Hash,
ContentType: obj.ContentType,
}
s.CreateObject(newObject)
w.Header().Set("Content-Type", "application/json")
Expand All @@ -206,6 +210,7 @@ func (s *Server) downloadObject(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Accept-Ranges", "bytes")
w.Header().Set("Content-Length", strconv.Itoa(len(content)))
w.Header().Set(contentTypeHeader, obj.ContentType)
w.WriteHeader(status)
if r.Method == http.MethodGet {
w.Write(content)
Expand Down
109 changes: 84 additions & 25 deletions fakestorage/object_test.go
Expand Up @@ -31,14 +31,22 @@ func uint32Checksum(b []byte) uint32 {

func TestServerClientObjectAttrs(t *testing.T) {
const (
bucketName = "some-bucket"
objectName = "img/hi-res/party-01.jpg"
content = "some nice content"
bucketName = "some-bucket"
objectName = "img/hi-res/party-01.jpg"
content = "some nice content"
contentType = "text/plain; charset=utf-8"
)
checksum := uint32Checksum([]byte(content))
hash := md5Hash([]byte(content))
objs := []Object{
{BucketName: bucketName, Name: objectName, Content: []byte(content), Crc32c: encodedChecksum(uint32ToBytes(checksum)), Md5Hash: encodedHash(hash)},
{
BucketName: bucketName,
Name: objectName,
Content: []byte(content),
ContentType: contentType,
Crc32c: encodedChecksum(uint32ToBytes(checksum)),
Md5Hash: encodedHash(hash),
},
}

runServersTest(t, objs, func(t *testing.T, server *Server) {
Expand All @@ -57,6 +65,9 @@ func TestServerClientObjectAttrs(t *testing.T) {
if attrs.Size != int64(len(content)) {
t.Errorf("wrong size returned\nwant %d\ngot %d", len(content), attrs.Size)
}
if attrs.ContentType != contentType {
t.Errorf("wrong content type\nwant %q\ngot %q", contentType, attrs.ContentType)
}
if attrs.CRC32C != checksum {
t.Errorf("wrong checksum returned\nwant %d\ngot %d", checksum, attrs.CRC32C)
}
Expand All @@ -69,10 +80,15 @@ func TestServerClientObjectAttrs(t *testing.T) {
func TestServerClientObjectAttrsAfterCreateObject(t *testing.T) {
runServersTest(t, nil, func(t *testing.T, server *Server) {
const (
bucketName = "prod-bucket"
objectName = "video/hi-res/best_video_1080p.mp4"
bucketName = "prod-bucket"
objectName = "video/hi-res/best_video_1080p.mp4"
contentType = "text/html; charset=utf-8"
)
server.CreateObject(Object{BucketName: bucketName, Name: objectName})
server.CreateObject(Object{
BucketName: bucketName,
Name: objectName,
ContentType: contentType,
})
client := server.Client()
objHandle := client.Bucket(bucketName).Object(objectName)
attrs, err := objHandle.Attrs(context.TODO())
Expand All @@ -85,6 +101,9 @@ func TestServerClientObjectAttrsAfterCreateObject(t *testing.T) {
if attrs.Name != objectName {
t.Errorf("wrong object name\n want %q\ngot %q", objectName, attrs.Name)
}
if attrs.ContentType != contentType {
t.Errorf("wrong content type\n want %q\ngot %q", contentType, attrs.ContentType)
}
})
}

Expand Down Expand Up @@ -128,12 +147,18 @@ func TestServerClientObjectAttrsErrors(t *testing.T) {

func TestServerClientObjectReader(t *testing.T) {
const (
bucketName = "some-bucket"
objectName = "items/data.txt"
content = "some nice content"
bucketName = "some-bucket"
objectName = "items/data.txt"
content = "some nice content"
contentType = "text/plain; charset=utf-8"
)
objs := []Object{
{BucketName: bucketName, Name: objectName, Content: []byte(content)},
{
BucketName: bucketName,
Name: objectName,
Content: []byte(content),
ContentType: contentType,
},
}

runServersTest(t, objs, func(t *testing.T, server *Server) {
Expand All @@ -151,17 +176,26 @@ func TestServerClientObjectReader(t *testing.T) {
if string(data) != content {
t.Errorf("wrong data returned\nwant %q\ngot %q", content, string(data))
}
if ct := reader.ContentType(); ct != contentType {
t.Errorf("wrong content type\nwant %q\ngot %q", contentType, ct)
}
})
}

func TestServerClientObjectRangeReader(t *testing.T) {
const (
bucketName = "some-bucket"
objectName = "items/data.txt"
content = "some really nice but long content stored in my object"
bucketName = "some-bucket"
objectName = "items/data.txt"
content = "some really nice but long content stored in my object"
contentType = "text/plain; charset=iso-8859"
)
objs := []Object{
{BucketName: bucketName, Name: objectName, Content: []byte(content)},
{
BucketName: bucketName,
Name: objectName,
Content: []byte(content),
ContentType: contentType,
},
}

runServersTest(t, objs, func(t *testing.T, server *Server) {
Expand Down Expand Up @@ -208,23 +242,29 @@ func TestServerClientObjectRangeReader(t *testing.T) {
if string(data) != expectedData {
t.Errorf("wrong data returned\nwant %q\ngot %q", expectedData, string(data))
}
if ct := reader.ContentType(); ct != contentType {
t.Errorf("wrong content type\nwant %q\ngot %q", contentType, ct)
}
})
}
})
}

func TestServerClientObjectReaderAfterCreateObject(t *testing.T) {
const (
bucketName = "staging-bucket"
objectName = "items/data-overwritten.txt"
content = "data inside the object"
bucketName = "staging-bucket"
objectName = "items/data-overwritten.txt"
content = "data inside the object"
contentType = "text/plain; charset=iso-8859"
)
objs := []Object{
{BucketName: bucketName, Name: objectName},
}

runServersTest(t, objs, func(t *testing.T, server *Server) {
server.CreateObject(Object{BucketName: bucketName, Name: objectName, Content: []byte(content)})
runServersTest(t, nil, func(t *testing.T, server *Server) {
server.CreateObject(Object{
BucketName: bucketName,
Name: objectName,
Content: []byte(content),
ContentType: contentType,
})
client := server.Client()
objHandle := client.Bucket(bucketName).Object(objectName)
reader, err := objHandle.NewReader(context.TODO())
Expand All @@ -239,6 +279,9 @@ func TestServerClientObjectReaderAfterCreateObject(t *testing.T) {
if string(data) != content {
t.Errorf("wrong data returned\nwant %q\ngot %q", content, string(data))
}
if ct := reader.ContentType(); ct != contentType {
t.Errorf("wrong content type\nwant %q\ngot %q", contentType, ct)
}
})
}

Expand Down Expand Up @@ -413,11 +456,21 @@ func TestServiceClientListObjectsBucketNotFound(t *testing.T) {
}

func TestServiceClientRewriteObject(t *testing.T) {
const content = "some content"
const (
content = "some content"
contentType = "text/plain; charset=utf-8"
)
checksum := uint32Checksum([]byte(content))
hash := md5Hash([]byte(content))
objs := []Object{
{BucketName: "first-bucket", Name: "files/some-file.txt", Content: []byte(content), Crc32c: encodedChecksum(uint32ToBytes(checksum)), Md5Hash: encodedHash(hash)},
{
BucketName: "first-bucket",
Name: "files/some-file.txt",
Content: []byte(content),
ContentType: contentType,
Crc32c: encodedChecksum(uint32ToBytes(checksum)),
Md5Hash: encodedHash(hash),
},
}

runServersTest(t, objs, func(t *testing.T, server *Server) {
Expand Down Expand Up @@ -466,6 +519,9 @@ func TestServiceClientRewriteObject(t *testing.T) {
if attrs.CRC32C != checksum {
t.Errorf("wrong checksum in copied object attrs\nwant %d\ngot %d", checksum, attrs.CRC32C)
}
if attrs.ContentType != contentType {
t.Errorf("wrong content type\nwant %q\ngot %q", contentType, attrs.ContentType)
}
if !bytes.Equal(attrs.MD5, hash) {
t.Errorf("wrong hash returned\nwant %d\ngot %d", hash, attrs.MD5)
}
Expand All @@ -482,6 +538,9 @@ func TestServiceClientRewriteObject(t *testing.T) {
if expect := encodedHash(hash); expect != obj.Md5Hash {
t.Errorf("wrong hash on object\nwant %s\ngot %s", expect, obj.Md5Hash)
}
if obj.ContentType != contentType {
t.Errorf("wrong content type\nwant %q\ngot %q", contentType, obj.ContentType)
}
})
}
})
Expand Down
31 changes: 16 additions & 15 deletions fakestorage/response.go
Expand Up @@ -51,25 +51,26 @@ func newListObjectsResponse(objs []Object, prefixes []string) listResponse {
}

type objectResponse struct {
Kind string `json:"kind"`
Name string `json:"name"`
ID string `json:"id"`
Bucket string `json:"bucket"`
Size int64 `json:"size,string"`
// Crc32c: CRC32c checksum, same as in google storage client code
Crc32c string `json:"crc32c,omitempty"`
Md5Hash string `json:"md5hash,omitempty"`
Kind string `json:"kind"`
Name string `json:"name"`
ID string `json:"id"`
Bucket string `json:"bucket"`
Size int64 `json:"size,string"`
ContentType string `json:"contentType,omitempty"`
Crc32c string `json:"crc32c,omitempty"`
Md5Hash string `json:"md5hash,omitempty"`
}

func newObjectResponse(obj Object) objectResponse {
return objectResponse{
Kind: "storage#object",
ID: obj.id(),
Bucket: obj.BucketName,
Name: obj.Name,
Size: int64(len(obj.Content)),
Crc32c: obj.Crc32c,
Md5Hash: obj.Md5Hash,
Kind: "storage#object",
ID: obj.id(),
Bucket: obj.BucketName,
Name: obj.Name,
Size: int64(len(obj.Content)),
ContentType: obj.ContentType,
Crc32c: obj.Crc32c,
Md5Hash: obj.Md5Hash,
}
}

Expand Down

0 comments on commit 5e96638

Please sign in to comment.