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

     1  /*
     2   * MinIO Cloud Storage, (C) 2016, 2017 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  	"os"
    22  	"path/filepath"
    23  	"testing"
    24  
    25  	"storj.io/minio/pkg/madmin"
    26  )
    27  
    28  // Tests for if parent directory is object
    29  func TestFSParentDirIsObject(t *testing.T) {
    30  	obj, disk, err := prepareFS()
    31  	if err != nil {
    32  		t.Fatal(err)
    33  	}
    34  	defer os.RemoveAll(disk)
    35  
    36  	bucketName := "testbucket"
    37  	objectName := "object"
    38  
    39  	if err = obj.MakeBucketWithLocation(GlobalContext, bucketName, BucketOptions{}); err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	objectContent := "12345"
    43  	objInfo, err := obj.PutObject(GlobalContext, bucketName, objectName,
    44  		mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), ObjectOptions{})
    45  	if err != nil {
    46  		t.Fatal(err)
    47  	}
    48  	if objInfo.Name != objectName {
    49  		t.Fatalf("Unexpected object name returned got %s, expected %s", objInfo.Name, objectName)
    50  	}
    51  
    52  	fs := obj.(*FSObjects)
    53  	testCases := []struct {
    54  		parentIsObject bool
    55  		objectName     string
    56  	}{
    57  		// parentIsObject is true if object is available.
    58  		{
    59  			parentIsObject: true,
    60  			objectName:     objectName,
    61  		},
    62  		{
    63  			parentIsObject: false,
    64  			objectName:     "",
    65  		},
    66  		{
    67  			parentIsObject: false,
    68  			objectName:     ".",
    69  		},
    70  		// Should not cause infinite loop.
    71  		{
    72  			parentIsObject: false,
    73  			objectName:     SlashSeparator,
    74  		},
    75  		{
    76  			parentIsObject: false,
    77  			objectName:     "\\",
    78  		},
    79  		// Should not cause infinite loop with double forward slash.
    80  		{
    81  			parentIsObject: false,
    82  			objectName:     "//",
    83  		},
    84  	}
    85  	for i, testCase := range testCases {
    86  		gotValue := fs.parentDirIsObject(GlobalContext, bucketName, testCase.objectName)
    87  		if testCase.parentIsObject != gotValue {
    88  			t.Errorf("Test %d: Unexpected value returned got %t, expected %t", i+1, gotValue, testCase.parentIsObject)
    89  		}
    90  	}
    91  }
    92  
    93  // TestNewFS - tests initialization of all input disks
    94  // and constructs a valid `FS` object layer.
    95  func TestNewFS(t *testing.T) {
    96  	// Do not attempt to create this path, the test validates
    97  	// so that NewFSObjectLayer initializes non existing paths
    98  	// and successfully returns initialized object layer.
    99  	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
   100  	defer os.RemoveAll(disk)
   101  
   102  	_, err := NewFSObjectLayer("")
   103  	if err != errInvalidArgument {
   104  		t.Errorf("Expecting error invalid argument, got %s", err)
   105  	}
   106  	_, err = NewFSObjectLayer(disk)
   107  	if err != nil {
   108  		errMsg := "Unable to recognize backend format, Disk is not in FS format."
   109  		if err.Error() == errMsg {
   110  			t.Errorf("Expecting %s, got %s", errMsg, err)
   111  		}
   112  	}
   113  }
   114  
   115  // TestFSShutdown - initialize a new FS object layer then calls
   116  // Shutdown to check returned results
   117  func TestFSShutdown(t *testing.T) {
   118  	bucketName := "testbucket"
   119  	objectName := "object"
   120  	// Create and return an fsObject with its path in the disk
   121  	prepareTest := func() (*FSObjects, string) {
   122  		disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
   123  		obj := initFSObjects(disk, t)
   124  		fs := obj.(*FSObjects)
   125  
   126  		objectContent := "12345"
   127  		obj.MakeBucketWithLocation(GlobalContext, bucketName, BucketOptions{})
   128  		obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), ObjectOptions{})
   129  		return fs, disk
   130  	}
   131  
   132  	// Test Shutdown with regular conditions
   133  	fs, disk := prepareTest()
   134  	if err := fs.Shutdown(GlobalContext); err != nil {
   135  		t.Fatal("Cannot shutdown the FS object: ", err)
   136  	}
   137  	os.RemoveAll(disk)
   138  
   139  	// Test Shutdown with faulty disk
   140  	fs, disk = prepareTest()
   141  	fs.DeleteObject(GlobalContext, bucketName, objectName, ObjectOptions{})
   142  	os.RemoveAll(disk)
   143  	if err := fs.Shutdown(GlobalContext); err != nil {
   144  		t.Fatal("Got unexpected fs shutdown error: ", err)
   145  	}
   146  }
   147  
   148  // TestFSGetBucketInfo - test GetBucketInfo with healty and faulty disks
   149  func TestFSGetBucketInfo(t *testing.T) {
   150  	// Prepare for testing
   151  	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
   152  	defer os.RemoveAll(disk)
   153  
   154  	obj := initFSObjects(disk, t)
   155  	fs := obj.(*FSObjects)
   156  	bucketName := "bucket"
   157  
   158  	err := obj.MakeBucketWithLocation(GlobalContext, "a", BucketOptions{})
   159  	if !isSameType(err, BucketNameInvalid{}) {
   160  		t.Fatal("BucketNameInvalid error not returned")
   161  	}
   162  
   163  	err = obj.MakeBucketWithLocation(GlobalContext, bucketName, BucketOptions{})
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  
   168  	// Test with valid parameters
   169  	info, err := fs.GetBucketInfo(GlobalContext, bucketName)
   170  	if err != nil {
   171  		t.Fatal(err)
   172  	}
   173  	if info.Name != bucketName {
   174  		t.Fatalf("wrong bucket name, expected: %s, found: %s", bucketName, info.Name)
   175  	}
   176  
   177  	// Test with non-existent bucket
   178  	_, err = fs.GetBucketInfo(GlobalContext, "a")
   179  	if !isSameType(err, BucketNotFound{}) {
   180  		t.Fatal("BucketNotFound error not returned")
   181  	}
   182  
   183  	// Check for buckets and should get disk not found.
   184  	os.RemoveAll(disk)
   185  
   186  	if _, err = fs.GetBucketInfo(GlobalContext, bucketName); err != nil {
   187  		if !isSameType(err, BucketNotFound{}) {
   188  			t.Fatal("BucketNotFound error not returned")
   189  		}
   190  	}
   191  }
   192  
   193  func TestFSPutObject(t *testing.T) {
   194  	// Prepare for tests
   195  	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
   196  	defer os.RemoveAll(disk)
   197  
   198  	obj := initFSObjects(disk, t)
   199  	bucketName := "bucket"
   200  	objectName := "1/2/3/4/object"
   201  
   202  	if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, BucketOptions{}); err != nil {
   203  		t.Fatal(err)
   204  	}
   205  
   206  	// With a regular object.
   207  	_, err := obj.PutObject(GlobalContext, bucketName+"non-existent", objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{})
   208  	if err == nil {
   209  		t.Fatal("Unexpected should fail here, bucket doesn't exist")
   210  	}
   211  	if _, ok := err.(BucketNotFound); !ok {
   212  		t.Fatalf("Expected error type BucketNotFound, got %#v", err)
   213  	}
   214  
   215  	// With a directory object.
   216  	_, err = obj.PutObject(GlobalContext, bucketName+"non-existent", objectName+SlashSeparator, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), 0, "", ""), ObjectOptions{})
   217  	if err == nil {
   218  		t.Fatal("Unexpected should fail here, bucket doesn't exist")
   219  	}
   220  	if _, ok := err.(BucketNotFound); !ok {
   221  		t.Fatalf("Expected error type BucketNotFound, got %#v", err)
   222  	}
   223  
   224  	_, err = obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{})
   225  	if err != nil {
   226  		t.Fatal(err)
   227  	}
   228  	_, err = obj.PutObject(GlobalContext, bucketName, objectName+"/1", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{})
   229  	if err == nil {
   230  		t.Fatal("Unexpected should fail here, backend corruption occurred")
   231  	}
   232  	if nerr, ok := err.(ParentIsObject); !ok {
   233  		t.Fatalf("Expected ParentIsObject, got %#v", err)
   234  	} else {
   235  		if nerr.Bucket != "bucket" {
   236  			t.Fatalf("Expected 'bucket', got %s", nerr.Bucket)
   237  		}
   238  		if nerr.Object != "1/2/3/4/object/1" {
   239  			t.Fatalf("Expected '1/2/3/4/object/1', got %s", nerr.Object)
   240  		}
   241  	}
   242  
   243  	_, err = obj.PutObject(GlobalContext, bucketName, objectName+"/1/", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), 0, "", ""), ObjectOptions{})
   244  	if err == nil {
   245  		t.Fatal("Unexpected should fail here, backned corruption occurred")
   246  	}
   247  	if nerr, ok := err.(ParentIsObject); !ok {
   248  		t.Fatalf("Expected ParentIsObject, got %#v", err)
   249  	} else {
   250  		if nerr.Bucket != "bucket" {
   251  			t.Fatalf("Expected 'bucket', got %s", nerr.Bucket)
   252  		}
   253  		if nerr.Object != "1/2/3/4/object/1/" {
   254  			t.Fatalf("Expected '1/2/3/4/object/1/', got %s", nerr.Object)
   255  		}
   256  	}
   257  }
   258  
   259  // TestFSDeleteObject - test fs.DeleteObject() with healthy and corrupted disks
   260  func TestFSDeleteObject(t *testing.T) {
   261  	// Prepare for tests
   262  	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
   263  	defer os.RemoveAll(disk)
   264  
   265  	obj := initFSObjects(disk, t)
   266  	fs := obj.(*FSObjects)
   267  	bucketName := "bucket"
   268  	objectName := "object"
   269  
   270  	obj.MakeBucketWithLocation(GlobalContext, bucketName, BucketOptions{})
   271  	obj.PutObject(GlobalContext, bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{})
   272  
   273  	// Test with invalid bucket name
   274  	if _, err := fs.DeleteObject(GlobalContext, "fo", objectName, ObjectOptions{}); !isSameType(err, BucketNameInvalid{}) {
   275  		t.Fatal("Unexpected error: ", err)
   276  	}
   277  	// Test with bucket does not exist
   278  	if _, err := fs.DeleteObject(GlobalContext, "foobucket", "fooobject", ObjectOptions{}); !isSameType(err, BucketNotFound{}) {
   279  		t.Fatal("Unexpected error: ", err)
   280  	}
   281  	// Test with invalid object name
   282  	if _, err := fs.DeleteObject(GlobalContext, bucketName, "\\", ObjectOptions{}); !(isSameType(err, ObjectNotFound{}) || isSameType(err, ObjectNameInvalid{})) {
   283  		t.Fatal("Unexpected error: ", err)
   284  	}
   285  	// Test with object does not exist.
   286  	if _, err := fs.DeleteObject(GlobalContext, bucketName, "foooobject", ObjectOptions{}); !isSameType(err, ObjectNotFound{}) {
   287  		t.Fatal("Unexpected error: ", err)
   288  	}
   289  	// Test with valid condition
   290  	if _, err := fs.DeleteObject(GlobalContext, bucketName, objectName, ObjectOptions{}); err != nil {
   291  		t.Fatal("Unexpected error: ", err)
   292  	}
   293  
   294  	// Delete object should err disk not found.
   295  	os.RemoveAll(disk)
   296  	if _, err := fs.DeleteObject(GlobalContext, bucketName, objectName, ObjectOptions{}); err != nil {
   297  		if !isSameType(err, BucketNotFound{}) {
   298  			t.Fatal("Unexpected error: ", err)
   299  		}
   300  	}
   301  
   302  }
   303  
   304  // TestFSDeleteBucket - tests for fs DeleteBucket
   305  func TestFSDeleteBucket(t *testing.T) {
   306  	// Prepare for testing
   307  	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
   308  	defer os.RemoveAll(disk)
   309  
   310  	obj := initFSObjects(disk, t)
   311  	fs := obj.(*FSObjects)
   312  	bucketName := "bucket"
   313  
   314  	err := obj.MakeBucketWithLocation(GlobalContext, bucketName, BucketOptions{})
   315  	if err != nil {
   316  		t.Fatal("Unexpected error: ", err)
   317  	}
   318  
   319  	// Test with an invalid bucket name
   320  	if err = fs.DeleteBucket(GlobalContext, "fo", false); !isSameType(err, BucketNotFound{}) {
   321  		t.Fatal("Unexpected error: ", err)
   322  	}
   323  
   324  	// Test with an inexistant bucket
   325  	if err = fs.DeleteBucket(GlobalContext, "foobucket", false); !isSameType(err, BucketNotFound{}) {
   326  		t.Fatal("Unexpected error: ", err)
   327  	}
   328  	// Test with a valid case
   329  	if err = fs.DeleteBucket(GlobalContext, bucketName, false); err != nil {
   330  		t.Fatal("Unexpected error: ", err)
   331  	}
   332  
   333  	obj.MakeBucketWithLocation(GlobalContext, bucketName, BucketOptions{})
   334  
   335  	// Delete bucket should get error disk not found.
   336  	os.RemoveAll(disk)
   337  	if err = fs.DeleteBucket(GlobalContext, bucketName, false); err != nil {
   338  		if !isSameType(err, BucketNotFound{}) {
   339  			t.Fatal("Unexpected error: ", err)
   340  		}
   341  	}
   342  }
   343  
   344  // TestFSListBuckets - tests for fs ListBuckets
   345  func TestFSListBuckets(t *testing.T) {
   346  	// Prepare for tests
   347  	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
   348  	defer os.RemoveAll(disk)
   349  
   350  	obj := initFSObjects(disk, t)
   351  	fs := obj.(*FSObjects)
   352  
   353  	bucketName := "bucket"
   354  	if err := obj.MakeBucketWithLocation(GlobalContext, bucketName, BucketOptions{}); err != nil {
   355  		t.Fatal("Unexpected error: ", err)
   356  	}
   357  
   358  	// Create a bucket with invalid name
   359  	if err := os.MkdirAll(pathJoin(fs.fsPath, "vo^"), 0777); err != nil {
   360  		t.Fatal("Unexpected error: ", err)
   361  	}
   362  	f, err := os.Create(pathJoin(fs.fsPath, "test"))
   363  	if err != nil {
   364  		t.Fatal("Unexpected error: ", err)
   365  	}
   366  	f.Close()
   367  
   368  	// Test list buckets to have only one entry.
   369  	buckets, err := fs.ListBuckets(GlobalContext)
   370  	if err != nil {
   371  		t.Fatal("Unexpected error: ", err)
   372  	}
   373  	if len(buckets) != 1 {
   374  		t.Fatal("ListBuckets not working properly", buckets)
   375  	}
   376  
   377  	// Test ListBuckets with disk not found.
   378  	os.RemoveAll(disk)
   379  	if _, err := fs.ListBuckets(GlobalContext); err != nil {
   380  		if err != errDiskNotFound {
   381  			t.Fatal("Unexpected error: ", err)
   382  		}
   383  	}
   384  }
   385  
   386  // TestFSHealObject - tests for fs HealObject
   387  func TestFSHealObject(t *testing.T) {
   388  	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
   389  	defer os.RemoveAll(disk)
   390  
   391  	obj := initFSObjects(disk, t)
   392  	_, err := obj.HealObject(GlobalContext, "bucket", "object", "", madmin.HealOpts{})
   393  	if err == nil || !isSameType(err, NotImplemented{}) {
   394  		t.Fatalf("Heal Object should return NotImplemented error ")
   395  	}
   396  }
   397  
   398  // TestFSHealObjects - tests for fs HealObjects to return not implemented.
   399  func TestFSHealObjects(t *testing.T) {
   400  	disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix())
   401  	defer os.RemoveAll(disk)
   402  
   403  	obj := initFSObjects(disk, t)
   404  	err := obj.HealObjects(GlobalContext, "bucket", "prefix", madmin.HealOpts{}, nil)
   405  	if err == nil || !isSameType(err, NotImplemented{}) {
   406  		t.Fatalf("Heal Object should return NotImplemented error ")
   407  	}
   408  }