From f02620b291b988848392c455a7719699f6b5c00f Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Wed, 26 Oct 2016 05:21:07 -0700 Subject: Moving away from goamz to use minio-go instead. (#4193) minio-go does fully managed way of handling S3 API requests - Automatic bucket location management across all s3 regions. - Transparently upload large files in multipart if file 64MB or larger. - Right GetObject() API provides compatibility with io.ReadWriteSeeker interface. - Various other APIs including bulk deletes, server side object copy, bucket policies and bucket notifications. Fixes #4182 --- .../github.com/minio/minio-go/bucket-cache_test.go | 323 +++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 vendor/github.com/minio/minio-go/bucket-cache_test.go (limited to 'vendor/github.com/minio/minio-go/bucket-cache_test.go') diff --git a/vendor/github.com/minio/minio-go/bucket-cache_test.go b/vendor/github.com/minio/minio-go/bucket-cache_test.go new file mode 100644 index 000000000..81cfbc097 --- /dev/null +++ b/vendor/github.com/minio/minio-go/bucket-cache_test.go @@ -0,0 +1,323 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage (C) 2016, 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 minio + +import ( + "bytes" + "encoding/hex" + "encoding/xml" + "io/ioutil" + "net/http" + "net/url" + "path" + "reflect" + "testing" +) + +// Test validates `newBucketLocationCache`. +func TestNewBucketLocationCache(t *testing.T) { + expectedBucketLocationcache := &bucketLocationCache{ + items: make(map[string]string), + } + actualBucketLocationCache := newBucketLocationCache() + + if !reflect.DeepEqual(actualBucketLocationCache, expectedBucketLocationcache) { + t.Errorf("Unexpected return value") + } +} + +// Tests validate bucketLocationCache operations. +func TestBucketLocationCacheOps(t *testing.T) { + testBucketLocationCache := newBucketLocationCache() + expectedBucketName := "minio-bucket" + expectedLocation := "us-east-1" + testBucketLocationCache.Set(expectedBucketName, expectedLocation) + actualLocation, ok := testBucketLocationCache.Get(expectedBucketName) + if !ok { + t.Errorf("Bucket location cache not set") + } + if expectedLocation != actualLocation { + t.Errorf("Bucket location cache not set to expected value") + } + testBucketLocationCache.Delete(expectedBucketName) + _, ok = testBucketLocationCache.Get(expectedBucketName) + if ok { + t.Errorf("Bucket location cache not deleted as expected") + } +} + +// Tests validate http request generation for 'getBucketLocation'. +func TestGetBucketLocationRequest(t *testing.T) { + // Generates expected http request for getBucketLocation. + // Used for asserting with the actual request generated. + createExpectedRequest := func(c *Client, bucketName string, req *http.Request) (*http.Request, error) { + // Set location query. + urlValues := make(url.Values) + urlValues.Set("location", "") + + // Set get bucket location always as path style. + targetURL, err := url.Parse(c.endpointURL) + if err != nil { + return nil, err + } + targetURL.Path = path.Join(bucketName, "") + "/" + targetURL.RawQuery = urlValues.Encode() + + // Get a new HTTP request for the method. + req, err = http.NewRequest("GET", targetURL.String(), nil) + if err != nil { + return nil, err + } + + // Set UserAgent for the request. + c.setUserAgent(req) + + // Set sha256 sum for signature calculation only with signature version '4'. + if c.signature.isV4() { + req.Header.Set("X-Amz-Content-Sha256", hex.EncodeToString(sum256([]byte{}))) + } + + // Sign the request. + if c.signature.isV4() { + req = signV4(*req, c.accessKeyID, c.secretAccessKey, "us-east-1") + } else if c.signature.isV2() { + req = signV2(*req, c.accessKeyID, c.secretAccessKey) + } + return req, nil + + } + // Info for 'Client' creation. + // Will be used as arguments for 'NewClient'. + type infoForClient struct { + endPoint string + accessKey string + secretKey string + enableInsecure bool + } + // dataset for 'NewClient' call. + info := []infoForClient{ + // endpoint localhost. + // both access-key and secret-key are empty. + {"localhost:9000", "", "", false}, + // both access-key are secret-key exists. + {"localhost:9000", "my-access-key", "my-secret-key", false}, + // one of acess-key and secret-key are empty. + {"localhost:9000", "", "my-secret-key", false}, + + // endpoint amazon s3. + {"s3.amazonaws.com", "", "", false}, + {"s3.amazonaws.com", "my-access-key", "my-secret-key", false}, + {"s3.amazonaws.com", "my-acess-key", "", false}, + + // endpoint google cloud storage. + {"storage.googleapis.com", "", "", false}, + {"storage.googleapis.com", "my-access-key", "my-secret-key", false}, + {"storage.googleapis.com", "", "my-secret-key", false}, + + // endpoint custom domain running Minio server. + {"play.minio.io", "", "", false}, + {"play.minio.io", "my-access-key", "my-secret-key", false}, + {"play.minio.io", "my-acess-key", "", false}, + } + testCases := []struct { + bucketName string + // data for new client creation. + info infoForClient + // error in the output. + err error + // flag indicating whether tests should pass. + shouldPass bool + }{ + // Client is constructed using the info struct. + // case with empty location. + {"my-bucket", info[0], nil, true}, + // case with location set to standard 'us-east-1'. + {"my-bucket", info[0], nil, true}, + // case with location set to a value different from 'us-east-1'. + {"my-bucket", info[0], nil, true}, + + {"my-bucket", info[1], nil, true}, + {"my-bucket", info[1], nil, true}, + {"my-bucket", info[1], nil, true}, + + {"my-bucket", info[2], nil, true}, + {"my-bucket", info[2], nil, true}, + {"my-bucket", info[2], nil, true}, + + {"my-bucket", info[3], nil, true}, + {"my-bucket", info[3], nil, true}, + {"my-bucket", info[3], nil, true}, + + {"my-bucket", info[4], nil, true}, + {"my-bucket", info[4], nil, true}, + {"my-bucket", info[4], nil, true}, + + {"my-bucket", info[5], nil, true}, + {"my-bucket", info[5], nil, true}, + {"my-bucket", info[5], nil, true}, + + {"my-bucket", info[6], nil, true}, + {"my-bucket", info[6], nil, true}, + {"my-bucket", info[6], nil, true}, + + {"my-bucket", info[7], nil, true}, + {"my-bucket", info[7], nil, true}, + {"my-bucket", info[7], nil, true}, + + {"my-bucket", info[8], nil, true}, + {"my-bucket", info[8], nil, true}, + {"my-bucket", info[8], nil, true}, + + {"my-bucket", info[9], nil, true}, + {"my-bucket", info[9], nil, true}, + {"my-bucket", info[9], nil, true}, + + {"my-bucket", info[10], nil, true}, + {"my-bucket", info[10], nil, true}, + {"my-bucket", info[10], nil, true}, + + {"my-bucket", info[11], nil, true}, + {"my-bucket", info[11], nil, true}, + {"my-bucket", info[11], nil, true}, + } + for i, testCase := range testCases { + // cannot create a newclient with empty endPoint value. + // validates and creates a new client only if the endPoint value is not empty. + client := &Client{} + var err error + if testCase.info.endPoint != "" { + + client, err = New(testCase.info.endPoint, testCase.info.accessKey, testCase.info.secretKey, testCase.info.enableInsecure) + if err != nil { + t.Fatalf("Test %d: Failed to create new Client: %s", i+1, err.Error()) + } + } + + actualReq, err := client.getBucketLocationRequest(testCase.bucketName) + if err != nil && testCase.shouldPass { + t.Errorf("Test %d: Expected to pass, but failed with: %s", i+1, err.Error()) + } + if err == nil && !testCase.shouldPass { + t.Errorf("Test %d: Expected to fail with \"%s\", but passed instead", i+1, testCase.err.Error()) + } + // Failed as expected, but does it fail for the expected reason. + if err != nil && !testCase.shouldPass { + if err.Error() != testCase.err.Error() { + t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\" instead", i+1, testCase.err.Error(), err.Error()) + } + } + + // Test passes as expected, but the output values are verified for correctness here. + if err == nil && testCase.shouldPass { + expectedReq := &http.Request{} + expectedReq, err = createExpectedRequest(client, testCase.bucketName, expectedReq) + if err != nil { + t.Fatalf("Test %d: Expected request Creation failed", i+1) + } + if expectedReq.Method != actualReq.Method { + t.Errorf("Test %d: The expected Request method doesn't match with the actual one", i+1) + } + if expectedReq.URL.String() != actualReq.URL.String() { + t.Errorf("Test %d: Expected the request URL to be '%s', but instead found '%s'", i+1, expectedReq.URL.String(), actualReq.URL.String()) + } + if expectedReq.ContentLength != actualReq.ContentLength { + t.Errorf("Test %d: Expected the request body Content-Length to be '%d', but found '%d' instead", i+1, expectedReq.ContentLength, actualReq.ContentLength) + } + + if expectedReq.Header.Get("X-Amz-Content-Sha256") != actualReq.Header.Get("X-Amz-Content-Sha256") { + t.Errorf("Test %d: 'X-Amz-Content-Sha256' header of the expected request doesn't match with that of the actual request", i+1) + } + if expectedReq.Header.Get("User-Agent") != actualReq.Header.Get("User-Agent") { + t.Errorf("Test %d: Expected 'User-Agent' header to be \"%s\",but found \"%s\" instead", i+1, expectedReq.Header.Get("User-Agent"), actualReq.Header.Get("User-Agent")) + } + } + } +} + +// generates http response with bucket location set in the body. +func generateLocationResponse(resp *http.Response, bodyContent []byte) (*http.Response, error) { + resp.StatusCode = http.StatusOK + resp.Body = ioutil.NopCloser(bytes.NewBuffer(bodyContent)) + return resp, nil +} + +// Tests the processing of GetPolicy response from server. +func TestProcessBucketLocationResponse(t *testing.T) { + // LocationResponse - format for location response. + type LocationResponse struct { + XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ LocationConstraint" json:"-"` + Location string `xml:",chardata"` + } + + APIErrors := []APIError{ + { + Code: "AccessDenied", + Description: "Access Denied", + HTTPStatusCode: http.StatusUnauthorized, + }, + } + testCases := []struct { + bucketName string + inputLocation string + isAPIError bool + apiErr APIError + // expected results. + expectedResult string + err error + // flag indicating whether tests should pass. + shouldPass bool + }{ + {"my-bucket", "", true, APIErrors[0], "us-east-1", nil, true}, + {"my-bucket", "", false, APIError{}, "us-east-1", nil, true}, + {"my-bucket", "EU", false, APIError{}, "eu-west-1", nil, true}, + {"my-bucket", "eu-central-1", false, APIError{}, "eu-central-1", nil, true}, + {"my-bucket", "us-east-1", false, APIError{}, "us-east-1", nil, true}, + } + + for i, testCase := range testCases { + inputResponse := &http.Response{} + var err error + if testCase.isAPIError { + inputResponse = generateErrorResponse(inputResponse, testCase.apiErr, testCase.bucketName) + } else { + inputResponse, err = generateLocationResponse(inputResponse, encodeResponse(LocationResponse{ + Location: testCase.inputLocation, + })) + if err != nil { + t.Fatalf("Test %d: Creation of valid response failed", i+1) + } + } + actualResult, err := processBucketLocationResponse(inputResponse, "my-bucket") + if err != nil && testCase.shouldPass { + t.Errorf("Test %d: Expected to pass, but failed with: %s", i+1, err.Error()) + } + if err == nil && !testCase.shouldPass { + t.Errorf("Test %d: Expected to fail with \"%s\", but passed instead", i+1, testCase.err.Error()) + } + // Failed as expected, but does it fail for the expected reason. + if err != nil && !testCase.shouldPass { + if err.Error() != testCase.err.Error() { + t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\" instead", i+1, testCase.err.Error(), err.Error()) + } + } + if err == nil && testCase.shouldPass { + if !reflect.DeepEqual(testCase.expectedResult, actualResult) { + t.Errorf("Test %d: The expected BucketPolicy doesn't match the actual BucketPolicy", i+1) + } + } + } +} -- cgit v1.2.3-1-g7c22