github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/client-fs_test.go (about)

     1  // Copyright (c) 2015-2022 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"bytes"
    22  	"context"
    23  	"io"
    24  	"os"
    25  	"path/filepath"
    26  	"runtime"
    27  
    28  	checkv1 "gopkg.in/check.v1"
    29  )
    30  
    31  // Test list files in a folder.
    32  func (s *TestSuite) TestList(c *checkv1.C) {
    33  	root, e := os.MkdirTemp(os.TempDir(), "fs-")
    34  	c.Assert(e, checkv1.IsNil)
    35  	defer os.RemoveAll(root)
    36  
    37  	// Create multiple files.
    38  	objectPath := filepath.Join(root, "object1")
    39  	fsClient, err := fsNew(objectPath)
    40  	c.Assert(err, checkv1.IsNil)
    41  
    42  	data := "hello"
    43  
    44  	reader := bytes.NewReader([]byte(data))
    45  	var n int64
    46  	n, err = fsClient.Put(context.Background(), reader, int64(len(data)), nil, PutOptions{
    47  		metadata: map[string]string{
    48  			"Content-Type": "application/octet-stream",
    49  		},
    50  	},
    51  	)
    52  	c.Assert(err, checkv1.IsNil)
    53  	c.Assert(n, checkv1.Equals, int64(len(data)))
    54  
    55  	objectPath = filepath.Join(root, "object2")
    56  	fsClient, err = fsNew(objectPath)
    57  	c.Assert(err, checkv1.IsNil)
    58  
    59  	reader = bytes.NewReader([]byte(data))
    60  	n, err = fsClient.Put(context.Background(), reader, int64(len(data)), nil, PutOptions{
    61  		metadata: map[string]string{
    62  			"Content-Type": "application/octet-stream",
    63  		},
    64  	})
    65  	c.Assert(err, checkv1.IsNil)
    66  	c.Assert(n, checkv1.Equals, int64(len(data)))
    67  
    68  	fsClient, err = fsNew(root)
    69  	c.Assert(err, checkv1.IsNil)
    70  
    71  	// Verify previously create files and list them.
    72  	var contents []*ClientContent
    73  	for content := range fsClient.List(globalContext, ListOptions{ShowDir: DirNone}) {
    74  		if content.Err != nil {
    75  			err = content.Err
    76  			break
    77  		}
    78  		contents = append(contents, content)
    79  	}
    80  	c.Assert(err, checkv1.IsNil)
    81  	c.Assert(len(contents), checkv1.Equals, 1)
    82  	c.Assert(contents[0].Type.IsDir(), checkv1.Equals, true)
    83  
    84  	// Create another file.
    85  	objectPath = filepath.Join(root, "test1/newObject1")
    86  	fsClient, err = fsNew(objectPath)
    87  	c.Assert(err, checkv1.IsNil)
    88  
    89  	reader = bytes.NewReader([]byte(data))
    90  	n, err = fsClient.Put(context.Background(), reader, int64(len(data)), nil, PutOptions{
    91  		metadata: map[string]string{
    92  			"Content-Type": "application/octet-stream",
    93  		},
    94  	})
    95  	c.Assert(err, checkv1.IsNil)
    96  	c.Assert(n, checkv1.Equals, int64(len(data)))
    97  
    98  	fsClient, err = fsNew(root)
    99  	c.Assert(err, checkv1.IsNil)
   100  
   101  	contents = nil
   102  	// List non recursive to list only top level files.
   103  	for content := range fsClient.List(globalContext, ListOptions{ShowDir: DirNone}) {
   104  		if content.Err != nil {
   105  			err = content.Err
   106  			break
   107  		}
   108  		contents = append(contents, content)
   109  	}
   110  	c.Assert(err, checkv1.IsNil)
   111  	c.Assert(len(contents), checkv1.Equals, 1)
   112  	c.Assert(contents[0].Type.IsDir(), checkv1.Equals, true)
   113  
   114  	fsClient, err = fsNew(root)
   115  	c.Assert(err, checkv1.IsNil)
   116  
   117  	contents = nil
   118  	// List recursively all files and verify.
   119  	for content := range fsClient.List(globalContext, ListOptions{Recursive: true, ShowDir: DirNone}) {
   120  		if content.Err != nil {
   121  			err = content.Err
   122  			break
   123  		}
   124  		contents = append(contents, content)
   125  	}
   126  
   127  	c.Assert(err, checkv1.IsNil)
   128  	c.Assert(len(contents), checkv1.Equals, 3)
   129  
   130  	var regularFiles int
   131  	var regularDirs int
   132  	// Test number of expected files and directories.
   133  	for _, content := range contents {
   134  		if content.Type.IsRegular() {
   135  			regularFiles++
   136  			continue
   137  		}
   138  		if content.Type.IsDir() {
   139  			regularDirs++
   140  			continue
   141  		}
   142  	}
   143  	c.Assert(regularDirs, checkv1.Equals, 0)
   144  	c.Assert(regularFiles, checkv1.Equals, 3)
   145  
   146  	// Create an ignored file and list to verify if its ignored.
   147  	objectPath = filepath.Join(root, "test1/.DS_Store")
   148  	fsClient, err = fsNew(objectPath)
   149  	c.Assert(err, checkv1.IsNil)
   150  
   151  	reader = bytes.NewReader([]byte(data))
   152  	n, err = fsClient.Put(context.Background(), reader, int64(len(data)), nil, PutOptions{
   153  		metadata: map[string]string{
   154  			"Content-Type": "application/octet-stream",
   155  		},
   156  	})
   157  	c.Assert(err, checkv1.IsNil)
   158  	c.Assert(n, checkv1.Equals, int64(len(data)))
   159  
   160  	fsClient, err = fsNew(root)
   161  	c.Assert(err, checkv1.IsNil)
   162  
   163  	contents = nil
   164  	// List recursively all files and verify.
   165  	for content := range fsClient.List(globalContext, ListOptions{Recursive: true, ShowDir: DirNone}) {
   166  		if content.Err != nil {
   167  			err = content.Err
   168  			break
   169  		}
   170  		contents = append(contents, content)
   171  	}
   172  
   173  	c.Assert(err, checkv1.IsNil)
   174  	switch runtime.GOOS {
   175  	case "darwin":
   176  		c.Assert(len(contents), checkv1.Equals, 3)
   177  	default:
   178  		c.Assert(len(contents), checkv1.Equals, 4)
   179  	}
   180  
   181  	regularFiles = 0
   182  	// Test number of expected files.
   183  	for _, content := range contents {
   184  		if content.Type.IsRegular() {
   185  			regularFiles++
   186  			continue
   187  		}
   188  	}
   189  	switch runtime.GOOS {
   190  	case "darwin":
   191  		c.Assert(regularFiles, checkv1.Equals, 3)
   192  	default:
   193  		c.Assert(regularFiles, checkv1.Equals, 4)
   194  	}
   195  }
   196  
   197  // Test put bucket aka 'mkdir()' operation.
   198  func (s *TestSuite) TestPutBucket(c *checkv1.C) {
   199  	root, e := os.MkdirTemp(os.TempDir(), "fs-")
   200  	c.Assert(e, checkv1.IsNil)
   201  	defer os.RemoveAll(root)
   202  
   203  	bucketPath := filepath.Join(root, "bucket")
   204  	fsClient, err := fsNew(bucketPath)
   205  	c.Assert(err, checkv1.IsNil)
   206  	err = fsClient.MakeBucket(context.Background(), "us-east-1", true, false)
   207  	c.Assert(err, checkv1.IsNil)
   208  }
   209  
   210  // Test stat bucket aka 'stat()' operation.
   211  func (s *TestSuite) TestStatBucket(c *checkv1.C) {
   212  	root, e := os.MkdirTemp(os.TempDir(), "fs-")
   213  	c.Assert(e, checkv1.IsNil)
   214  	defer os.RemoveAll(root)
   215  
   216  	bucketPath := filepath.Join(root, "bucket")
   217  
   218  	fsClient, err := fsNew(bucketPath)
   219  	c.Assert(err, checkv1.IsNil)
   220  	err = fsClient.MakeBucket(context.Background(), "us-east-1", true, false)
   221  	c.Assert(err, checkv1.IsNil)
   222  	_, err = fsClient.Stat(context.Background(), StatOptions{})
   223  	c.Assert(err, checkv1.IsNil)
   224  }
   225  
   226  // Test bucket acl fails for directories.
   227  func (s *TestSuite) TestBucketACLFails(c *checkv1.C) {
   228  	root, e := os.MkdirTemp(os.TempDir(), "fs-")
   229  	c.Assert(e, checkv1.IsNil)
   230  	defer os.RemoveAll(root)
   231  
   232  	bucketPath := filepath.Join(root, "bucket")
   233  	fsClient, err := fsNew(bucketPath)
   234  	c.Assert(err, checkv1.IsNil)
   235  	err = fsClient.MakeBucket(context.Background(), "us-east-1", true, false)
   236  	c.Assert(err, checkv1.IsNil)
   237  
   238  	// On windows setting permissions is not supported.
   239  	if runtime.GOOS != "windows" {
   240  		err = fsClient.SetAccess(context.Background(), "readonly", false)
   241  		c.Assert(err, checkv1.IsNil)
   242  
   243  		_, _, err = fsClient.GetAccess(context.Background())
   244  		c.Assert(err, checkv1.IsNil)
   245  	}
   246  }
   247  
   248  // Test creating a file.
   249  func (s *TestSuite) TestPut(c *checkv1.C) {
   250  	root, e := os.MkdirTemp(os.TempDir(), "fs-")
   251  	c.Assert(e, checkv1.IsNil)
   252  	defer os.RemoveAll(root)
   253  
   254  	objectPath := filepath.Join(root, "object")
   255  	fsClient, err := fsNew(objectPath)
   256  	c.Assert(err, checkv1.IsNil)
   257  
   258  	data := "hello"
   259  	reader := bytes.NewReader([]byte(data))
   260  	var n int64
   261  	n, err = fsClient.Put(context.Background(), reader, int64(len(data)), nil, PutOptions{
   262  		metadata: map[string]string{
   263  			"Content-Type": "application/octet-stream",
   264  		},
   265  	},
   266  	)
   267  
   268  	c.Assert(err, checkv1.IsNil)
   269  	c.Assert(n, checkv1.Equals, int64(len(data)))
   270  }
   271  
   272  // Test read a file.
   273  func (s *TestSuite) TestGet(c *checkv1.C) {
   274  	root, e := os.MkdirTemp(os.TempDir(), "fs-")
   275  	c.Assert(e, checkv1.IsNil)
   276  	defer os.RemoveAll(root)
   277  
   278  	objectPath := filepath.Join(root, "object")
   279  	fsClient, err := fsNew(objectPath)
   280  	c.Assert(err, checkv1.IsNil)
   281  
   282  	data := "hello"
   283  	var reader io.Reader
   284  	reader = bytes.NewReader([]byte(data))
   285  	n, err := fsClient.Put(context.Background(), reader, int64(len(data)), nil, PutOptions{
   286  		metadata: map[string]string{
   287  			"Content-Type": "application/octet-stream",
   288  		},
   289  	})
   290  	c.Assert(err, checkv1.IsNil)
   291  	c.Assert(n, checkv1.Equals, int64(len(data)))
   292  
   293  	reader, _, err = fsClient.Get(context.Background(), GetOptions{})
   294  	c.Assert(err, checkv1.IsNil)
   295  	var results bytes.Buffer
   296  	_, e = io.Copy(&results, reader)
   297  	c.Assert(e, checkv1.IsNil)
   298  	c.Assert([]byte(data), checkv1.DeepEquals, results.Bytes())
   299  }
   300  
   301  // Test get range in a file.
   302  func (s *TestSuite) TestGetRange(c *checkv1.C) {
   303  	root, e := os.MkdirTemp(os.TempDir(), "fs-")
   304  	c.Assert(e, checkv1.IsNil)
   305  	defer os.RemoveAll(root)
   306  
   307  	objectPath := filepath.Join(root, "object")
   308  	fsClient, err := fsNew(objectPath)
   309  	c.Assert(err, checkv1.IsNil)
   310  
   311  	data := "hello world"
   312  	var reader io.Reader
   313  	reader = bytes.NewReader([]byte(data))
   314  	n, err := fsClient.Put(context.Background(), reader, int64(len(data)), nil, PutOptions{
   315  		metadata: map[string]string{
   316  			"Content-Type": "application/octet-stream",
   317  		},
   318  	})
   319  	c.Assert(err, checkv1.IsNil)
   320  	c.Assert(n, checkv1.Equals, int64(len(data)))
   321  
   322  	reader, _, err = fsClient.Get(context.Background(), GetOptions{})
   323  	c.Assert(err, checkv1.IsNil)
   324  	var results bytes.Buffer
   325  	buf := make([]byte, 5)
   326  	m, e := reader.(io.ReaderAt).ReadAt(buf, 0)
   327  	c.Assert(e, checkv1.IsNil)
   328  	c.Assert(m, checkv1.Equals, 5)
   329  	_, e = results.Write(buf)
   330  	c.Assert(e, checkv1.IsNil)
   331  	c.Assert([]byte("hello"), checkv1.DeepEquals, results.Bytes())
   332  }
   333  
   334  // Test stat file.
   335  func (s *TestSuite) TestStatObject(c *checkv1.C) {
   336  	root, e := os.MkdirTemp(os.TempDir(), "fs-")
   337  	c.Assert(e, checkv1.IsNil)
   338  	defer os.RemoveAll(root)
   339  
   340  	objectPath := filepath.Join(root, "object")
   341  	fsClient, err := fsNew(objectPath)
   342  	c.Assert(err, checkv1.IsNil)
   343  
   344  	data := "hello"
   345  	dataLen := len(data)
   346  	reader := bytes.NewReader([]byte(data))
   347  	n, err := fsClient.Put(context.Background(), reader, int64(dataLen), nil, PutOptions{
   348  		metadata: map[string]string{
   349  			"Content-Type": "application/octet-stream",
   350  		},
   351  	},
   352  	)
   353  	c.Assert(err, checkv1.IsNil)
   354  	c.Assert(n, checkv1.Equals, int64(len(data)))
   355  
   356  	content, err := fsClient.Stat(context.Background(), StatOptions{})
   357  	c.Assert(err, checkv1.IsNil)
   358  	c.Assert(content.Size, checkv1.Equals, int64(dataLen))
   359  }
   360  
   361  // Test copy.
   362  func (s *TestSuite) TestCopy(c *checkv1.C) {
   363  	root, e := os.MkdirTemp(os.TempDir(), "fs-")
   364  	c.Assert(e, checkv1.IsNil)
   365  	defer os.RemoveAll(root)
   366  	sourcePath := filepath.Join(root, "source")
   367  	targetPath := filepath.Join(root, "target")
   368  	fsClientTarget, err := fsNew(targetPath)
   369  	c.Assert(err, checkv1.IsNil)
   370  	fsClientSource, err := fsNew(sourcePath)
   371  	c.Assert(err, checkv1.IsNil)
   372  
   373  	data := "hello world"
   374  	reader := bytes.NewReader([]byte(data))
   375  	n, err := fsClientSource.Put(context.Background(), reader, int64(len(data)), nil, PutOptions{
   376  		metadata: map[string]string{
   377  			"Content-Type": "application/octet-stream",
   378  		},
   379  	})
   380  	c.Assert(err, checkv1.IsNil)
   381  	c.Assert(n, checkv1.Equals, int64(len(data)))
   382  	err = fsClientTarget.Copy(context.Background(), sourcePath, CopyOptions{size: int64(len(data))}, nil)
   383  	c.Assert(err, checkv1.IsNil)
   384  }