storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/xl-storage_test.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2016-2020 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"crypto/rand"
    23  	"fmt"
    24  	"io"
    25  	"io/ioutil"
    26  	"os"
    27  	slashpath "path"
    28  	"runtime"
    29  	"strings"
    30  	"syscall"
    31  	"testing"
    32  
    33  	"storj.io/minio/cmd/config/storageclass"
    34  )
    35  
    36  func TestCheckPathLength(t *testing.T) {
    37  	// Check path length restrictions are not same on windows/darwin
    38  	if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
    39  		t.Skip()
    40  	}
    41  
    42  	testCases := []struct {
    43  		path        string
    44  		expectedErr error
    45  	}{
    46  		{".", errFileAccessDenied},
    47  		{"/", errFileAccessDenied},
    48  		{"..", errFileAccessDenied},
    49  		{"data/G_792/srv-tse/c/users/denis/documents/gestion!20locative/heritier/propri!E9taire/20190101_a2.03!20-!20m.!20heritier!20re!B4mi!20-!20proce!60s-verbal!20de!20livraison!20et!20de!20remise!20des!20cle!B4s!20acque!B4reurs!20-!204-!20livraison!20-!20lp!20promotion!20toulouse!20-!20encre!20et!20plume!20-!205!20de!B4c.!202019!20a!60!2012-49.pdf.ecc", errFileNameTooLong},
    50  		{"data/G_792/srv-tse/c/users/denis/documents/gestionlocative.txt", nil},
    51  	}
    52  
    53  	for _, testCase := range testCases {
    54  		gotErr := checkPathLength(testCase.path)
    55  		t.Run("", func(t *testing.T) {
    56  			if gotErr != testCase.expectedErr {
    57  				t.Errorf("Expected %s, got %s", testCase.expectedErr, gotErr)
    58  			}
    59  		})
    60  	}
    61  }
    62  
    63  // Tests validate volume name.
    64  func TestIsValidVolname(t *testing.T) {
    65  	testCases := []struct {
    66  		volName    string
    67  		shouldPass bool
    68  	}{
    69  		// Cases which should pass the test.
    70  		// passing in valid bucket names.
    71  		{"lol", true},
    72  		{"1-this-is-valid", true},
    73  		{"1-this-too-is-valid-1", true},
    74  		{"this.works.too.1", true},
    75  		{"1234567", true},
    76  		{"123", true},
    77  		{"s3-eu-west-1.amazonaws.com", true},
    78  		{"ideas-are-more-powerful-than-guns", true},
    79  		{"testbucket", true},
    80  		{"1bucket", true},
    81  		{"bucket1", true},
    82  		{"$this-is-not-valid-too", true},
    83  		{"contains-$-dollar", true},
    84  		{"contains-^-carrot", true},
    85  		{"contains-$-dollar", true},
    86  		{"contains-$-dollar", true},
    87  		{".starts-with-a-dot", true},
    88  		{"ends-with-a-dot.", true},
    89  		{"ends-with-a-dash-", true},
    90  		{"-starts-with-a-dash", true},
    91  		{"THIS-BEINGS-WITH-UPPERCASe", true},
    92  		{"tHIS-ENDS-WITH-UPPERCASE", true},
    93  		{"ThisBeginsAndEndsWithUpperCase", true},
    94  		{"una ñina", true},
    95  		{"lalalallalallalalalallalallalala-theString-size-is-greater-than-64", true},
    96  		// cases for which test should fail.
    97  		// passing invalid bucket names.
    98  		{"", false},
    99  		{SlashSeparator, false},
   100  		{"a", false},
   101  		{"ab", false},
   102  		{"ab/", true},
   103  		{"......", true},
   104  	}
   105  
   106  	for i, testCase := range testCases {
   107  		isValidVolname := isValidVolname(testCase.volName)
   108  		if testCase.shouldPass && !isValidVolname {
   109  			t.Errorf("Test case %d: Expected \"%s\" to be a valid bucket name", i+1, testCase.volName)
   110  		}
   111  		if !testCase.shouldPass && isValidVolname {
   112  			t.Errorf("Test case %d: Expected bucket name \"%s\" to be invalid", i+1, testCase.volName)
   113  		}
   114  	}
   115  }
   116  
   117  // creates a temp dir and sets up xlStorage layer.
   118  // returns xlStorage layer, temp dir path to be used for the purpose of tests.
   119  func newXLStorageTestSetup() (*xlStorageDiskIDCheck, string, error) {
   120  	diskPath, err := ioutil.TempDir(globalTestTmpDir, "minio-")
   121  	if err != nil {
   122  		return nil, "", err
   123  	}
   124  
   125  	// Initialize a new xlStorage layer.
   126  	storage, err := newLocalXLStorage(diskPath)
   127  	if err != nil {
   128  		return nil, "", err
   129  	}
   130  	// Create a sample format.json file
   131  	err = storage.WriteAll(context.Background(), minioMetaBucket, formatConfigFile, []byte(`{"version":"1","format":"xl","id":"592a41c2-b7cc-4130-b883-c4b5cb15965b","xl":{"version":"3","this":"da017d62-70e3-45f1-8a1a-587707e69ad1","sets":[["e07285a6-8c73-4962-89c6-047fb939f803","33b8d431-482d-4376-b63c-626d229f0a29","cff6513a-4439-4dc1-bcaa-56c9e880c352","da017d62-70e3-45f1-8a1a-587707e69ad1","9c9f21d5-1f15-4737-bce6-835faa0d9626","0a59b346-1424-4fc2-9fa2-a2e80541d0c1","7924a3dc-b69a-4971-9a2e-014966d6aebb","4d2b8dd9-4e48-444b-bdca-c89194b26042"]],"distributionAlgo":"CRCMOD"}}`))
   132  	if err != nil {
   133  		return nil, "", err
   134  	}
   135  	disk := newXLStorageDiskIDCheck(storage)
   136  	disk.diskID = "da017d62-70e3-45f1-8a1a-587707e69ad1"
   137  	return disk, diskPath, nil
   138  }
   139  
   140  // createPermDeniedFile - creates temporary directory and file with path '/mybucket/myobject'
   141  func createPermDeniedFile(t *testing.T) (permDeniedDir string) {
   142  	var errMsg string
   143  
   144  	defer func() {
   145  		if errMsg == "" {
   146  			return
   147  		}
   148  
   149  		if permDeniedDir != "" {
   150  			os.RemoveAll(permDeniedDir)
   151  		}
   152  
   153  		t.Fatalf(errMsg)
   154  	}()
   155  
   156  	var err error
   157  	if permDeniedDir, err = ioutil.TempDir(globalTestTmpDir, "minio-"); err != nil {
   158  		errMsg = fmt.Sprintf("Unable to create temporary directory. %v", err)
   159  		return permDeniedDir
   160  	}
   161  
   162  	if err = os.Mkdir(slashpath.Join(permDeniedDir, "mybucket"), 0775); err != nil {
   163  		errMsg = fmt.Sprintf("Unable to create temporary directory %v. %v", slashpath.Join(permDeniedDir, "mybucket"), err)
   164  		return permDeniedDir
   165  	}
   166  
   167  	if err = ioutil.WriteFile(slashpath.Join(permDeniedDir, "mybucket", "myobject"), []byte(""), 0400); err != nil {
   168  		errMsg = fmt.Sprintf("Unable to create file %v. %v", slashpath.Join(permDeniedDir, "mybucket", "myobject"), err)
   169  		return permDeniedDir
   170  	}
   171  
   172  	if err = os.Chmod(slashpath.Join(permDeniedDir, "mybucket"), 0400); err != nil {
   173  		errMsg = fmt.Sprintf("Unable to change permission to temporary directory %v. %v", slashpath.Join(permDeniedDir, "mybucket"), err)
   174  		return permDeniedDir
   175  	}
   176  
   177  	if err = os.Chmod(permDeniedDir, 0400); err != nil {
   178  		errMsg = fmt.Sprintf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
   179  	}
   180  
   181  	return permDeniedDir
   182  }
   183  
   184  // removePermDeniedFile - removes temporary directory and file with path '/mybucket/myobject'
   185  func removePermDeniedFile(permDeniedDir string) {
   186  	if err := os.Chmod(permDeniedDir, 0775); err == nil {
   187  		if err = os.Chmod(slashpath.Join(permDeniedDir, "mybucket"), 0775); err == nil {
   188  			os.RemoveAll(permDeniedDir)
   189  		}
   190  	}
   191  }
   192  
   193  // TestXLStorages xlStorage.getDiskInfo()
   194  func TestXLStorageGetDiskInfo(t *testing.T) {
   195  	path, err := ioutil.TempDir(globalTestTmpDir, "minio-")
   196  	if err != nil {
   197  		t.Fatalf("Unable to create a temporary directory, %s", err)
   198  	}
   199  	defer os.RemoveAll(path)
   200  
   201  	testCases := []struct {
   202  		diskPath    string
   203  		expectedErr error
   204  	}{
   205  		{path, nil},
   206  		{"/nonexistent-dir", errDiskNotFound},
   207  	}
   208  
   209  	// Check test cases.
   210  	for _, testCase := range testCases {
   211  		if _, err := getDiskInfo(testCase.diskPath); err != testCase.expectedErr {
   212  			t.Fatalf("expected: %s, got: %s", testCase.expectedErr, err)
   213  		}
   214  	}
   215  }
   216  
   217  func TestXLStorageIsDirEmpty(t *testing.T) {
   218  	tmp, err := ioutil.TempDir(globalTestTmpDir, "minio-")
   219  	if err != nil {
   220  		t.Fatal(err)
   221  	}
   222  	defer os.RemoveAll(tmp)
   223  
   224  	// Should give false on non-existent directory.
   225  	dir1 := slashpath.Join(tmp, "non-existent-directory")
   226  	if isDirEmpty(dir1) {
   227  		t.Error("expected false for non-existent directory, got true")
   228  	}
   229  
   230  	// Should give false for not-a-directory.
   231  	dir2 := slashpath.Join(tmp, "file")
   232  	err = ioutil.WriteFile(dir2, []byte("hello"), 0777)
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  
   237  	if isDirEmpty(dir2) {
   238  		t.Error("expected false for a file, got true")
   239  	}
   240  
   241  	// Should give true for a real empty directory.
   242  	dir3 := slashpath.Join(tmp, "empty")
   243  	err = os.Mkdir(dir3, 0777)
   244  	if err != nil {
   245  		t.Fatal(err)
   246  	}
   247  
   248  	if !isDirEmpty(dir3) {
   249  		t.Error("expected true for empty dir, got false")
   250  	}
   251  }
   252  
   253  // TestXLStorageReadVersion - TestXLStorages the functionality implemented by xlStorage ReadVersion storage API.
   254  func TestXLStorageReadVersion(t *testing.T) {
   255  	// create xlStorage test setup
   256  	xlStorage, path, err := newXLStorageTestSetup()
   257  	if err != nil {
   258  		t.Fatalf("Unable to cfgreate xlStorage test setup, %s", err)
   259  	}
   260  
   261  	defer os.RemoveAll(path)
   262  
   263  	xlMeta, _ := ioutil.ReadFile("testdata/xl.meta")
   264  
   265  	// Create files for the test cases.
   266  	if err = xlStorage.MakeVol(context.Background(), "exists"); err != nil {
   267  		t.Fatalf("Unable to create a volume \"exists\", %s", err)
   268  	}
   269  	if err = xlStorage.AppendFile(context.Background(), "exists", "as-directory/as-file/xl.meta", xlMeta); err != nil {
   270  		t.Fatalf("Unable to create a file \"as-directory/as-file\", %s", err)
   271  	}
   272  	if err = xlStorage.AppendFile(context.Background(), "exists", "as-file/xl.meta", xlMeta); err != nil {
   273  		t.Fatalf("Unable to create a file \"as-file\", %s", err)
   274  	}
   275  	if err = xlStorage.AppendFile(context.Background(), "exists", "as-file-parent/xl.meta", xlMeta); err != nil {
   276  		t.Fatalf("Unable to create a file \"as-file-parent\", %s", err)
   277  	}
   278  
   279  	// TestXLStoragecases to validate different conditions for ReadVersion API.
   280  	testCases := []struct {
   281  		volume string
   282  		path   string
   283  		err    error
   284  	}{
   285  		// TestXLStorage case - 1.
   286  		// Validate volume does not exist.
   287  		{
   288  			volume: "i-dont-exist",
   289  			path:   "",
   290  			err:    errVolumeNotFound,
   291  		},
   292  		// TestXLStorage case - 2.
   293  		// Validate bad condition file does not exist.
   294  		{
   295  			volume: "exists",
   296  			path:   "as-file-not-found",
   297  			err:    errFileNotFound,
   298  		},
   299  		// TestXLStorage case - 3.
   300  		// Validate bad condition file exists as prefix/directory and
   301  		// we are attempting to read it.
   302  		{
   303  			volume: "exists",
   304  			path:   "as-directory",
   305  			err:    errFileNotFound,
   306  		},
   307  		// TestXLStorage case - 4.
   308  		{
   309  			volume: "exists",
   310  			path:   "as-file-parent/as-file",
   311  			err:    errFileNotFound,
   312  		},
   313  		// TestXLStorage case - 5.
   314  		// Validate the good condition file exists and we are able to read it.
   315  		{
   316  			volume: "exists",
   317  			path:   "as-file",
   318  			err:    nil,
   319  		},
   320  		// TestXLStorage case - 6.
   321  		// TestXLStorage case with invalid volume name.
   322  		{
   323  			volume: "ab",
   324  			path:   "as-file",
   325  			err:    errVolumeNotFound,
   326  		},
   327  	}
   328  
   329  	// Run through all the test cases and validate for ReadVersion.
   330  	for i, testCase := range testCases {
   331  		_, err = xlStorage.ReadVersion(context.Background(), testCase.volume, testCase.path, "", false)
   332  		if err != testCase.err {
   333  			t.Fatalf("TestXLStorage %d: Expected err \"%s\", got err \"%s\"", i+1, testCase.err, err)
   334  		}
   335  	}
   336  }
   337  
   338  // TestXLStorageReadAll - TestXLStorages the functionality implemented by xlStorage ReadAll storage API.
   339  func TestXLStorageReadAll(t *testing.T) {
   340  	// create xlStorage test setup
   341  	xlStorage, path, err := newXLStorageTestSetup()
   342  	if err != nil {
   343  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   344  	}
   345  
   346  	defer os.RemoveAll(path)
   347  
   348  	// Create files for the test cases.
   349  	if err = xlStorage.MakeVol(context.Background(), "exists"); err != nil {
   350  		t.Fatalf("Unable to create a volume \"exists\", %s", err)
   351  	}
   352  	if err = xlStorage.AppendFile(context.Background(), "exists", "as-directory/as-file", []byte("Hello, World")); err != nil {
   353  		t.Fatalf("Unable to create a file \"as-directory/as-file\", %s", err)
   354  	}
   355  	if err = xlStorage.AppendFile(context.Background(), "exists", "as-file", []byte("Hello, World")); err != nil {
   356  		t.Fatalf("Unable to create a file \"as-file\", %s", err)
   357  	}
   358  	if err = xlStorage.AppendFile(context.Background(), "exists", "as-file-parent", []byte("Hello, World")); err != nil {
   359  		t.Fatalf("Unable to create a file \"as-file-parent\", %s", err)
   360  	}
   361  
   362  	// TestXLStoragecases to validate different conditions for ReadAll API.
   363  	testCases := []struct {
   364  		volume string
   365  		path   string
   366  		err    error
   367  	}{
   368  		// TestXLStorage case - 1.
   369  		// Validate volume does not exist.
   370  		{
   371  			volume: "i-dont-exist",
   372  			path:   "",
   373  			err:    errVolumeNotFound,
   374  		},
   375  		// TestXLStorage case - 2.
   376  		// Validate bad condition file does not exist.
   377  		{
   378  			volume: "exists",
   379  			path:   "as-file-not-found",
   380  			err:    errFileNotFound,
   381  		},
   382  		// TestXLStorage case - 3.
   383  		// Validate bad condition file exists as prefix/directory and
   384  		// we are attempting to read it.
   385  		{
   386  			volume: "exists",
   387  			path:   "as-directory",
   388  			err:    errFileNotFound,
   389  		},
   390  		// TestXLStorage case - 4.
   391  		{
   392  			volume: "exists",
   393  			path:   "as-file-parent/as-file",
   394  			err:    errFileNotFound,
   395  		},
   396  		// TestXLStorage case - 5.
   397  		// Validate the good condition file exists and we are able to read it.
   398  		{
   399  			volume: "exists",
   400  			path:   "as-file",
   401  			err:    nil,
   402  		},
   403  		// TestXLStorage case - 6.
   404  		// TestXLStorage case with invalid volume name.
   405  		{
   406  			volume: "ab",
   407  			path:   "as-file",
   408  			err:    errVolumeNotFound,
   409  		},
   410  	}
   411  
   412  	var dataRead []byte
   413  	// Run through all the test cases and validate for ReadAll.
   414  	for i, testCase := range testCases {
   415  		dataRead, err = xlStorage.ReadAll(context.Background(), testCase.volume, testCase.path)
   416  		if err != testCase.err {
   417  			t.Fatalf("TestXLStorage %d: Expected err \"%s\", got err \"%s\"", i+1, testCase.err, err)
   418  		}
   419  		if err == nil {
   420  			if string(dataRead) != string([]byte("Hello, World")) {
   421  				t.Errorf("TestXLStorage %d: Expected the data read to be \"%s\", but instead got \"%s\"", i+1, "Hello, World", string(dataRead))
   422  			}
   423  		}
   424  	}
   425  }
   426  
   427  // TestNewXLStorage all the cases handled in xlStorage storage layer initialization.
   428  func TestNewXLStorage(t *testing.T) {
   429  	// Temporary dir name.
   430  	tmpDirName := globalTestTmpDir + SlashSeparator + "minio-" + nextSuffix()
   431  	// Temporary file name.
   432  	tmpFileName := globalTestTmpDir + SlashSeparator + "minio-" + nextSuffix()
   433  	f, _ := os.Create(tmpFileName)
   434  	f.Close()
   435  	defer os.Remove(tmpFileName)
   436  
   437  	// List of all tests for xlStorage initialization.
   438  	testCases := []struct {
   439  		name string
   440  		err  error
   441  	}{
   442  		// Validates input argument cannot be empty.
   443  		{
   444  			"",
   445  			errInvalidArgument,
   446  		},
   447  		// Validates if the directory does not exist and
   448  		// gets automatically created.
   449  		{
   450  			tmpDirName,
   451  			nil,
   452  		},
   453  		// Validates if the disk exists as file and returns error
   454  		// not a directory.
   455  		{
   456  			tmpFileName,
   457  			errDiskNotDir,
   458  		},
   459  	}
   460  
   461  	// Validate all test cases.
   462  	for i, testCase := range testCases {
   463  		// Initialize a new xlStorage layer.
   464  		_, err := newLocalXLStorage(testCase.name)
   465  		if err != testCase.err {
   466  			t.Fatalf("TestXLStorage %d failed wanted: %s, got: %s", i+1, err, testCase.err)
   467  		}
   468  	}
   469  }
   470  
   471  // TestXLStorageMakeVol - TestXLStorage validate the logic for creation of new xlStorage volume.
   472  // Asserts the failures too against the expected failures.
   473  func TestXLStorageMakeVol(t *testing.T) {
   474  	// create xlStorage test setup
   475  	xlStorage, path, err := newXLStorageTestSetup()
   476  	if err != nil {
   477  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   478  	}
   479  	defer os.RemoveAll(path)
   480  
   481  	// Setup test environment.
   482  	// Create a file.
   483  	if err := ioutil.WriteFile(slashpath.Join(path, "vol-as-file"), []byte{}, os.ModePerm); err != nil {
   484  		t.Fatalf("Unable to create file, %s", err)
   485  	}
   486  	// Create a directory.
   487  	if err := os.Mkdir(slashpath.Join(path, "existing-vol"), 0777); err != nil {
   488  		t.Fatalf("Unable to create directory, %s", err)
   489  	}
   490  
   491  	testCases := []struct {
   492  		volName     string
   493  		expectedErr error
   494  	}{
   495  		// TestXLStorage case - 1.
   496  		// A valid case, volume creation is expected to succeed.
   497  		{
   498  			volName:     "success-vol",
   499  			expectedErr: nil,
   500  		},
   501  		// TestXLStorage case - 2.
   502  		// Case where a file exists by the name of the volume to be created.
   503  		{
   504  			volName:     "vol-as-file",
   505  			expectedErr: errVolumeExists,
   506  		},
   507  		// TestXLStorage case - 3.
   508  		{
   509  			volName:     "existing-vol",
   510  			expectedErr: errVolumeExists,
   511  		},
   512  		// TestXLStorage case - 5.
   513  		// TestXLStorage case with invalid volume name.
   514  		{
   515  			volName:     "ab",
   516  			expectedErr: errInvalidArgument,
   517  		},
   518  	}
   519  
   520  	for i, testCase := range testCases {
   521  		if err := xlStorage.MakeVol(context.Background(), testCase.volName); err != testCase.expectedErr {
   522  			t.Fatalf("TestXLStorage %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err)
   523  		}
   524  	}
   525  
   526  	// TestXLStorage for permission denied.
   527  	if runtime.GOOS != globalWindowsOSName {
   528  		permDeniedDir, err := ioutil.TempDir(globalTestTmpDir, "minio-")
   529  		if err != nil {
   530  			t.Fatalf("Unable to create temporary directory. %v", err)
   531  		}
   532  		defer os.RemoveAll(permDeniedDir)
   533  		if err = os.Chmod(permDeniedDir, 0400); err != nil {
   534  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
   535  		}
   536  
   537  		// Initialize xlStorage storage layer for permission denied error.
   538  		_, err = newLocalXLStorage(permDeniedDir)
   539  		if err != nil && err != errDiskAccessDenied {
   540  			t.Fatalf("Unable to initialize xlStorage, %s", err)
   541  		}
   542  
   543  		if err = os.Chmod(permDeniedDir, 0755); err != nil {
   544  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
   545  		}
   546  
   547  		xlStorageNew, err := newLocalXLStorage(permDeniedDir)
   548  		if err != nil {
   549  			t.Fatalf("Unable to initialize xlStorage, %s", err)
   550  		}
   551  
   552  		// change backend permissions for MakeVol error.
   553  		if err = os.Chmod(permDeniedDir, 0400); err != nil {
   554  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
   555  		}
   556  
   557  		if err := xlStorageNew.MakeVol(context.Background(), "test-vol"); err != errDiskAccessDenied {
   558  			t.Fatalf("expected: %s, got: %s", errDiskAccessDenied, err)
   559  		}
   560  	}
   561  }
   562  
   563  // TestXLStorageDeleteVol - Validates the expected behavior of xlStorage.DeleteVol for various cases.
   564  func TestXLStorageDeleteVol(t *testing.T) {
   565  	// create xlStorage test setup
   566  	xlStorage, path, err := newXLStorageTestSetup()
   567  	if err != nil {
   568  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   569  	}
   570  	defer os.RemoveAll(path)
   571  
   572  	// Setup test environment.
   573  	if err = xlStorage.MakeVol(context.Background(), "success-vol"); err != nil {
   574  		t.Fatalf("Unable to create volume, %s", err)
   575  	}
   576  
   577  	// TestXLStorage failure cases.
   578  	vol := slashpath.Join(path, "nonempty-vol")
   579  	if err = os.Mkdir(vol, 0777); err != nil {
   580  		t.Fatalf("Unable to create directory, %s", err)
   581  	}
   582  	if err = ioutil.WriteFile(slashpath.Join(vol, "test-file"), []byte{}, os.ModePerm); err != nil {
   583  		t.Fatalf("Unable to create file, %s", err)
   584  	}
   585  
   586  	testCases := []struct {
   587  		volName     string
   588  		expectedErr error
   589  	}{
   590  		// TestXLStorage case  - 1.
   591  		// A valida case. Empty vol, should be possible to delete.
   592  		{
   593  			volName:     "success-vol",
   594  			expectedErr: nil,
   595  		},
   596  		// TestXLStorage case - 2.
   597  		// volume is non-existent.
   598  		{
   599  			volName:     "nonexistent-vol",
   600  			expectedErr: errVolumeNotFound,
   601  		},
   602  		// TestXLStorage case - 3.
   603  		// It shouldn't be possible to delete an non-empty volume, validating the same.
   604  		{
   605  			volName:     "nonempty-vol",
   606  			expectedErr: errVolumeNotEmpty,
   607  		},
   608  		// TestXLStorage case - 5.
   609  		// Invalid volume name.
   610  		{
   611  			volName:     "ab",
   612  			expectedErr: errVolumeNotFound,
   613  		},
   614  	}
   615  
   616  	for i, testCase := range testCases {
   617  		if err = xlStorage.DeleteVol(context.Background(), testCase.volName, false); err != testCase.expectedErr {
   618  			t.Fatalf("TestXLStorage: %d, expected: %s, got: %s", i+1, testCase.expectedErr, err)
   619  		}
   620  	}
   621  
   622  	// TestXLStorage for permission denied.
   623  	if runtime.GOOS != globalWindowsOSName {
   624  		var permDeniedDir string
   625  		if permDeniedDir, err = ioutil.TempDir(globalTestTmpDir, "minio-"); err != nil {
   626  			t.Fatalf("Unable to create temporary directory. %v", err)
   627  		}
   628  		defer removePermDeniedFile(permDeniedDir)
   629  		if err = os.Mkdir(slashpath.Join(permDeniedDir, "mybucket"), 0400); err != nil {
   630  			t.Fatalf("Unable to create temporary directory %v. %v", slashpath.Join(permDeniedDir, "mybucket"), err)
   631  		}
   632  		if err = os.Chmod(permDeniedDir, 0400); err != nil {
   633  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
   634  		}
   635  
   636  		// Initialize xlStorage storage layer for permission denied error.
   637  		_, err = newLocalXLStorage(permDeniedDir)
   638  		if err != nil && err != errDiskAccessDenied {
   639  			t.Fatalf("Unable to initialize xlStorage, %s", err)
   640  		}
   641  
   642  		if err = os.Chmod(permDeniedDir, 0755); err != nil {
   643  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
   644  		}
   645  
   646  		xlStorageNew, err := newLocalXLStorage(permDeniedDir)
   647  		if err != nil {
   648  			t.Fatalf("Unable to initialize xlStorage, %s", err)
   649  		}
   650  
   651  		// change backend permissions for MakeVol error.
   652  		if err = os.Chmod(permDeniedDir, 0400); err != nil {
   653  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
   654  		}
   655  
   656  		if err = xlStorageNew.DeleteVol(context.Background(), "mybucket", false); err != errDiskAccessDenied {
   657  			t.Fatalf("expected: Permission error, got: %s", err)
   658  		}
   659  	}
   660  
   661  	xlStorageDeletedStorage, diskPath, err := newXLStorageTestSetup()
   662  	if err != nil {
   663  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   664  	}
   665  	// removing the disk, used to recreate disk not found error.
   666  	os.RemoveAll(diskPath)
   667  
   668  	// TestXLStorage for delete on an removed disk.
   669  	// should fail with disk not found.
   670  	err = xlStorageDeletedStorage.DeleteVol(context.Background(), "Del-Vol", false)
   671  	if err != errDiskNotFound {
   672  		t.Errorf("Expected: \"Disk not found\", got \"%s\"", err)
   673  	}
   674  }
   675  
   676  // TestXLStorageStatVol - TestXLStorages validate the volume info returned by xlStorage.StatVol() for various inputs.
   677  func TestXLStorageStatVol(t *testing.T) {
   678  	// create xlStorage test setup
   679  	xlStorage, path, err := newXLStorageTestSetup()
   680  	if err != nil {
   681  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   682  	}
   683  	defer os.RemoveAll(path)
   684  
   685  	// Setup test environment.
   686  	if err = xlStorage.MakeVol(context.Background(), "success-vol"); err != nil {
   687  		t.Fatalf("Unable to create volume, %s", err)
   688  	}
   689  
   690  	testCases := []struct {
   691  		volName     string
   692  		expectedErr error
   693  	}{
   694  		// TestXLStorage case - 1.
   695  		{
   696  			volName:     "success-vol",
   697  			expectedErr: nil,
   698  		},
   699  		// TestXLStorage case - 2.
   700  		{
   701  			volName:     "nonexistent-vol",
   702  			expectedErr: errVolumeNotFound,
   703  		},
   704  		// TestXLStorage case - 3.
   705  		{
   706  			volName:     "ab",
   707  			expectedErr: errVolumeNotFound,
   708  		},
   709  	}
   710  
   711  	for i, testCase := range testCases {
   712  		var volInfo VolInfo
   713  		volInfo, err = xlStorage.StatVol(context.Background(), testCase.volName)
   714  		if err != testCase.expectedErr {
   715  			t.Fatalf("TestXLStorage case : %d, Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err)
   716  		}
   717  
   718  		if err == nil {
   719  			if volInfo.Name != testCase.volName {
   720  				t.Errorf("TestXLStorage case %d: Expected the volume name to be \"%s\", instead found \"%s\"",
   721  					i+1, volInfo.Name, testCase.volName)
   722  			}
   723  		}
   724  	}
   725  
   726  	xlStorageDeletedStorage, diskPath, err := newXLStorageTestSetup()
   727  	if err != nil {
   728  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   729  	}
   730  	// removing the disk, used to recreate disk not found error.
   731  	os.RemoveAll(diskPath)
   732  
   733  	// TestXLStorage for delete on an removed disk.
   734  	// should fail with disk not found.
   735  	_, err = xlStorageDeletedStorage.StatVol(context.Background(), "Stat vol")
   736  	if err != errDiskNotFound {
   737  		t.Errorf("Expected: \"Disk not found\", got \"%s\"", err)
   738  	}
   739  }
   740  
   741  // TestXLStorageListVols - Validates the result and the error output for xlStorage volume listing functionality xlStorage.ListVols().
   742  func TestXLStorageListVols(t *testing.T) {
   743  	// create xlStorage test setup
   744  	xlStorage, path, err := newXLStorageTestSetup()
   745  	if err != nil {
   746  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   747  	}
   748  
   749  	var volInfos []VolInfo
   750  	// TestXLStorage empty list vols.
   751  	if volInfos, err = xlStorage.ListVols(context.Background()); err != nil {
   752  		t.Fatalf("expected: <nil>, got: %s", err)
   753  	} else if len(volInfos) != 1 {
   754  		t.Fatalf("expected: one entry, got: %s", volInfos)
   755  	}
   756  
   757  	// TestXLStorage non-empty list vols.
   758  	if err = xlStorage.MakeVol(context.Background(), "success-vol"); err != nil {
   759  		t.Fatalf("Unable to create volume, %s", err)
   760  	}
   761  
   762  	volInfos, err = xlStorage.ListVols(context.Background())
   763  	if err != nil {
   764  		t.Fatalf("expected: <nil>, got: %s", err)
   765  	}
   766  	if len(volInfos) != 2 {
   767  		t.Fatalf("expected: 2, got: %d", len(volInfos))
   768  	}
   769  	volFound := false
   770  	for _, info := range volInfos {
   771  		if info.Name == "success-vol" {
   772  			volFound = true
   773  			break
   774  		}
   775  	}
   776  	if !volFound {
   777  		t.Errorf("expected: success-vol to be created")
   778  	}
   779  
   780  	// removing the path and simulating disk failure
   781  	os.RemoveAll(path)
   782  	// should fail with errDiskNotFound.
   783  	if _, err = xlStorage.ListVols(context.Background()); err != errDiskNotFound {
   784  		t.Errorf("Expected to fail with \"%s\", but instead failed with \"%s\"", errDiskNotFound, err)
   785  	}
   786  }
   787  
   788  // TestXLStorageListDir -  TestXLStorages validate the directory listing functionality provided by xlStorage.ListDir .
   789  func TestXLStorageListDir(t *testing.T) {
   790  	// create xlStorage test setup
   791  	xlStorage, path, err := newXLStorageTestSetup()
   792  	if err != nil {
   793  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   794  	}
   795  	defer os.RemoveAll(path)
   796  
   797  	// create xlStorage test setup.
   798  	xlStorageDeletedStorage, diskPath, err := newXLStorageTestSetup()
   799  	if err != nil {
   800  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   801  	}
   802  	// removing the disk, used to recreate disk not found error.
   803  	os.RemoveAll(diskPath)
   804  	// Setup test environment.
   805  	if err = xlStorage.MakeVol(context.Background(), "success-vol"); err != nil {
   806  		t.Fatalf("Unable to create volume, %s", err)
   807  	}
   808  	if err = xlStorage.AppendFile(context.Background(), "success-vol", "abc/def/ghi/success-file", []byte("Hello, world")); err != nil {
   809  		t.Fatalf("Unable to create file, %s", err)
   810  	}
   811  	if err = xlStorage.AppendFile(context.Background(), "success-vol", "abc/xyz/ghi/success-file", []byte("Hello, world")); err != nil {
   812  		t.Fatalf("Unable to create file, %s", err)
   813  	}
   814  
   815  	testCases := []struct {
   816  		srcVol  string
   817  		srcPath string
   818  		// expected result.
   819  		expectedListDir []string
   820  		expectedErr     error
   821  	}{
   822  		// TestXLStorage case - 1.
   823  		// valid case with existing volume and file to delete.
   824  		{
   825  			srcVol:          "success-vol",
   826  			srcPath:         "abc",
   827  			expectedListDir: []string{"def/", "xyz/"},
   828  			expectedErr:     nil,
   829  		},
   830  		// TestXLStorage case - 1.
   831  		// valid case with existing volume and file to delete.
   832  		{
   833  			srcVol:          "success-vol",
   834  			srcPath:         "abc/def",
   835  			expectedListDir: []string{"ghi/"},
   836  			expectedErr:     nil,
   837  		},
   838  		// TestXLStorage case - 1.
   839  		// valid case with existing volume and file to delete.
   840  		{
   841  			srcVol:          "success-vol",
   842  			srcPath:         "abc/def/ghi",
   843  			expectedListDir: []string{"success-file"},
   844  			expectedErr:     nil,
   845  		},
   846  		// TestXLStorage case - 2.
   847  		{
   848  			srcVol:      "success-vol",
   849  			srcPath:     "abcdef",
   850  			expectedErr: errFileNotFound,
   851  		},
   852  		// TestXLStorage case - 3.
   853  		// TestXLStorage case with invalid volume name.
   854  		{
   855  			srcVol:      "ab",
   856  			srcPath:     "success-file",
   857  			expectedErr: errVolumeNotFound,
   858  		},
   859  		// TestXLStorage case - 4.
   860  		// TestXLStorage case with non existent volume.
   861  		{
   862  			srcVol:      "non-existent-vol",
   863  			srcPath:     "success-file",
   864  			expectedErr: errVolumeNotFound,
   865  		},
   866  	}
   867  
   868  	for i, testCase := range testCases {
   869  		var dirList []string
   870  		dirList, err = xlStorage.ListDir(context.Background(), testCase.srcVol, testCase.srcPath, -1)
   871  		if err != testCase.expectedErr {
   872  			t.Errorf("TestXLStorage case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err)
   873  		}
   874  		if err == nil {
   875  			for _, expected := range testCase.expectedListDir {
   876  				if !strings.Contains(strings.Join(dirList, ","), expected) {
   877  					t.Errorf("TestXLStorage case %d: Expected the directory listing to be \"%v\", but got \"%v\"", i+1, testCase.expectedListDir, dirList)
   878  				}
   879  			}
   880  		}
   881  	}
   882  
   883  	// TestXLStorage for permission denied.
   884  	if runtime.GOOS != globalWindowsOSName {
   885  		permDeniedDir := createPermDeniedFile(t)
   886  		defer removePermDeniedFile(permDeniedDir)
   887  
   888  		// Initialize xlStorage storage layer for permission denied error.
   889  		_, err = newLocalXLStorage(permDeniedDir)
   890  		if err != nil && err != errDiskAccessDenied {
   891  			t.Fatalf("Unable to initialize xlStorage, %s", err)
   892  		}
   893  
   894  		if err = os.Chmod(permDeniedDir, 0755); err != nil {
   895  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
   896  		}
   897  
   898  		xlStorageNew, err := newLocalXLStorage(permDeniedDir)
   899  		if err != nil {
   900  			t.Fatalf("Unable to initialize xlStorage, %s", err)
   901  		}
   902  
   903  		if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", false); err != errVolumeAccessDenied {
   904  			t.Errorf("expected: %s, got: %s", errVolumeAccessDenied, err)
   905  		}
   906  	}
   907  
   908  	// TestXLStorage for delete on an removed disk.
   909  	// should fail with disk not found.
   910  	err = xlStorageDeletedStorage.Delete(context.Background(), "del-vol", "my-file", false)
   911  	if err != errDiskNotFound {
   912  		t.Errorf("Expected: \"Disk not found\", got \"%s\"", err)
   913  	}
   914  }
   915  
   916  // TestXLStorageDeleteFile - Series of test cases construct valid and invalid input data and validates the result and the error response.
   917  func TestXLStorageDeleteFile(t *testing.T) {
   918  	if runtime.GOOS == globalWindowsOSName {
   919  		t.Skip()
   920  	}
   921  
   922  	// create xlStorage test setup
   923  	xlStorage, path, err := newXLStorageTestSetup()
   924  	if err != nil {
   925  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   926  	}
   927  	defer os.RemoveAll(path)
   928  
   929  	// create xlStorage test setup
   930  	xlStorageDeletedStorage, diskPath, err := newXLStorageTestSetup()
   931  	if err != nil {
   932  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
   933  	}
   934  	// removing the disk, used to recreate disk not found error.
   935  	os.RemoveAll(diskPath)
   936  	// Setup test environment.
   937  	if err = xlStorage.MakeVol(context.Background(), "success-vol"); err != nil {
   938  		t.Fatalf("Unable to create volume, %s", err)
   939  	}
   940  	if err = xlStorage.AppendFile(context.Background(), "success-vol", "success-file", []byte("Hello, world")); err != nil {
   941  		t.Fatalf("Unable to create file, %s", err)
   942  	}
   943  
   944  	if err = xlStorage.MakeVol(context.Background(), "no-permissions"); err != nil {
   945  		t.Fatalf("Unable to create volume, %s", err.Error())
   946  	}
   947  	if err = xlStorage.AppendFile(context.Background(), "no-permissions", "dir/file", []byte("Hello, world")); err != nil {
   948  		t.Fatalf("Unable to create file, %s", err.Error())
   949  	}
   950  	// Parent directory must have write permissions, this is read + execute.
   951  	if err = os.Chmod(pathJoin(path, "no-permissions"), 0555); err != nil {
   952  		t.Fatalf("Unable to chmod directory, %s", err.Error())
   953  	}
   954  
   955  	testCases := []struct {
   956  		srcVol      string
   957  		srcPath     string
   958  		expectedErr error
   959  	}{
   960  		// TestXLStorage case - 1.
   961  		// valid case with existing volume and file to delete.
   962  		{
   963  			srcVol:      "success-vol",
   964  			srcPath:     "success-file",
   965  			expectedErr: nil,
   966  		},
   967  		// TestXLStorage case - 2.
   968  		// The file was deleted in the last  case, so Delete should fail.
   969  		{
   970  			srcVol:      "success-vol",
   971  			srcPath:     "success-file",
   972  			expectedErr: errFileNotFound,
   973  		},
   974  		// TestXLStorage case - 3.
   975  		// TestXLStorage case with segment of the volume name > 255.
   976  		{
   977  			srcVol:      "my",
   978  			srcPath:     "success-file",
   979  			expectedErr: errVolumeNotFound,
   980  		},
   981  		// TestXLStorage case - 4.
   982  		// TestXLStorage case with non-existent volume.
   983  		{
   984  			srcVol:      "non-existent-vol",
   985  			srcPath:     "success-file",
   986  			expectedErr: errVolumeNotFound,
   987  		},
   988  		// TestXLStorage case - 5.
   989  		// TestXLStorage case with src path segment > 255.
   990  		{
   991  			srcVol:      "success-vol",
   992  			srcPath:     "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
   993  			expectedErr: errFileNameTooLong,
   994  		},
   995  		// TestXLStorage case - 6.
   996  		// TestXLStorage case with undeletable parent directory.
   997  		// File can delete, dir cannot delete because no-permissions doesn't have write perms.
   998  		{
   999  			srcVol:      "no-permissions",
  1000  			srcPath:     "dir/file",
  1001  			expectedErr: errVolumeAccessDenied,
  1002  		},
  1003  	}
  1004  
  1005  	for i, testCase := range testCases {
  1006  		if err = xlStorage.Delete(context.Background(), testCase.srcVol, testCase.srcPath, false); err != testCase.expectedErr {
  1007  			t.Errorf("TestXLStorage case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err)
  1008  		}
  1009  	}
  1010  
  1011  	// TestXLStorage for permission denied.
  1012  	if runtime.GOOS != globalWindowsOSName {
  1013  		permDeniedDir := createPermDeniedFile(t)
  1014  		defer removePermDeniedFile(permDeniedDir)
  1015  
  1016  		// Initialize xlStorage storage layer for permission denied error.
  1017  		_, err = newLocalXLStorage(permDeniedDir)
  1018  		if err != nil && err != errDiskAccessDenied {
  1019  			t.Fatalf("Unable to initialize xlStorage, %s", err)
  1020  		}
  1021  
  1022  		if err = os.Chmod(permDeniedDir, 0755); err != nil {
  1023  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
  1024  		}
  1025  
  1026  		xlStorageNew, err := newLocalXLStorage(permDeniedDir)
  1027  		if err != nil {
  1028  			t.Fatalf("Unable to initialize xlStorage, %s", err)
  1029  		}
  1030  
  1031  		if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", false); err != errVolumeAccessDenied {
  1032  			t.Errorf("expected: %s, got: %s", errVolumeAccessDenied, err)
  1033  		}
  1034  	}
  1035  
  1036  	// TestXLStorage for delete on an removed disk.
  1037  	// should fail with disk not found.
  1038  	err = xlStorageDeletedStorage.Delete(context.Background(), "del-vol", "my-file", false)
  1039  	if err != errDiskNotFound {
  1040  		t.Errorf("Expected: \"Disk not found\", got \"%s\"", err)
  1041  	}
  1042  }
  1043  
  1044  // TestXLStorageReadFile - TestXLStorages xlStorage.ReadFile with wide range of cases and asserts the result and error response.
  1045  func TestXLStorageReadFile(t *testing.T) {
  1046  	// create xlStorage test setup
  1047  	xlStorage, path, err := newXLStorageTestSetup()
  1048  	if err != nil {
  1049  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
  1050  	}
  1051  	defer os.RemoveAll(path)
  1052  
  1053  	volume := "success-vol"
  1054  	// Setup test environment.
  1055  	if err = xlStorage.MakeVol(context.Background(), volume); err != nil {
  1056  		t.Fatalf("Unable to create volume, %s", err)
  1057  	}
  1058  
  1059  	// Create directory to make errIsNotRegular
  1060  	if err = os.Mkdir(slashpath.Join(path, "success-vol", "object-as-dir"), 0777); err != nil {
  1061  		t.Fatalf("Unable to create directory, %s", err)
  1062  	}
  1063  
  1064  	testCases := []struct {
  1065  		volume      string
  1066  		fileName    string
  1067  		offset      int64
  1068  		bufSize     int
  1069  		expectedBuf []byte
  1070  		expectedErr error
  1071  	}{
  1072  		// Successful read at offset 0 and proper buffer size. - 1
  1073  		{
  1074  			volume, "myobject", 0, 5,
  1075  			[]byte("hello"), nil,
  1076  		},
  1077  		// Success read at hierarchy. - 2
  1078  		{
  1079  			volume, "path/to/my/object", 0, 5,
  1080  			[]byte("hello"), nil,
  1081  		},
  1082  		// Object is a directory. - 3
  1083  		{
  1084  			volume, "object-as-dir",
  1085  			0, 5, nil, errIsNotRegular},
  1086  		// One path segment length is > 255 chars long. - 4
  1087  		{
  1088  			volume, "path/to/my/object0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
  1089  			0, 5, nil, errFileNameTooLong},
  1090  		// Path length is > 1024 chars long. - 5
  1091  		{
  1092  			volume, "level0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001/level0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002/level0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003/object000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
  1093  			0, 5, nil, errFileNameTooLong},
  1094  		// Buffer size greater than object size. - 6
  1095  		{
  1096  			volume, "myobject", 0, 16,
  1097  			[]byte("hello, world"),
  1098  			io.ErrUnexpectedEOF,
  1099  		},
  1100  		// Reading from an offset success. - 7
  1101  		{
  1102  			volume, "myobject", 7, 5,
  1103  			[]byte("world"), nil,
  1104  		},
  1105  		// Reading from an object but buffer size greater. - 8
  1106  		{
  1107  			volume, "myobject",
  1108  			7, 8,
  1109  			[]byte("world"),
  1110  			io.ErrUnexpectedEOF,
  1111  		},
  1112  		// Seeking ahead returns io.EOF. - 9
  1113  		{
  1114  			volume, "myobject", 14, 1, nil, io.EOF,
  1115  		},
  1116  		// Empty volume name. - 10
  1117  		{
  1118  			"", "myobject", 14, 1, nil, errVolumeNotFound,
  1119  		},
  1120  		// Empty filename name. - 11
  1121  		{
  1122  			volume, "", 14, 1, nil, errIsNotRegular,
  1123  		},
  1124  		// Non existent volume name - 12
  1125  		{
  1126  			"abcd", "", 14, 1, nil, errVolumeNotFound,
  1127  		},
  1128  		// Non existent filename - 13
  1129  		{
  1130  			volume, "abcd", 14, 1, nil, errFileNotFound,
  1131  		},
  1132  	}
  1133  
  1134  	// Create all files needed during testing.
  1135  	appendFiles := testCases[:4]
  1136  	v := NewBitrotVerifier(SHA256, getSHA256Sum([]byte("hello, world")))
  1137  	// Create test files for further reading.
  1138  	for i, appendFile := range appendFiles {
  1139  		err = xlStorage.AppendFile(context.Background(), volume, appendFile.fileName, []byte("hello, world"))
  1140  		if err != appendFile.expectedErr {
  1141  			t.Fatalf("Creating file failed: %d %#v, expected: %s, got: %s", i+1, appendFile, appendFile.expectedErr, err)
  1142  		}
  1143  	}
  1144  
  1145  	{
  1146  		buf := make([]byte, 5)
  1147  		// Test for negative offset.
  1148  		if _, err = xlStorage.ReadFile(context.Background(), volume, "myobject", -1, buf, v); err == nil {
  1149  			t.Fatalf("expected: error, got: <nil>")
  1150  		}
  1151  	}
  1152  
  1153  	for l := 0; l < 2; l++ {
  1154  		// 1st loop tests with dma=write, 2nd loop tests with dma=read-write.
  1155  		if l == 1 {
  1156  			globalStorageClass.DMA = storageclass.DMAReadWrite
  1157  		}
  1158  		// Following block validates all ReadFile test cases.
  1159  		for i, testCase := range testCases {
  1160  			var n int64
  1161  			// Common read buffer.
  1162  			var buf = make([]byte, testCase.bufSize)
  1163  			n, err = xlStorage.ReadFile(context.Background(), testCase.volume, testCase.fileName, testCase.offset, buf, v)
  1164  			if err != nil && testCase.expectedErr != nil {
  1165  				// Validate if the type string of the errors are an exact match.
  1166  				if err.Error() != testCase.expectedErr.Error() {
  1167  					if runtime.GOOS != globalWindowsOSName {
  1168  						t.Errorf("Case: %d %#v, expected: %s, got: %s", i+1, testCase, testCase.expectedErr, err)
  1169  					} else {
  1170  						var resultErrno, expectErrno uintptr
  1171  						if pathErr, ok := err.(*os.PathError); ok {
  1172  							if errno, pok := pathErr.Err.(syscall.Errno); pok {
  1173  								resultErrno = uintptr(errno)
  1174  							}
  1175  						}
  1176  						if pathErr, ok := testCase.expectedErr.(*os.PathError); ok {
  1177  							if errno, pok := pathErr.Err.(syscall.Errno); pok {
  1178  								expectErrno = uintptr(errno)
  1179  							}
  1180  						}
  1181  						if !(expectErrno != 0 && resultErrno != 0 && expectErrno == resultErrno) {
  1182  							t.Errorf("Case: %d %#v, expected: %s, got: %s", i+1, testCase, testCase.expectedErr, err)
  1183  						}
  1184  					}
  1185  				}
  1186  				// Err unexpected EOF special case, where we verify we have provided a larger
  1187  				// buffer than the data itself, but the results are in-fact valid. So we validate
  1188  				// this error condition specifically treating it as a good condition with valid
  1189  				// results. In this scenario return 'n' is always lesser than the input buffer.
  1190  				if err == io.ErrUnexpectedEOF {
  1191  					if !bytes.Equal(testCase.expectedBuf, buf[:n]) {
  1192  						t.Errorf("Case: %d %#v, expected: \"%s\", got: \"%s\"", i+1, testCase, string(testCase.expectedBuf), string(buf[:n]))
  1193  					}
  1194  					if n > int64(len(buf)) {
  1195  						t.Errorf("Case: %d %#v, expected: %d, got: %d", i+1, testCase, testCase.bufSize, n)
  1196  					}
  1197  				}
  1198  			}
  1199  			// ReadFile has returned success, but our expected error is non 'nil'.
  1200  			if err == nil && err != testCase.expectedErr {
  1201  				t.Errorf("Case: %d %#v, expected: %s, got :%s", i+1, testCase, testCase.expectedErr, err)
  1202  			}
  1203  			// Expected error retured, proceed further to validate the returned results.
  1204  			if err == nil && err == testCase.expectedErr {
  1205  				if !bytes.Equal(testCase.expectedBuf, buf) {
  1206  					t.Errorf("Case: %d %#v, expected: \"%s\", got: \"%s\"", i+1, testCase, string(testCase.expectedBuf), string(buf[:testCase.bufSize]))
  1207  				}
  1208  				if n != int64(testCase.bufSize) {
  1209  					t.Errorf("Case: %d %#v, expected: %d, got: %d", i+1, testCase, testCase.bufSize, n)
  1210  				}
  1211  			}
  1212  		}
  1213  	}
  1214  
  1215  	// Reset the flag.
  1216  	globalStorageClass.DMA = storageclass.DMAWrite
  1217  
  1218  	// TestXLStorage for permission denied.
  1219  	if runtime.GOOS != globalWindowsOSName {
  1220  		permDeniedDir := createPermDeniedFile(t)
  1221  		defer removePermDeniedFile(permDeniedDir)
  1222  
  1223  		// Initialize xlStorage storage layer for permission denied error.
  1224  		_, err = newLocalXLStorage(permDeniedDir)
  1225  		if err != nil && err != errDiskAccessDenied {
  1226  			t.Fatalf("Unable to initialize xlStorage, %s", err)
  1227  		}
  1228  
  1229  		if err = os.Chmod(permDeniedDir, 0755); err != nil {
  1230  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
  1231  		}
  1232  
  1233  		xlStoragePermStorage, err := newLocalXLStorage(permDeniedDir)
  1234  		if err != nil {
  1235  			t.Fatalf("Unable to initialize xlStorage, %s", err)
  1236  		}
  1237  
  1238  		// Common read buffer.
  1239  		var buf = make([]byte, 10)
  1240  		if _, err = xlStoragePermStorage.ReadFile(context.Background(), "mybucket", "myobject", 0, buf, v); err != errFileAccessDenied {
  1241  			t.Errorf("expected: %s, got: %s", errFileAccessDenied, err)
  1242  		}
  1243  	}
  1244  }
  1245  
  1246  var xlStorageReadFileWithVerifyTests = []struct {
  1247  	file      string
  1248  	offset    int
  1249  	length    int
  1250  	algorithm BitrotAlgorithm
  1251  	expError  error
  1252  }{
  1253  	{file: "myobject", offset: 0, length: 100, algorithm: SHA256, expError: nil},                // 0
  1254  	{file: "myobject", offset: 25, length: 74, algorithm: SHA256, expError: nil},                // 1
  1255  	{file: "myobject", offset: 29, length: 70, algorithm: SHA256, expError: nil},                // 2
  1256  	{file: "myobject", offset: 100, length: 0, algorithm: SHA256, expError: nil},                // 3
  1257  	{file: "myobject", offset: 1, length: 120, algorithm: SHA256, expError: errFileCorrupt},     // 4
  1258  	{file: "myobject", offset: 3, length: 1100, algorithm: SHA256, expError: nil},               // 5
  1259  	{file: "myobject", offset: 2, length: 100, algorithm: SHA256, expError: errFileCorrupt},     // 6
  1260  	{file: "myobject", offset: 1000, length: 1001, algorithm: SHA256, expError: nil},            // 7
  1261  	{file: "myobject", offset: 0, length: 100, algorithm: BLAKE2b512, expError: errFileCorrupt}, // 8
  1262  	{file: "myobject", offset: 25, length: 74, algorithm: BLAKE2b512, expError: nil},            // 9
  1263  	{file: "myobject", offset: 29, length: 70, algorithm: BLAKE2b512, expError: errFileCorrupt}, // 10
  1264  	{file: "myobject", offset: 100, length: 0, algorithm: BLAKE2b512, expError: nil},            // 11
  1265  	{file: "myobject", offset: 1, length: 120, algorithm: BLAKE2b512, expError: nil},            // 12
  1266  	{file: "myobject", offset: 3, length: 1100, algorithm: BLAKE2b512, expError: nil},           // 13
  1267  	{file: "myobject", offset: 2, length: 100, algorithm: BLAKE2b512, expError: nil},            // 14
  1268  	{file: "myobject", offset: 1000, length: 1001, algorithm: BLAKE2b512, expError: nil},        // 15
  1269  }
  1270  
  1271  // TestXLStorageReadFile with bitrot verification - tests the xlStorage level
  1272  // ReadFile API with a BitrotVerifier. Only tests hashing related
  1273  // functionality. Other functionality is tested with
  1274  // TestXLStorageReadFile.
  1275  func TestXLStorageReadFileWithVerify(t *testing.T) {
  1276  	volume, object := "test-vol", "myobject"
  1277  	xlStorage, path, err := newXLStorageTestSetup()
  1278  	if err != nil {
  1279  		os.RemoveAll(path)
  1280  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
  1281  	}
  1282  	if err = xlStorage.MakeVol(context.Background(), volume); err != nil {
  1283  		os.RemoveAll(path)
  1284  		t.Fatalf("Unable to create volume %s: %v", volume, err)
  1285  	}
  1286  	data := make([]byte, 8*1024)
  1287  	if _, err = io.ReadFull(rand.Reader, data); err != nil {
  1288  		os.RemoveAll(path)
  1289  		t.Fatalf("Unable to create generate random data: %v", err)
  1290  	}
  1291  	if err = xlStorage.AppendFile(context.Background(), volume, object, data); err != nil {
  1292  		os.RemoveAll(path)
  1293  		t.Fatalf("Unable to create object: %v", err)
  1294  	}
  1295  
  1296  	for i, test := range xlStorageReadFileWithVerifyTests {
  1297  		h := test.algorithm.New()
  1298  		h.Write(data)
  1299  		if test.expError != nil {
  1300  			h.Write([]byte{0})
  1301  		}
  1302  
  1303  		buffer := make([]byte, test.length)
  1304  		n, err := xlStorage.ReadFile(context.Background(), volume, test.file, int64(test.offset), buffer, NewBitrotVerifier(test.algorithm, h.Sum(nil)))
  1305  
  1306  		switch {
  1307  		case err == nil && test.expError != nil:
  1308  			t.Errorf("Test %d: Expected error %v but got none.", i, test.expError)
  1309  		case err == nil && n != int64(test.length):
  1310  			t.Errorf("Test %d: %d bytes were expected, but %d were written", i, test.length, n)
  1311  		case err == nil && !bytes.Equal(data[test.offset:test.offset+test.length], buffer):
  1312  			t.Errorf("Test %d: Expected bytes: %v, but got: %v", i, data[test.offset:test.offset+test.length], buffer)
  1313  		case err != nil && err != test.expError:
  1314  			t.Errorf("Test %d: Expected error: %v, but got: %v", i, test.expError, err)
  1315  		}
  1316  	}
  1317  }
  1318  
  1319  // TestXLStorageFormatFileChange - to test if changing the diskID makes the calls fail.
  1320  func TestXLStorageFormatFileChange(t *testing.T) {
  1321  	xlStorage, path, err := newXLStorageTestSetup()
  1322  	if err != nil {
  1323  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
  1324  	}
  1325  	defer os.RemoveAll(path)
  1326  
  1327  	if err = xlStorage.MakeVol(context.Background(), volume); err != nil {
  1328  		t.Fatalf("MakeVol failed with %s", err)
  1329  	}
  1330  
  1331  	// Change the format.json such that "this" is changed to "randomid".
  1332  	if err = ioutil.WriteFile(pathJoin(xlStorage.String(), minioMetaBucket, formatConfigFile), []byte(`{"version":"1","format":"xl","id":"592a41c2-b7cc-4130-b883-c4b5cb15965b","xl":{"version":"3","this":"randomid","sets":[["e07285a6-8c73-4962-89c6-047fb939f803","33b8d431-482d-4376-b63c-626d229f0a29","cff6513a-4439-4dc1-bcaa-56c9e880c352","randomid","9c9f21d5-1f15-4737-bce6-835faa0d9626","0a59b346-1424-4fc2-9fa2-a2e80541d0c1","7924a3dc-b69a-4971-9a2e-014966d6aebb","4d2b8dd9-4e48-444b-bdca-c89194b26042"]],"distributionAlgo":"CRCMOD"}}`), 0644); err != nil {
  1333  		t.Fatalf("ioutil.WriteFile failed with %s", err)
  1334  	}
  1335  
  1336  	err = xlStorage.MakeVol(context.Background(), volume)
  1337  	if err != errVolumeExists {
  1338  		t.Fatalf("MakeVol expected to fail with errDiskNotFound but failed with %s", err)
  1339  	}
  1340  }
  1341  
  1342  // TestXLStorage xlStorage.AppendFile()
  1343  func TestXLStorageAppendFile(t *testing.T) {
  1344  	// create xlStorage test setup
  1345  	xlStorage, path, err := newXLStorageTestSetup()
  1346  	if err != nil {
  1347  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
  1348  	}
  1349  	defer os.RemoveAll(path)
  1350  
  1351  	// Setup test environment.
  1352  	if err = xlStorage.MakeVol(context.Background(), "success-vol"); err != nil {
  1353  		t.Fatalf("Unable to create volume, %s", err)
  1354  	}
  1355  
  1356  	// Create directory to make errIsNotRegular
  1357  	if err = os.Mkdir(slashpath.Join(path, "success-vol", "object-as-dir"), 0777); err != nil {
  1358  		t.Fatalf("Unable to create directory, %s", err)
  1359  	}
  1360  
  1361  	testCases := []struct {
  1362  		fileName    string
  1363  		expectedErr error
  1364  	}{
  1365  		{"myobject", nil},
  1366  		{"path/to/my/object", nil},
  1367  		// TestXLStorage to append to previously created file.
  1368  		{"myobject", nil},
  1369  		// TestXLStorage to use same path of previously created file.
  1370  		{"path/to/my/testobject", nil},
  1371  		// TestXLStorage to use object is a directory now.
  1372  		{"object-as-dir", errIsNotRegular},
  1373  		// path segment uses previously uploaded object.
  1374  		{"myobject/testobject", errFileAccessDenied},
  1375  		// One path segment length is > 255 chars long.
  1376  		{"path/to/my/object0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", errFileNameTooLong},
  1377  		// path length is > 1024 chars long.
  1378  		{"level0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001/level0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002/level0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003/object000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", errFileNameTooLong},
  1379  	}
  1380  
  1381  	for i, testCase := range testCases {
  1382  		if err = xlStorage.AppendFile(context.Background(), "success-vol", testCase.fileName, []byte("hello, world")); err != testCase.expectedErr {
  1383  			t.Errorf("Case: %d, expected: %s, got: %s", i+1, testCase.expectedErr, err)
  1384  		}
  1385  	}
  1386  
  1387  	// TestXLStorage for permission denied.
  1388  	if runtime.GOOS != globalWindowsOSName {
  1389  		permDeniedDir := createPermDeniedFile(t)
  1390  		defer removePermDeniedFile(permDeniedDir)
  1391  
  1392  		var xlStoragePermStorage StorageAPI
  1393  		// Initialize xlStorage storage layer for permission denied error.
  1394  		_, err = newLocalXLStorage(permDeniedDir)
  1395  		if err != nil && err != errDiskAccessDenied {
  1396  			t.Fatalf("Unable to initialize xlStorage, %s", err)
  1397  		}
  1398  
  1399  		if err = os.Chmod(permDeniedDir, 0755); err != nil {
  1400  			t.Fatalf("Unable to change permission to temporary directory %v. %v", permDeniedDir, err)
  1401  		}
  1402  
  1403  		xlStoragePermStorage, err = newLocalXLStorage(permDeniedDir)
  1404  		if err != nil {
  1405  			t.Fatalf("Unable to initialize xlStorage, %s", err)
  1406  		}
  1407  
  1408  		if err = xlStoragePermStorage.AppendFile(context.Background(), "mybucket", "myobject", []byte("hello, world")); err != errVolumeAccessDenied {
  1409  			t.Fatalf("expected: errVolumeAccessDenied error, got: %s", err)
  1410  		}
  1411  	}
  1412  
  1413  	// TestXLStorage case with invalid volume name.
  1414  	// A valid volume name should be atleast of size 3.
  1415  	err = xlStorage.AppendFile(context.Background(), "bn", "yes", []byte("hello, world"))
  1416  	if err != errVolumeNotFound {
  1417  		t.Fatalf("expected: \"Invalid argument error\", got: \"%s\"", err)
  1418  	}
  1419  }
  1420  
  1421  // TestXLStorage xlStorage.RenameFile()
  1422  func TestXLStorageRenameFile(t *testing.T) {
  1423  	// create xlStorage test setup
  1424  	xlStorage, path, err := newXLStorageTestSetup()
  1425  	if err != nil {
  1426  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
  1427  	}
  1428  	defer os.RemoveAll(path)
  1429  
  1430  	// Setup test environment.
  1431  	if err := xlStorage.MakeVol(context.Background(), "src-vol"); err != nil {
  1432  		t.Fatalf("Unable to create volume, %s", err)
  1433  	}
  1434  
  1435  	if err := xlStorage.MakeVol(context.Background(), "dest-vol"); err != nil {
  1436  		t.Fatalf("Unable to create volume, %s", err)
  1437  	}
  1438  
  1439  	if err := xlStorage.AppendFile(context.Background(), "src-vol", "file1", []byte("Hello, world")); err != nil {
  1440  		t.Fatalf("Unable to create file, %s", err)
  1441  	}
  1442  
  1443  	if err := xlStorage.AppendFile(context.Background(), "src-vol", "file2", []byte("Hello, world")); err != nil {
  1444  		t.Fatalf("Unable to create file, %s", err)
  1445  	}
  1446  	if err := xlStorage.AppendFile(context.Background(), "src-vol", "file3", []byte("Hello, world")); err != nil {
  1447  		t.Fatalf("Unable to create file, %s", err)
  1448  	}
  1449  	if err := xlStorage.AppendFile(context.Background(), "src-vol", "file4", []byte("Hello, world")); err != nil {
  1450  		t.Fatalf("Unable to create file, %s", err)
  1451  	}
  1452  
  1453  	if err := xlStorage.AppendFile(context.Background(), "src-vol", "file5", []byte("Hello, world")); err != nil {
  1454  		t.Fatalf("Unable to create file, %s", err)
  1455  	}
  1456  	if err := xlStorage.AppendFile(context.Background(), "src-vol", "path/to/file1", []byte("Hello, world")); err != nil {
  1457  		t.Fatalf("Unable to create file, %s", err)
  1458  	}
  1459  
  1460  	testCases := []struct {
  1461  		srcVol      string
  1462  		destVol     string
  1463  		srcPath     string
  1464  		destPath    string
  1465  		expectedErr error
  1466  	}{
  1467  		// TestXLStorage case - 1.
  1468  		{
  1469  			srcVol:      "src-vol",
  1470  			destVol:     "dest-vol",
  1471  			srcPath:     "file1",
  1472  			destPath:    "file-one",
  1473  			expectedErr: nil,
  1474  		},
  1475  		// TestXLStorage case - 2.
  1476  		{
  1477  			srcVol:      "src-vol",
  1478  			destVol:     "dest-vol",
  1479  			srcPath:     "path/",
  1480  			destPath:    "new-path/",
  1481  			expectedErr: nil,
  1482  		},
  1483  		// TestXLStorage case - 3.
  1484  		// TestXLStorage to overwrite destination file.
  1485  		{
  1486  			srcVol:      "src-vol",
  1487  			destVol:     "dest-vol",
  1488  			srcPath:     "file2",
  1489  			destPath:    "file-one",
  1490  			expectedErr: nil,
  1491  		},
  1492  		// TestXLStorage case - 4.
  1493  		// TestXLStorage case with io error count set to 1.
  1494  		// expected not to fail.
  1495  		{
  1496  			srcVol:      "src-vol",
  1497  			destVol:     "dest-vol",
  1498  			srcPath:     "file3",
  1499  			destPath:    "file-two",
  1500  			expectedErr: nil,
  1501  		},
  1502  		// TestXLStorage case - 5.
  1503  		// TestXLStorage case with io error count set to maximum allowed count.
  1504  		// expected not to fail.
  1505  		{
  1506  			srcVol:      "src-vol",
  1507  			destVol:     "dest-vol",
  1508  			srcPath:     "file4",
  1509  			destPath:    "file-three",
  1510  			expectedErr: nil,
  1511  		},
  1512  		// TestXLStorage case - 6.
  1513  		// TestXLStorage case with non-existent source file.
  1514  		{
  1515  			srcVol:      "src-vol",
  1516  			destVol:     "dest-vol",
  1517  			srcPath:     "non-existent-file",
  1518  			destPath:    "file-three",
  1519  			expectedErr: errFileNotFound,
  1520  		},
  1521  		// TestXLStorage case - 7.
  1522  		// TestXLStorage to check failure of source and destination are not same type.
  1523  		{
  1524  			srcVol:      "src-vol",
  1525  			destVol:     "dest-vol",
  1526  			srcPath:     "path/",
  1527  			destPath:    "file-one",
  1528  			expectedErr: errFileAccessDenied,
  1529  		},
  1530  		// TestXLStorage case - 8.
  1531  		// TestXLStorage to check failure of destination directory exists.
  1532  		{
  1533  			srcVol:      "src-vol",
  1534  			destVol:     "dest-vol",
  1535  			srcPath:     "path/",
  1536  			destPath:    "new-path/",
  1537  			expectedErr: errFileAccessDenied,
  1538  		},
  1539  		// TestXLStorage case - 9.
  1540  		// TestXLStorage case with source being a file and destination being a directory.
  1541  		// Either both have to be files or directories.
  1542  		// Expecting to fail with `errFileAccessDenied`.
  1543  		{
  1544  			srcVol:      "src-vol",
  1545  			destVol:     "dest-vol",
  1546  			srcPath:     "file4",
  1547  			destPath:    "new-path/",
  1548  			expectedErr: errFileAccessDenied,
  1549  		},
  1550  		// TestXLStorage case - 10.
  1551  		// TestXLStorage case with non-existent source volume.
  1552  		// Expecting to fail with `errVolumeNotFound`.
  1553  		{
  1554  			srcVol:      "src-vol-non-existent",
  1555  			destVol:     "dest-vol",
  1556  			srcPath:     "file4",
  1557  			destPath:    "new-path/",
  1558  			expectedErr: errVolumeNotFound,
  1559  		},
  1560  		// TestXLStorage case - 11.
  1561  		// TestXLStorage case with non-existent destination volume.
  1562  		// Expecting to fail with `errVolumeNotFound`.
  1563  		{
  1564  			srcVol:      "src-vol",
  1565  			destVol:     "dest-vol-non-existent",
  1566  			srcPath:     "file4",
  1567  			destPath:    "new-path/",
  1568  			expectedErr: errVolumeNotFound,
  1569  		},
  1570  		// TestXLStorage case - 12.
  1571  		// TestXLStorage case with invalid src volume name. Length should be atleast 3.
  1572  		// Expecting to fail with `errInvalidArgument`.
  1573  		{
  1574  			srcVol:      "ab",
  1575  			destVol:     "dest-vol-non-existent",
  1576  			srcPath:     "file4",
  1577  			destPath:    "new-path/",
  1578  			expectedErr: errVolumeNotFound,
  1579  		},
  1580  		// TestXLStorage case - 13.
  1581  		// TestXLStorage case with invalid destination volume name. Length should be atleast 3.
  1582  		// Expecting to fail with `errInvalidArgument`.
  1583  		{
  1584  			srcVol:      "abcd",
  1585  			destVol:     "ef",
  1586  			srcPath:     "file4",
  1587  			destPath:    "new-path/",
  1588  			expectedErr: errVolumeNotFound,
  1589  		},
  1590  		// TestXLStorage case - 14.
  1591  		// TestXLStorage case with invalid destination volume name. Length should be atleast 3.
  1592  		// Expecting to fail with `errInvalidArgument`.
  1593  		{
  1594  			srcVol:      "abcd",
  1595  			destVol:     "ef",
  1596  			srcPath:     "file4",
  1597  			destPath:    "new-path/",
  1598  			expectedErr: errVolumeNotFound,
  1599  		},
  1600  		// TestXLStorage case - 15.
  1601  		// TestXLStorage case with the parent of the destination being a file.
  1602  		// expected to fail with `errFileAccessDenied`.
  1603  		{
  1604  			srcVol:      "src-vol",
  1605  			destVol:     "dest-vol",
  1606  			srcPath:     "file5",
  1607  			destPath:    "file-one/parent-is-file",
  1608  			expectedErr: errFileAccessDenied,
  1609  		},
  1610  		// TestXLStorage case - 16.
  1611  		// TestXLStorage case with segment of source file name more than 255.
  1612  		// expected not to fail.
  1613  		{
  1614  			srcVol:      "src-vol",
  1615  			destVol:     "dest-vol",
  1616  			srcPath:     "path/to/my/object0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
  1617  			destPath:    "file-six",
  1618  			expectedErr: errFileNameTooLong,
  1619  		},
  1620  		// TestXLStorage case - 17.
  1621  		// TestXLStorage case with segment of destination file name more than 255.
  1622  		// expected not to fail.
  1623  		{
  1624  			srcVol:      "src-vol",
  1625  			destVol:     "dest-vol",
  1626  			srcPath:     "file6",
  1627  			destPath:    "path/to/my/object0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
  1628  			expectedErr: errFileNameTooLong,
  1629  		},
  1630  	}
  1631  
  1632  	for i, testCase := range testCases {
  1633  		if err := xlStorage.RenameFile(context.Background(), testCase.srcVol, testCase.srcPath, testCase.destVol, testCase.destPath); err != testCase.expectedErr {
  1634  			t.Fatalf("TestXLStorage %d:  Expected the error to be : \"%v\", got: \"%v\".", i+1, testCase.expectedErr, err)
  1635  		}
  1636  	}
  1637  }
  1638  
  1639  // TestXLStorage xlStorage.CheckFile()
  1640  func TestXLStorageCheckFile(t *testing.T) {
  1641  	// create xlStorage test setup
  1642  	xlStorage, path, err := newXLStorageTestSetup()
  1643  	if err != nil {
  1644  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
  1645  	}
  1646  	defer os.RemoveAll(path)
  1647  
  1648  	// Setup test environment.
  1649  	if err := xlStorage.MakeVol(context.Background(), "success-vol"); err != nil {
  1650  		t.Fatalf("Unable to create volume, %s", err)
  1651  	}
  1652  
  1653  	if err := xlStorage.AppendFile(context.Background(), "success-vol", pathJoin("success-file", xlStorageFormatFile), []byte("Hello, world")); err != nil {
  1654  		t.Fatalf("Unable to create file, %s", err)
  1655  	}
  1656  
  1657  	if err := xlStorage.AppendFile(context.Background(), "success-vol", pathJoin("path/to/success-file", xlStorageFormatFile), []byte("Hello, world")); err != nil {
  1658  		t.Fatalf("Unable to create file, %s", err)
  1659  	}
  1660  
  1661  	if err := xlStorage.MakeVol(context.Background(), "success-vol/path/to/"+xlStorageFormatFile); err != nil {
  1662  		t.Fatalf("Unable to create path, %s", err)
  1663  	}
  1664  
  1665  	testCases := []struct {
  1666  		srcVol      string
  1667  		srcPath     string
  1668  		expectedErr error
  1669  	}{
  1670  		// TestXLStorage case - 1.
  1671  		// TestXLStorage case with valid inputs, expected to pass.
  1672  		{
  1673  			srcVol:      "success-vol",
  1674  			srcPath:     "success-file",
  1675  			expectedErr: nil,
  1676  		},
  1677  		// TestXLStorage case - 2.
  1678  		// TestXLStorage case with valid inputs, expected to pass.
  1679  		{
  1680  			srcVol:      "success-vol",
  1681  			srcPath:     "path/to/success-file",
  1682  			expectedErr: nil,
  1683  		},
  1684  		// TestXLStorage case - 3.
  1685  		// TestXLStorage case with non-existent file.
  1686  		{
  1687  			srcVol:      "success-vol",
  1688  			srcPath:     "nonexistent-file",
  1689  			expectedErr: errPathNotFound,
  1690  		},
  1691  		// TestXLStorage case - 4.
  1692  		// TestXLStorage case with non-existent file path.
  1693  		{
  1694  			srcVol:      "success-vol",
  1695  			srcPath:     "path/2/success-file",
  1696  			expectedErr: errPathNotFound,
  1697  		},
  1698  		// TestXLStorage case - 5.
  1699  		// TestXLStorage case with path being a directory.
  1700  		{
  1701  			srcVol:      "success-vol",
  1702  			srcPath:     "path",
  1703  			expectedErr: errPathNotFound,
  1704  		},
  1705  		// TestXLStorage case - 6.
  1706  		// TestXLStorage case with non existent volume.
  1707  		{
  1708  			srcVol:      "non-existent-vol",
  1709  			srcPath:     "success-file",
  1710  			expectedErr: errPathNotFound,
  1711  		},
  1712  		// TestXLStorage case - 7.
  1713  		// TestXLStorage case with file with directory.
  1714  		{
  1715  			srcVol:      "success-vol",
  1716  			srcPath:     "path/to",
  1717  			expectedErr: errFileNotFound,
  1718  		},
  1719  	}
  1720  
  1721  	for i, testCase := range testCases {
  1722  		if err := xlStorage.CheckFile(context.Background(), testCase.srcVol, testCase.srcPath); err != testCase.expectedErr {
  1723  			t.Errorf("TestXLStorage case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err)
  1724  		}
  1725  	}
  1726  }
  1727  
  1728  // Test xlStorage.VerifyFile()
  1729  func TestXLStorageVerifyFile(t *testing.T) {
  1730  	// We test 4 cases:
  1731  	// 1) Whole-file bitrot check on proper file
  1732  	// 2) Whole-file bitrot check on corrupted file
  1733  	// 3) Streaming bitrot check on proper file
  1734  	// 4) Streaming bitrot check on corrupted file
  1735  
  1736  	// create xlStorage test setup
  1737  	storage, path, err := newXLStorageTestSetup()
  1738  	if err != nil {
  1739  		t.Fatalf("Unable to create xlStorage test setup, %s", err)
  1740  	}
  1741  	defer os.RemoveAll(path)
  1742  
  1743  	volName := "testvol"
  1744  	fileName := "testfile"
  1745  	if err := storage.MakeVol(context.Background(), volName); err != nil {
  1746  		t.Fatal(err)
  1747  	}
  1748  
  1749  	// 1) Whole-file bitrot check on proper file
  1750  	size := int64(4*1024*1024 + 100*1024) // 4.1 MB
  1751  	data := make([]byte, size)
  1752  	if _, err := rand.Read(data); err != nil {
  1753  		t.Fatal(err)
  1754  	}
  1755  	algo := HighwayHash256
  1756  	h := algo.New()
  1757  	h.Write(data)
  1758  	hashBytes := h.Sum(nil)
  1759  	if err := storage.WriteAll(context.Background(), volName, fileName, data); err != nil {
  1760  		t.Fatal(err)
  1761  	}
  1762  	if err := storage.storage.(*xlStorage).bitrotVerify(pathJoin(path, volName, fileName), size, algo, hashBytes, 0); err != nil {
  1763  		t.Fatal(err)
  1764  	}
  1765  
  1766  	// 2) Whole-file bitrot check on corrupted file
  1767  	if err := storage.AppendFile(context.Background(), volName, fileName, []byte("a")); err != nil {
  1768  		t.Fatal(err)
  1769  	}
  1770  
  1771  	// Check if VerifyFile reports the incorrect file length (the correct length is `size+1`)
  1772  	if err := storage.storage.(*xlStorage).bitrotVerify(pathJoin(path, volName, fileName), size, algo, hashBytes, 0); err == nil {
  1773  		t.Fatal("expected to fail bitrot check")
  1774  	}
  1775  
  1776  	// Check if bitrot fails
  1777  	if err := storage.storage.(*xlStorage).bitrotVerify(pathJoin(path, volName, fileName), size+1, algo, hashBytes, 0); err == nil {
  1778  		t.Fatal("expected to fail bitrot check")
  1779  	}
  1780  
  1781  	if err := storage.Delete(context.Background(), volName, fileName, false); err != nil {
  1782  		t.Fatal(err)
  1783  	}
  1784  
  1785  	// 3) Streaming bitrot check on proper file
  1786  	algo = HighwayHash256S
  1787  	shardSize := int64(1024 * 1024)
  1788  	shard := make([]byte, shardSize)
  1789  	w := newStreamingBitrotWriter(storage, volName, fileName, size, algo, shardSize, false)
  1790  	reader := bytes.NewReader(data)
  1791  	for {
  1792  		// Using io.Copy instead of this loop will not work for us as io.Copy
  1793  		// will use bytes.Reader.WriteTo() which will not do shardSize'ed writes
  1794  		// causing error.
  1795  		n, err := reader.Read(shard)
  1796  		w.Write(shard[:n])
  1797  		if err == nil {
  1798  			continue
  1799  		}
  1800  		if err == io.EOF {
  1801  			break
  1802  		}
  1803  		t.Fatal(err)
  1804  	}
  1805  	w.(io.Closer).Close()
  1806  	if err := storage.storage.(*xlStorage).bitrotVerify(pathJoin(path, volName, fileName), size, algo, nil, shardSize); err != nil {
  1807  		t.Fatal(err)
  1808  	}
  1809  
  1810  	// 4) Streaming bitrot check on corrupted file
  1811  	filePath := pathJoin(storage.String(), volName, fileName)
  1812  	f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_SYNC, 0644)
  1813  	if err != nil {
  1814  		t.Fatal(err)
  1815  	}
  1816  	// Replace first 256 with 'a'.
  1817  	if _, err := f.WriteString(strings.Repeat("a", 256)); err != nil {
  1818  		t.Fatal(err)
  1819  	}
  1820  	f.Close()
  1821  	if err := storage.storage.(*xlStorage).bitrotVerify(pathJoin(path, volName, fileName), size, algo, nil, shardSize); err == nil {
  1822  		t.Fatal("expected to fail bitrot check")
  1823  	}
  1824  	if err := storage.storage.(*xlStorage).bitrotVerify(pathJoin(path, volName, fileName), size+1, algo, nil, shardSize); err == nil {
  1825  		t.Fatal("expected to fail bitrot check")
  1826  	}
  1827  }