mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
parent
5eb4002bf7
commit
91a0ade908
@ -46,6 +46,152 @@ const (
|
|||||||
MissingUploadID
|
MissingUploadID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Wrapper for calling HeadObject API handler tests for both XL multiple disks and FS single drive setup.
|
||||||
|
func TestAPIHeadObjectHandler(t *testing.T) {
|
||||||
|
ExecObjectLayerAPITest(t, testAPIHeadObjectHandler, []string{"HeadObject"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAPIHeadObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
|
||||||
|
credentials credential, t *testing.T) {
|
||||||
|
objectName := "test-object"
|
||||||
|
// set of byte data for PutObject.
|
||||||
|
// object has to be created before running tests for HeadObject.
|
||||||
|
// this is required even to assert the HeadObject data,
|
||||||
|
// since dataInserted === dataFetched back is a primary criteria for any object storage this assertion is critical.
|
||||||
|
bytesData := []struct {
|
||||||
|
byteData []byte
|
||||||
|
}{
|
||||||
|
{generateBytesData(6 * 1024 * 1024)},
|
||||||
|
}
|
||||||
|
// set of inputs for uploading the objects before tests for downloading is done.
|
||||||
|
putObjectInputs := []struct {
|
||||||
|
bucketName string
|
||||||
|
objectName string
|
||||||
|
contentLength int64
|
||||||
|
textData []byte
|
||||||
|
metaData map[string]string
|
||||||
|
}{
|
||||||
|
{bucketName, objectName, int64(len(bytesData[0].byteData)), bytesData[0].byteData, make(map[string]string)},
|
||||||
|
}
|
||||||
|
sha256sum := ""
|
||||||
|
// iterate through the above set of inputs and upload the object.
|
||||||
|
for i, input := range putObjectInputs {
|
||||||
|
// uploading the object.
|
||||||
|
_, err := obj.PutObject(input.bucketName, input.objectName, input.contentLength, bytes.NewBuffer(input.textData), input.metaData, sha256sum)
|
||||||
|
// if object upload fails stop the test.
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Put Object case %d: Error uploading object: <ERROR> %v", i+1, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test cases with inputs and expected result for HeadObject.
|
||||||
|
testCases := []struct {
|
||||||
|
bucketName string
|
||||||
|
objectName string
|
||||||
|
accessKey string
|
||||||
|
secretKey string
|
||||||
|
// expected output.
|
||||||
|
expectedRespStatus int // expected response status body.
|
||||||
|
}{
|
||||||
|
// Test case - 1.
|
||||||
|
// Fetching stat info of object and validating it.
|
||||||
|
{
|
||||||
|
bucketName: bucketName,
|
||||||
|
objectName: objectName,
|
||||||
|
accessKey: credentials.AccessKeyID,
|
||||||
|
secretKey: credentials.SecretAccessKey,
|
||||||
|
expectedRespStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
// Test case - 2.
|
||||||
|
// Case with non-existent object name.
|
||||||
|
{
|
||||||
|
bucketName: bucketName,
|
||||||
|
objectName: "abcd",
|
||||||
|
accessKey: credentials.AccessKeyID,
|
||||||
|
secretKey: credentials.SecretAccessKey,
|
||||||
|
expectedRespStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
// Test case - 3.
|
||||||
|
// Test case to induce a signature mismatch.
|
||||||
|
// Using invalid accessID.
|
||||||
|
{
|
||||||
|
bucketName: bucketName,
|
||||||
|
objectName: objectName,
|
||||||
|
accessKey: "Invalid-AccessID",
|
||||||
|
secretKey: credentials.SecretAccessKey,
|
||||||
|
expectedRespStatus: http.StatusForbidden,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterating over the cases, fetching the object validating the response.
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
// construct HTTP request for Get Object end point.
|
||||||
|
req, err := newTestSignedRequestV4("HEAD", getHeadObjectURL("", testCase.bucketName, testCase.objectName),
|
||||||
|
0, nil, testCase.accessKey, testCase.secretKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test %d: %s: Failed to create HTTP request for Head Object: <ERROR> %v", i+1, instanceType, err)
|
||||||
|
}
|
||||||
|
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
|
||||||
|
// Call the ServeHTTP to execute the handler,`func (api objectAPIHandlers) GetObjectHandler` handles the request.
|
||||||
|
apiRouter.ServeHTTP(rec, req)
|
||||||
|
|
||||||
|
// Assert the response code with the expected status.
|
||||||
|
if rec.Code != testCase.expectedRespStatus {
|
||||||
|
t.Fatalf("Case %d: Expected the response status to be `%d`, but instead found `%d`", i+1, testCase.expectedRespStatus, rec.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify response of the V2 signed HTTP request.
|
||||||
|
// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
|
||||||
|
recV2 := httptest.NewRecorder()
|
||||||
|
// construct HTTP request for Head Object endpoint.
|
||||||
|
reqV2, err := newTestSignedRequestV2("HEAD", getHeadObjectURL("", testCase.bucketName, testCase.objectName),
|
||||||
|
0, nil, testCase.accessKey, testCase.secretKey)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test %d: %s: Failed to create HTTP request for Head Object: <ERROR> %v", i+1, instanceType, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
|
||||||
|
// Call the ServeHTTP to execute the handler.
|
||||||
|
apiRouter.ServeHTTP(recV2, reqV2)
|
||||||
|
if recV2.Code != testCase.expectedRespStatus {
|
||||||
|
t.Errorf("Test %d: %s: Expected the response status to be `%d`, but instead found `%d`", i+1, instanceType, testCase.expectedRespStatus, recV2.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for Anonymous/unsigned http request.
|
||||||
|
anonReq, err := newTestRequest("HEAD", getHeadObjectURL("", bucketName, objectName), 0, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Minio %s: Failed to create an anonymous request for %s/%s: <ERROR> %v",
|
||||||
|
instanceType, bucketName, objectName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecObjectLayerAPIAnonTest - Calls the HTTP API handler using the anonymous request, validates the ErrAccessDeniedResponse,
|
||||||
|
// sets the bucket policy using the policy statement generated from `getWriteOnlyObjectStatement` so that the
|
||||||
|
// unsigned request goes through and its validated again.
|
||||||
|
ExecObjectLayerAPIAnonTest(t, "TestAPIHeadObjectHandler", bucketName, objectName, instanceType, apiRouter, anonReq, getReadOnlyObjectStatement)
|
||||||
|
|
||||||
|
// HTTP request for testing when `objectLayer` is set to `nil`.
|
||||||
|
// There is no need to use an existing bucket and valid input for creating the request
|
||||||
|
// since the `objectLayer==nil` check is performed before any other checks inside the handlers.
|
||||||
|
// The only aim is to generate an HTTP request in a way that the relevant/registered end point is evoked/called.
|
||||||
|
|
||||||
|
nilBucket := "dummy-bucket"
|
||||||
|
nilObject := "dummy-object"
|
||||||
|
nilReq, err := newTestSignedRequestV4("HEAD", getGetObjectURL("", nilBucket, nilObject),
|
||||||
|
0, nil, "", "")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Minio %s: Failed to create HTTP request for testing the response when object Layer is set to `nil`.", instanceType)
|
||||||
|
}
|
||||||
|
// execute the object layer set to `nil` test.
|
||||||
|
// `ExecObjectLayerAPINilTest` manages the operation.
|
||||||
|
ExecObjectLayerAPINilTest(t, nilBucket, nilObject, instanceType, apiRouter, nilReq)
|
||||||
|
}
|
||||||
|
|
||||||
// Wrapper for calling GetObject API handler tests for both XL multiple disks and FS single drive setup.
|
// Wrapper for calling GetObject API handler tests for both XL multiple disks and FS single drive setup.
|
||||||
func TestAPIGetObjectHandler(t *testing.T) {
|
func TestAPIGetObjectHandler(t *testing.T) {
|
||||||
defer DetectTestLeak(t)()
|
defer DetectTestLeak(t)()
|
||||||
|
@ -1948,56 +1948,59 @@ func registerBucketLevelFunc(bucket *router.Router, api objectAPIHandlers, apiFu
|
|||||||
case "PostPolicy":
|
case "PostPolicy":
|
||||||
// Register PostPolicy handler.
|
// Register PostPolicy handler.
|
||||||
bucket.Methods("POST").HeadersRegexp("Content-Type", "multipart/form-data*").HandlerFunc(api.PostPolicyBucketHandler)
|
bucket.Methods("POST").HeadersRegexp("Content-Type", "multipart/form-data*").HandlerFunc(api.PostPolicyBucketHandler)
|
||||||
// Register GetObject handler.
|
case "HeadObject":
|
||||||
|
// Register HeadObject handler.
|
||||||
|
bucket.Methods("Head").Path("/{object:.+}").HandlerFunc(api.HeadObjectHandler)
|
||||||
case "GetObject":
|
case "GetObject":
|
||||||
|
// Register GetObject handler.
|
||||||
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(api.GetObjectHandler)
|
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(api.GetObjectHandler)
|
||||||
// Register PutObject handler.
|
|
||||||
case "PutObject":
|
case "PutObject":
|
||||||
|
// Register PutObject handler.
|
||||||
bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(api.PutObjectHandler)
|
bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(api.PutObjectHandler)
|
||||||
// Register Delete Object handler.
|
|
||||||
case "DeleteObject":
|
case "DeleteObject":
|
||||||
|
// Register Delete Object handler.
|
||||||
bucket.Methods("DELETE").Path("/{object:.+}").HandlerFunc(api.DeleteObjectHandler)
|
bucket.Methods("DELETE").Path("/{object:.+}").HandlerFunc(api.DeleteObjectHandler)
|
||||||
// Register Copy Object handler.
|
|
||||||
case "CopyObject":
|
case "CopyObject":
|
||||||
|
// Register Copy Object handler.
|
||||||
bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(api.CopyObjectHandler)
|
bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(api.CopyObjectHandler)
|
||||||
// Register PutBucket Policy handler.
|
|
||||||
case "PutBucketPolicy":
|
case "PutBucketPolicy":
|
||||||
|
// Register PutBucket Policy handler.
|
||||||
bucket.Methods("PUT").HandlerFunc(api.PutBucketPolicyHandler).Queries("policy", "")
|
bucket.Methods("PUT").HandlerFunc(api.PutBucketPolicyHandler).Queries("policy", "")
|
||||||
// Register Delete bucket HTTP policy handler.
|
|
||||||
case "DeleteBucketPolicy":
|
case "DeleteBucketPolicy":
|
||||||
|
// Register Delete bucket HTTP policy handler.
|
||||||
bucket.Methods("DELETE").HandlerFunc(api.DeleteBucketPolicyHandler).Queries("policy", "")
|
bucket.Methods("DELETE").HandlerFunc(api.DeleteBucketPolicyHandler).Queries("policy", "")
|
||||||
// Register Get Bucket policy HTTP Handler.
|
|
||||||
case "GetBucketPolicy":
|
case "GetBucketPolicy":
|
||||||
|
// Register Get Bucket policy HTTP Handler.
|
||||||
bucket.Methods("GET").HandlerFunc(api.GetBucketPolicyHandler).Queries("policy", "")
|
bucket.Methods("GET").HandlerFunc(api.GetBucketPolicyHandler).Queries("policy", "")
|
||||||
// Register GetBucketLocation handler.
|
|
||||||
case "GetBucketLocation":
|
case "GetBucketLocation":
|
||||||
|
// Register GetBucketLocation handler.
|
||||||
bucket.Methods("GET").HandlerFunc(api.GetBucketLocationHandler).Queries("location", "")
|
bucket.Methods("GET").HandlerFunc(api.GetBucketLocationHandler).Queries("location", "")
|
||||||
// Register HeadBucket handler.
|
|
||||||
case "HeadBucket":
|
case "HeadBucket":
|
||||||
|
// Register HeadBucket handler.
|
||||||
bucket.Methods("HEAD").HandlerFunc(api.HeadBucketHandler)
|
bucket.Methods("HEAD").HandlerFunc(api.HeadBucketHandler)
|
||||||
// Register New Multipart upload handler.
|
|
||||||
case "NewMultipart":
|
case "NewMultipart":
|
||||||
|
// Register New Multipart upload handler.
|
||||||
bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(api.NewMultipartUploadHandler).Queries("uploads", "")
|
bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(api.NewMultipartUploadHandler).Queries("uploads", "")
|
||||||
// Register PutObjectPart handler.
|
|
||||||
case "PutObjectPart":
|
case "PutObjectPart":
|
||||||
|
// Register PutObjectPart handler.
|
||||||
bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(api.PutObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}")
|
bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(api.PutObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}")
|
||||||
// Register ListObjectParts handler.
|
|
||||||
case "ListObjectParts":
|
case "ListObjectParts":
|
||||||
|
// Register ListObjectParts handler.
|
||||||
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(api.ListObjectPartsHandler).Queries("uploadId", "{uploadId:.*}")
|
bucket.Methods("GET").Path("/{object:.+}").HandlerFunc(api.ListObjectPartsHandler).Queries("uploadId", "{uploadId:.*}")
|
||||||
// Register ListMultipartUploads handler.
|
|
||||||
case "ListMultipartUploads":
|
case "ListMultipartUploads":
|
||||||
|
// Register ListMultipartUploads handler.
|
||||||
bucket.Methods("GET").HandlerFunc(api.ListMultipartUploadsHandler).Queries("uploads", "")
|
bucket.Methods("GET").HandlerFunc(api.ListMultipartUploadsHandler).Queries("uploads", "")
|
||||||
// Register Complete Multipart Upload handler.
|
|
||||||
case "CompleteMultipart":
|
case "CompleteMultipart":
|
||||||
|
// Register Complete Multipart Upload handler.
|
||||||
bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(api.CompleteMultipartUploadHandler).Queries("uploadId", "{uploadId:.*}")
|
bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(api.CompleteMultipartUploadHandler).Queries("uploadId", "{uploadId:.*}")
|
||||||
// Register GetBucketNotification Handler.
|
|
||||||
case "GetBucketNotification":
|
case "GetBucketNotification":
|
||||||
|
// Register GetBucketNotification Handler.
|
||||||
bucket.Methods("GET").HandlerFunc(api.GetBucketNotificationHandler).Queries("notification", "")
|
bucket.Methods("GET").HandlerFunc(api.GetBucketNotificationHandler).Queries("notification", "")
|
||||||
// Register PutBucketNotification Handler.
|
|
||||||
case "PutBucketNotification":
|
case "PutBucketNotification":
|
||||||
|
// Register PutBucketNotification Handler.
|
||||||
bucket.Methods("PUT").HandlerFunc(api.PutBucketNotificationHandler).Queries("notification", "")
|
bucket.Methods("PUT").HandlerFunc(api.PutBucketNotificationHandler).Queries("notification", "")
|
||||||
// Register ListenBucketNotification Handler.
|
|
||||||
case "ListenBucketNotification":
|
case "ListenBucketNotification":
|
||||||
|
// Register ListenBucketNotification Handler.
|
||||||
bucket.Methods("GET").HandlerFunc(api.ListenBucketNotificationHandler).Queries("events", "{events:.*}")
|
bucket.Methods("GET").HandlerFunc(api.ListenBucketNotificationHandler).Queries("events", "{events:.*}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user