| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Minio Cloud Storage, (C) 2017 Minio, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2018-03-16 04:27:16 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	"errors" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestParseStorageClass(t *testing.T) { | 
					
						
							|  |  |  | 	ExecObjectLayerTest(t, testParseStorageClass) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testParseStorageClass(obj ObjectLayer, instanceType string, t TestErrHandler) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		storageClassEnv string | 
					
						
							|  |  |  | 		wantSc          storageClass | 
					
						
							|  |  |  | 		expectedError   error | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		{"EC:3", storageClass{ | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			Scheme: "EC", | 
					
						
							|  |  |  | 			Parity: 3}, | 
					
						
							|  |  |  | 			nil}, | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		{"EC:4", storageClass{ | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			Scheme: "EC", | 
					
						
							|  |  |  | 			Parity: 4}, | 
					
						
							|  |  |  | 			nil}, | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		{"AB:4", storageClass{ | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			Scheme: "EC", | 
					
						
							|  |  |  | 			Parity: 4}, | 
					
						
							|  |  |  | 			errors.New("Unsupported scheme AB. Supported scheme is EC")}, | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		{"EC:4:5", storageClass{ | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			Scheme: "EC", | 
					
						
							|  |  |  | 			Parity: 4}, | 
					
						
							|  |  |  | 			errors.New("Too many sections in EC:4:5")}, | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		{"AB", storageClass{ | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			Scheme: "EC", | 
					
						
							|  |  |  | 			Parity: 4}, | 
					
						
							|  |  |  | 			errors.New("Too few sections in AB")}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 	for i, tt := range tests { | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		gotSc, err := parseStorageClass(tt.storageClassEnv) | 
					
						
							|  |  |  | 		if err != nil && tt.expectedError == nil { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected %s, got %s", i+1, tt.expectedError, err) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err == nil && tt.expectedError != nil { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected %s, got %s", i+1, tt.expectedError, err) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tt.expectedError == nil && !reflect.DeepEqual(gotSc, tt.wantSc) { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected %v, got %v", i+1, tt.wantSc, gotSc) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-09 10:04:36 +08:00
										 |  |  | 		if tt.expectedError != nil && err.Error() != tt.expectedError.Error() { | 
					
						
							|  |  |  | 			t.Errorf("Test %d, Expected `%v`, got `%v`", i+1, tt.expectedError, err) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | func TestValidateParity(t *testing.T) { | 
					
						
							|  |  |  | 	ExecObjectLayerTestWithDirs(t, testValidateParity) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | func testValidateParity(obj ObjectLayer, instanceType string, dirs []string, t TestErrHandler) { | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	// Reset global storage class flags
 | 
					
						
							|  |  |  | 	resetGlobalStorageEnvs() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 	// Set proper envs for a single node XL setup.
 | 
					
						
							|  |  |  | 	saveIsXL := globalIsXL | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 	defer func() { | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 		globalIsXL = saveIsXL | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 	globalIsXL = true | 
					
						
							|  |  |  | 	saveSetDriveCount := globalXLSetDriveCount | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 	defer func() { | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 		globalXLSetDriveCount = saveSetDriveCount | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 	globalXLSetCount = len(dirs) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		rrsParity int | 
					
						
							|  |  |  | 		ssParity  int | 
					
						
							|  |  |  | 		success   bool | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		{2, 4, true}, | 
					
						
							|  |  |  | 		{3, 3, true}, | 
					
						
							|  |  |  | 		{1, 4, false}, | 
					
						
							|  |  |  | 		{7, 6, false}, | 
					
						
							|  |  |  | 		{9, 0, false}, | 
					
						
							|  |  |  | 		{9, 9, false}, | 
					
						
							|  |  |  | 		{2, 9, false}, | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 	for i, tt := range tests { | 
					
						
							|  |  |  | 		err := validateParity(tt.ssParity, tt.rrsParity) | 
					
						
							|  |  |  | 		if err != nil && tt.success { | 
					
						
							|  |  |  | 			t.Errorf("Test %d, Expected success, got %s", i+1, err) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		if err == nil && !tt.success { | 
					
						
							|  |  |  | 			t.Errorf("Test %d, Expected failure, got success", i+1) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-27 12:36:16 +08:00
										 |  |  | func TestRedundancyCount(t *testing.T) { | 
					
						
							|  |  |  | 	ExecObjectLayerTestWithDirs(t, testGetRedundancyCount) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-27 12:36:16 +08:00
										 |  |  | func testGetRedundancyCount(obj ObjectLayer, instanceType string, dirs []string, t TestErrHandler) { | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	// Reset global storage class flags
 | 
					
						
							|  |  |  | 	resetGlobalStorageEnvs() | 
					
						
							|  |  |  | 	xl := obj.(*xlObjects) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		sc             string | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 		disksCount     int | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		expectedData   int | 
					
						
							|  |  |  | 		expectedParity int | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 		{reducedRedundancyStorageClass, len(xl.storageDisks), 14, 2}, | 
					
						
							|  |  |  | 		{standardStorageClass, len(xl.storageDisks), 8, 8}, | 
					
						
							|  |  |  | 		{"", len(xl.storageDisks), 8, 8}, | 
					
						
							|  |  |  | 		{reducedRedundancyStorageClass, len(xl.storageDisks), 9, 7}, | 
					
						
							|  |  |  | 		{standardStorageClass, len(xl.storageDisks), 10, 6}, | 
					
						
							|  |  |  | 		{"", len(xl.storageDisks), 9, 7}, | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 	for i, tt := range tests { | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		// Set env var for test case 4
 | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		if i+1 == 4 { | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			globalRRStorageClass.Parity = 7 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Set env var for test case 5
 | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		if i+1 == 5 { | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			globalStandardStorageClass.Parity = 6 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-11 17:28:12 +08:00
										 |  |  | 		// Set env var for test case 6
 | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		if i+1 == 6 { | 
					
						
							| 
									
										
										
										
											2018-01-11 17:28:12 +08:00
										 |  |  | 			globalStandardStorageClass.Parity = 7 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-16 09:45:57 +08:00
										 |  |  | 		data, parity := getRedundancyCount(tt.sc, tt.disksCount) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		if data != tt.expectedData { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected data disks %d, got %d", i+1, tt.expectedData, data) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if parity != tt.expectedParity { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected parity disks %d, got %d", i+1, tt.expectedParity, parity) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestObjectQuorumFromMeta(t *testing.T) { | 
					
						
							|  |  |  | 	ExecObjectLayerTestWithDirs(t, testObjectQuorumFromMeta) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testObjectQuorumFromMeta(obj ObjectLayer, instanceType string, dirs []string, t TestErrHandler) { | 
					
						
							|  |  |  | 	// Reset global storage class flags
 | 
					
						
							|  |  |  | 	resetGlobalStorageEnvs() | 
					
						
							|  |  |  | 	bucket := getRandomBucketName() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// make data with more than one part
 | 
					
						
							|  |  |  | 	partCount := 3 | 
					
						
							|  |  |  | 	data := bytes.Repeat([]byte("a"), int(globalPutPartSize)*partCount) | 
					
						
							|  |  |  | 	xl := obj.(*xlObjects) | 
					
						
							|  |  |  | 	xlDisks := xl.storageDisks | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 04:27:16 +08:00
										 |  |  | 	err := obj.MakeBucketWithLocation(context.Background(), bucket, globalMinioDefaultRegion) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to make a bucket %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Object for test case 1 - No StorageClass defined, no MetaData in PutObject
 | 
					
						
							|  |  |  | 	object1 := "object1" | 
					
						
							| 
									
										
										
										
											2018-03-16 04:27:16 +08:00
										 |  |  | 	_, err = obj.PutObject(context.Background(), bucket, object1, mustGetHashReader(t, bytes.NewReader(data), int64(len(data)), "", ""), nil) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to putObject %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	parts1, errs1 := readAllXLMetadata(context.Background(), xlDisks, bucket, object1) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Object for test case 2 - No StorageClass defined, MetaData in PutObject requesting RRS Class
 | 
					
						
							|  |  |  | 	object2 := "object2" | 
					
						
							|  |  |  | 	metadata2 := make(map[string]string) | 
					
						
							|  |  |  | 	metadata2["x-amz-storage-class"] = reducedRedundancyStorageClass | 
					
						
							| 
									
										
										
										
											2018-03-16 04:27:16 +08:00
										 |  |  | 	_, err = obj.PutObject(context.Background(), bucket, object2, mustGetHashReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata2) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to putObject %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	parts2, errs2 := readAllXLMetadata(context.Background(), xlDisks, bucket, object2) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Object for test case 3 - No StorageClass defined, MetaData in PutObject requesting Standard Storage Class
 | 
					
						
							|  |  |  | 	object3 := "object3" | 
					
						
							|  |  |  | 	metadata3 := make(map[string]string) | 
					
						
							|  |  |  | 	metadata3["x-amz-storage-class"] = standardStorageClass | 
					
						
							| 
									
										
										
										
											2018-03-16 04:27:16 +08:00
										 |  |  | 	_, err = obj.PutObject(context.Background(), bucket, object3, mustGetHashReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata3) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to putObject %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	parts3, errs3 := readAllXLMetadata(context.Background(), xlDisks, bucket, object3) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Object for test case 4 - Standard StorageClass defined as Parity 6, MetaData in PutObject requesting Standard Storage Class
 | 
					
						
							|  |  |  | 	object4 := "object4" | 
					
						
							|  |  |  | 	metadata4 := make(map[string]string) | 
					
						
							|  |  |  | 	metadata4["x-amz-storage-class"] = standardStorageClass | 
					
						
							|  |  |  | 	globalStandardStorageClass = storageClass{ | 
					
						
							|  |  |  | 		Parity: 6, | 
					
						
							|  |  |  | 		Scheme: "EC", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 04:27:16 +08:00
										 |  |  | 	_, err = obj.PutObject(context.Background(), bucket, object4, mustGetHashReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata4) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to putObject %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	parts4, errs4 := readAllXLMetadata(context.Background(), xlDisks, bucket, object4) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Object for test case 5 - RRS StorageClass defined as Parity 2, MetaData in PutObject requesting RRS Class
 | 
					
						
							|  |  |  | 	// Reset global storage class flags
 | 
					
						
							|  |  |  | 	resetGlobalStorageEnvs() | 
					
						
							|  |  |  | 	object5 := "object5" | 
					
						
							|  |  |  | 	metadata5 := make(map[string]string) | 
					
						
							|  |  |  | 	metadata5["x-amz-storage-class"] = reducedRedundancyStorageClass | 
					
						
							|  |  |  | 	globalRRStorageClass = storageClass{ | 
					
						
							|  |  |  | 		Parity: 2, | 
					
						
							|  |  |  | 		Scheme: "EC", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 04:27:16 +08:00
										 |  |  | 	_, err = obj.PutObject(context.Background(), bucket, object5, mustGetHashReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata5) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to putObject %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	parts5, errs5 := readAllXLMetadata(context.Background(), xlDisks, bucket, object5) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Object for test case 6 - RRS StorageClass defined as Parity 2, MetaData in PutObject requesting Standard Storage Class
 | 
					
						
							|  |  |  | 	// Reset global storage class flags
 | 
					
						
							|  |  |  | 	resetGlobalStorageEnvs() | 
					
						
							|  |  |  | 	object6 := "object6" | 
					
						
							|  |  |  | 	metadata6 := make(map[string]string) | 
					
						
							|  |  |  | 	metadata6["x-amz-storage-class"] = standardStorageClass | 
					
						
							|  |  |  | 	globalRRStorageClass = storageClass{ | 
					
						
							|  |  |  | 		Parity: 2, | 
					
						
							|  |  |  | 		Scheme: "EC", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 04:27:16 +08:00
										 |  |  | 	_, err = obj.PutObject(context.Background(), bucket, object6, mustGetHashReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata6) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to putObject %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	parts6, errs6 := readAllXLMetadata(context.Background(), xlDisks, bucket, object6) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Object for test case 7 - Standard StorageClass defined as Parity 5, MetaData in PutObject requesting RRS Class
 | 
					
						
							|  |  |  | 	// Reset global storage class flags
 | 
					
						
							|  |  |  | 	resetGlobalStorageEnvs() | 
					
						
							|  |  |  | 	object7 := "object7" | 
					
						
							|  |  |  | 	metadata7 := make(map[string]string) | 
					
						
							|  |  |  | 	metadata7["x-amz-storage-class"] = reducedRedundancyStorageClass | 
					
						
							|  |  |  | 	globalStandardStorageClass = storageClass{ | 
					
						
							|  |  |  | 		Parity: 5, | 
					
						
							|  |  |  | 		Scheme: "EC", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 04:27:16 +08:00
										 |  |  | 	_, err = obj.PutObject(context.Background(), bucket, object7, mustGetHashReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata7) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to putObject %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	parts7, errs7 := readAllXLMetadata(context.Background(), xlDisks, bucket, object7) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		parts               []xlMetaV1 | 
					
						
							|  |  |  | 		errs                []error | 
					
						
							|  |  |  | 		expectedReadQuorum  int | 
					
						
							|  |  |  | 		expectedWriteQuorum int | 
					
						
							|  |  |  | 		expectedError       error | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		{parts1, errs1, 8, 9, nil}, | 
					
						
							|  |  |  | 		{parts2, errs2, 14, 15, nil}, | 
					
						
							|  |  |  | 		{parts3, errs3, 8, 9, nil}, | 
					
						
							|  |  |  | 		{parts4, errs4, 10, 11, nil}, | 
					
						
							|  |  |  | 		{parts5, errs5, 14, 15, nil}, | 
					
						
							|  |  |  | 		{parts6, errs6, 8, 9, nil}, | 
					
						
							|  |  |  | 		{parts7, errs7, 14, 15, nil}, | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 	for i, tt := range tests { | 
					
						
							|  |  |  | 		actualReadQuorum, actualWriteQuorum, err := objectQuorumFromMeta(*xl, tt.parts, tt.errs) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 		if tt.expectedError != nil && err == nil { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected %s, got %s", i+1, tt.expectedError, err) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tt.expectedError == nil && err != nil { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected %s, got %s", i+1, tt.expectedError, err) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tt.expectedReadQuorum != actualReadQuorum { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected Read Quorum %d, got %d", i+1, tt.expectedReadQuorum, actualReadQuorum) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tt.expectedWriteQuorum != actualWriteQuorum { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected Write Quorum %d, got %d", i+1, tt.expectedWriteQuorum, actualWriteQuorum) | 
					
						
							| 
									
										
										
										
											2017-12-22 19:28:13 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-12-27 12:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Test isValidStorageClassMeta method with valid and invalid inputs
 | 
					
						
							|  |  |  | func TestIsValidStorageClassMeta(t *testing.T) { | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		sc   string | 
					
						
							|  |  |  | 		want bool | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 		{"STANDARD", true}, | 
					
						
							|  |  |  | 		{"REDUCED_REDUNDANCY", true}, | 
					
						
							|  |  |  | 		{"", false}, | 
					
						
							|  |  |  | 		{"INVALID", false}, | 
					
						
							|  |  |  | 		{"123", false}, | 
					
						
							|  |  |  | 		{"MINIO_STORAGE_CLASS_RRS", false}, | 
					
						
							|  |  |  | 		{"MINIO_STORAGE_CLASS_STANDARD", false}, | 
					
						
							| 
									
										
										
										
											2017-12-27 12:36:16 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 	for i, tt := range tests { | 
					
						
							| 
									
										
										
										
											2017-12-27 12:36:16 +08:00
										 |  |  | 		if got := isValidStorageClassMeta(tt.sc); got != tt.want { | 
					
						
							| 
									
										
										
										
											2018-02-01 15:30:07 +08:00
										 |  |  | 			t.Errorf("Test %d, Expected Storage Class to be %t, got %t", i+1, tt.want, got) | 
					
						
							| 
									
										
										
										
											2017-12-27 12:36:16 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |