| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2017-01-19 04:24:34 +08:00
										 |  |  |  * Minio Cloud Storage, (C) 2016, 2017 Minio, Inc. | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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 cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	"encoding/xml" | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/http/httptest" | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2017-02-08 16:13:02 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	router "github.com/gorilla/mux" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | var configJSON = []byte(`{ | 
					
						
							|  |  |  | 	"version": "13", | 
					
						
							|  |  |  | 	"credential": { | 
					
						
							|  |  |  | 		"accessKey": "minio", | 
					
						
							|  |  |  | 		"secretKey": "minio123" | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	"region": "us-west-1", | 
					
						
							|  |  |  | 	"logger": { | 
					
						
							|  |  |  | 		"console": { | 
					
						
							|  |  |  | 			"enable": true, | 
					
						
							|  |  |  | 			"level": "fatal" | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"file": { | 
					
						
							|  |  |  | 			"enable": false, | 
					
						
							|  |  |  | 			"fileName": "", | 
					
						
							|  |  |  | 			"level": "" | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	"notify": { | 
					
						
							|  |  |  | 		"amqp": { | 
					
						
							|  |  |  | 			"1": { | 
					
						
							|  |  |  | 				"enable": false, | 
					
						
							|  |  |  | 				"url": "", | 
					
						
							|  |  |  | 				"exchange": "", | 
					
						
							|  |  |  | 				"routingKey": "", | 
					
						
							|  |  |  | 				"exchangeType": "", | 
					
						
							|  |  |  | 				"mandatory": false, | 
					
						
							|  |  |  | 				"immediate": false, | 
					
						
							|  |  |  | 				"durable": false, | 
					
						
							|  |  |  | 				"internal": false, | 
					
						
							|  |  |  | 				"noWait": false, | 
					
						
							|  |  |  | 				"autoDeleted": false | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"nats": { | 
					
						
							|  |  |  | 			"1": { | 
					
						
							|  |  |  | 				"enable": false, | 
					
						
							|  |  |  | 				"address": "", | 
					
						
							|  |  |  | 				"subject": "", | 
					
						
							|  |  |  | 				"username": "", | 
					
						
							|  |  |  | 				"password": "", | 
					
						
							|  |  |  | 				"token": "", | 
					
						
							|  |  |  | 				"secure": false, | 
					
						
							|  |  |  | 				"pingInterval": 0, | 
					
						
							|  |  |  | 				"streaming": { | 
					
						
							|  |  |  | 					"enable": false, | 
					
						
							|  |  |  | 					"clusterID": "", | 
					
						
							|  |  |  | 					"clientID": "", | 
					
						
							|  |  |  | 					"async": false, | 
					
						
							|  |  |  | 					"maxPubAcksInflight": 0 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"elasticsearch": { | 
					
						
							|  |  |  | 			"1": { | 
					
						
							|  |  |  | 				"enable": false, | 
					
						
							|  |  |  | 				"url": "", | 
					
						
							|  |  |  | 				"index": "" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"redis": { | 
					
						
							|  |  |  | 			"1": { | 
					
						
							|  |  |  | 				"enable": false, | 
					
						
							|  |  |  | 				"address": "", | 
					
						
							|  |  |  | 				"password": "", | 
					
						
							|  |  |  | 				"key": "" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"postgresql": { | 
					
						
							|  |  |  | 			"1": { | 
					
						
							|  |  |  | 				"enable": false, | 
					
						
							|  |  |  | 				"connectionString": "", | 
					
						
							|  |  |  | 				"table": "", | 
					
						
							|  |  |  | 				"host": "", | 
					
						
							|  |  |  | 				"port": "", | 
					
						
							|  |  |  | 				"user": "", | 
					
						
							|  |  |  | 				"password": "", | 
					
						
							|  |  |  | 				"database": "" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"kafka": { | 
					
						
							|  |  |  | 			"1": { | 
					
						
							|  |  |  | 				"enable": false, | 
					
						
							|  |  |  | 				"brokers": null, | 
					
						
							|  |  |  | 				"topic": "" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"webhook": { | 
					
						
							|  |  |  | 			"1": { | 
					
						
							|  |  |  | 				"enable": false, | 
					
						
							|  |  |  | 				"endpoint": "" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }`) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | // adminXLTestBed - encapsulates subsystems that need to be setup for
 | 
					
						
							|  |  |  | // admin-handler unit tests.
 | 
					
						
							|  |  |  | type adminXLTestBed struct { | 
					
						
							|  |  |  | 	configPath string | 
					
						
							|  |  |  | 	xlDirs     []string | 
					
						
							|  |  |  | 	objLayer   ObjectLayer | 
					
						
							|  |  |  | 	mux        *router.Router | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // prepareAdminXLTestBed - helper function that setups a single-node
 | 
					
						
							|  |  |  | // XL backend for admin-handler tests.
 | 
					
						
							|  |  |  | func prepareAdminXLTestBed() (*adminXLTestBed, error) { | 
					
						
							|  |  |  | 	// reset global variables to start afresh.
 | 
					
						
							|  |  |  | 	resetTestGlobals() | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	// Initialize minio server config.
 | 
					
						
							|  |  |  | 	rootPath, err := newTestConfig(globalMinioDefaultRegion) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Initializing objectLayer for HealFormatHandler.
 | 
					
						
							|  |  |  | 	objLayer, xlDirs, xlErr := initTestXLObjLayer() | 
					
						
							|  |  |  | 	if xlErr != nil { | 
					
						
							|  |  |  | 		return nil, xlErr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 16:13:02 +08:00
										 |  |  | 	// Initialize boot time
 | 
					
						
							|  |  |  | 	globalBootTime = time.Now().UTC() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	// Set globalEndpoints for a single node XL setup.
 | 
					
						
							|  |  |  | 	for _, xlDir := range xlDirs { | 
					
						
							|  |  |  | 		globalEndpoints = append(globalEndpoints, &url.URL{ | 
					
						
							|  |  |  | 			Path: xlDir, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set globalIsXL to indicate that the setup uses an erasure code backend.
 | 
					
						
							|  |  |  | 	globalIsXL = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// initialize NSLock.
 | 
					
						
							|  |  |  | 	isDistXL := false | 
					
						
							|  |  |  | 	initNSLock(isDistXL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Setup admin mgmt REST API handlers.
 | 
					
						
							|  |  |  | 	adminRouter := router.NewRouter() | 
					
						
							|  |  |  | 	registerAdminRouter(adminRouter) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &adminXLTestBed{ | 
					
						
							|  |  |  | 		configPath: rootPath, | 
					
						
							|  |  |  | 		xlDirs:     xlDirs, | 
					
						
							|  |  |  | 		objLayer:   objLayer, | 
					
						
							|  |  |  | 		mux:        adminRouter, | 
					
						
							|  |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TearDown - method that resets the test bed for subsequent unit
 | 
					
						
							|  |  |  | // tests to start afresh.
 | 
					
						
							|  |  |  | func (atb *adminXLTestBed) TearDown() { | 
					
						
							|  |  |  | 	removeAll(atb.configPath) | 
					
						
							|  |  |  | 	removeRoots(atb.xlDirs) | 
					
						
							|  |  |  | 	resetTestGlobals() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // initTestObjLayer - Helper function to initialize an XL-based object
 | 
					
						
							|  |  |  | // layer and set globalObjectAPI.
 | 
					
						
							|  |  |  | func initTestXLObjLayer() (ObjectLayer, []string, error) { | 
					
						
							|  |  |  | 	objLayer, xlDirs, xlErr := prepareXL() | 
					
						
							|  |  |  | 	if xlErr != nil { | 
					
						
							|  |  |  | 		return nil, nil, xlErr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Make objLayer available to all internal services via globalObjectAPI.
 | 
					
						
							|  |  |  | 	globalObjLayerMutex.Lock() | 
					
						
							|  |  |  | 	globalObjectAPI = objLayer | 
					
						
							|  |  |  | 	globalObjLayerMutex.Unlock() | 
					
						
							|  |  |  | 	return objLayer, xlDirs, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // cmdType - Represents different service subcomands like status, stop
 | 
					
						
							|  |  |  | // and restart.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | type cmdType int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	statusCmd cmdType = iota | 
					
						
							|  |  |  | 	restartCmd | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	setCreds | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // String - String representation for cmdType
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | func (c cmdType) String() string { | 
					
						
							|  |  |  | 	switch c { | 
					
						
							|  |  |  | 	case statusCmd: | 
					
						
							|  |  |  | 		return "status" | 
					
						
							|  |  |  | 	case restartCmd: | 
					
						
							|  |  |  | 		return "restart" | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	case setCreds: | 
					
						
							|  |  |  | 		return "set-credentials" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return "" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // apiMethod - Returns the HTTP method corresponding to the admin REST
 | 
					
						
							|  |  |  | // API for a given cmdType value.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | func (c cmdType) apiMethod() string { | 
					
						
							|  |  |  | 	switch c { | 
					
						
							|  |  |  | 	case statusCmd: | 
					
						
							|  |  |  | 		return "GET" | 
					
						
							|  |  |  | 	case restartCmd: | 
					
						
							|  |  |  | 		return "POST" | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	case setCreds: | 
					
						
							|  |  |  | 		return "POST" | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return "GET" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // toServiceSignal - Helper function that translates a given cmdType
 | 
					
						
							|  |  |  | // value to its corresponding serviceSignal value.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | func (c cmdType) toServiceSignal() serviceSignal { | 
					
						
							|  |  |  | 	switch c { | 
					
						
							|  |  |  | 	case statusCmd: | 
					
						
							|  |  |  | 		return serviceStatus | 
					
						
							|  |  |  | 	case restartCmd: | 
					
						
							|  |  |  | 		return serviceRestart | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return serviceStatus | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // testServiceSignalReceiver - Helper function that simulates a
 | 
					
						
							|  |  |  | // go-routine waiting on service signal.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | func testServiceSignalReceiver(cmd cmdType, t *testing.T) { | 
					
						
							|  |  |  | 	expectedCmd := cmd.toServiceSignal() | 
					
						
							|  |  |  | 	serviceCmd := <-globalServiceSignalCh | 
					
						
							|  |  |  | 	if serviceCmd != expectedCmd { | 
					
						
							|  |  |  | 		t.Errorf("Expected service command %v but received %v", expectedCmd, serviceCmd) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // getServiceCmdRequest - Constructs a management REST API request for service
 | 
					
						
							|  |  |  | // subcommands for a given cmdType value.
 | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | func getServiceCmdRequest(cmd cmdType, cred credential, body []byte) (*http.Request, error) { | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	req, err := newTestRequest(cmd.apiMethod(), "/?service", 0, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	// Set body
 | 
					
						
							|  |  |  | 	req.Body = ioutil.NopCloser(bytes.NewReader(body)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	// minioAdminOpHeader is to identify the request as a
 | 
					
						
							|  |  |  | 	// management REST API request.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	req.Header.Set(minioAdminOpHeader, cmd.String()) | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	req.Header.Set("X-Amz-Content-Sha256", getSHA256Hash(body)) | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// management REST API uses signature V4 for authentication.
 | 
					
						
							| 
									
										
										
										
											2016-12-27 02:21:23 +08:00
										 |  |  | 	err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return req, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // testServicesCmdHandler - parametrizes service subcommand tests on
 | 
					
						
							|  |  |  | // cmdType value.
 | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | func testServicesCmdHandler(cmd cmdType, t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	defer adminTestBed.TearDown() | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	// Initialize admin peers to make admin RPC calls. Note: In a
 | 
					
						
							|  |  |  | 	// single node setup, this degenerates to a simple function
 | 
					
						
							|  |  |  | 	// call under the hood.
 | 
					
						
							| 
									
										
										
										
											2017-02-10 15:26:44 +08:00
										 |  |  | 	eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to parse storage end point - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Set globalMinioAddr to be able to distinguish local endpoints from remote.
 | 
					
						
							|  |  |  | 	globalMinioAddr = eps[0].Host | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	initGlobalAdminPeers(eps) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Setting up a go routine to simulate ServerMux's
 | 
					
						
							|  |  |  | 	// handleServiceSignals for stop and restart commands.
 | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	if cmd == restartCmd { | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 		go testServiceSignalReceiver(cmd, t) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	credentials := serverConfig.GetCredential() | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 	var body []byte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req, err := getServiceCmdRequest(cmd, credentials, body) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to build service status request %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if cmd == statusCmd { | 
					
						
							| 
									
										
										
										
											2017-01-24 00:56:06 +08:00
										 |  |  | 		expectedInfo := ServerStatus{ | 
					
						
							|  |  |  | 			ServerVersion: ServerVersion{Version: Version, CommitID: CommitID}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		receivedInfo := ServerStatus{} | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 		if jsonErr := json.Unmarshal(rec.Body.Bytes(), &receivedInfo); jsonErr != nil { | 
					
						
							|  |  |  | 			t.Errorf("Failed to unmarshal StorageInfo - %v", jsonErr) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-08 16:13:02 +08:00
										 |  |  | 		if expectedInfo.ServerVersion != receivedInfo.ServerVersion { | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 			t.Errorf("Expected storage info and received storage info differ, %v %v", expectedInfo, receivedInfo) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if rec.Code != http.StatusOK { | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | 		resp, _ := ioutil.ReadAll(rec.Body) | 
					
						
							|  |  |  | 		t.Errorf("Expected to receive %d status code but received %d. Body (%s)", | 
					
						
							|  |  |  | 			http.StatusOK, rec.Code, string(resp)) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // Test for service status management REST API.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | func TestServiceStatusHandler(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | 	testServicesCmdHandler(statusCmd, t) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // Test for service restart management REST API.
 | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | func TestServiceRestartHandler(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | 	testServicesCmdHandler(restartCmd, t) | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | // Test for service set creds management REST API.
 | 
					
						
							| 
									
										
										
										
											2017-01-18 06:25:59 +08:00
										 |  |  | func TestServiceSetCreds(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer adminTestBed.TearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize admin peers to make admin RPC calls. Note: In a
 | 
					
						
							|  |  |  | 	// single node setup, this degenerates to a simple function
 | 
					
						
							|  |  |  | 	// call under the hood.
 | 
					
						
							| 
									
										
										
										
											2017-02-10 15:26:44 +08:00
										 |  |  | 	eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to parse storage end point - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set globalMinioAddr to be able to distinguish local endpoints from remote.
 | 
					
						
							|  |  |  | 	globalMinioAddr = eps[0].Host | 
					
						
							|  |  |  | 	initGlobalAdminPeers(eps) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	credentials := serverConfig.GetCredential() | 
					
						
							|  |  |  | 	var body []byte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		Username           string | 
					
						
							|  |  |  | 		Password           string | 
					
						
							|  |  |  | 		EnvKeysSet         bool | 
					
						
							|  |  |  | 		ExpectedStatusCode int | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// Bad secret key
 | 
					
						
							|  |  |  | 		{"minio", "minio", false, http.StatusBadRequest}, | 
					
						
							|  |  |  | 		// Bad  secret key set from the env
 | 
					
						
							|  |  |  | 		{"minio", "minio", true, http.StatusMethodNotAllowed}, | 
					
						
							|  |  |  | 		// Good keys set from the env
 | 
					
						
							|  |  |  | 		{"minio", "minio123", true, http.StatusMethodNotAllowed}, | 
					
						
							|  |  |  | 		// Successful operation should be the last one to do not change server credentials during tests.
 | 
					
						
							|  |  |  | 		{"minio", "minio123", false, http.StatusOK}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i, testCase := range testCases { | 
					
						
							|  |  |  | 		// Set or unset environement keys
 | 
					
						
							|  |  |  | 		if !testCase.EnvKeysSet { | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 			globalIsEnvCreds = false | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 			globalIsEnvCreds = true | 
					
						
							| 
									
										
										
										
											2017-01-25 00:08:36 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Construct setCreds request body
 | 
					
						
							|  |  |  | 		body, _ = xml.Marshal(setCredsReq{Username: testCase.Username, Password: testCase.Password}) | 
					
						
							|  |  |  | 		// Construct setCreds request
 | 
					
						
							|  |  |  | 		req, err := getServiceCmdRequest(setCreds, credentials, body) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Failed to build service status request %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rec := httptest.NewRecorder() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Execute request
 | 
					
						
							|  |  |  | 		adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Check if the http code response is expected
 | 
					
						
							|  |  |  | 		if rec.Code != testCase.ExpectedStatusCode { | 
					
						
							|  |  |  | 			t.Errorf("Test %d: Wrong status code, expected = %d, found = %d", i+1, testCase.ExpectedStatusCode, rec.Code) | 
					
						
							|  |  |  | 			resp, _ := ioutil.ReadAll(rec.Body) | 
					
						
							|  |  |  | 			t.Errorf("Expected to receive %d status code but received %d. Body (%s)", | 
					
						
							|  |  |  | 				http.StatusOK, rec.Code, string(resp)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// If we got 200 OK, check if new credentials are really set
 | 
					
						
							|  |  |  | 		if rec.Code == http.StatusOK { | 
					
						
							|  |  |  | 			cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 			if cred.AccessKey != testCase.Username { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: Wrong access key, expected = %s, found = %s", i+1, testCase.Username, cred.AccessKey) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if cred.SecretKey != testCase.Password { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: Wrong secret key, expected = %s, found = %s", i+1, testCase.Password, cred.SecretKey) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | // mkLockQueryVal - helper function to build lock query param.
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | func mkLockQueryVal(bucket, prefix, durationStr string) url.Values { | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	qVal := url.Values{} | 
					
						
							|  |  |  | 	qVal.Set("lock", "") | 
					
						
							|  |  |  | 	qVal.Set(string(mgmtBucket), bucket) | 
					
						
							|  |  |  | 	qVal.Set(string(mgmtPrefix), prefix) | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 	qVal.Set(string(mgmtLockDuration), durationStr) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	return qVal | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | // Test for locks list management REST API.
 | 
					
						
							|  |  |  | func TestListLocksHandler(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	defer adminTestBed.TearDown() | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize admin peers to make admin RPC calls.
 | 
					
						
							| 
									
										
										
										
											2017-02-10 15:26:44 +08:00
										 |  |  | 	eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to parse storage end point - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set globalMinioAddr to be able to distinguish local endpoints from remote.
 | 
					
						
							|  |  |  | 	globalMinioAddr = eps[0].Host | 
					
						
							|  |  |  | 	initGlobalAdminPeers(eps) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucket         string | 
					
						
							|  |  |  | 		prefix         string | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 		duration       string | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		expectedStatus int | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// Test 1 - valid testcase
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:         "mybucket", | 
					
						
							|  |  |  | 			prefix:         "myobject", | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 			duration:       "1s", | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 			expectedStatus: http.StatusOK, | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		// Test 2 - invalid duration
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:         "mybucket", | 
					
						
							|  |  |  | 			prefix:         "myprefix", | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 			duration:       "invalidDuration", | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 			expectedStatus: http.StatusBadRequest, | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		// Test 3 - invalid bucket name
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:         `invalid\\Bucket`, | 
					
						
							|  |  |  | 			prefix:         "myprefix", | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 			duration:       "1h", | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 			expectedStatus: http.StatusBadRequest, | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		// Test 4 - invalid prefix
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:         "mybucket", | 
					
						
							|  |  |  | 			prefix:         `invalid\\Prefix`, | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 			duration:       "1h", | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 			expectedStatus: http.StatusBadRequest, | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 		queryVal := mkLockQueryVal(test.bucket, test.prefix, test.duration) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 		req, err := newTestRequest("GET", "/?"+queryVal.Encode(), 0, nil) | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to construct list locks request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		req.Header.Set(minioAdminOpHeader, "list") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 		err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to sign list locks request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		if test.expectedStatus != rec.Code { | 
					
						
							|  |  |  | 			t.Errorf("Test %d - Expected HTTP status code %d but received %d", i+1, test.expectedStatus, rec.Code) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Test for locks clear management REST API.
 | 
					
						
							|  |  |  | func TestClearLocksHandler(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	defer adminTestBed.TearDown() | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize admin peers to make admin RPC calls.
 | 
					
						
							| 
									
										
										
										
											2017-02-10 15:26:44 +08:00
										 |  |  | 	eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to parse storage end point - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	initGlobalAdminPeers(eps) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucket         string | 
					
						
							|  |  |  | 		prefix         string | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 		duration       string | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		expectedStatus int | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// Test 1 - valid testcase
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:         "mybucket", | 
					
						
							|  |  |  | 			prefix:         "myobject", | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 			duration:       "1s", | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 			expectedStatus: http.StatusOK, | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		// Test 2 - invalid duration
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:         "mybucket", | 
					
						
							|  |  |  | 			prefix:         "myprefix", | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 			duration:       "invalidDuration", | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 			expectedStatus: http.StatusBadRequest, | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		// Test 3 - invalid bucket name
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:         `invalid\\Bucket`, | 
					
						
							|  |  |  | 			prefix:         "myprefix", | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 			duration:       "1h", | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 			expectedStatus: http.StatusBadRequest, | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		// Test 4 - invalid prefix
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:         "mybucket", | 
					
						
							|  |  |  | 			prefix:         `invalid\\Prefix`, | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 			duration:       "1h", | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 			expectedStatus: http.StatusBadRequest, | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							| 
									
										
										
										
											2017-02-02 03:17:30 +08:00
										 |  |  | 		queryVal := mkLockQueryVal(test.bucket, test.prefix, test.duration) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 		req, err := newTestRequest("POST", "/?"+queryVal.Encode(), 0, nil) | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to construct clear locks request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		req.Header.Set(minioAdminOpHeader, "clear") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 		err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to sign clear locks request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 		if test.expectedStatus != rec.Code { | 
					
						
							|  |  |  | 			t.Errorf("Test %d - Expected HTTP status code %d but received %d", i+1, test.expectedStatus, rec.Code) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Test for lock query param validation helper function.
 | 
					
						
							|  |  |  | func TestValidateLockQueryParams(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-08 03:27:01 +08:00
										 |  |  | 	// reset globals.
 | 
					
						
							|  |  |  | 	// this is to make sure that the tests are not affected by modified globals.
 | 
					
						
							|  |  |  | 	resetTestGlobals() | 
					
						
							|  |  |  | 	// initialize NSLock.
 | 
					
						
							|  |  |  | 	initNSLock(false) | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 	// Sample query values for test cases.
 | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	allValidVal := mkLockQueryVal("bucket", "prefix", "1s") | 
					
						
							|  |  |  | 	invalidBucketVal := mkLockQueryVal(`invalid\\Bucket`, "prefix", "1s") | 
					
						
							|  |  |  | 	invalidPrefixVal := mkLockQueryVal("bucket", `invalid\\Prefix`, "1s") | 
					
						
							|  |  |  | 	invalidOlderThanVal := mkLockQueryVal("bucket", "prefix", "invalidDuration") | 
					
						
							| 
									
										
										
										
											2017-01-04 15:39:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		qVals  url.Values | 
					
						
							|  |  |  | 		apiErr APIErrorCode | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			qVals:  invalidBucketVal, | 
					
						
							|  |  |  | 			apiErr: ErrInvalidBucketName, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			qVals:  invalidPrefixVal, | 
					
						
							|  |  |  | 			apiErr: ErrInvalidObjectName, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			qVals:  invalidOlderThanVal, | 
					
						
							|  |  |  | 			apiErr: ErrInvalidDuration, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			qVals:  allValidVal, | 
					
						
							|  |  |  | 			apiErr: ErrNone, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		_, _, _, apiErr := validateLockQueryParams(test.qVals) | 
					
						
							|  |  |  | 		if apiErr != test.apiErr { | 
					
						
							|  |  |  | 			t.Errorf("Test %d - Expected error %v but received %v", i+1, test.apiErr, apiErr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // mkListObjectsQueryStr - helper to build ListObjectsHeal query string.
 | 
					
						
							|  |  |  | func mkListObjectsQueryVal(bucket, prefix, marker, delimiter, maxKeyStr string) url.Values { | 
					
						
							|  |  |  | 	qVal := url.Values{} | 
					
						
							|  |  |  | 	qVal.Set("heal", "") | 
					
						
							|  |  |  | 	qVal.Set(string(mgmtBucket), bucket) | 
					
						
							|  |  |  | 	qVal.Set(string(mgmtPrefix), prefix) | 
					
						
							|  |  |  | 	qVal.Set(string(mgmtMarker), marker) | 
					
						
							|  |  |  | 	qVal.Set(string(mgmtDelimiter), delimiter) | 
					
						
							|  |  |  | 	qVal.Set(string(mgmtMaxKey), maxKeyStr) | 
					
						
							|  |  |  | 	return qVal | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestValidateHealQueryParams - Test for query param validation helper function for heal APIs.
 | 
					
						
							|  |  |  | func TestValidateHealQueryParams(t *testing.T) { | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucket    string | 
					
						
							|  |  |  | 		prefix    string | 
					
						
							|  |  |  | 		marker    string | 
					
						
							|  |  |  | 		delimiter string | 
					
						
							|  |  |  | 		maxKeys   string | 
					
						
							|  |  |  | 		apiErr    APIErrorCode | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// 1. Valid params.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:    "mybucket", | 
					
						
							|  |  |  | 			prefix:    "prefix", | 
					
						
							|  |  |  | 			marker:    "prefix11", | 
					
						
							|  |  |  | 			delimiter: "/", | 
					
						
							|  |  |  | 			maxKeys:   "10", | 
					
						
							|  |  |  | 			apiErr:    ErrNone, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 2. Valid params with meta bucket.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:    minioMetaBucket, | 
					
						
							|  |  |  | 			prefix:    "prefix", | 
					
						
							|  |  |  | 			marker:    "prefix11", | 
					
						
							|  |  |  | 			delimiter: "/", | 
					
						
							|  |  |  | 			maxKeys:   "10", | 
					
						
							|  |  |  | 			apiErr:    ErrNone, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 3. Valid params with empty prefix.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:    "mybucket", | 
					
						
							|  |  |  | 			prefix:    "", | 
					
						
							|  |  |  | 			marker:    "", | 
					
						
							|  |  |  | 			delimiter: "/", | 
					
						
							|  |  |  | 			maxKeys:   "10", | 
					
						
							|  |  |  | 			apiErr:    ErrNone, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 4. Invalid params with invalid bucket.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:    `invalid\\Bucket`, | 
					
						
							|  |  |  | 			prefix:    "prefix", | 
					
						
							|  |  |  | 			marker:    "prefix11", | 
					
						
							|  |  |  | 			delimiter: "/", | 
					
						
							|  |  |  | 			maxKeys:   "10", | 
					
						
							|  |  |  | 			apiErr:    ErrInvalidBucketName, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 5. Invalid params with invalid prefix.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:    "mybucket", | 
					
						
							|  |  |  | 			prefix:    `invalid\\Prefix`, | 
					
						
							|  |  |  | 			marker:    "prefix11", | 
					
						
							|  |  |  | 			delimiter: "/", | 
					
						
							|  |  |  | 			maxKeys:   "10", | 
					
						
							|  |  |  | 			apiErr:    ErrInvalidObjectName, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 6. Invalid params with invalid maxKeys.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:    "mybucket", | 
					
						
							|  |  |  | 			prefix:    "prefix", | 
					
						
							|  |  |  | 			marker:    "prefix11", | 
					
						
							|  |  |  | 			delimiter: "/", | 
					
						
							|  |  |  | 			maxKeys:   "-1", | 
					
						
							|  |  |  | 			apiErr:    ErrInvalidMaxKeys, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 7. Invalid params with unsupported prefix marker combination.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:    "mybucket", | 
					
						
							|  |  |  | 			prefix:    "prefix", | 
					
						
							|  |  |  | 			marker:    "notmatchingmarker", | 
					
						
							|  |  |  | 			delimiter: "/", | 
					
						
							|  |  |  | 			maxKeys:   "10", | 
					
						
							|  |  |  | 			apiErr:    ErrNotImplemented, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 8. Invalid params with unsupported delimiter.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:    "mybucket", | 
					
						
							|  |  |  | 			prefix:    "prefix", | 
					
						
							|  |  |  | 			marker:    "notmatchingmarker", | 
					
						
							|  |  |  | 			delimiter: "unsupported", | 
					
						
							|  |  |  | 			maxKeys:   "10", | 
					
						
							|  |  |  | 			apiErr:    ErrNotImplemented, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 9. Invalid params with invalid max Keys
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:    "mybucket", | 
					
						
							|  |  |  | 			prefix:    "prefix", | 
					
						
							|  |  |  | 			marker:    "prefix11", | 
					
						
							|  |  |  | 			delimiter: "/", | 
					
						
							|  |  |  | 			maxKeys:   "999999999999999999999999999", | 
					
						
							|  |  |  | 			apiErr:    ErrInvalidMaxKeys, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		vars := mkListObjectsQueryVal(test.bucket, test.prefix, test.marker, test.delimiter, test.maxKeys) | 
					
						
							| 
									
										
										
										
											2017-03-16 15:15:06 +08:00
										 |  |  | 		_, _, _, _, _, actualErr := extractListObjectsHealQuery(vars) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 		if actualErr != test.apiErr { | 
					
						
							|  |  |  | 			t.Errorf("Test %d - Expected %v but received %v", | 
					
						
							|  |  |  | 				i+1, getAPIError(test.apiErr), getAPIError(actualErr)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestListObjectsHeal - Test for ListObjectsHealHandler.
 | 
					
						
							|  |  |  | func TestListObjectsHealHandler(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	defer adminTestBed.TearDown() | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	err = adminTestBed.objLayer.MakeBucket("mybucket") | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to make bucket - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Delete bucket after running all test cases.
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	defer adminTestBed.objLayer.DeleteBucket("mybucket") | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucket     string | 
					
						
							|  |  |  | 		prefix     string | 
					
						
							|  |  |  | 		marker     string | 
					
						
							|  |  |  | 		delimiter  string | 
					
						
							|  |  |  | 		maxKeys    string | 
					
						
							|  |  |  | 		statusCode int | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// 1. Valid params.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			marker:     "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 2. Valid params with meta bucket.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     minioMetaBucket, | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			marker:     "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 3. Valid params with empty prefix.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "", | 
					
						
							|  |  |  | 			marker:     "", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 4. Invalid params with invalid bucket.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     `invalid\\Bucket`, | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			marker:     "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrInvalidBucketName).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 5. Invalid params with invalid prefix.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     `invalid\\Prefix`, | 
					
						
							|  |  |  | 			marker:     "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrInvalidObjectName).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 6. Invalid params with invalid maxKeys.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			marker:     "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "-1", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrInvalidMaxKeys).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 7. Invalid params with unsupported prefix marker combination.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			marker:     "notmatchingmarker", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrNotImplemented).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 8. Invalid params with unsupported delimiter.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			marker:     "notmatchingmarker", | 
					
						
							|  |  |  | 			delimiter:  "unsupported", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrNotImplemented).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 9. Invalid params with invalid max Keys
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			marker:     "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "999999999999999999999999999", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrInvalidMaxKeys).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		queryVal := mkListObjectsQueryVal(test.bucket, test.prefix, test.marker, test.delimiter, test.maxKeys) | 
					
						
							|  |  |  | 		req, err := newTestRequest("GET", "/?"+queryVal.Encode(), 0, nil) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to construct list objects needing heal request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-20 01:34:18 +08:00
										 |  |  | 		req.Header.Set(minioAdminOpHeader, "list-objects") | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 		err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to sign list objects needing heal request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 		if test.statusCode != rec.Code { | 
					
						
							|  |  |  | 			t.Errorf("Test %d - Expected HTTP status code %d but received %d", i+1, test.statusCode, rec.Code) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestHealBucketHandler - Test for HealBucketHandler.
 | 
					
						
							|  |  |  | func TestHealBucketHandler(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	defer adminTestBed.TearDown() | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	err = adminTestBed.objLayer.MakeBucket("mybucket") | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to make bucket - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Delete bucket after running all test cases.
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	defer adminTestBed.objLayer.DeleteBucket("mybucket") | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucket     string | 
					
						
							|  |  |  | 		statusCode int | 
					
						
							|  |  |  | 		dryrun     string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// 1. Valid test case.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			statusCode: http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 2. Invalid bucket name.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     `invalid\\Bucket`, | 
					
						
							|  |  |  | 			statusCode: http.StatusBadRequest, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 3. Bucket not found.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "bucketnotfound", | 
					
						
							|  |  |  | 			statusCode: http.StatusNotFound, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 4. Valid test case with dry-run.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			statusCode: http.StatusOK, | 
					
						
							|  |  |  | 			dryrun:     "yes", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		// Prepare query params.
 | 
					
						
							|  |  |  | 		queryVal := url.Values{} | 
					
						
							|  |  |  | 		queryVal.Set(string(mgmtBucket), test.bucket) | 
					
						
							|  |  |  | 		queryVal.Set("heal", "") | 
					
						
							|  |  |  | 		queryVal.Set(string(mgmtDryRun), test.dryrun) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		req, err := newTestRequest("POST", "/?"+queryVal.Encode(), 0, nil) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 			t.Fatalf("Test %d - Failed to construct heal bucket request - %v", | 
					
						
							|  |  |  | 				i+1, err) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		req.Header.Set(minioAdminOpHeader, "bucket") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 		err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 			t.Fatalf("Test %d - Failed to sign heal bucket request - %v", | 
					
						
							|  |  |  | 				i+1, err) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		rec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 		if test.statusCode != rec.Code { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 			t.Errorf("Test %d - Expected HTTP status code %d but received %d", | 
					
						
							|  |  |  | 				i+1, test.statusCode, rec.Code) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestHealObjectHandler - Test for HealObjectHandler.
 | 
					
						
							|  |  |  | func TestHealObjectHandler(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	defer adminTestBed.TearDown() | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Create an object myobject under bucket mybucket.
 | 
					
						
							|  |  |  | 	bucketName := "mybucket" | 
					
						
							|  |  |  | 	objName := "myobject" | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	err = adminTestBed.objLayer.MakeBucket(bucketName) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to make bucket %s - %v", bucketName, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	_, err = adminTestBed.objLayer.PutObject(bucketName, objName, | 
					
						
							|  |  |  | 		int64(len("hello")), bytes.NewReader([]byte("hello")), nil, "") | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to create %s - %v", objName, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Delete bucket and object after running all test cases.
 | 
					
						
							|  |  |  | 	defer func(objLayer ObjectLayer, bucketName, objName string) { | 
					
						
							|  |  |  | 		objLayer.DeleteObject(bucketName, objName) | 
					
						
							|  |  |  | 		objLayer.DeleteBucket(bucketName) | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 	}(adminTestBed.objLayer, bucketName, objName) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucket     string | 
					
						
							|  |  |  | 		object     string | 
					
						
							|  |  |  | 		dryrun     string | 
					
						
							|  |  |  | 		statusCode int | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// 1. Valid test case.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     bucketName, | 
					
						
							|  |  |  | 			object:     objName, | 
					
						
							|  |  |  | 			statusCode: http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 2. Invalid bucket name.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     `invalid\\Bucket`, | 
					
						
							|  |  |  | 			object:     "myobject", | 
					
						
							|  |  |  | 			statusCode: http.StatusBadRequest, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 3. Bucket not found.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "bucketnotfound", | 
					
						
							|  |  |  | 			object:     "myobject", | 
					
						
							|  |  |  | 			statusCode: http.StatusNotFound, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 4. Invalid object name.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     bucketName, | 
					
						
							|  |  |  | 			object:     `invalid\\Object`, | 
					
						
							|  |  |  | 			statusCode: http.StatusBadRequest, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 5. Object not found.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     bucketName, | 
					
						
							|  |  |  | 			object:     "objectnotfound", | 
					
						
							|  |  |  | 			statusCode: http.StatusNotFound, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 6. Valid test case with dry-run.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     bucketName, | 
					
						
							|  |  |  | 			object:     objName, | 
					
						
							|  |  |  | 			dryrun:     "yes", | 
					
						
							|  |  |  | 			statusCode: http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		// Prepare query params.
 | 
					
						
							|  |  |  | 		queryVal := url.Values{} | 
					
						
							|  |  |  | 		queryVal.Set(string(mgmtBucket), test.bucket) | 
					
						
							|  |  |  | 		queryVal.Set(string(mgmtObject), test.object) | 
					
						
							|  |  |  | 		queryVal.Set("heal", "") | 
					
						
							|  |  |  | 		queryVal.Set(string(mgmtDryRun), test.dryrun) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		req, err := newTestRequest("POST", "/?"+queryVal.Encode(), 0, nil) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to construct heal object request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		req.Header.Set(minioAdminOpHeader, "object") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 		err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to sign heal object request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rec := httptest.NewRecorder() | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 		adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							| 
									
										
										
										
											2017-01-18 02:02:58 +08:00
										 |  |  | 		if test.statusCode != rec.Code { | 
					
						
							|  |  |  | 			t.Errorf("Test %d - Expected HTTP status code %d but received %d", i+1, test.statusCode, rec.Code) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-01-23 16:32:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestHealFormatHandler - test for HealFormatHandler.
 | 
					
						
							|  |  |  | func TestHealFormatHandler(t *testing.T) { | 
					
						
							|  |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer adminTestBed.TearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Prepare query params for heal-format mgmt REST API.
 | 
					
						
							|  |  |  | 	queryVal := url.Values{} | 
					
						
							|  |  |  | 	queryVal.Set("heal", "") | 
					
						
							|  |  |  | 	req, err := newTestRequest("POST", "/?"+queryVal.Encode(), 0, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to construct heal object request - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set x-minio-operation header to format.
 | 
					
						
							|  |  |  | 	req.Header.Set(minioAdminOpHeader, "format") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Sign the request using signature v4.
 | 
					
						
							|  |  |  | 	cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 	err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to sign heal object request - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rec := httptest.NewRecorder() | 
					
						
							|  |  |  | 	adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							|  |  |  | 	if rec.Code != http.StatusOK { | 
					
						
							|  |  |  | 		t.Errorf("Expected to succeed but failed with %d", rec.Code) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-02-21 04:58:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestGetConfigHandler - test for GetConfigHandler.
 | 
					
						
							|  |  |  | func TestGetConfigHandler(t *testing.T) { | 
					
						
							|  |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer adminTestBed.TearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize admin peers to make admin RPC calls.
 | 
					
						
							|  |  |  | 	eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to parse storage end point - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set globalMinioAddr to be able to distinguish local endpoints from remote.
 | 
					
						
							|  |  |  | 	globalMinioAddr = eps[0].Host | 
					
						
							|  |  |  | 	initGlobalAdminPeers(eps) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Prepare query params for get-config mgmt REST API.
 | 
					
						
							|  |  |  | 	queryVal := url.Values{} | 
					
						
							|  |  |  | 	queryVal.Set("config", "") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req, err := newTestRequest("GET", "/?"+queryVal.Encode(), 0, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to construct get-config object request - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set x-minio-operation header to get.
 | 
					
						
							|  |  |  | 	req.Header.Set(minioAdminOpHeader, "get") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Sign the request using signature v4.
 | 
					
						
							|  |  |  | 	cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 	err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to sign heal object request - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rec := httptest.NewRecorder() | 
					
						
							|  |  |  | 	adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							|  |  |  | 	if rec.Code != http.StatusOK { | 
					
						
							|  |  |  | 		t.Errorf("Expected to succeed but failed with %d", rec.Code) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestSetConfigHandler - test for SetConfigHandler.
 | 
					
						
							|  |  |  | func TestSetConfigHandler(t *testing.T) { | 
					
						
							|  |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer adminTestBed.TearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize admin peers to make admin RPC calls.
 | 
					
						
							|  |  |  | 	eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to parse storage end point - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set globalMinioAddr to be able to distinguish local endpoints from remote.
 | 
					
						
							|  |  |  | 	globalMinioAddr = eps[0].Host | 
					
						
							|  |  |  | 	initGlobalAdminPeers(eps) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// SetConfigHandler restarts minio setup - need to start a
 | 
					
						
							|  |  |  | 	// signal receiver to receive on globalServiceSignalCh.
 | 
					
						
							|  |  |  | 	go testServiceSignalReceiver(restartCmd, t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Prepare query params for set-config mgmt REST API.
 | 
					
						
							|  |  |  | 	queryVal := url.Values{} | 
					
						
							|  |  |  | 	queryVal.Set("config", "") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req, err := newTestRequest("PUT", "/?"+queryVal.Encode(), int64(len(configJSON)), bytes.NewReader(configJSON)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to construct get-config object request - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set x-minio-operation header to set.
 | 
					
						
							|  |  |  | 	req.Header.Set(minioAdminOpHeader, "set") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Sign the request using signature v4.
 | 
					
						
							|  |  |  | 	cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 	err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to sign heal object request - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rec := httptest.NewRecorder() | 
					
						
							|  |  |  | 	adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							|  |  |  | 	if rec.Code != http.StatusOK { | 
					
						
							|  |  |  | 		t.Errorf("Expected to succeed but failed with %d", rec.Code) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result := setConfigResult{} | 
					
						
							|  |  |  | 	err = json.NewDecoder(rec.Body).Decode(&result) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to decode set config result json %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-09 02:00:47 +08:00
										 |  |  | 	if !result.Status { | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 		t.Error("Expected set-config to succeed, but failed") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestToAdminAPIErr - test for toAdminAPIErr helper function.
 | 
					
						
							|  |  |  | func TestToAdminAPIErr(t *testing.T) { | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		err            error | 
					
						
							|  |  |  | 		expectedAPIErr APIErrorCode | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// 1. Server not in quorum.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			err:            errXLWriteQuorum, | 
					
						
							|  |  |  | 			expectedAPIErr: ErrAdminConfigNoQuorum, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 2. No error.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			err:            nil, | 
					
						
							|  |  |  | 			expectedAPIErr: ErrNone, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 3. Non-admin API specific error.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			err:            errDiskNotFound, | 
					
						
							|  |  |  | 			expectedAPIErr: toAPIErrorCode(errDiskNotFound), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		actualErr := toAdminAPIErrCode(test.err) | 
					
						
							|  |  |  | 		if actualErr != test.expectedAPIErr { | 
					
						
							|  |  |  | 			t.Errorf("Test %d: Expected %v but received %v", | 
					
						
							|  |  |  | 				i+1, test.expectedAPIErr, actualErr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestWriteSetConfigResponse(t *testing.T) { | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		status bool | 
					
						
							|  |  |  | 		errs   []error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// 1. all nodes returned success.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			status: true, | 
					
						
							|  |  |  | 			errs:   []error{nil, nil, nil, nil}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 2. some nodes returned errors.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			status: false, | 
					
						
							|  |  |  | 			errs:   []error{errDiskNotFound, nil, errDiskAccessDenied, errFaultyDisk}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testPeers := []adminPeer{ | 
					
						
							| 
									
										
										
										
											2017-03-04 02:14:17 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 			addr: "localhost:9001", | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-03-04 02:14:17 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 			addr: "localhost:9002", | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-03-04 02:14:17 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 			addr: "localhost:9003", | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-03-04 02:14:17 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 			addr: "localhost:9004", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testURL, err := url.Parse("dummy.com") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to parse a place-holder url") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var actualResult setConfigResult | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		rec := httptest.NewRecorder() | 
					
						
							|  |  |  | 		writeSetConfigResponse(rec, testPeers, test.errs, test.status, testURL) | 
					
						
							|  |  |  | 		resp := rec.Result() | 
					
						
							|  |  |  | 		jsonBytes, err := ioutil.ReadAll(resp.Body) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d: Failed to read response %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		err = json.Unmarshal(jsonBytes, &actualResult) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d: Failed to unmarshal json %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if actualResult.Status != test.status { | 
					
						
							|  |  |  | 			t.Errorf("Test %d: Expected status %v but received %v", i+1, test.status, actualResult.Status) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for p, res := range actualResult.NodeResults { | 
					
						
							|  |  |  | 			if res.Name != testPeers[p].addr { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: Expected node name %s but received %s", i+1, testPeers[p].addr, res.Name) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-03-03 18:53:48 +08:00
										 |  |  | 			expectedErrMsg := fmt.Sprintf("%v", test.errs[p]) | 
					
						
							|  |  |  | 			if res.ErrMsg != expectedErrMsg { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: Expected error %s but received %s", i+1, expectedErrMsg, res.ErrMsg) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			expectedErrSet := test.errs[p] != nil | 
					
						
							|  |  |  | 			if res.ErrSet != expectedErrSet { | 
					
						
							|  |  |  | 				t.Errorf("Test %d: Expected ErrSet %v but received %v", i+1, expectedErrSet, res.ErrSet) | 
					
						
							| 
									
										
										
										
											2017-02-28 03:40:27 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-03-16 15:15:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // mkUploadsHealQuery - helper function to construct query values for
 | 
					
						
							|  |  |  | // listUploadsHeal.
 | 
					
						
							|  |  |  | func mkUploadsHealQuery(bucket, prefix, keyMarker, uploadIDMarker, delimiter, maxUploadsStr string) url.Values { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	queryVal := make(url.Values) | 
					
						
							|  |  |  | 	queryVal.Set("heal", "") | 
					
						
							|  |  |  | 	queryVal.Set(string(mgmtBucket), bucket) | 
					
						
							|  |  |  | 	queryVal.Set(string(mgmtPrefix), prefix) | 
					
						
							|  |  |  | 	queryVal.Set(string(mgmtKeyMarker), keyMarker) | 
					
						
							|  |  |  | 	queryVal.Set(string(mgmtUploadIDMarker), uploadIDMarker) | 
					
						
							|  |  |  | 	queryVal.Set(string(mgmtDelimiter), delimiter) | 
					
						
							|  |  |  | 	queryVal.Set(string(mgmtMaxUploads), maxUploadsStr) | 
					
						
							|  |  |  | 	return queryVal | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestListHealUploadsHandler(t *testing.T) { | 
					
						
							|  |  |  | 	adminTestBed, err := prepareAdminXLTestBed() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to initialize a single node XL backend for admin handler tests.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer adminTestBed.TearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = adminTestBed.objLayer.MakeBucket("mybucket") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to make bucket - %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Delete bucket after running all test cases.
 | 
					
						
							|  |  |  | 	defer adminTestBed.objLayer.DeleteBucket("mybucket") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testCases := []struct { | 
					
						
							|  |  |  | 		bucket     string | 
					
						
							|  |  |  | 		prefix     string | 
					
						
							|  |  |  | 		keyMarker  string | 
					
						
							|  |  |  | 		delimiter  string | 
					
						
							|  |  |  | 		maxKeys    string | 
					
						
							|  |  |  | 		statusCode int | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		// 1. Valid params.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			keyMarker:  "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 2. Valid params with empty prefix.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "", | 
					
						
							|  |  |  | 			keyMarker:  "", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 3. Invalid params with invalid bucket.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     `invalid\\Bucket`, | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			keyMarker:  "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrInvalidBucketName).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 4. Invalid params with invalid prefix.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     `invalid\\Prefix`, | 
					
						
							|  |  |  | 			keyMarker:  "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrInvalidObjectName).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 5. Invalid params with invalid maxKeys.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			keyMarker:  "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "-1", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrInvalidMaxUploads).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 6. Invalid params with unsupported prefix marker combination.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			keyMarker:  "notmatchingmarker", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrNotImplemented).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 7. Invalid params with unsupported delimiter.
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			keyMarker:  "notmatchingmarker", | 
					
						
							|  |  |  | 			delimiter:  "unsupported", | 
					
						
							|  |  |  | 			maxKeys:    "10", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrNotImplemented).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// 8. Invalid params with invalid max Keys
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bucket:     "mybucket", | 
					
						
							|  |  |  | 			prefix:     "prefix", | 
					
						
							|  |  |  | 			keyMarker:  "prefix11", | 
					
						
							|  |  |  | 			delimiter:  "/", | 
					
						
							|  |  |  | 			maxKeys:    "999999999999999999999999999", | 
					
						
							|  |  |  | 			statusCode: getAPIError(ErrInvalidMaxUploads).HTTPStatusCode, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, test := range testCases { | 
					
						
							|  |  |  | 		queryVal := mkUploadsHealQuery(test.bucket, test.prefix, test.keyMarker, "", test.delimiter, test.maxKeys) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		req, err := newTestRequest("GET", "/?"+queryVal.Encode(), 0, nil) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to construct list uploads needing heal request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		req.Header.Set(minioAdminOpHeader, "list-uploads") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cred := serverConfig.GetCredential() | 
					
						
							|  |  |  | 		err = signRequestV4(req, cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Test %d - Failed to sign list uploads needing heal request - %v", i+1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rec := httptest.NewRecorder() | 
					
						
							|  |  |  | 		adminTestBed.mux.ServeHTTP(rec, req) | 
					
						
							|  |  |  | 		if test.statusCode != rec.Code { | 
					
						
							|  |  |  | 			t.Errorf("Test %d - Expected HTTP status code %d but received %d", i+1, test.statusCode, rec.Code) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |