| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 	"bufio" | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 	"encoding/xml" | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 	"net/http/httptest" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Implement a dummy flush writer.
 | 
					
						
							|  |  |  | type flushWriter struct { | 
					
						
							|  |  |  | 	io.Writer | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Flush writer is a dummy writer compatible with http.Flusher and http.ResponseWriter.
 | 
					
						
							|  |  |  | func (f *flushWriter) Flush()                            {} | 
					
						
							|  |  |  | func (f *flushWriter) Write(b []byte) (n int, err error) { return f.Writer.Write(b) } | 
					
						
							|  |  |  | func (f *flushWriter) Header() http.Header               { return http.Header{} } | 
					
						
							|  |  |  | func (f *flushWriter) WriteHeader(code int)              {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | func newFlushWriter(writer io.Writer) http.ResponseWriter { | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 	return &flushWriter{writer} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests write notification code.
 | 
					
						
							|  |  |  | func TestWriteNotification(t *testing.T) { | 
					
						
							|  |  |  | 	// Initialize a new test config.
 | 
					
						
							|  |  |  | 	root, err := newTestConfig("us-east-1") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Unable to initialize test config %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer removeAll(root) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var buffer bytes.Buffer | 
					
						
							|  |  |  | 	// Collection of test cases for each event writer.
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 		writer http.ResponseWriter | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 		event  map[string][]NotificationEvent | 
					
						
							|  |  |  | 		err    error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// Invalid input argument with writer `nil` - Test - 1
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			writer: nil, | 
					
						
							|  |  |  | 			event:  nil, | 
					
						
							|  |  |  | 			err:    errInvalidArgument, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// Invalid input argument with event `nil` - Test - 2
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			writer: newFlushWriter(ioutil.Discard), | 
					
						
							|  |  |  | 			event:  nil, | 
					
						
							|  |  |  | 			err:    errInvalidArgument, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// Unmarshal and write, validate last 5 bytes. - Test - 3
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			writer: newFlushWriter(&buffer), | 
					
						
							|  |  |  | 			event: map[string][]NotificationEvent{ | 
					
						
							|  |  |  | 				"Records": {newNotificationEvent(eventData{ | 
					
						
							|  |  |  | 					Type:   ObjectCreatedPut, | 
					
						
							|  |  |  | 					Bucket: "testbucket", | 
					
						
							|  |  |  | 					ObjInfo: ObjectInfo{ | 
					
						
							|  |  |  | 						Name: "key", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					ReqParams: map[string]string{ | 
					
						
							|  |  |  | 						"ip": "10.1.10.1", | 
					
						
							|  |  |  | 					}}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			err: nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Validates all the testcases for writing notification.
 | 
					
						
							|  |  |  | 	for _, testCase := range testCases { | 
					
						
							|  |  |  | 		err := writeNotification(testCase.writer, testCase.event) | 
					
						
							|  |  |  | 		if err != testCase.err { | 
					
						
							|  |  |  | 			t.Errorf("Unable to write notification %s", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Validates if the ending string has 'crlf'
 | 
					
						
							|  |  |  | 		if err == nil && !bytes.HasSuffix(buffer.Bytes(), crlf) { | 
					
						
							|  |  |  | 			buf := buffer.Bytes()[buffer.Len()-5 : 0] | 
					
						
							|  |  |  | 			t.Errorf("Invalid suffix found from the writer last 5 bytes %s, expected `\r\n`", string(buf)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Not printing 'buf' on purpose, validates look for string '10.1.10.1'.
 | 
					
						
							|  |  |  | 		if err == nil && !bytes.Contains(buffer.Bytes(), []byte("10.1.10.1")) { | 
					
						
							|  |  |  | 			// Enable when debugging)
 | 
					
						
							|  |  |  | 			// fmt.Println(string(buffer.Bytes()))
 | 
					
						
							|  |  |  | 			t.Errorf("Requested content couldn't be found, expected `10.1.10.1`") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestSendBucketNotification(t *testing.T) { | 
					
						
							|  |  |  | 	// Initialize a new test config.
 | 
					
						
							|  |  |  | 	root, err := newTestConfig("us-east-1") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Unable to initialize test config %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer removeAll(root) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	eventCh := make(chan []NotificationEvent) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a Pipe with FlushWriter on the write-side and bufio.Scanner
 | 
					
						
							|  |  |  | 	// on the reader-side to receive notification over the listen channel in a
 | 
					
						
							|  |  |  | 	// synchronized manner.
 | 
					
						
							|  |  |  | 	pr, pw := io.Pipe() | 
					
						
							|  |  |  | 	fw := newFlushWriter(pw) | 
					
						
							|  |  |  | 	scanner := bufio.NewScanner(pr) | 
					
						
							|  |  |  | 	// Start a go-routine to wait for notification events.
 | 
					
						
							|  |  |  | 	go func(listenerCh <-chan []NotificationEvent) { | 
					
						
							|  |  |  | 		sendBucketNotification(fw, listenerCh) | 
					
						
							|  |  |  | 	}(eventCh) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Construct notification events to be passed on the events channel.
 | 
					
						
							|  |  |  | 	var events []NotificationEvent | 
					
						
							|  |  |  | 	evTypes := []EventName{ | 
					
						
							|  |  |  | 		ObjectCreatedPut, | 
					
						
							|  |  |  | 		ObjectCreatedPost, | 
					
						
							|  |  |  | 		ObjectCreatedCopy, | 
					
						
							|  |  |  | 		ObjectCreatedCompleteMultipartUpload, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, evType := range evTypes { | 
					
						
							|  |  |  | 		events = append(events, newNotificationEvent(eventData{ | 
					
						
							|  |  |  | 			Type: evType, | 
					
						
							|  |  |  | 		})) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Send notification events to the channel on which sendBucketNotification
 | 
					
						
							|  |  |  | 	// is waiting on.
 | 
					
						
							|  |  |  | 	eventCh <- events | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Read from the pipe connected to the ResponseWriter.
 | 
					
						
							|  |  |  | 	scanner.Scan() | 
					
						
							|  |  |  | 	notificationBytes := scanner.Bytes() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Close the read-end and send an empty notification event on the channel
 | 
					
						
							|  |  |  | 	// to signal sendBucketNotification to terminate.
 | 
					
						
							|  |  |  | 	pr.Close() | 
					
						
							|  |  |  | 	eventCh <- []NotificationEvent{} | 
					
						
							|  |  |  | 	close(eventCh) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Checking if the notification are the same as those sent over the channel.
 | 
					
						
							|  |  |  | 	var notifications map[string][]NotificationEvent | 
					
						
							|  |  |  | 	err = json.Unmarshal(notificationBytes, ¬ifications) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to Unmarshal notification") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	records := notifications["Records"] | 
					
						
							|  |  |  | 	for i, rec := range records { | 
					
						
							|  |  |  | 		if rec.EventName == evTypes[i].String() { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		t.Errorf("Failed to receive %d event %s", i, evTypes[i].String()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func initMockEventNotifier(objAPI ObjectLayer) error { | 
					
						
							|  |  |  | 	if objAPI == nil { | 
					
						
							|  |  |  | 		return errInvalidArgument | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	globalEventNotifier = &eventNotifier{ | 
					
						
							|  |  |  | 		rwMutex:             &sync.RWMutex{}, | 
					
						
							|  |  |  | 		queueTargets:        nil, | 
					
						
							|  |  |  | 		notificationConfigs: make(map[string]*notificationConfig), | 
					
						
							|  |  |  | 		snsTargets:          make(map[string][]chan []NotificationEvent), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testGetBucketNotificationHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { | 
					
						
							|  |  |  | 	// get random bucket name.
 | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 	randBucket := getRandomBucketName() | 
					
						
							|  |  |  | 	noNotificationBucket := "nonotification" | 
					
						
							|  |  |  | 	invalidBucket := "Invalid^Bucket" | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 	// Create buckets for the following test cases.
 | 
					
						
							|  |  |  | 	for _, bucket := range []string{randBucket, noNotificationBucket} { | 
					
						
							|  |  |  | 		err := obj.MakeBucket(bucket) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			// failed to create newbucket, abort.
 | 
					
						
							|  |  |  | 			t.Fatalf("Failed to create bucket %s %s : %s", bucket, | 
					
						
							|  |  |  | 				instanceType, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 	// Initialize sample bucket notification config.
 | 
					
						
							|  |  |  | 	sampleNotificationBytes := []byte("<NotificationConfiguration><TopicConfiguration>" + | 
					
						
							|  |  |  | 		"<Event>s3:ObjectCreated:*</Event><Event>s3:ObjectRemoved:*</Event><Filter>" + | 
					
						
							|  |  |  | 		"<S3Key></S3Key></Filter><Id></Id><Topic>arn:minio:sns:us-east-1:1474332374:listen</Topic>" + | 
					
						
							|  |  |  | 		"</TopicConfiguration></NotificationConfiguration>") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	emptyNotificationBytes := []byte("<NotificationConfiguration></NotificationConfiguration>") | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Register the API end points with XL/FS object layer.
 | 
					
						
							|  |  |  | 	apiRouter := initTestAPIEndPoints(obj, []string{ | 
					
						
							|  |  |  | 		"GetBucketNotificationHandler", | 
					
						
							|  |  |  | 		"PutBucketNotificationHandler", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//Initialize global event notifier with mock queue targets.
 | 
					
						
							|  |  |  | 	err = initMockEventNotifier(obj) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Test %s: Failed to initialize mock event notifier %v", | 
					
						
							|  |  |  | 			instanceType, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Initialize httptest recorder.
 | 
					
						
							|  |  |  | 	rec := httptest.NewRecorder() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Prepare notification config for one of the test cases.
 | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 	req, err := newTestSignedRequestV4("PUT", getPutBucketNotificationURL("", randBucket), | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 		int64(len(sampleNotificationBytes)), bytes.NewReader(sampleNotificationBytes), | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 		credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Test %d %s: Failed to create HTTP request for PutBucketNotification: <ERROR> %v", | 
					
						
							|  |  |  | 			1, instanceType, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	apiRouter.ServeHTTP(rec, req) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 	type testKind int | 
					
						
							|  |  |  | 	const ( | 
					
						
							|  |  |  | 		CompareBytes testKind = iota | 
					
						
							|  |  |  | 		CheckStatus | 
					
						
							|  |  |  | 		InvalidAuth | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucketName                string | 
					
						
							|  |  |  | 		kind                      testKind | 
					
						
							|  |  |  | 		expectedNotificationBytes []byte | 
					
						
							|  |  |  | 		expectedHTTPCode          int | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{randBucket, CompareBytes, sampleNotificationBytes, http.StatusOK}, | 
					
						
							|  |  |  | 		{randBucket, InvalidAuth, nil, http.StatusBadRequest}, | 
					
						
							|  |  |  | 		{noNotificationBucket, CompareBytes, emptyNotificationBytes, http.StatusOK}, | 
					
						
							|  |  |  | 		{invalidBucket, CheckStatus, nil, http.StatusBadRequest}, | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 	signatureMismatchCode := getAPIError(ErrContentSHA256Mismatch).Code | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		testRec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 		testReq, tErr := newTestSignedRequestV4("GET", getGetBucketNotificationURL("", test.bucketName), | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 			int64(0), nil, credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							|  |  |  | 		if tErr != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d: %s: Failed to create HTTP testRequest for GetBucketNotification: <ERROR> %v", | 
					
						
							|  |  |  | 				i+1, instanceType, tErr) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 		// Set X-Amz-Content-SHA256 in header different from what was used to calculate Signature.
 | 
					
						
							|  |  |  | 		if test.kind == InvalidAuth { | 
					
						
							|  |  |  | 			// Triggering a authentication type check failure.
 | 
					
						
							|  |  |  | 			testReq.Header.Set("x-amz-content-sha256", "somethingElse") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		apiRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch test.kind { | 
					
						
							|  |  |  | 		case CompareBytes: | 
					
						
							|  |  |  | 			rspBytes, rErr := ioutil.ReadAll(testRec.Body) | 
					
						
							|  |  |  | 			if rErr != nil { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Failed to read response body: <ERROR> %v", i+1, instanceType, rErr) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !bytes.Equal(rspBytes, test.expectedNotificationBytes) { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Notification config doesn't match expected value %s: <ERROR> %v", | 
					
						
							|  |  |  | 					i+1, instanceType, string(test.expectedNotificationBytes), err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case InvalidAuth: | 
					
						
							|  |  |  | 			rspBytes, rErr := ioutil.ReadAll(testRec.Body) | 
					
						
							|  |  |  | 			if rErr != nil { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Failed to read response body: <ERROR> %v", i+1, instanceType, rErr) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var errCode APIError | 
					
						
							|  |  |  | 			xErr := xml.Unmarshal(rspBytes, &errCode) | 
					
						
							|  |  |  | 			if xErr != nil { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Failed to unmarshal error XML: <ERROR> %v", i+1, instanceType, xErr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if errCode.Code != signatureMismatchCode { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Expected error code %s but received %s: <ERROR> %v", i+1, | 
					
						
							|  |  |  | 					instanceType, signatureMismatchCode, errCode.Code, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			fallthrough | 
					
						
							|  |  |  | 		case CheckStatus: | 
					
						
							|  |  |  | 			if testRec.Code != test.expectedHTTPCode { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: expected HTTP code %d, but received %d: <ERROR> %v", | 
					
						
							|  |  |  | 					i+1, instanceType, test.expectedHTTPCode, testRec.Code, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 	// Nil Object layer
 | 
					
						
							|  |  |  | 	nilAPIRouter := initTestAPIEndPoints(nil, []string{ | 
					
						
							|  |  |  | 		"GetBucketNotificationHandler", | 
					
						
							|  |  |  | 		"PutBucketNotificationHandler", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	testRec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 	testReq, tErr := newTestSignedRequestV4("GET", getGetBucketNotificationURL("", randBucket), | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 		int64(0), nil, credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 	if tErr != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Test %d: %s: Failed to create HTTP testRequest for GetBucketNotification: <ERROR> %v", | 
					
						
							|  |  |  | 			len(testCases)+1, instanceType, tErr) | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-24 04:32:51 +08:00
										 |  |  | 	nilAPIRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 	if testRec.Code != http.StatusServiceUnavailable { | 
					
						
							|  |  |  | 		t.Errorf("Test %d: %s: expected HTTP code %d, but received %d: <ERROR> %v", | 
					
						
							|  |  |  | 			len(testCases)+1, instanceType, http.StatusServiceUnavailable, testRec.Code, err) | 
					
						
							| 
									
										
										
										
											2016-09-22 08:41:34 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestGetBucketNotificationHandler(t *testing.T) { | 
					
						
							|  |  |  | 	ExecObjectLayerTest(t, testGetBucketNotificationHandler) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-28 16:08:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func testPutBucketNotificationHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { | 
					
						
							|  |  |  | 	invalidBucket := "Invalid^Bucket" | 
					
						
							|  |  |  | 	// get random bucket name.
 | 
					
						
							|  |  |  | 	randBucket := getRandomBucketName() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := obj.MakeBucket(randBucket) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		// failed to create randBucket, abort.
 | 
					
						
							|  |  |  | 		t.Fatalf("Failed to create bucket %s %s : %s", randBucket, | 
					
						
							|  |  |  | 			instanceType, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sampleNotificationBytes := []byte("<NotificationConfiguration><TopicConfiguration>" + | 
					
						
							|  |  |  | 		"<Event>s3:ObjectCreated:*</Event><Event>s3:ObjectRemoved:*</Event><Filter>" + | 
					
						
							|  |  |  | 		"<S3Key></S3Key></Filter><Id></Id><Topic>arn:minio:sns:us-east-1:1474332374:listen</Topic>" + | 
					
						
							|  |  |  | 		"</TopicConfiguration></NotificationConfiguration>") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Register the API end points with XL/FS object layer.
 | 
					
						
							|  |  |  | 	apiRouter := initTestAPIEndPoints(obj, []string{ | 
					
						
							|  |  |  | 		"GetBucketNotificationHandler", | 
					
						
							|  |  |  | 		"PutBucketNotificationHandler", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//Initialize global event notifier with mock queue targets.
 | 
					
						
							|  |  |  | 	err = initMockEventNotifier(obj) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Test %s: Failed to initialize mock event notifier %v", | 
					
						
							|  |  |  | 			instanceType, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	signatureMismatchError := getAPIError(ErrContentSHA256Mismatch) | 
					
						
							|  |  |  | 	missingContentLengthError := getAPIError(ErrMissingContentLength) | 
					
						
							|  |  |  | 	type testKind int | 
					
						
							|  |  |  | 	const ( | 
					
						
							|  |  |  | 		CompareBytes testKind = iota | 
					
						
							|  |  |  | 		CheckStatus | 
					
						
							|  |  |  | 		InvalidAuth | 
					
						
							|  |  |  | 		MissingContentLength | 
					
						
							|  |  |  | 		ChunkedEncoding | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucketName                string | 
					
						
							|  |  |  | 		kind                      testKind | 
					
						
							|  |  |  | 		expectedNotificationBytes []byte | 
					
						
							|  |  |  | 		expectedHTTPCode          int | 
					
						
							|  |  |  | 		expectedAPIError          string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{randBucket, CompareBytes, sampleNotificationBytes, http.StatusOK, ""}, | 
					
						
							|  |  |  | 		{randBucket, ChunkedEncoding, sampleNotificationBytes, http.StatusOK, ""}, | 
					
						
							|  |  |  | 		{randBucket, InvalidAuth, nil, signatureMismatchError.HTTPStatusCode, signatureMismatchError.Code}, | 
					
						
							|  |  |  | 		{randBucket, MissingContentLength, nil, missingContentLengthError.HTTPStatusCode, missingContentLengthError.Code}, | 
					
						
							|  |  |  | 		{invalidBucket, CheckStatus, nil, http.StatusBadRequest, ""}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		testRec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 		testReq, tErr := newTestSignedRequestV4("PUT", getPutBucketNotificationURL("", test.bucketName), | 
					
						
							| 
									
										
										
										
											2016-09-28 16:08:03 +08:00
										 |  |  | 			int64(len(test.expectedNotificationBytes)), bytes.NewReader(test.expectedNotificationBytes), | 
					
						
							|  |  |  | 			credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							|  |  |  | 		if tErr != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d: %s: Failed to create HTTP testRequest for PutBucketNotification: <ERROR> %v", | 
					
						
							|  |  |  | 				i+1, instanceType, tErr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Set X-Amz-Content-SHA256 in header different from what was used to calculate Signature.
 | 
					
						
							|  |  |  | 		switch test.kind { | 
					
						
							|  |  |  | 		case InvalidAuth: | 
					
						
							|  |  |  | 			// Triggering a authentication type check failure.
 | 
					
						
							|  |  |  | 			testReq.Header.Set("x-amz-content-sha256", "somethingElse") | 
					
						
							|  |  |  | 		case MissingContentLength: | 
					
						
							|  |  |  | 			testReq.ContentLength = -1 | 
					
						
							|  |  |  | 		case ChunkedEncoding: | 
					
						
							|  |  |  | 			testReq.ContentLength = -1 | 
					
						
							|  |  |  | 			testReq.TransferEncoding = append(testReq.TransferEncoding, "chunked") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		apiRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch test.kind { | 
					
						
							|  |  |  | 		case CompareBytes: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 			testReq, tErr = newTestSignedRequestV4("GET", getGetBucketNotificationURL("", test.bucketName), | 
					
						
							| 
									
										
										
										
											2016-09-28 16:08:03 +08:00
										 |  |  | 				int64(0), nil, credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							|  |  |  | 			if tErr != nil { | 
					
						
							|  |  |  | 				t.Fatalf("Test %d: %s: Failed to create HTTP testRequest for GetBucketNotification: <ERROR> %v", | 
					
						
							|  |  |  | 					i+1, instanceType, tErr) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			apiRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			rspBytes, rErr := ioutil.ReadAll(testRec.Body) | 
					
						
							|  |  |  | 			if rErr != nil { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Failed to read response body: <ERROR> %v", i+1, instanceType, rErr) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !bytes.Equal(rspBytes, test.expectedNotificationBytes) { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Notification config doesn't match expected value %s: <ERROR> %v", | 
					
						
							|  |  |  | 					i+1, instanceType, string(test.expectedNotificationBytes), err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case MissingContentLength, InvalidAuth: | 
					
						
							|  |  |  | 			rspBytes, rErr := ioutil.ReadAll(testRec.Body) | 
					
						
							|  |  |  | 			if rErr != nil { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Failed to read response body: <ERROR> %v", i+1, instanceType, rErr) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var errCode APIError | 
					
						
							|  |  |  | 			xErr := xml.Unmarshal(rspBytes, &errCode) | 
					
						
							|  |  |  | 			if xErr != nil { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Failed to unmarshal error XML: <ERROR> %v", i+1, instanceType, xErr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if errCode.Code != test.expectedAPIError { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: Expected error code %s but received %s: <ERROR> %v", i+1, | 
					
						
							|  |  |  | 					instanceType, test.expectedAPIError, errCode.Code, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			fallthrough | 
					
						
							|  |  |  | 		case CheckStatus: | 
					
						
							|  |  |  | 			if testRec.Code != test.expectedHTTPCode { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: %s: expected HTTP code %d, but received %d: <ERROR> %v", | 
					
						
							|  |  |  | 					i+1, instanceType, test.expectedHTTPCode, testRec.Code, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Nil Object layer
 | 
					
						
							|  |  |  | 	nilAPIRouter := initTestAPIEndPoints(nil, []string{ | 
					
						
							|  |  |  | 		"GetBucketNotificationHandler", | 
					
						
							|  |  |  | 		"PutBucketNotificationHandler", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	testRec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 	testReq, tErr := newTestSignedRequestV4("PUT", getPutBucketNotificationURL("", randBucket), | 
					
						
							| 
									
										
										
										
											2016-09-28 16:08:03 +08:00
										 |  |  | 		int64(len(sampleNotificationBytes)), bytes.NewReader(sampleNotificationBytes), | 
					
						
							|  |  |  | 		credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							|  |  |  | 	if tErr != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Test %d: %s: Failed to create HTTP testRequest for PutBucketNotification: <ERROR> %v", | 
					
						
							|  |  |  | 			len(testCases)+1, instanceType, tErr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	nilAPIRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 	if testRec.Code != http.StatusServiceUnavailable { | 
					
						
							|  |  |  | 		t.Errorf("Test %d: %s: expected HTTP code %d, but received %d: <ERROR> %v", | 
					
						
							|  |  |  | 			len(testCases)+1, instanceType, http.StatusServiceUnavailable, testRec.Code, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestPutBucketNotificationHandler(t *testing.T) { | 
					
						
							|  |  |  | 	ExecObjectLayerTest(t, testPutBucketNotificationHandler) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testListenBucketNotificationHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { | 
					
						
							|  |  |  | 	invalidBucket := "Invalid^Bucket" | 
					
						
							|  |  |  | 	noNotificationBucket := "nonotificationbucket" | 
					
						
							|  |  |  | 	// get random bucket name.
 | 
					
						
							|  |  |  | 	randBucket := getRandomBucketName() | 
					
						
							|  |  |  | 	for _, bucket := range []string{randBucket, noNotificationBucket} { | 
					
						
							|  |  |  | 		err := obj.MakeBucket(bucket) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			// failed to create bucket, abort.
 | 
					
						
							|  |  |  | 			t.Fatalf("Failed to create bucket %s %s : %s", bucket, | 
					
						
							|  |  |  | 				instanceType, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sampleNotificationBytes := []byte("<NotificationConfiguration><TopicConfiguration>" + | 
					
						
							|  |  |  | 		"<Event>s3:ObjectCreated:*</Event><Event>s3:ObjectRemoved:*</Event><Filter>" + | 
					
						
							|  |  |  | 		"<S3Key></S3Key></Filter><Id></Id><Topic>arn:minio:sns:us-east-1:1474332374:listen</Topic>" + | 
					
						
							|  |  |  | 		"</TopicConfiguration></NotificationConfiguration>") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Register the API end points with XL/FS object layer.
 | 
					
						
							|  |  |  | 	apiRouter := initTestAPIEndPoints(obj, []string{ | 
					
						
							|  |  |  | 		"PutBucketNotificationHandler", | 
					
						
							|  |  |  | 		"ListenBucketNotificationHandler", | 
					
						
							|  |  |  | 		"PutObject", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//Initialize global event notifier with mock queue targets.
 | 
					
						
							|  |  |  | 	err = initMockEventNotifier(obj) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Test %s: Failed to initialize mock event notifier %v", | 
					
						
							|  |  |  | 			instanceType, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	testRec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 	testReq, tErr := newTestSignedRequestV4("PUT", getPutBucketNotificationURL("", randBucket), | 
					
						
							| 
									
										
										
										
											2016-09-28 16:08:03 +08:00
										 |  |  | 		int64(len(sampleNotificationBytes)), bytes.NewReader(sampleNotificationBytes), | 
					
						
							|  |  |  | 		credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							|  |  |  | 	if tErr != nil { | 
					
						
							|  |  |  | 		t.Fatalf("%s: Failed to create HTTP testRequest for PutBucketNotification: <ERROR> %v", instanceType, tErr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	apiRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	signatureMismatchError := getAPIError(ErrContentSHA256Mismatch) | 
					
						
							|  |  |  | 	type testKind int | 
					
						
							|  |  |  | 	const ( | 
					
						
							|  |  |  | 		CheckStatus testKind = iota | 
					
						
							|  |  |  | 		InvalidAuth | 
					
						
							|  |  |  | 		AsyncHandler | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	tooBigPrefix := string(bytes.Repeat([]byte("a"), 1025)) | 
					
						
							|  |  |  | 	validEvents := []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:*"} | 
					
						
							|  |  |  | 	invalidEvents := []string{"invalidEvent"} | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucketName       string | 
					
						
							|  |  |  | 		prefix           string | 
					
						
							|  |  |  | 		suffix           string | 
					
						
							|  |  |  | 		events           []string | 
					
						
							|  |  |  | 		kind             testKind | 
					
						
							|  |  |  | 		expectedHTTPCode int | 
					
						
							|  |  |  | 		expectedAPIError string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// FIXME: Need to find a way to run valid listen bucket notification test case without blocking the unit test.
 | 
					
						
							|  |  |  | 		{randBucket, "", "", invalidEvents, CheckStatus, signatureMismatchError.HTTPStatusCode, ""}, | 
					
						
							|  |  |  | 		{randBucket, tooBigPrefix, "", validEvents, CheckStatus, http.StatusBadRequest, ""}, | 
					
						
							|  |  |  | 		{invalidBucket, "", "", nil, CheckStatus, http.StatusBadRequest, ""}, | 
					
						
							|  |  |  | 		{randBucket, "", "", nil, InvalidAuth, signatureMismatchError.HTTPStatusCode, signatureMismatchError.Code}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		testRec = httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 		testReq, tErr = newTestSignedRequestV4("GET", | 
					
						
							| 
									
										
										
										
											2016-09-28 16:08:03 +08:00
										 |  |  | 			getListenBucketNotificationURL("", test.bucketName, test.prefix, test.suffix, test.events), | 
					
						
							|  |  |  | 			0, nil, credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							|  |  |  | 		if tErr != nil { | 
					
						
							|  |  |  | 			t.Fatalf("%s: Failed to create HTTP testRequest for ListenBucketNotification: <ERROR> %v", instanceType, tErr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Set X-Amz-Content-SHA256 in header different from what was used to calculate Signature.
 | 
					
						
							|  |  |  | 		if test.kind == InvalidAuth { | 
					
						
							|  |  |  | 			// Triggering a authentication type check failure.
 | 
					
						
							|  |  |  | 			testReq.Header.Set("x-amz-content-sha256", "somethingElse") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if test.kind == AsyncHandler { | 
					
						
							|  |  |  | 			go apiRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			apiRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 			switch test.kind { | 
					
						
							|  |  |  | 			case InvalidAuth: | 
					
						
							|  |  |  | 				rspBytes, rErr := ioutil.ReadAll(testRec.Body) | 
					
						
							|  |  |  | 				if rErr != nil { | 
					
						
							|  |  |  | 					t.Errorf("Test %d: %s: Failed to read response body: <ERROR> %v", i+1, instanceType, rErr) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				var errCode APIError | 
					
						
							|  |  |  | 				xErr := xml.Unmarshal(rspBytes, &errCode) | 
					
						
							|  |  |  | 				if xErr != nil { | 
					
						
							|  |  |  | 					t.Errorf("Test %d: %s: Failed to unmarshal error XML: <ERROR> %v", i+1, instanceType, xErr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if errCode.Code != test.expectedAPIError { | 
					
						
							|  |  |  | 					t.Errorf("Test %d: %s: Expected error code %s but received %s: <ERROR> %v", i+1, | 
					
						
							|  |  |  | 						instanceType, test.expectedAPIError, errCode.Code, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				fallthrough | 
					
						
							|  |  |  | 			case CheckStatus: | 
					
						
							|  |  |  | 				if testRec.Code != test.expectedHTTPCode { | 
					
						
							|  |  |  | 					t.Errorf("Test %d: %s: expected HTTP code %d, but received %d: <ERROR> %v", | 
					
						
							|  |  |  | 						i+1, instanceType, test.expectedHTTPCode, testRec.Code, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Nil Object layer
 | 
					
						
							|  |  |  | 	nilAPIRouter := initTestAPIEndPoints(nil, []string{ | 
					
						
							|  |  |  | 		"PutBucketNotificationHandler", | 
					
						
							|  |  |  | 		"ListenBucketNotificationHandler", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	testRec = httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 	testReq, tErr = newTestSignedRequestV4("GET", | 
					
						
							| 
									
										
										
										
											2016-09-28 16:08:03 +08:00
										 |  |  | 		getListenBucketNotificationURL("", randBucket, "", "*.jpg", []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:*"}), | 
					
						
							|  |  |  | 		0, nil, credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							|  |  |  | 	if tErr != nil { | 
					
						
							|  |  |  | 		t.Fatalf("%s: Failed to create HTTP testRequest for ListenBucketNotification: <ERROR> %v", instanceType, tErr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	nilAPIRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 	if testRec.Code != http.StatusServiceUnavailable { | 
					
						
							|  |  |  | 		t.Errorf("Test %d: %s: expected HTTP code %d, but received %d: <ERROR> %v", | 
					
						
							|  |  |  | 			1, instanceType, http.StatusServiceUnavailable, testRec.Code, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestListenBucketNotificationHandler(t *testing.T) { | 
					
						
							|  |  |  | 	ExecObjectLayerTest(t, testListenBucketNotificationHandler) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testRemoveNotificationConfig(obj ObjectLayer, instanceType string, t TestErrHandler) { | 
					
						
							|  |  |  | 	invalidBucket := "Invalid^Bucket" | 
					
						
							|  |  |  | 	// get random bucket name.
 | 
					
						
							|  |  |  | 	randBucket := getRandomBucketName() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := obj.MakeBucket(randBucket) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		// failed to create bucket, abort.
 | 
					
						
							|  |  |  | 		t.Fatalf("Failed to create bucket %s %s : %s", randBucket, | 
					
						
							|  |  |  | 			instanceType, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sampleNotificationBytes := []byte("<NotificationConfiguration><TopicConfiguration>" + | 
					
						
							|  |  |  | 		"<Event>s3:ObjectCreated:*</Event><Event>s3:ObjectRemoved:*</Event><Filter>" + | 
					
						
							|  |  |  | 		"<S3Key></S3Key></Filter><Id></Id><Topic>arn:minio:sns:us-east-1:1474332374:listen</Topic>" + | 
					
						
							|  |  |  | 		"</TopicConfiguration></NotificationConfiguration>") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Register the API end points with XL/FS object layer.
 | 
					
						
							|  |  |  | 	apiRouter := initTestAPIEndPoints(obj, []string{ | 
					
						
							|  |  |  | 		"PutBucketNotificationHandler", | 
					
						
							|  |  |  | 		"ListenBucketNotificationHandler", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//Initialize global event notifier with mock queue targets.
 | 
					
						
							|  |  |  | 	err = initMockEventNotifier(obj) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Test %s: Failed to initialize mock event notifier %v", | 
					
						
							|  |  |  | 			instanceType, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Set sample bucket notification on randBucket.
 | 
					
						
							|  |  |  | 	testRec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2016-10-01 05:32:13 +08:00
										 |  |  | 	testReq, tErr := newTestSignedRequestV4("PUT", getPutBucketNotificationURL("", randBucket), | 
					
						
							| 
									
										
										
										
											2016-09-28 16:08:03 +08:00
										 |  |  | 		int64(len(sampleNotificationBytes)), bytes.NewReader(sampleNotificationBytes), | 
					
						
							|  |  |  | 		credentials.AccessKeyID, credentials.SecretAccessKey) | 
					
						
							|  |  |  | 	if tErr != nil { | 
					
						
							|  |  |  | 		t.Fatalf("%s: Failed to create HTTP testRequest for PutBucketNotification: <ERROR> %v", instanceType, tErr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	apiRouter.ServeHTTP(testRec, testReq) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucketName  string | 
					
						
							|  |  |  | 		expectedErr error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{invalidBucket, BucketNameInvalid{Bucket: invalidBucket}}, | 
					
						
							|  |  |  | 		{randBucket, nil}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		tErr := removeNotificationConfig(test.bucketName, obj) | 
					
						
							|  |  |  | 		if tErr != test.expectedErr { | 
					
						
							|  |  |  | 			t.Errorf("Test %d: %s expected error %v, but received %v", i+1, instanceType, test.expectedErr, tErr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestRemoveNotificationConfig(t *testing.T) { | 
					
						
							|  |  |  | 	ExecObjectLayerTest(t, testRemoveNotificationConfig) | 
					
						
							|  |  |  | } |