Adding test for partial objects
This commit is contained in:
parent
376dc30428
commit
959d90fcf7
|
@ -20,6 +20,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/minio-io/iodine"
|
||||||
"github.com/minio-io/minio/pkg/drivers"
|
"github.com/minio-io/minio/pkg/drivers"
|
||||||
"github.com/minio-io/minio/pkg/utils/log"
|
"github.com/minio-io/minio/pkg/utils/log"
|
||||||
)
|
)
|
||||||
|
@ -46,21 +47,27 @@ func (server *minioAPI) getObjectHandler(w http.ResponseWriter, req *http.Reques
|
||||||
}
|
}
|
||||||
switch httpRange.start == 0 && httpRange.length == 0 {
|
switch httpRange.start == 0 && httpRange.length == 0 {
|
||||||
case true:
|
case true:
|
||||||
|
{
|
||||||
setObjectHeaders(w, metadata)
|
setObjectHeaders(w, metadata)
|
||||||
if _, err := server.driver.GetObject(w, bucket, object); err != nil {
|
if _, err := server.driver.GetObject(w, bucket, object); err != nil {
|
||||||
// unable to write headers, we've already printed data. Just close the connection.
|
// unable to write headers, we've already printed data. Just close the connection.
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case false:
|
case false:
|
||||||
|
{
|
||||||
metadata.Size = httpRange.length
|
metadata.Size = httpRange.length
|
||||||
setRangeObjectHeaders(w, metadata, httpRange)
|
setRangeObjectHeaders(w, metadata, httpRange)
|
||||||
|
// contentRangeValue := "bytes " + strconv.FormatInt(httpRange.start, 10) + "-" + strconv.FormatInt(httpRange.length, 10) + "/" + strconv.FormatInt(httpRange.size, 10)
|
||||||
w.WriteHeader(http.StatusPartialContent)
|
w.WriteHeader(http.StatusPartialContent)
|
||||||
_, err := server.driver.GetPartialObject(w, bucket, object, httpRange.start, httpRange.length)
|
_, err := server.driver.GetPartialObject(w, bucket, object, httpRange.start, httpRange.length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
err = iodine.New(err, nil)
|
||||||
// unable to write headers, we've already printed data. Just close the connection.
|
// unable to write headers, we've already printed data. Just close the connection.
|
||||||
log.Error.Println(err)
|
log.Error.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case drivers.ObjectNotFound:
|
case drivers.ObjectNotFound:
|
||||||
{
|
{
|
||||||
writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
|
writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
|
||||||
|
|
|
@ -45,7 +45,7 @@ type MySuite struct {
|
||||||
|
|
||||||
var _ = Suite(&MySuite{
|
var _ = Suite(&MySuite{
|
||||||
Driver: func() drivers.Driver {
|
Driver: func() drivers.Driver {
|
||||||
return startDriver()
|
return startMockDriver()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -152,7 +152,6 @@ func (s *MySuite) TestObject(c *C) {
|
||||||
|
|
||||||
responseBody, err := ioutil.ReadAll(response.Body)
|
responseBody, err := ioutil.ReadAll(response.Body)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
println(string(responseBody))
|
|
||||||
c.Assert(responseBody, DeepEquals, []byte("hello world"))
|
c.Assert(responseBody, DeepEquals, []byte("hello world"))
|
||||||
|
|
||||||
metadata, err := driver.GetObjectMetadata("bucket", "object", "")
|
metadata, err := driver.GetObjectMetadata("bucket", "object", "")
|
||||||
|
@ -172,7 +171,7 @@ func (s *MySuite) TestMultipleObjects(c *C) {
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
typedDriver = startDriver()
|
typedDriver = startMockDriver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
metadata1 := drivers.ObjectMetadata{
|
metadata1 := drivers.ObjectMetadata{
|
||||||
|
@ -307,7 +306,7 @@ func (s *MySuite) TestNotImplemented(c *C) {
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// we never assert expectations
|
// we never assert expectations
|
||||||
typedDriver = startDriver()
|
typedDriver = startMockDriver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
httpHandler := api.HTTPHandler("", driver)
|
httpHandler := api.HTTPHandler("", driver)
|
||||||
|
@ -331,7 +330,7 @@ func (s *MySuite) TestHeader(c *C) {
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// we never assert expectations
|
// we never assert expectations
|
||||||
typedDriver = startDriver()
|
typedDriver = startMockDriver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +385,7 @@ func (s *MySuite) TestPutBucket(c *C) {
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// we never assert expectations
|
// we never assert expectations
|
||||||
typedDriver = startDriver()
|
typedDriver = startMockDriver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +427,7 @@ func (s *MySuite) TestPutObject(c *C) {
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// we never assert expectations
|
// we never assert expectations
|
||||||
typedDriver = startDriver()
|
typedDriver = startMockDriver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
httpHandler := api.HTTPHandler("", driver)
|
httpHandler := api.HTTPHandler("", driver)
|
||||||
|
@ -460,7 +459,6 @@ func (s *MySuite) TestPutObject(c *C) {
|
||||||
|
|
||||||
typedDriver.On("CreateObject", "bucket", "two", "", "", mock.Anything).Return(nil).Once()
|
typedDriver.On("CreateObject", "bucket", "two", "", "", mock.Anything).Return(nil).Once()
|
||||||
request, err = http.NewRequest("PUT", testServer.URL+"/bucket/two", bytes.NewBufferString("hello world"))
|
request, err = http.NewRequest("PUT", testServer.URL+"/bucket/two", bytes.NewBufferString("hello world"))
|
||||||
println(err)
|
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
response, err = client.Do(request)
|
response, err = client.Do(request)
|
||||||
|
@ -516,7 +514,7 @@ func (s *MySuite) TestListBuckets(c *C) {
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// we never assert expectations
|
// we never assert expectations
|
||||||
typedDriver = startDriver()
|
typedDriver = startMockDriver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
httpHandler := api.HTTPHandler("", driver)
|
httpHandler := api.HTTPHandler("", driver)
|
||||||
|
@ -621,7 +619,7 @@ func (s *MySuite) TestXMLNameNotInBucketListJson(c *C) {
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// we never assert expectations
|
// we never assert expectations
|
||||||
typedDriver = startDriver()
|
typedDriver = startMockDriver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
httpHandler := api.HTTPHandler("", driver)
|
httpHandler := api.HTTPHandler("", driver)
|
||||||
|
@ -661,7 +659,7 @@ func (s *MySuite) TestXMLNameNotInObjectListJson(c *C) {
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// we never assert expectations
|
// we never assert expectations
|
||||||
typedDriver = startDriver()
|
typedDriver = startMockDriver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
httpHandler := api.HTTPHandler("", driver)
|
httpHandler := api.HTTPHandler("", driver)
|
||||||
|
@ -701,7 +699,7 @@ func (s *MySuite) TestContentTypePersists(c *C) {
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// we never assert expectations
|
// we never assert expectations
|
||||||
typedDriver = startDriver()
|
typedDriver = startMockDriver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
httpHandler := api.HTTPHandler("", driver)
|
httpHandler := api.HTTPHandler("", driver)
|
||||||
|
@ -776,7 +774,62 @@ func (s *MySuite) TestContentTypePersists(c *C) {
|
||||||
c.Assert(response.Header.Get("Content-Type"), Equals, "application/octet-stream")
|
c.Assert(response.Header.Get("Content-Type"), Equals, "application/octet-stream")
|
||||||
}
|
}
|
||||||
|
|
||||||
func startDriver() *mocks.Driver {
|
func (s *MySuite) TestPartialContent(c *C) {
|
||||||
|
driver := s.Driver()
|
||||||
|
var typedDriver *mocks.Driver
|
||||||
|
switch driver := driver.(type) {
|
||||||
|
case *mocks.Driver:
|
||||||
|
{
|
||||||
|
typedDriver = driver
|
||||||
|
defer driver.AssertExpectations(c)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// we never assert expectations
|
||||||
|
typedDriver = startMockDriver()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpHandler := api.HTTPHandler("", driver)
|
||||||
|
testServer := httptest.NewServer(httpHandler)
|
||||||
|
defer testServer.Close()
|
||||||
|
|
||||||
|
metadata := drivers.ObjectMetadata{
|
||||||
|
Bucket: "foo",
|
||||||
|
Key: "bar",
|
||||||
|
ContentType: "application/octet-stream",
|
||||||
|
Created: time.Now(),
|
||||||
|
// TODO Determine if md5 of range or full object needed
|
||||||
|
Md5: "e81c4e4f2b7b93b481e13a8553c2ae1b",
|
||||||
|
Size: 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
typedDriver.On("CreateBucket", "foo").Return(nil).Once()
|
||||||
|
|
||||||
|
typedDriver.On("CreateObject", "foo", "bar", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
driver.CreateBucket("foo")
|
||||||
|
driver.CreateObject("foo", "bar", "", "", bytes.NewBufferString("hello world"))
|
||||||
|
|
||||||
|
// prepare for GET on range request
|
||||||
|
typedDriver.SetGetObjectWriter("foo", "bar", []byte("hello world"))
|
||||||
|
typedDriver.On("GetObjectMetadata", "foo", "bar", "").Return(metadata, nil).Once()
|
||||||
|
typedDriver.On("GetPartialObject", mock.Anything, "foo", "bar", int64(6), int64(2)).Return(int64(2), nil).Once()
|
||||||
|
|
||||||
|
// prepare request
|
||||||
|
request, err := http.NewRequest("GET", testServer.URL+"/foo/bar", bytes.NewBufferString(""))
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
request.Header.Add("Accept", "application/json")
|
||||||
|
request.Header.Add("Range", "bytes=6-7")
|
||||||
|
client := http.Client{}
|
||||||
|
response, err := client.Do(request)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(response.StatusCode, Equals, http.StatusPartialContent)
|
||||||
|
partialObject, err := ioutil.ReadAll(response.Body)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
c.Assert(string(partialObject), Equals, "wo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func startMockDriver() *mocks.Driver {
|
||||||
return &mocks.Driver{
|
return &mocks.Driver{
|
||||||
ObjectWriterData: make(map[string][]byte),
|
ObjectWriterData: make(map[string][]byte),
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,16 @@ func (memory memoryDriver) GetObject(w io.Writer, bucket string, object string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPartialObject - GET object from memory buffer range
|
// GetPartialObject - GET object from memory buffer range
|
||||||
func (memory memoryDriver) GetPartialObject(w io.Writer, bucket, object string, start, end int64) (int64, error) {
|
func (memory memoryDriver) GetPartialObject(w io.Writer, bucket, object string, start, length int64) (int64, error) {
|
||||||
return 0, drivers.APINotImplemented{API: "GetPartialObject"}
|
var sourceBuffer bytes.Buffer
|
||||||
|
if _, err := memory.GetObject(&sourceBuffer, bucket, object); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
var nilBuffer bytes.Buffer
|
||||||
|
if _, err := io.CopyN(&nilBuffer, &sourceBuffer, start); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return io.CopyN(w, &sourceBuffer, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBucketPolicy - Not implemented
|
// CreateBucketPolicy - Not implemented
|
||||||
|
|
|
@ -6,6 +6,8 @@ import "github.com/stretchr/testify/mock"
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/minio-io/iodine"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Driver is a mock
|
// Driver is a mock
|
||||||
|
@ -56,7 +58,7 @@ func (m *Driver) GetBucketPolicy(bucket string) (drivers.BucketPolicy, error) {
|
||||||
// SetGetObjectWriter is a mock
|
// SetGetObjectWriter is a mock
|
||||||
func (m *Driver) SetGetObjectWriter(bucket, object string, data []byte) {
|
func (m *Driver) SetGetObjectWriter(bucket, object string, data []byte) {
|
||||||
m.ObjectWriterData[bucket+":"+object] = data
|
m.ObjectWriterData[bucket+":"+object] = data
|
||||||
println(string(m.ObjectWriterData["bucket:object"]))
|
// println(string(m.ObjectWriterData["bucket:object"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetObject is a mock
|
// GetObject is a mock
|
||||||
|
@ -81,6 +83,17 @@ func (m *Driver) GetPartialObject(w io.Writer, bucket string, object string, sta
|
||||||
r0 := ret.Get(0).(int64)
|
r0 := ret.Get(0).(int64)
|
||||||
r1 := ret.Error(1)
|
r1 := ret.Error(1)
|
||||||
|
|
||||||
|
if r1 == nil {
|
||||||
|
if obj, ok := m.ObjectWriterData[bucket+":"+object]; ok {
|
||||||
|
source := bytes.NewBuffer(obj)
|
||||||
|
var nilSink bytes.Buffer
|
||||||
|
io.CopyN(&nilSink, source, start)
|
||||||
|
n, _ := io.CopyN(w, source, length)
|
||||||
|
r0 = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r1 = iodine.New(r1, nil)
|
||||||
|
|
||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue