diff --git a/test-utils_test.go b/test-utils_test.go index 82f5a3659..f75128155 100644 --- a/test-utils_test.go +++ b/test-utils_test.go @@ -20,6 +20,8 @@ import ( "bytes" "encoding/base64" "encoding/hex" + "encoding/json" + "errors" "fmt" "io" "io/ioutil" @@ -342,6 +344,74 @@ func newTestSignedRequest(method, urlStr string, contentLength int64, body io.Re return req, nil } +// Return new WebRPC request object. +func newWebRPCRequest(methodRPC, authorization string, body io.ReadSeeker) (*http.Request, error) { + req, err := http.NewRequest("POST", "/minio/webrpc", nil) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + if authorization != "" { + req.Header.Set("Authorization", "Bearer "+authorization) + } + // Seek back to beginning. + if body != nil { + body.Seek(0, 0) + // Add body + req.Body = ioutil.NopCloser(body) + } else { + // this is added to avoid panic during ioutil.ReadAll(req.Body). + // th stack trace can be found here https://github.com/minio/minio/pull/2074 . + // This is very similar to https://github.com/golang/go/issues/7527. + req.Body = ioutil.NopCloser(bytes.NewReader([]byte(""))) + } + return req, nil +} + +// Marshal request and return a new HTTP request object to call the webrpc +func newTestWebRPCRequest(rpcMethod string, authorization string, data interface{}) (*http.Request, error) { + type genericJSON struct { + JSONRPC string `json:"jsonrpc"` + ID string `json:"id"` + Method string `json:"method"` + Params interface{} `json:"params"` + } + encapsulatedData := genericJSON{JSONRPC: "2.0", ID: "1", Method: rpcMethod, Params: data} + jsonData, err := json.Marshal(encapsulatedData) + req, err := newWebRPCRequest(rpcMethod, authorization, bytes.NewReader(jsonData)) + if err != nil { + return nil, err + } + return req, nil +} + +type ErrWebRPC struct { + Code int `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data"` +} + +// Unmarshal response and return the webrpc response +func getTestWebRPCResponse(resp *httptest.ResponseRecorder, data interface{}) error { + type rpcReply struct { + ID string `json:"id"` + JSONRPC string `json:"jsonrpc"` + Result interface{} `json:"result"` + Error *ErrWebRPC `json:"error"` + } + reply := &rpcReply{Result: &data} + err := json.NewDecoder(resp.Body).Decode(reply) + if err != nil { + return err + } + // For the moment, web handlers errors code are not meaningful + // Return only the error message + if reply.Error != nil { + return errors.New(reply.Error.Message) + } + return nil +} + // creates the temp backend setup. // if the option is // FS: Returns a temp single disk setup initializes FS Backend. @@ -831,3 +901,15 @@ func initTestAPIEndPoints(objLayer ObjectLayer, apiFunctions []string) http.Hand } return muxRouter } + +func initTestWebRPCEndPoint(objLayer ObjectLayer) http.Handler { + // Initialize Web. + webHandlers := &webAPIHandlers{ + ObjectAPI: objLayer, + } + + // Initialize router. + muxRouter := router.NewRouter() + registerWebRouter(muxRouter, webHandlers) + return muxRouter +} diff --git a/web-handlers_test.go b/web-handlers_test.go new file mode 100644 index 000000000..50c3314c7 --- /dev/null +++ b/web-handlers_test.go @@ -0,0 +1,713 @@ +/* + * Minio Cloud Storage, (C) 2016 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" + "errors" + "io/ioutil" + "net/http" + "net/http/httptest" + "strconv" + "testing" +) + +// Authenticate and get JWT token - will be called before every webrpc handler invocation +func getWebRPCToken(apiRouter http.Handler, accessKey, secretKey string) (token string, err error) { + rec := httptest.NewRecorder() + request := LoginArgs{Username: accessKey, Password: secretKey} + reply := &LoginRep{} + req, err := newTestWebRPCRequest("Web.Login", "", request) + if err != nil { + return "", err + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + return "", errors.New("Auth failed") + } + err = getTestWebRPCResponse(rec, &reply) + if err != nil { + return "", err + } + if reply.Token == "" { + return "", errors.New("Auth failed") + } + return reply.Token, nil +} + +// Wrapper for calling Login Web Handler +func TestWebHandlerLogin(t *testing.T) { + ExecObjectLayerTest(t, testLoginWebHandler) +} + +// testLoginWebHandler - Test login web handler +func testLoginWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + // test cases with sample input and expected output. + testCases := []struct { + username string + password string + success bool + }{ + {"", "", false}, + {"azerty", "foo", false}, + {"", "foo", false}, + {"azerty", "", false}, + {"azerty", "foo", false}, + {credentials.AccessKeyID, credentials.SecretAccessKey, true}, + } + + // Iterating over the test cases, calling the function under test and asserting the response. + for i, testCase := range testCases { + _, err := getWebRPCToken(apiRouter, testCase.username, testCase.password) + if err != nil && testCase.success { + t.Fatalf("Test %d: Expected to succeed but it failed, %v", i+1, err) + } + if err == nil && !testCase.success { + t.Fatalf("Test %d: Expected to fail but it didn't, %v", i+1, err) + } + + } +} + +// Wrapper for calling StorageInfo Web Handler +func TestWebHandlerStorageInfo(t *testing.T) { + ExecObjectLayerTest(t, testStorageInfoWebHandler) +} + +// testStorageInfoWebHandler - Test StorageInfo web handler +func testStorageInfoWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // get random bucket name. + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + rec := httptest.NewRecorder() + + storageInfoRequest := GenericArgs{} + storageInfoReply := &StorageInfoRep{} + req, err := newTestWebRPCRequest("Web.StorageInfo", authorization, storageInfoRequest) + if err != nil { + t.Fatalf("Failed to create HTTP request: %v", err) + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) + } + err = getTestWebRPCResponse(rec, &storageInfoReply) + if err != nil { + t.Fatalf("Failed %v", err) + } + if storageInfoReply.StorageInfo.Total <= 0 { + t.Fatalf("Got a zero or negative total free space disk") + } +} + +// Wrapper for calling ServerInfo Web Handler +func TestWebHandlerServerInfo(t *testing.T) { + ExecObjectLayerTest(t, testServerInfoWebHandler) +} + +// testServerInfoWebHandler - Test ServerInfo web handler +func testServerInfoWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + rec := httptest.NewRecorder() + + serverInfoRequest := GenericArgs{} + serverInfoReply := &ServerInfoRep{} + req, err := newTestWebRPCRequest("Web.ServerInfo", authorization, serverInfoRequest) + if err != nil { + t.Fatalf("Failed to create HTTP request: %v", err) + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) + } + err = getTestWebRPCResponse(rec, &serverInfoReply) + if err != nil { + t.Fatalf("Failed, %v", err) + } + if serverInfoReply.MinioVersion != minioVersion { + t.Fatalf("Cannot get minio version from server info handler") + } +} + +// Wrapper for calling MakeBucket Web Handler +func TestWebHandlerMakeBucket(t *testing.T) { + ExecObjectLayerTest(t, testMakeBucketWebHandler) +} + +// testMakeBucketWebHandler - Test MakeBucket web handler +func testMakeBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + rec := httptest.NewRecorder() + + bucketName := getRandomBucketName() + + testCases := []struct { + bucketName string + success bool + }{ + {"", false}, + {".", false}, + {"ab", false}, + {bucketName, true}, + } + + for i, testCase := range testCases { + makeBucketRequest := MakeBucketArgs{BucketName: testCase.bucketName} + makeBucketReply := &WebGenericRep{} + req, err := newTestWebRPCRequest("Web.MakeBucket", authorization, makeBucketRequest) + if err != nil { + t.Fatalf("Test %d: Failed to create HTTP request: %v", i+1, err) + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Test %d: Expected the response status to be 200, but instead found `%d`", i+1, rec.Code) + } + err = getTestWebRPCResponse(rec, &makeBucketReply) + if testCase.success && err != nil { + t.Fatalf("Test %d: Should succeed but it didn't, %v", i+1, err) + } + if !testCase.success && err == nil { + t.Fatalf("Test %d: Should fail but it didn't (%s)", i+1, testCase.bucketName) + } + } +} + +// Wrapper for calling ListBuckets Web Handler +func TestWebHandlerListBuckets(t *testing.T) { + ExecObjectLayerTest(t, testListBucketsWebHandler) +} + +// testListBucketsHandler - Test ListBuckets web handler +func testListBucketsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + rec := httptest.NewRecorder() + + bucketName := getRandomBucketName() + // Create bucket. + err = obj.MakeBucket(bucketName) + if err != nil { + // failed to create newbucket, abort. + t.Fatalf("%s : %s", instanceType, err) + } + + listBucketsRequest := WebGenericArgs{} + listBucketsReply := &ListBucketsRep{} + req, err := newTestWebRPCRequest("Web.ListBuckets", authorization, listBucketsRequest) + if err != nil { + t.Fatalf("Failed to create HTTP request: %v", err) + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) + } + err = getTestWebRPCResponse(rec, &listBucketsReply) + if err != nil { + t.Fatalf("Failed, %v", err) + } + if len(listBucketsReply.Buckets) == 0 { + t.Fatalf("Cannot find the bucket already created by MakeBucket") + } + if listBucketsReply.Buckets[0].Name != bucketName { + t.Fatalf("Found another bucket other than already created by MakeBucket") + } +} + +// Wrapper for calling ListObjects Web Handler +func TestWebHandlerListObjects(t *testing.T) { + ExecObjectLayerTest(t, testListObjectsWebHandler) +} + +// testListObjectsHandler - Test ListObjects web handler +func testListObjectsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + rec := httptest.NewRecorder() + + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + bucketName := getRandomBucketName() + objectName := "object" + objectSize := 1024 + + // Create bucket. + err = obj.MakeBucket(bucketName) + if err != nil { + // failed to create newbucket, abort. + t.Fatalf("%s : %s", instanceType, err) + } + + data := bytes.Repeat([]byte("a"), objectSize) + + _, err = obj.PutObject(bucketName, objectName, int64(len(data)), bytes.NewReader(data), map[string]string{"md5Sum": "c9a34cfc85d982698c6ac89f76071abd"}) + + if err != nil { + t.Fatalf("Was not able to upload an object, %v", err) + } + + listObjectsRequest := ListObjectsArgs{BucketName: bucketName, Prefix: ""} + listObjectsReply := &ListObjectsRep{} + req, err := newTestWebRPCRequest("Web.ListObjects", authorization, listObjectsRequest) + if err != nil { + t.Fatalf("Failed to create HTTP request: %v", err) + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) + } + err = getTestWebRPCResponse(rec, &listObjectsReply) + if err != nil { + t.Fatalf("Failed, %v", err) + } + if len(listObjectsReply.Objects) == 0 { + t.Fatalf("Cannot find the object") + } + if listObjectsReply.Objects[0].Key != objectName { + t.Fatalf("Found another object other than already created by PutObject") + } + if listObjectsReply.Objects[0].Size != int64(objectSize) { + t.Fatalf("Found a object with the same name but with a different size") + } + +} + +// Wrapper for calling RemoveObject Web Handler +func TestWebHandlerRemoveObject(t *testing.T) { + ExecObjectLayerTest(t, testRemoveObjectWebHandler) +} + +// testRemoveObjectWebHandler - Test RemoveObject web handler +func testRemoveObjectWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + rec := httptest.NewRecorder() + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + bucketName := getRandomBucketName() + objectName := "object" + objectSize := 1024 + + // Create bucket. + err = obj.MakeBucket(bucketName) + if err != nil { + // failed to create newbucket, abort. + t.Fatalf("%s : %s", instanceType, err) + } + + data := bytes.Repeat([]byte("a"), objectSize) + + _, err = obj.PutObject(bucketName, objectName, int64(len(data)), bytes.NewReader(data), map[string]string{"md5Sum": "c9a34cfc85d982698c6ac89f76071abd"}) + + if err != nil { + t.Fatalf("Was not able to upload an object, %v", err) + } + + removeObjectRequest := RemoveObjectArgs{BucketName: bucketName, ObjectName: objectName} + removeObjectReply := &WebGenericRep{} + req, err := newTestWebRPCRequest("Web.RemoveObject", authorization, removeObjectRequest) + if err != nil { + t.Fatalf("Failed to create HTTP request: %v", err) + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) + } + err = getTestWebRPCResponse(rec, &removeObjectReply) + if err != nil { + t.Fatalf("Failed, %v", err) + } +} + +// Wrapper for calling Generate Auth Handler +func TestWebHandlerGenerateAuth(t *testing.T) { + ExecObjectLayerTest(t, testGenerateAuthWebHandler) +} + +// testGenerateAuthWebHandler - Test GenerateAuth web handler +func testGenerateAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + rec := httptest.NewRecorder() + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + generateAuthRequest := WebGenericArgs{} + generateAuthReply := &GenerateAuthReply{} + req, err := newTestWebRPCRequest("Web.GenerateAuth", authorization, generateAuthRequest) + if err != nil { + t.Fatalf("Failed to create HTTP request: %v", err) + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) + } + err = getTestWebRPCResponse(rec, &generateAuthReply) + if err != nil { + t.Fatalf("Failed, %v", err) + } + + if generateAuthReply.AccessKey == "" || generateAuthReply.SecretKey == "" { + t.Fatalf("Failed to generate auth keys") + } +} + +// Wrapper for calling Set Auth Handler +func TestWebHandlerSetAuth(t *testing.T) { + ExecObjectLayerTest(t, testSetAuthWebHandler) +} + +// testSetAuthWebHandler - Test SetAuth web handler +func testSetAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + rec := httptest.NewRecorder() + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + testCases := []struct { + username string + password string + success bool + }{ + {"", "", false}, + {"azerty", "foooooooooooooo", true}, + } + + // Iterating over the test cases, calling the function under test and asserting the response. + for i, testCase := range testCases { + + setAuthRequest := SetAuthArgs{AccessKey: testCase.username, SecretKey: testCase.password} + setAuthReply := &SetAuthReply{} + req, err := newTestWebRPCRequest("Web.SetAuth", authorization, setAuthRequest) + if err != nil { + t.Fatalf("Test %d: Failed to create HTTP request: %v", i+1, err) + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Test %d: Expected the response status to be 200, but instead found `%d`", i+1, rec.Code) + } + err = getTestWebRPCResponse(rec, &setAuthReply) + if testCase.success && err != nil { + t.Fatalf("Test %d: Supposed to succeed but failed, %v", i+1, err) + } + if !testCase.success && err == nil { + t.Fatalf("Test %d: Supposed to fail but succeeded, %v", i+1, err) + } + if testCase.success && setAuthReply.Token == "" { + t.Fatalf("Test %d: Failed to set auth keys", i+1) + } + } +} + +// Wrapper for calling Get Auth Handler +func TestWebHandlerGetAuth(t *testing.T) { + ExecObjectLayerTest(t, testGetAuthWebHandler) +} + +// testGetAuthWebHandler - Test GetAuth web handler +func testGetAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + rec := httptest.NewRecorder() + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + getAuthRequest := WebGenericArgs{} + getAuthReply := &GetAuthReply{} + req, err := newTestWebRPCRequest("Web.GetAuth", authorization, getAuthRequest) + if err != nil { + t.Fatalf("Failed to create HTTP request: %v", err) + } + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) + } + err = getTestWebRPCResponse(rec, &getAuthReply) + if err != nil { + t.Fatalf("Failed, %v", err) + } + if getAuthReply.AccessKey != credentials.AccessKeyID || getAuthReply.SecretKey != credentials.SecretAccessKey { + t.Fatalf("Failed to get correct auth keys") + } +} + +// Wrapper for calling Upload Handler +func TestWebHandlerUpload(t *testing.T) { + ExecObjectLayerTest(t, testUploadWebHandler) +} + +// testUploadWebHandler - Test Upload web handler +func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + rec := httptest.NewRecorder() + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + objectName := "test.file" + bucketName := getRandomBucketName() + // Create bucket. + err = obj.MakeBucket(bucketName) + if err != nil { + // failed to create newbucket, abort. + t.Fatalf("%s : %s", instanceType, err) + } + + content := []byte("temporary file's content") + + req, err := http.NewRequest("PUT", "/minio/upload/"+bucketName+"/"+objectName, nil) + req.Header.Set("Authorization", "Bearer "+authorization) + req.Header.Set("Content-Length", strconv.Itoa(len(content))) + req.Header.Set("x-amz-date", "20160814T114029Z") + req.Header.Set("Accept", "*/*") + req.Body = ioutil.NopCloser(bytes.NewReader(content)) + + if err != nil { + t.Fatalf("Cannot create upload request, %v", err) + } + + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) + } + + var byteBuffer bytes.Buffer + err = obj.GetObject(bucketName, objectName, 0, int64(len(content)), &byteBuffer) + if err != nil { + t.Fatalf("Failed, %v", err) + } + + if bytes.Compare(byteBuffer.Bytes(), content) != 0 { + t.Fatalf("The upload file is different from the download file") + } +} + +// Wrapper for calling Upload Handler +func TestWebHandlerDownload(t *testing.T) { + ExecObjectLayerTest(t, testDownloadWebHandler) +} + +// testDownloadWebHandler - Test Download web handler +func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { + // Register the API end points with XL/FS object layer. + apiRouter := initTestWebRPCEndPoint(obj) + // initialize the server and obtain the credentials and root. + // credentials are necessary to sign the HTTP request. + rootPath, err := newTestConfig("us-east-1") + if err != nil { + t.Fatalf("Init Test config failed") + } + // remove the root folder after the test ends. + defer removeAll(rootPath) + + credentials := serverConfig.GetCredential() + + rec := httptest.NewRecorder() + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKeyID, credentials.SecretAccessKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + objectName := "test.file" + bucketName := getRandomBucketName() + // Create bucket. + err = obj.MakeBucket(bucketName) + if err != nil { + // failed to create newbucket, abort. + t.Fatalf("%s : %s", instanceType, err) + } + + content := []byte("temporary file's content") + _, err = obj.PutObject(bucketName, objectName, int64(len(content)), bytes.NewReader(content), map[string]string{"md5Sum": "01ce59706106fe5e02e7f55fffda7f34"}) + if err != nil { + t.Fatalf("Was not able to upload an object, %v", err) + } + + req, err := http.NewRequest("GET", "/minio/download/"+bucketName+"/"+objectName+"?token="+authorization, nil) + + if err != nil { + t.Fatalf("Cannot create upload request, %v", err) + } + + apiRouter.ServeHTTP(rec, req) + if rec.Code != http.StatusOK { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) + } + + if bytes.Compare(rec.Body.Bytes(), content) != 0 { + t.Fatalf("The downloaded file is corrupted") + } +}