diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index b17ad1fb..7dc32ac1 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -36,7 +36,7 @@ }, { "ImportPath": "github.com/minio/objectstorage-go", - "Rev": "83fd992ca0e7ba5a26317a41c1c298244b0ce83d" + "Rev": "0b5d5f294de9f3871ae9cc23bb9753175da8f2dd" }, { "ImportPath": "github.com/shiena/ansicolor", diff --git a/Godeps/_workspace/src/github.com/minio/objectstorage-go/api_test.go b/Godeps/_workspace/src/github.com/minio/objectstorage-go/api_test.go index 88863af6..e6a5ed61 100644 --- a/Godeps/_workspace/src/github.com/minio/objectstorage-go/api_test.go +++ b/Godeps/_workspace/src/github.com/minio/objectstorage-go/api_test.go @@ -17,11 +17,14 @@ package objectstorage import ( + "bytes" "fmt" + "io" "net/http" "net/http/httptest" "strconv" "testing" + "time" ) func ExampleGetPartSize() { @@ -41,13 +44,16 @@ type bucketHandler struct { func (h bucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch { case r.Method == "GET": - if r.URL.Path == "/" { + switch { + case r.URL.Path == "/": response := []byte("bucket2015-05-20T23:05:09.230Zminiominio") w.Header().Set("Content-Length", strconv.Itoa(len(response))) w.Write(response) + case r.URL.Path == "/bucket": + response := []byte("259d04a13802ae09c7e41be50ccc6baaobject2015-05-21T18:24:21.097Z22061miniominioSTANDARDfalse1000testbucket") + w.Header().Set("Content-Length", strconv.Itoa(len(response))) + w.Write(response) } - case r.Method == "POST": - w.WriteHeader(http.StatusOK) case r.Method == "PUT": switch { case r.URL.Path == h.resource: @@ -118,6 +124,16 @@ func TestBucketOperations(t *testing.T) { t.Errorf("Error") } } + + for o := range a.ListObjects("bucket", "", true) { + if o.Err != nil { + t.Fatalf(o.Err.Error()) + } + if o.Data.Key != "object" { + t.Errorf("Error") + } + } + err = a.DeleteBucket("bucket") if err != nil { t.Errorf("Error") @@ -141,10 +157,99 @@ type objectHandler struct { func (h objectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch { case r.Method == "PUT": + length, err := strconv.Atoi(r.Header.Get("Content-Length")) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + var buffer bytes.Buffer + _, err = io.CopyN(&buffer, r.Body, int64(length)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + if !bytes.Equal(h.data, buffer.Bytes()) { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.Header().Set("ETag", "9af2f8218b150c351ad802c6f3d66abe") + w.WriteHeader(http.StatusOK) case r.Method == "HEAD": + if r.URL.Path != h.resource { + w.WriteHeader(http.StatusNotFound) + return + } + w.Header().Set("Content-Length", strconv.Itoa(len(h.data))) + w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) + w.Header().Set("ETag", "9af2f8218b150c351ad802c6f3d66abe") + w.WriteHeader(http.StatusOK) case r.Method == "POST": case r.Method == "GET": + if r.URL.Path != h.resource { + w.WriteHeader(http.StatusNotFound) + return + } + w.Header().Set("Content-Length", strconv.Itoa(len(h.data))) + w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) + w.Header().Set("ETag", "9af2f8218b150c351ad802c6f3d66abe") + w.WriteHeader(http.StatusOK) + io.Copy(w, bytes.NewReader(h.data)) case r.Method == "DELETE": + if r.URL.Path != h.resource { + w.WriteHeader(http.StatusNotFound) + return + } + h.resource = "" + h.data = nil + w.WriteHeader(http.StatusOK) + } +} + +func TestObjectOperations(t *testing.T) { + object := objectHandler(objectHandler{ + resource: "/bucket/object", + data: []byte("Hello, World"), + }) + server := httptest.NewServer(object) + defer server.Close() + + a := New(&Config{Endpoint: server.URL}) + data := []byte("Hello, World") + err := a.PutObject("bucket", "object", uint64(len(data)), bytes.NewReader(data)) + if err != nil { + t.Fatalf("Error") + } + metadata, err := a.StatObject("bucket", "object") + if err != nil { + t.Fatalf("Error") + } + if metadata.Key != "object" { + t.Fatalf("Error") + } + if metadata.ETag != "9af2f8218b150c351ad802c6f3d66abe" { + t.Fatalf("Error") + } + + reader, metadata, err := a.GetObject("bucket", "object", 0, 0) + if err != nil { + t.Fatalf("Error") + } + if metadata.Key != "object" { + t.Fatalf("Error") + } + if metadata.ETag != "9af2f8218b150c351ad802c6f3d66abe" { + t.Fatalf("Error") + } + + var buffer bytes.Buffer + _, err = io.Copy(&buffer, reader) + if !bytes.Equal(buffer.Bytes(), data) { + t.Fatalf("Error") + } + + err = a.DeleteObject("bucket", "object") + if err != nil { + t.Fatalf("Error") } } diff --git a/api_handlers_test.go b/api_handlers_test.go new file mode 100644 index 00000000..e3bd479d --- /dev/null +++ b/api_handlers_test.go @@ -0,0 +1,115 @@ +/* + * Minio Client (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "bytes" + "io" + "net/http" + "path/filepath" + "strconv" + "time" +) + +type objectAPIHandler struct { + bucket string + object map[string][]byte +} + +func (h objectAPIHandler) getHandler(w http.ResponseWriter, r *http.Request) { + switch { + case r.URL.Path == "/": + response := []byte("bucket2015-05-20T23:05:09.230Zminiominio") + w.Header().Set("Content-Length", strconv.Itoa(len(response))) + w.Write(response) + return + case r.URL.Path == "/bucket": + response := []byte("b1946ac92492d2347c6235b4d2611184object02015-05-21T18:24:21.097Z22061miniominioSTANDARDb1946ac92492d2347c6235b4d2611184object12015-05-21T18:24:21.097Z22061miniominioSTANDARDb1946ac92492d2347c6235b4d2611184object22015-05-21T18:24:21.097Z22061miniominioSTANDARDb1946ac92492d2347c6235b4d2611184object32015-05-21T18:24:21.097Z22061miniominioSTANDARDb1946ac92492d2347c6235b4d2611184object42015-05-21T18:24:21.097Z22061miniominioSTANDARDb1946ac92492d2347c6235b4d2611184object52015-05-21T18:24:21.097Z22061miniominioSTANDARDb1946ac92492d2347c6235b4d2611184object62015-05-21T18:24:21.097Z22061miniominioSTANDARDb1946ac92492d2347c6235b4d2611184object72015-05-21T18:24:21.097Z22061miniominioSTANDARDfalse1000testbucket") + w.Header().Set("Content-Length", strconv.Itoa(len(response))) + w.Write(response) + return + case r.URL.Path != "": + w.Header().Set("Content-Length", strconv.Itoa(len(h.object[filepath.Base(r.URL.Path)]))) + w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) + w.Header().Set("ETag", "b1946ac92492d2347c6235b4d2611184") + w.WriteHeader(http.StatusOK) + io.Copy(w, bytes.NewReader(h.object[filepath.Base(r.URL.Path)])) + return + } +} + +func (h objectAPIHandler) headHandler(w http.ResponseWriter, r *http.Request) { + switch { + case r.URL.Path == "/": + w.WriteHeader(http.StatusOK) + return + case r.URL.Path == "/bucket": + w.WriteHeader(http.StatusOK) + return + case r.URL.Path != "": + w.Header().Set("Content-Length", strconv.Itoa(len(h.object[filepath.Base(r.URL.Path)]))) + w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) + w.Header().Set("ETag", "b1946ac92492d2347c6235b4d2611184") + w.WriteHeader(http.StatusOK) + return + } +} + +func (h objectAPIHandler) putHandler(w http.ResponseWriter, r *http.Request) { + switch { + case r.URL.Path == "/": + w.WriteHeader(http.StatusBadRequest) + return + case r.URL.Path == "/bucket": + _, ok := r.URL.Query()["acl"] + if ok { + if r.Header.Get("x-amz-acl") != "public-read-write" { + w.WriteHeader(http.StatusNotImplemented) + return + } + } + w.WriteHeader(http.StatusOK) + return + case r.URL.Path != "": + length, err := strconv.Atoi(r.Header.Get("Content-Length")) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + var buffer bytes.Buffer + _, err = io.CopyN(&buffer, r.Body, int64(length)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + h.object[filepath.Base(r.URL.Path)] = buffer.Bytes() + w.Header().Set("ETag", "b1946ac92492d2347c6235b4d2611184") + w.WriteHeader(http.StatusOK) + return + } +} + +func (h objectAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + switch { + case r.Method == "GET": + h.getHandler(w, r) + case r.Method == "HEAD": + h.headHandler(w, r) + case r.Method == "PUT": + h.putHandler(w, r) + } +} diff --git a/cat_test.go b/cat_test.go index 9f957aee..cc67d837 100644 --- a/cat_test.go +++ b/cat_test.go @@ -32,13 +32,17 @@ func (s *CmdTestSuite) TestCatCmd(c *C) { defer os.RemoveAll(root) objectPath := filepath.Join(root, "object1") + objectPathServer := server.URL + "/bucket/object1" data := "hello" dataLen := len(data) err = putTarget(objectPath, &hostConfig{}, uint64(dataLen), bytes.NewReader([]byte(data))) c.Assert(err, IsNil) + err = putTarget(objectPathServer, &hostConfig{}, uint64(dataLen), bytes.NewReader([]byte(data))) + c.Assert(err, IsNil) sourceConfigMap := make(map[string]*hostConfig) sourceConfigMap[objectPath] = &hostConfig{} + sourceConfigMap[server.URL+"/bucket/object1"] = &hostConfig{} _, err = doCatCmd(sourceConfigMap, false) c.Assert(err, IsNil) diff --git a/cmd_test.go b/cmd_test.go index d635ac87..d64d43f6 100644 --- a/cmd_test.go +++ b/cmd_test.go @@ -28,7 +28,6 @@ import ( "errors" "net" - "net/http" "net/http/httptest" . "github.com/minio/check" @@ -49,20 +48,6 @@ func mustGetMcConfigDir() string { var server *httptest.Server -type objectAPIHandler struct { - bucket string - object []string - data []byte -} - -func (h objectAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - switch { - case r.Method == "GET": - case r.Method == "PUT": - case r.Method == "POST": - } -} - func (s *CmdTestSuite) SetUpSuite(c *C) { configDir, err := ioutil.TempDir(os.TempDir(), "cmd-") c.Assert(err, IsNil) @@ -71,14 +56,13 @@ func (s *CmdTestSuite) SetUpSuite(c *C) { _, err = doConfig("generate", nil) c.Assert(err, IsNil) - objectAPI := objectAPIHandler(objectAPIHandler{}) + objectAPI := objectAPIHandler(objectAPIHandler{bucket: "bucket", object: make(map[string][]byte)}) server = httptest.NewServer(objectAPI) } func (s *CmdTestSuite) TearDownSuite(c *C) { os.RemoveAll(customConfigDir) server.Close() - } func (s *CmdTestSuite) TestGetNewClient(c *C) { diff --git a/cp_test.go b/cp_test.go index ef27a117..f3e8b669 100644 --- a/cp_test.go +++ b/cp_test.go @@ -49,6 +49,11 @@ func (s *CmdTestSuite) TestCpTypeA(c *C) { for err := range doCopyCmd([]string{sourcePath}, targetPath, bar) { c.Assert(err, IsNil) } + + targetURL := server.URL + "/bucket/newObject" + for err := range doCopyCmd([]string{sourcePath}, targetURL, bar) { + c.Assert(err, IsNil) + } } func (s *CmdTestSuite) TestCpTypeB(c *C) { @@ -70,6 +75,11 @@ func (s *CmdTestSuite) TestCpTypeB(c *C) { for err := range doCopyCmd([]string{sourcePath}, target, bar) { c.Assert(err, IsNil) } + + targetURL := server.URL + "/bucket" + for err := range doCopyCmd([]string{sourcePath}, targetURL, bar) { + c.Assert(err, IsNil) + } } func (s *CmdTestSuite) TestCpTypeC(c *C) { @@ -93,6 +103,11 @@ func (s *CmdTestSuite) TestCpTypeC(c *C) { for err := range doCopyCmd([]string{source + "..."}, target, bar) { c.Assert(err, IsNil) } + + targetURL := server.URL + "/bucket" + for err := range doCopyCmd([]string{source + "..."}, targetURL, bar) { + c.Assert(err, IsNil) + } } func (s *CmdTestSuite) TestCpTypeD(c *C) { @@ -127,4 +142,9 @@ func (s *CmdTestSuite) TestCpTypeD(c *C) { for err := range doCopyCmd([]string{source1 + "...", source2 + "..."}, target, bar) { c.Assert(err, IsNil) } + + targetURL := server.URL + "/bucket" + for err := range doCopyCmd([]string{source1 + "...", source2 + "..."}, targetURL, bar) { + c.Assert(err, IsNil) + } } diff --git a/diff_test.go b/diff_test.go index 1ef328ea..a4f73ead 100644 --- a/diff_test.go +++ b/diff_test.go @@ -50,6 +50,7 @@ func (s *CmdTestSuite) TestDiffObjects(c *C) { for diff := range doDiffCmd(objectPath1, objectPath2, false) { c.Assert(diff.err, IsNil) + c.Assert(len(diff.message), Equals, 0) } } @@ -78,7 +79,9 @@ func (s *CmdTestSuite) TestDiffDirs(c *C) { err = putTarget(objectPath, &hostConfig{}, uint64(dataLen), bytes.NewReader([]byte(data))) c.Assert(err, IsNil) } + for diff := range doDiffCmd(root1, root2, false) { c.Assert(diff.err, IsNil) + c.Assert(len(diff.message), Equals, 0) } } diff --git a/ls_test.go b/ls_test.go index 95976047..62b6af1b 100644 --- a/ls_test.go +++ b/ls_test.go @@ -26,7 +26,7 @@ import ( . "github.com/minio/check" ) -func (s *CmdTestSuite) TestLSNonRecursive(c *C) { +func (s *CmdTestSuite) TestLSCmd(c *C) { /// filesystem root, err := ioutil.TempDir(os.TempDir(), "cmd-") c.Assert(err, IsNil) @@ -40,28 +40,23 @@ func (s *CmdTestSuite) TestLSNonRecursive(c *C) { c.Assert(err, IsNil) } - clnt, err := getNewClient(root, &hostConfig{}, false) + err = doListCmd(root, &hostConfig{}, false, false) c.Assert(err, IsNil) - err = doList(clnt, root, false) - c.Assert(err, IsNil) -} -func (s *CmdTestSuite) TestLSRecursive(c *C) { - /// filesystem - root, err := ioutil.TempDir(os.TempDir(), "cmd-") + err = doListCmd(root, &hostConfig{}, true, false) c.Assert(err, IsNil) - defer os.RemoveAll(root) for i := 0; i < 10; i++ { - objectPath := filepath.Join(root, "object"+strconv.Itoa(i)) + objectPath := server.URL + "/bucket/object" + strconv.Itoa(i) data := "hello" dataLen := len(data) - err = putTarget(objectPath, &hostConfig{}, uint64(dataLen), bytes.NewReader([]byte(data))) + err := putTarget(objectPath, &hostConfig{}, uint64(dataLen), bytes.NewReader([]byte(data))) c.Assert(err, IsNil) } + err = doListCmd(server.URL+"/bucket", &hostConfig{}, false, false) + c.Assert(err, IsNil) - clnt, err := getNewClient(root, &hostConfig{}, true) - c.Assert(err, IsNil) - err = doList(clnt, root, false) + err = doListCmd(server.URL+"/bucket", &hostConfig{}, true, false) c.Assert(err, IsNil) + } diff --git a/mb_access_test.go b/mb_access_test.go index 30b2450b..023d2e04 100644 --- a/mb_access_test.go +++ b/mb_access_test.go @@ -24,17 +24,7 @@ import ( . "github.com/minio/check" ) -func (s *CmdTestSuite) TestMbCmd(c *C) { - /// filesystem - root, err := ioutil.TempDir(os.TempDir(), "cmd-") - c.Assert(err, IsNil) - defer os.RemoveAll(root) - - _, err = doMakeBucketCmd(filepath.Join(root, "bucket"), &hostConfig{}, false) - c.Assert(err, IsNil) -} - -func (s *CmdTestSuite) TestAccessCmd(c *C) { +func (s *CmdTestSuite) TestMbAndAccessCmd(c *C) { /// filesystem root, err := ioutil.TempDir(os.TempDir(), "cmd-") c.Assert(err, IsNil) @@ -45,4 +35,17 @@ func (s *CmdTestSuite) TestAccessCmd(c *C) { _, err = doUpdateAccessCmd(filepath.Join(root, "bucket"), "public-read-write", &hostConfig{}, false) c.Assert(err, IsNil) + + _, err = doUpdateAccessCmd(filepath.Join(root, "bucket"), "invalid", &hostConfig{}, false) + c.Assert(err, Not(IsNil)) + + _, err = doMakeBucketCmd(server.URL+"/bucket", &hostConfig{}, false) + c.Assert(err, IsNil) + + _, err = doUpdateAccessCmd(server.URL+"/bucket", "public-read-write", &hostConfig{}, false) + c.Assert(err, IsNil) + + _, err = doUpdateAccessCmd(server.URL+"/bucket", "invalid", &hostConfig{}, false) + c.Assert(err, Not(IsNil)) + }