mirror of https://github.com/minio/minio.git
				
				
				
			
		
			
				
	
	
		
			1057 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			1057 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
|  * Minio Cloud Storage, (C) 2016, 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"
 | |
| 	"errors"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"testing"
 | |
| 
 | |
| 	errors2 "github.com/minio/minio/pkg/errors"
 | |
| 	"github.com/minio/minio/pkg/hash"
 | |
| 	"github.com/minio/minio/pkg/lock"
 | |
| )
 | |
| 
 | |
| // generates a valid format.json for XL backend.
 | |
| func genFormatXLValid() []*formatConfigV1 {
 | |
| 	jbod := make([]string, 8)
 | |
| 	formatConfigs := make([]*formatConfigV1, 8)
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		formatConfigs[index] = &formatConfigV1{
 | |
| 			Version: formatFileV1,
 | |
| 			Format:  formatBackendXL,
 | |
| 			XL: &xlFormat{
 | |
| 				Version: xlFormatBackendV1,
 | |
| 				Disk:    jbod[index],
 | |
| 				JBOD:    jbod,
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 	return formatConfigs
 | |
| }
 | |
| 
 | |
| // generates a invalid format.json version for XL backend.
 | |
| func genFormatXLInvalidVersion() []*formatConfigV1 {
 | |
| 	jbod := make([]string, 8)
 | |
| 	formatConfigs := make([]*formatConfigV1, 8)
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		formatConfigs[index] = &formatConfigV1{
 | |
| 			Version: formatFileV1,
 | |
| 			Format:  formatBackendXL,
 | |
| 			XL: &xlFormat{
 | |
| 				Version: xlFormatBackendV1,
 | |
| 				Disk:    jbod[index],
 | |
| 				JBOD:    jbod,
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 	// Corrupt version numbers.
 | |
| 	formatConfigs[0].Version = "2"
 | |
| 	formatConfigs[3].Version = "-1"
 | |
| 	return formatConfigs
 | |
| }
 | |
| 
 | |
| // generates a invalid format.json version for XL backend.
 | |
| func genFormatXLInvalidFormat() []*formatConfigV1 {
 | |
| 	jbod := make([]string, 8)
 | |
| 	formatConfigs := make([]*formatConfigV1, 8)
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		formatConfigs[index] = &formatConfigV1{
 | |
| 			Version: formatFileV1,
 | |
| 			Format:  formatBackendXL,
 | |
| 			XL: &xlFormat{
 | |
| 				Version: xlFormatBackendV1,
 | |
| 				Disk:    jbod[index],
 | |
| 				JBOD:    jbod,
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 	// Corrupt version numbers.
 | |
| 	formatConfigs[0].Format = "lx"
 | |
| 	formatConfigs[3].Format = "lx"
 | |
| 	return formatConfigs
 | |
| }
 | |
| 
 | |
| // generates a invalid format.json version for XL backend.
 | |
| func genFormatXLInvalidXLVersion() []*formatConfigV1 {
 | |
| 	jbod := make([]string, 8)
 | |
| 	formatConfigs := make([]*formatConfigV1, 8)
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		formatConfigs[index] = &formatConfigV1{
 | |
| 			Version: formatFileV1,
 | |
| 			Format:  formatBackendXL,
 | |
| 			XL: &xlFormat{
 | |
| 				Version: xlFormatBackendV1,
 | |
| 				Disk:    jbod[index],
 | |
| 				JBOD:    jbod,
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 	// Corrupt version numbers.
 | |
| 	formatConfigs[0].XL.Version = "10"
 | |
| 	formatConfigs[3].XL.Version = "-1"
 | |
| 	return formatConfigs
 | |
| }
 | |
| 
 | |
| func genFormatFS() *formatConfigV1 {
 | |
| 	return &formatConfigV1{
 | |
| 		Version: formatFileV1,
 | |
| 		Format:  formatBackendFS,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // generates a invalid format.json version for XL backend.
 | |
| func genFormatXLInvalidJBODCount() []*formatConfigV1 {
 | |
| 	jbod := make([]string, 7)
 | |
| 	formatConfigs := make([]*formatConfigV1, 8)
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		formatConfigs[index] = &formatConfigV1{
 | |
| 			Version: formatFileV1,
 | |
| 			Format:  formatBackendXL,
 | |
| 			XL: &xlFormat{
 | |
| 				Version: xlFormatBackendV1,
 | |
| 				Disk:    jbod[index],
 | |
| 				JBOD:    jbod,
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 	return formatConfigs
 | |
| }
 | |
| 
 | |
| // generates a invalid format.json JBOD for XL backend.
 | |
| func genFormatXLInvalidJBOD() []*formatConfigV1 {
 | |
| 	jbod := make([]string, 8)
 | |
| 	formatConfigs := make([]*formatConfigV1, 8)
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		formatConfigs[index] = &formatConfigV1{
 | |
| 			Version: formatFileV1,
 | |
| 			Format:  formatBackendXL,
 | |
| 			XL: &xlFormat{
 | |
| 				Version: xlFormatBackendV1,
 | |
| 				Disk:    jbod[index],
 | |
| 				JBOD:    jbod,
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 	}
 | |
| 	// Corrupt JBOD entries on disk 6 and disk 8.
 | |
| 	formatConfigs[5].XL.JBOD = jbod
 | |
| 	formatConfigs[7].XL.JBOD = jbod
 | |
| 	return formatConfigs
 | |
| }
 | |
| 
 | |
| // generates a invalid format.json Disk UUID for XL backend.
 | |
| func genFormatXLInvalidDisks() []*formatConfigV1 {
 | |
| 	jbod := make([]string, 8)
 | |
| 	formatConfigs := make([]*formatConfigV1, 8)
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		formatConfigs[index] = &formatConfigV1{
 | |
| 			Version: formatFileV1,
 | |
| 			Format:  formatBackendXL,
 | |
| 			XL: &xlFormat{
 | |
| 				Version: xlFormatBackendV1,
 | |
| 				Disk:    jbod[index],
 | |
| 				JBOD:    jbod,
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 	// Make disk 5 and disk 8 have inconsistent disk uuid's.
 | |
| 	formatConfigs[4].XL.Disk = mustGetUUID()
 | |
| 	formatConfigs[7].XL.Disk = mustGetUUID()
 | |
| 	return formatConfigs
 | |
| }
 | |
| 
 | |
| // generates a invalid format.json Disk UUID in wrong order for XL backend.
 | |
| func genFormatXLInvalidDisksOrder() []*formatConfigV1 {
 | |
| 	jbod := make([]string, 8)
 | |
| 	formatConfigs := make([]*formatConfigV1, 8)
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		formatConfigs[index] = &formatConfigV1{
 | |
| 			Version: formatFileV1,
 | |
| 			Format:  formatBackendXL,
 | |
| 			XL: &xlFormat{
 | |
| 				Version: xlFormatBackendV1,
 | |
| 				Disk:    jbod[index],
 | |
| 				JBOD:    jbod,
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 	// Re order jbod for failure case.
 | |
| 	var jbod1 = make([]string, 8)
 | |
| 	copy(jbod1, jbod)
 | |
| 	jbod1[1], jbod1[2] = jbod[2], jbod[1]
 | |
| 	formatConfigs[2].XL.JBOD = jbod1
 | |
| 	return formatConfigs
 | |
| }
 | |
| 
 | |
| func prepareFormatXLHealFreshDisks(obj ObjectLayer) ([]StorageAPI, error) {
 | |
| 	var err error
 | |
| 	xl := obj.(*xlObjects)
 | |
| 
 | |
| 	err = obj.MakeBucketWithLocation("bucket", "")
 | |
| 	if err != nil {
 | |
| 		return []StorageAPI{}, err
 | |
| 	}
 | |
| 
 | |
| 	bucket := "bucket"
 | |
| 	object := "object"
 | |
| 
 | |
| 	hashReader, err := hash.NewReader(bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", "")
 | |
| 	if err != nil {
 | |
| 		return []StorageAPI{}, err
 | |
| 	}
 | |
| 
 | |
| 	if _, err = obj.PutObject(bucket, object, hashReader, nil); err != nil {
 | |
| 		return []StorageAPI{}, err
 | |
| 	}
 | |
| 
 | |
| 	// Remove the content of export dir 10 but preserve .minio.sys because it is automatically
 | |
| 	// created when minio starts
 | |
| 	for i := 3; i <= 5; i++ {
 | |
| 		if err = xl.storageDisks[i].DeleteFile(minioMetaBucket, formatConfigFile); err != nil {
 | |
| 			return []StorageAPI{}, err
 | |
| 		}
 | |
| 		if err = xl.storageDisks[i].DeleteFile(minioMetaBucket, "tmp"); err != nil {
 | |
| 			return []StorageAPI{}, err
 | |
| 		}
 | |
| 		if err = xl.storageDisks[i].DeleteFile(bucket, object+"/xl.json"); err != nil {
 | |
| 			return []StorageAPI{}, err
 | |
| 		}
 | |
| 		if err = xl.storageDisks[i].DeleteFile(bucket, object+"/part.1"); err != nil {
 | |
| 			return []StorageAPI{}, err
 | |
| 		}
 | |
| 		if err = xl.storageDisks[i].DeleteVol(bucket); err != nil {
 | |
| 			return []StorageAPI{}, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	permutedStorageDisks := []StorageAPI{xl.storageDisks[1], xl.storageDisks[4],
 | |
| 		xl.storageDisks[2], xl.storageDisks[8], xl.storageDisks[6], xl.storageDisks[7],
 | |
| 		xl.storageDisks[0], xl.storageDisks[15], xl.storageDisks[13], xl.storageDisks[14],
 | |
| 		xl.storageDisks[3], xl.storageDisks[10], xl.storageDisks[12], xl.storageDisks[9],
 | |
| 		xl.storageDisks[5], xl.storageDisks[11]}
 | |
| 
 | |
| 	return permutedStorageDisks, nil
 | |
| 
 | |
| }
 | |
| 
 | |
| func TestFormatXLHealFreshDisks(t *testing.T) {
 | |
| 	nDisks := 16
 | |
| 	fsDirs, err := getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	// Create an instance of xl backend.
 | |
| 	obj, _, err := initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Error(err)
 | |
| 	}
 | |
| 
 | |
| 	storageDisks, err := prepareFormatXLHealFreshDisks(obj)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Attempt to load all `format.json`.
 | |
| 	formatConfigs, _ := loadAllFormats(storageDisks)
 | |
| 
 | |
| 	// Start healing disks
 | |
| 	err = healFormatXLFreshDisks(storageDisks, formatConfigs)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("healing corrupted disk failed: ", err)
 | |
| 	}
 | |
| 
 | |
| 	// Load again XL format.json to validate it
 | |
| 	_, err = loadFormatXL(storageDisks, 8)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("loading healed disk failed: ", err)
 | |
| 	}
 | |
| 
 | |
| 	// Clean all
 | |
| 	removeRoots(fsDirs)
 | |
| }
 | |
| 
 | |
| // Simulate XL disks creation, delete some format.json and remove the content of
 | |
| // a given disk to test healing a corrupted disk
 | |
| func TestFormatXLHealCorruptedDisks(t *testing.T) {
 | |
| 	// Create an instance of xl backend.
 | |
| 	obj, fsDirs, err := prepareXL16()
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	xl := obj.(*xlObjects)
 | |
| 
 | |
| 	err = obj.MakeBucketWithLocation("bucket", "")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	bucket := "bucket"
 | |
| 	object := "object"
 | |
| 
 | |
| 	_, err = obj.PutObject(bucket, object, mustGetHashReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Now, remove two format files.. Load them and reorder
 | |
| 	if err = xl.storageDisks[3].DeleteFile(minioMetaBucket, formatConfigFile); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if err = xl.storageDisks[11].DeleteFile(minioMetaBucket, formatConfigFile); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Remove the content of export dir 10 but preserve .minio.sys because it is automatically
 | |
| 	// created when minio starts
 | |
| 	if err = xl.storageDisks[10].DeleteFile(minioMetaBucket, formatConfigFile); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if err = xl.storageDisks[10].DeleteFile(minioMetaBucket, "tmp"); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if err = xl.storageDisks[10].DeleteFile(bucket, object+"/xl.json"); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if err = xl.storageDisks[10].DeleteFile(bucket, object+"/part.1"); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if err = xl.storageDisks[10].DeleteVol(bucket); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	permutedStorageDisks := []StorageAPI{xl.storageDisks[1], xl.storageDisks[4],
 | |
| 		xl.storageDisks[2], xl.storageDisks[8], xl.storageDisks[6], xl.storageDisks[7],
 | |
| 		xl.storageDisks[0], xl.storageDisks[15], xl.storageDisks[13], xl.storageDisks[14],
 | |
| 		xl.storageDisks[3], xl.storageDisks[10], xl.storageDisks[12], xl.storageDisks[9],
 | |
| 		xl.storageDisks[5], xl.storageDisks[11]}
 | |
| 
 | |
| 	formatConfigs, _ := loadAllFormats(permutedStorageDisks)
 | |
| 
 | |
| 	// Start healing disks
 | |
| 	err = healFormatXLCorruptedDisks(permutedStorageDisks, formatConfigs)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("healing corrupted disk failed: ", err)
 | |
| 	}
 | |
| 
 | |
| 	// Load again XL format.json to validate it
 | |
| 	_, err = loadFormatXL(permutedStorageDisks, 8)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("loading healed disk failed: ", err)
 | |
| 	}
 | |
| 
 | |
| 	// Clean all
 | |
| 	removeRoots(fsDirs)
 | |
| }
 | |
| 
 | |
| // Test on ReorderByInspection by simulating creating disks and removing
 | |
| // some of format.json
 | |
| func TestFormatXLReorderByInspection(t *testing.T) {
 | |
| 	// Create an instance of xl backend.
 | |
| 	obj, fsDirs, err := prepareXL16()
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	xl := obj.(*xlObjects)
 | |
| 
 | |
| 	err = obj.MakeBucketWithLocation("bucket", "")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	bucket := "bucket"
 | |
| 	object := "object"
 | |
| 
 | |
| 	_, err = obj.PutObject(bucket, object, mustGetHashReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Now, remove two format files.. Load them and reorder
 | |
| 	if err = xl.storageDisks[3].DeleteFile(minioMetaBucket, formatConfigFile); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	if err = xl.storageDisks[5].DeleteFile(minioMetaBucket, formatConfigFile); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	permutedStorageDisks := []StorageAPI{xl.storageDisks[1], xl.storageDisks[4],
 | |
| 		xl.storageDisks[2], xl.storageDisks[8], xl.storageDisks[6], xl.storageDisks[7],
 | |
| 		xl.storageDisks[0], xl.storageDisks[15], xl.storageDisks[13], xl.storageDisks[14],
 | |
| 		xl.storageDisks[3], xl.storageDisks[10], xl.storageDisks[12], xl.storageDisks[9],
 | |
| 		xl.storageDisks[5], xl.storageDisks[11]}
 | |
| 
 | |
| 	permutedFormatConfigs, _ := loadAllFormats(permutedStorageDisks)
 | |
| 
 | |
| 	_, orderedDisks, err := reorderDisks(permutedStorageDisks, permutedFormatConfigs, false)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("error reordering disks\n")
 | |
| 	}
 | |
| 
 | |
| 	orderedDisks, err = reorderDisksByInspection(orderedDisks, permutedStorageDisks, permutedFormatConfigs)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("failed to reorder disk by inspection")
 | |
| 	}
 | |
| 
 | |
| 	// Check disks reordering
 | |
| 	for i := 0; i <= 15; i++ {
 | |
| 		if orderedDisks[i] == nil && i != 3 && i != 5 {
 | |
| 			t.Fatal("should not be nil")
 | |
| 		}
 | |
| 		if orderedDisks[i] != nil && orderedDisks[i] != xl.storageDisks[i] {
 | |
| 			t.Fatal("Disks were not ordered correctly")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	removeRoots(fsDirs)
 | |
| }
 | |
| 
 | |
| // Wrapper for calling FormatXL tests - currently validates
 | |
| //  - valid format
 | |
| //  - unrecognized version number
 | |
| //  - unrecognized format tag
 | |
| //  - unrecognized xl version
 | |
| //  - wrong number of JBOD entries
 | |
| //  - invalid JBOD
 | |
| //  - invalid Disk uuid
 | |
| func TestFormatXL(t *testing.T) {
 | |
| 	formatInputCases := [][]*formatConfigV1{
 | |
| 		genFormatXLValid(),
 | |
| 		genFormatXLInvalidVersion(),
 | |
| 		genFormatXLInvalidFormat(),
 | |
| 		genFormatXLInvalidXLVersion(),
 | |
| 		genFormatXLInvalidJBODCount(),
 | |
| 		genFormatXLInvalidJBOD(),
 | |
| 		genFormatXLInvalidDisks(),
 | |
| 		genFormatXLInvalidDisksOrder(),
 | |
| 	}
 | |
| 	testCases := []struct {
 | |
| 		formatConfigs []*formatConfigV1
 | |
| 		shouldPass    bool
 | |
| 	}{
 | |
| 		{
 | |
| 			formatConfigs: formatInputCases[0],
 | |
| 			shouldPass:    true,
 | |
| 		},
 | |
| 		{
 | |
| 			formatConfigs: formatInputCases[1],
 | |
| 			shouldPass:    false,
 | |
| 		},
 | |
| 		{
 | |
| 			formatConfigs: formatInputCases[2],
 | |
| 			shouldPass:    false,
 | |
| 		},
 | |
| 		{
 | |
| 			formatConfigs: formatInputCases[3],
 | |
| 			shouldPass:    false,
 | |
| 		},
 | |
| 		{
 | |
| 			formatConfigs: formatInputCases[4],
 | |
| 			shouldPass:    false,
 | |
| 		},
 | |
| 		{
 | |
| 			formatConfigs: formatInputCases[5],
 | |
| 			shouldPass:    false,
 | |
| 		},
 | |
| 		{
 | |
| 			formatConfigs: formatInputCases[6],
 | |
| 			shouldPass:    false,
 | |
| 		},
 | |
| 		{
 | |
| 			formatConfigs: formatInputCases[7],
 | |
| 			shouldPass:    false,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for i, testCase := range testCases {
 | |
| 		err := checkFormatXL(testCase.formatConfigs)
 | |
| 		if err != nil && testCase.shouldPass {
 | |
| 			t.Errorf("Test %d: Expected to pass but failed with %s", i+1, err)
 | |
| 		}
 | |
| 		if err == nil && !testCase.shouldPass {
 | |
| 			t.Errorf("Test %d: Expected to fail but passed instead", i+1)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Tests uuid order verification function.
 | |
| func TestSavedUUIDOrder(t *testing.T) {
 | |
| 	uuidTestCases := make([]struct {
 | |
| 		uuid       string
 | |
| 		shouldPass bool
 | |
| 	}, 8)
 | |
| 	jbod := make([]string, 8)
 | |
| 	formatConfigs := make([]*formatConfigV1, 8)
 | |
| 	for index := range jbod {
 | |
| 		jbod[index] = mustGetUUID()
 | |
| 		uuidTestCases[index].uuid = jbod[index]
 | |
| 		uuidTestCases[index].shouldPass = true
 | |
| 	}
 | |
| 	for index := range jbod {
 | |
| 		formatConfigs[index] = &formatConfigV1{
 | |
| 			Version: formatFileV1,
 | |
| 			Format:  formatBackendXL,
 | |
| 			XL: &xlFormat{
 | |
| 				Version: xlFormatBackendV1,
 | |
| 				Disk:    jbod[index],
 | |
| 				JBOD:    jbod,
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 	// Re order jbod for failure case.
 | |
| 	var jbod1 = make([]string, 8)
 | |
| 	copy(jbod1, jbod)
 | |
| 	jbod1[1], jbod1[2] = jbod[2], jbod[1]
 | |
| 	formatConfigs[2].XL.JBOD = jbod1
 | |
| 	uuidTestCases[1].shouldPass = false
 | |
| 	uuidTestCases[2].shouldPass = false
 | |
| 
 | |
| 	for i, testCase := range uuidTestCases {
 | |
| 		// Is uuid present on all JBOD ?.
 | |
| 		if testCase.shouldPass != isSavedUUIDInOrder(testCase.uuid, formatConfigs) {
 | |
| 			t.Errorf("Test %d: Expected to pass but failed", i+1)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Test initFormatXL() when disks are expected to return errors
 | |
| func TestInitFormatXLErrors(t *testing.T) {
 | |
| 	nDisks := 16
 | |
| 	fsDirs, err := getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	defer removeRoots(fsDirs)
 | |
| 	// Create an instance of xl backend.
 | |
| 	obj, _, err := initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl := obj.(*xlObjects)
 | |
| 
 | |
| 	testStorageDisks := make([]StorageAPI, 16)
 | |
| 
 | |
| 	// All disks API return disk not found
 | |
| 	for i := 0; i < 16; i++ {
 | |
| 		d := xl.storageDisks[i].(*retryStorage)
 | |
| 		testStorageDisks[i] = &naughtyDisk{disk: d, defaultErr: errDiskNotFound}
 | |
| 	}
 | |
| 	if err := initFormatXL(testStorageDisks); err != errDiskNotFound {
 | |
| 		t.Fatal("Got a different error: ", err)
 | |
| 	}
 | |
| 
 | |
| 	// All disks returns disk not found in the fourth call
 | |
| 	for i := 0; i < 15; i++ {
 | |
| 		d := xl.storageDisks[i].(*retryStorage)
 | |
| 		testStorageDisks[i] = &naughtyDisk{disk: d, defaultErr: errDiskNotFound, errors: map[int]error{0: nil, 1: nil, 2: nil}}
 | |
| 	}
 | |
| 	if err := initFormatXL(testStorageDisks); err != errDiskNotFound {
 | |
| 		t.Fatal("Got a different error: ", err)
 | |
| 	}
 | |
| 
 | |
| 	// All disks are nil (disk not found)
 | |
| 	for i := 0; i < 15; i++ {
 | |
| 		testStorageDisks[i] = nil
 | |
| 	}
 | |
| 	if err := initFormatXL(testStorageDisks); err != errDiskNotFound {
 | |
| 		t.Fatal("Got a different error: ", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Test formatErrsSummary()
 | |
| func TestFormatErrsSummary(t *testing.T) {
 | |
| 	type errSummary struct {
 | |
| 		fc, unfmt, ntfnd, crrptd, othr int
 | |
| 	}
 | |
| 
 | |
| 	testCases := []struct {
 | |
| 		errs     []error
 | |
| 		expected errSummary
 | |
| 	}{
 | |
| 		{nil, errSummary{0, 0, 0, 0, 0}},
 | |
| 		{[]error{errDiskNotFound, errUnformattedDisk, errCorruptedFormat, nil, errFaultyDisk},
 | |
| 			errSummary{1, 1, 1, 1, 1}},
 | |
| 		{[]error{errDiskNotFound, errDiskNotFound, errCorruptedFormat, nil, nil},
 | |
| 			errSummary{2, 0, 2, 1, 0}},
 | |
| 	}
 | |
| 	for i, testCase := range testCases {
 | |
| 		a, b, c, d, e := formatErrsSummary(testCase.errs)
 | |
| 		got := errSummary{a, b, c, d, e}
 | |
| 		if got != testCase.expected {
 | |
| 			t.Errorf("Test %d: Got wrong results: %#v %#v", i+1,
 | |
| 				got, testCase.expected)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Tests for genericFormatCheckXL()
 | |
| func TestGenericFormatCheckXL(t *testing.T) {
 | |
| 	var errs []error
 | |
| 	formatConfigs := genFormatXLInvalidJBOD()
 | |
| 
 | |
| 	// Some disks has corrupted formats, one faulty disk
 | |
| 	errs = []error{nil, nil, errCorruptedFormat, errCorruptedFormat, errCorruptedFormat, errCorruptedFormat,
 | |
| 		errCorruptedFormat, errFaultyDisk}
 | |
| 	if err := genericFormatCheckXL(formatConfigs, errs); err != errCorruptedFormat {
 | |
| 		t.Fatal("Got unexpected err: ", err)
 | |
| 	}
 | |
| 
 | |
| 	// Many faulty disks
 | |
| 	errs = []error{nil, nil, errFaultyDisk, errFaultyDisk, errFaultyDisk, errFaultyDisk,
 | |
| 		errCorruptedFormat, errFaultyDisk}
 | |
| 	if err := genericFormatCheckXL(formatConfigs, errs); err != errXLReadQuorum {
 | |
| 		t.Fatal("Got unexpected err: ", err)
 | |
| 	}
 | |
| 
 | |
| 	// All formats successfully loaded
 | |
| 	errs = []error{nil, nil, nil, nil, nil, nil, nil, nil}
 | |
| 	if err := genericFormatCheckXL(formatConfigs, errs); err == nil {
 | |
| 		t.Fatalf("Should fail here")
 | |
| 	}
 | |
| 	errs = []error{nil}
 | |
| 	if err := genericFormatCheckXL([]*formatConfigV1{genFormatFS()}, errs); err == nil {
 | |
| 		t.Fatalf("Should fail here")
 | |
| 	}
 | |
| 	errs = []error{errFaultyDisk}
 | |
| 	if err := genericFormatCheckXL([]*formatConfigV1{genFormatFS()}, errs); err == nil {
 | |
| 		t.Fatalf("Should fail here")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // TestFSCheckFormatFSErr - test loadFormatFS loading older format.
 | |
| func TestFSCheckFormatFSErr(t *testing.T) {
 | |
| 	// Prepare for testing
 | |
| 	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
 | |
| 	defer os.RemoveAll(disk)
 | |
| 
 | |
| 	// Assign a new UUID.
 | |
| 	uuid := mustGetUUID()
 | |
| 
 | |
| 	// Initialize meta volume, if volume already exists ignores it.
 | |
| 	if err := initMetaVolumeFS(disk, uuid); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	testCases := []struct {
 | |
| 		format         *formatConfigV1
 | |
| 		formatWriteErr error
 | |
| 		formatCheckErr error
 | |
| 		shouldPass     bool
 | |
| 	}{
 | |
| 		{
 | |
| 			format: &formatConfigV1{
 | |
| 				Version: formatFileV1,
 | |
| 				Format:  formatBackendFS,
 | |
| 				FS: &fsFormat{
 | |
| 					Version: fsFormatBackendV1,
 | |
| 				},
 | |
| 			},
 | |
| 			formatCheckErr: nil,
 | |
| 			shouldPass:     true,
 | |
| 		},
 | |
| 		{
 | |
| 			format: &formatConfigV1{
 | |
| 				Version: formatFileV1,
 | |
| 				Format:  formatBackendFS,
 | |
| 				FS: &fsFormat{
 | |
| 					Version: "10",
 | |
| 				},
 | |
| 			},
 | |
| 			formatCheckErr: errors.New("Unknown backend FS format version '10'"),
 | |
| 			shouldPass:     false,
 | |
| 		},
 | |
| 		{
 | |
| 			format: &formatConfigV1{
 | |
| 				Version: formatFileV1,
 | |
| 				Format:  "garbage",
 | |
| 				FS: &fsFormat{
 | |
| 					Version: fsFormatBackendV1,
 | |
| 				},
 | |
| 			},
 | |
| 			formatCheckErr: errors.New("FS backend format required. Found 'garbage'"),
 | |
| 		},
 | |
| 		{
 | |
| 			format: &formatConfigV1{
 | |
| 				Version: "-1",
 | |
| 				Format:  formatBackendFS,
 | |
| 				FS: &fsFormat{
 | |
| 					Version: fsFormatBackendV1,
 | |
| 				},
 | |
| 			},
 | |
| 			formatCheckErr: errors.New("Unknown format file version '-1'"),
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	fsFormatPath := pathJoin(disk, minioMetaBucket, formatConfigFile)
 | |
| 	for i, testCase := range testCases {
 | |
| 		lk, err := lock.LockedOpenFile((fsFormatPath), os.O_RDWR|os.O_CREATE, 0600)
 | |
| 		if err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 		_, err = testCase.format.WriteTo(lk)
 | |
| 		lk.Close()
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Test %d: Expected nil, got %s", i+1, err)
 | |
| 		}
 | |
| 
 | |
| 		lk, err = lock.LockedOpenFile((fsFormatPath), os.O_RDWR|os.O_CREATE, 0600)
 | |
| 		if err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 
 | |
| 		formatCfg := &formatConfigV1{}
 | |
| 		_, err = formatCfg.ReadFrom(lk)
 | |
| 		lk.Close()
 | |
| 		if err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 		err = formatCfg.CheckFS()
 | |
| 		if err != nil && testCase.shouldPass {
 | |
| 			t.Errorf("Test %d: Should not fail with unexpected %s, expected nil", i+1, err)
 | |
| 		}
 | |
| 		if err == nil && !testCase.shouldPass {
 | |
| 			t.Errorf("Test %d: Should fail with expected %s, got nil", i+1, testCase.formatCheckErr)
 | |
| 		}
 | |
| 		if err != nil && !testCase.shouldPass {
 | |
| 			if errors2.Cause(err).Error() != testCase.formatCheckErr.Error() {
 | |
| 				t.Errorf("Test %d: Should fail with expected %s, got %s", i+1, testCase.formatCheckErr, err)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // TestFSCheckFormatFS - test loadFormatFS with healty and faulty disks
 | |
| func TestFSCheckFormatFS(t *testing.T) {
 | |
| 	// Prepare for testing
 | |
| 	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
 | |
| 	defer os.RemoveAll(disk)
 | |
| 
 | |
| 	// Assign a new UUID.
 | |
| 	uuid := mustGetUUID()
 | |
| 
 | |
| 	// Initialize meta volume, if volume already exists ignores it.
 | |
| 	if err := initMetaVolumeFS(disk, uuid); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	fsFormatPath := pathJoin(disk, minioMetaBucket, formatConfigFile)
 | |
| 	lk, err := lock.LockedOpenFile((fsFormatPath), os.O_RDWR|os.O_CREATE, 0600)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	format := newFSFormatV1()
 | |
| 	_, err = format.WriteTo(lk)
 | |
| 	lk.Close()
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Loading corrupted format file
 | |
| 	file, err := os.OpenFile((fsFormatPath), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Should not fail here", err)
 | |
| 	}
 | |
| 	file.Write([]byte{'b'})
 | |
| 	file.Close()
 | |
| 
 | |
| 	lk, err = lock.LockedOpenFile((fsFormatPath), os.O_RDWR|os.O_CREATE, 0600)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	format = &formatConfigV1{}
 | |
| 	_, err = format.ReadFrom(lk)
 | |
| 	lk.Close()
 | |
| 	if err == nil {
 | |
| 		t.Fatal("Should return an error here")
 | |
| 	}
 | |
| 
 | |
| 	// Loading format file from disk not found.
 | |
| 	os.RemoveAll(disk)
 | |
| 	_, err = lock.LockedOpenFile((fsFormatPath), os.O_RDONLY, 0600)
 | |
| 	if err != nil && !os.IsNotExist(err) {
 | |
| 		t.Fatal("Should return 'format.json' does not exist, but got", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestLoadFormatXLErrs(t *testing.T) {
 | |
| 	nDisks := 16
 | |
| 	fsDirs, err := getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	defer removeRoots(fsDirs)
 | |
| 
 | |
| 	// Create an instance of xl backend.
 | |
| 	obj, _, err := initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl := obj.(*xlObjects)
 | |
| 
 | |
| 	xl.storageDisks[11] = nil
 | |
| 
 | |
| 	// disk 12 returns faulty disk
 | |
| 	posixDisk, ok := xl.storageDisks[12].(*retryStorage)
 | |
| 	if !ok {
 | |
| 		t.Fatal("storage disk is not *retryStorage type")
 | |
| 	}
 | |
| 	xl.storageDisks[10] = newNaughtyDisk(posixDisk, nil, errFaultyDisk)
 | |
| 	if _, err = loadFormatXL(xl.storageDisks, 8); err != errFaultyDisk {
 | |
| 		t.Fatal("Got an unexpected error: ", err)
 | |
| 	}
 | |
| 
 | |
| 	removeRoots(fsDirs)
 | |
| 
 | |
| 	fsDirs, err = getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	defer removeRoots(fsDirs)
 | |
| 
 | |
| 	obj, _, err = initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl = obj.(*xlObjects)
 | |
| 
 | |
| 	// disks 0..10 returns disk not found
 | |
| 	for i := 0; i <= 10; i++ {
 | |
| 		posixDisk, ok := xl.storageDisks[i].(*retryStorage)
 | |
| 		if !ok {
 | |
| 			t.Fatal("storage disk is not *retryStorage type")
 | |
| 		}
 | |
| 		xl.storageDisks[i] = newNaughtyDisk(posixDisk, nil, errDiskNotFound)
 | |
| 	}
 | |
| 	if _, err = loadFormatXL(xl.storageDisks, 8); err != errXLReadQuorum {
 | |
| 		t.Fatal("Got an unexpected error: ", err)
 | |
| 	}
 | |
| 
 | |
| 	fsDirs, err = getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	defer removeRoots(fsDirs)
 | |
| 
 | |
| 	obj, _, err = initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl = obj.(*xlObjects)
 | |
| 
 | |
| 	// disks 0..10 returns unformatted disk
 | |
| 	for i := 0; i <= 10; i++ {
 | |
| 		if err = xl.storageDisks[i].DeleteFile(minioMetaBucket, formatConfigFile); err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| 	if _, err = loadFormatXL(xl.storageDisks, 8); err != errUnformattedDisk {
 | |
| 		t.Fatal("Got an unexpected error: ", err)
 | |
| 	}
 | |
| 
 | |
| 	fsDirs, err = getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	defer removeRoots(fsDirs)
 | |
| 
 | |
| 	obj, _, err = initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl = obj.(*xlObjects)
 | |
| 
 | |
| 	// disks 0..15 returns is nil (disk not found)
 | |
| 	for i := 0; i < 16; i++ {
 | |
| 		xl.storageDisks[i] = nil
 | |
| 	}
 | |
| 	if _, err := loadFormatXL(xl.storageDisks, 8); err != errDiskNotFound {
 | |
| 		t.Fatal("Got an unexpected error: ", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Tests for healFormatXLCorruptedDisks() with cases which lead to errors
 | |
| func TestHealFormatXLCorruptedDisksErrs(t *testing.T) {
 | |
| 	root, err := newTestConfig(globalMinioDefaultRegion)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	defer os.RemoveAll(root)
 | |
| 
 | |
| 	nDisks := 16
 | |
| 	fsDirs, err := getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Everything is fine, should return nil
 | |
| 	obj, _, err := initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	xl := obj.(*xlObjects)
 | |
| 	formatConfigs, _ := loadAllFormats(xl.storageDisks)
 | |
| 	if err = healFormatXLCorruptedDisks(xl.storageDisks, formatConfigs); err != nil {
 | |
| 		t.Fatal("Got an unexpected error: ", err)
 | |
| 	}
 | |
| 
 | |
| 	removeRoots(fsDirs)
 | |
| 
 | |
| 	fsDirs, err = getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// One disk returns Faulty Disk
 | |
| 	obj, _, err = initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl = obj.(*xlObjects)
 | |
| 	posixDisk, ok := xl.storageDisks[0].(*retryStorage)
 | |
| 	if !ok {
 | |
| 		t.Fatal("storage disk is not *retryStorage type")
 | |
| 	}
 | |
| 	xl.storageDisks[0] = newNaughtyDisk(posixDisk, nil, errFaultyDisk)
 | |
| 	formatConfigs, _ = loadAllFormats(xl.storageDisks)
 | |
| 	if err = healFormatXLCorruptedDisks(xl.storageDisks, formatConfigs); err != errFaultyDisk {
 | |
| 		t.Fatal("Got an unexpected error: ", err)
 | |
| 	}
 | |
| 	removeRoots(fsDirs)
 | |
| 
 | |
| 	fsDirs, err = getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Corrupted format json in one disk
 | |
| 	obj, _, err = initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl = obj.(*xlObjects)
 | |
| 	for i := 0; i <= 15; i++ {
 | |
| 		if err = xl.storageDisks[i].AppendFile(minioMetaBucket, formatConfigFile, []byte("corrupted data")); err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 	}
 | |
| 	formatConfigs, _ = loadAllFormats(xl.storageDisks)
 | |
| 	if err = healFormatXLCorruptedDisks(xl.storageDisks, formatConfigs); err == nil {
 | |
| 		t.Fatal("Should get a json parsing error, ")
 | |
| 	}
 | |
| 	removeRoots(fsDirs)
 | |
| }
 | |
| 
 | |
| // Tests for healFormatXLFreshDisks() with cases which lead to errors
 | |
| func TestHealFormatXLFreshDisksErrs(t *testing.T) {
 | |
| 	root, err := newTestConfig(globalMinioDefaultRegion)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	defer os.RemoveAll(root)
 | |
| 
 | |
| 	nDisks := 16
 | |
| 	fsDirs, err := getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Everything is fine, should return nil
 | |
| 	obj, _, err := initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl := obj.(*xlObjects)
 | |
| 	formatConfigs, _ := loadAllFormats(xl.storageDisks)
 | |
| 	if err = healFormatXLFreshDisks(xl.storageDisks, formatConfigs); err != nil {
 | |
| 		t.Fatal("Got an unexpected error: ", err)
 | |
| 	}
 | |
| 	removeRoots(fsDirs)
 | |
| 
 | |
| 	fsDirs, err = getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// One disk returns Faulty Disk
 | |
| 	obj, _, err = initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl = obj.(*xlObjects)
 | |
| 	posixDisk, ok := xl.storageDisks[0].(*retryStorage)
 | |
| 	if !ok {
 | |
| 		t.Fatal("storage disk is not *retryStorage type")
 | |
| 	}
 | |
| 	xl.storageDisks[0] = newNaughtyDisk(posixDisk, nil, errFaultyDisk)
 | |
| 	formatConfigs, _ = loadAllFormats(xl.storageDisks)
 | |
| 	if err = healFormatXLFreshDisks(xl.storageDisks, formatConfigs); err != errFaultyDisk {
 | |
| 		t.Fatal("Got an unexpected error: ", err)
 | |
| 	}
 | |
| 	removeRoots(fsDirs)
 | |
| 
 | |
| 	fsDirs, err = getRandomDisks(nDisks)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// One disk is not found, heal corrupted disks should return nil
 | |
| 	obj, _, err = initObjectLayer(mustGetNewEndpointList(fsDirs...))
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	xl = obj.(*xlObjects)
 | |
| 	xl.storageDisks[0] = nil
 | |
| 	formatConfigs, _ = loadAllFormats(xl.storageDisks)
 | |
| 	if err = healFormatXLFreshDisks(xl.storageDisks, formatConfigs); err != nil {
 | |
| 		t.Fatal("Got an unexpected error: ", err)
 | |
| 	}
 | |
| 	removeRoots(fsDirs)
 | |
| }
 |