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

     1  /*
     2   * MinIO Cloud Storage, (C) 2016 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  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"path"
    24  	"path/filepath"
    25  	"runtime"
    26  	"sort"
    27  	"testing"
    28  )
    29  
    30  // Test to check for different input arguments.
    31  func TestReadDirFail(t *testing.T) {
    32  	// Check non existent directory.
    33  	if _, err := readDir("/tmp/non-existent-directory"); err != errFileNotFound {
    34  		t.Fatalf("expected = %s, got: %s", errFileNotFound, err)
    35  	}
    36  
    37  	file := path.Join(os.TempDir(), "issue")
    38  	if err := ioutil.WriteFile(file, []byte(""), 0644); err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	defer os.RemoveAll(file)
    42  
    43  	// Check if file is given.
    44  	if _, err := readDir(path.Join(file, "mydir")); err != errFileNotFound {
    45  		t.Fatalf("expected = %s, got: %s", errFileNotFound, err)
    46  	}
    47  
    48  	// Only valid for linux.
    49  	if runtime.GOOS == "linux" {
    50  		permDir := path.Join(os.TempDir(), "perm-dir")
    51  		if err := os.MkdirAll(permDir, os.FileMode(0200)); err != nil {
    52  			t.Fatal(err)
    53  		}
    54  		defer os.RemoveAll(permDir)
    55  
    56  		// Check if permission denied.
    57  		if _, err := readDir(permDir); err == nil {
    58  			t.Fatalf("expected = an error, got: nil")
    59  		}
    60  	}
    61  }
    62  
    63  // Represents data type for all the test results.
    64  type result struct {
    65  	dir     string
    66  	entries []string
    67  }
    68  
    69  func mustSetupDir(t *testing.T) string {
    70  	// Create unique test directory.
    71  	dir, err := ioutil.TempDir(globalTestTmpDir, "minio-list-dir")
    72  	if err != nil {
    73  		t.Fatalf("Unable to setup directory, %s", err)
    74  	}
    75  	return dir
    76  }
    77  
    78  // Test to read empty directory.
    79  func setupTestReadDirEmpty(t *testing.T) (testResults []result) {
    80  	// Add empty entry slice for this test directory.
    81  	testResults = append(testResults, result{mustSetupDir(t), []string{}})
    82  	return testResults
    83  }
    84  
    85  // Test to read non-empty directory with only files.
    86  func setupTestReadDirFiles(t *testing.T) (testResults []result) {
    87  	dir := mustSetupDir(t)
    88  	entries := []string{}
    89  	for i := 0; i < 10; i++ {
    90  		name := fmt.Sprintf("file-%d", i)
    91  		if err := ioutil.WriteFile(filepath.Join(dir, name), []byte{}, os.ModePerm); err != nil {
    92  			// For cleanup, its required to add these entries into test results.
    93  			testResults = append(testResults, result{dir, entries})
    94  			t.Fatalf("Unable to create file, %s", err)
    95  		}
    96  		entries = append(entries, name)
    97  	}
    98  
    99  	// Keep entries sorted for easier comparison.
   100  	sort.Strings(entries)
   101  
   102  	// Add entries slice for this test directory.
   103  	testResults = append(testResults, result{dir, entries})
   104  	return testResults
   105  }
   106  
   107  // Test to read non-empty directory with directories and files.
   108  func setupTestReadDirGeneric(t *testing.T) (testResults []result) {
   109  	dir := mustSetupDir(t)
   110  	if err := os.MkdirAll(filepath.Join(dir, "mydir"), 0777); err != nil {
   111  		t.Fatalf("Unable to create prefix directory \"mydir\", %s", err)
   112  	}
   113  	entries := []string{"mydir/"}
   114  	for i := 0; i < 10; i++ {
   115  		name := fmt.Sprintf("file-%d", i)
   116  		if err := ioutil.WriteFile(filepath.Join(dir, "mydir", name), []byte{}, os.ModePerm); err != nil {
   117  			// For cleanup, its required to add these entries into test results.
   118  			testResults = append(testResults, result{dir, entries})
   119  			t.Fatalf("Unable to write file, %s", err)
   120  		}
   121  	}
   122  	// Keep entries sorted for easier comparison.
   123  	sort.Strings(entries)
   124  
   125  	// Add entries slice for this test directory.
   126  	testResults = append(testResults, result{dir, entries})
   127  	return testResults
   128  }
   129  
   130  // Test to read non-empty directory with symlinks.
   131  func setupTestReadDirSymlink(t *testing.T) (testResults []result) {
   132  	if runtime.GOOS == globalWindowsOSName {
   133  		t.Skip("symlinks not available on windows")
   134  		return nil
   135  	}
   136  	dir := mustSetupDir(t)
   137  	entries := []string{}
   138  	for i := 0; i < 10; i++ {
   139  		name1 := fmt.Sprintf("file-%d", i)
   140  		name2 := fmt.Sprintf("file-%d", i+10)
   141  		if err := ioutil.WriteFile(filepath.Join(dir, name1), []byte{}, os.ModePerm); err != nil {
   142  			// For cleanup, its required to add these entries into test results.
   143  			testResults = append(testResults, result{dir, entries})
   144  			t.Fatalf("Unable to create a file, %s", err)
   145  		}
   146  		// Symlink will not be added to entries.
   147  		if err := os.Symlink(filepath.Join(dir, name1), filepath.Join(dir, name2)); err != nil {
   148  			t.Fatalf("Unable to create a symlink, %s", err)
   149  		}
   150  		// Add to entries.
   151  		entries = append(entries, name1)
   152  		// Symlinks are preserved for regular files
   153  		entries = append(entries, name2)
   154  	}
   155  	if err := os.MkdirAll(filepath.Join(dir, "mydir"), 0777); err != nil {
   156  		t.Fatalf("Unable to create \"mydir\", %s", err)
   157  	}
   158  	entries = append(entries, "mydir/")
   159  
   160  	// Keep entries sorted for easier comparison.
   161  	sort.Strings(entries)
   162  
   163  	// Add entries slice for this test directory.
   164  	testResults = append(testResults, result{dir, entries})
   165  	return testResults
   166  }
   167  
   168  // checkResult - checks whether entries are got are same as expected entries.
   169  func checkResult(expected []string, got []string) bool {
   170  	// If length of expected and got slice are different, the test actually failed.
   171  	if len(expected) != len(got) {
   172  		return false
   173  	}
   174  
   175  	for i := range expected {
   176  		// If entry in expected is not same as entry it got, the test is failed.
   177  		if expected[i] != got[i] {
   178  			return false
   179  		}
   180  	}
   181  
   182  	// expected and got have same entries.
   183  	return true
   184  }
   185  
   186  // teardown - cleans up test directories.
   187  func teardown(testResults []result) {
   188  	for _, r := range testResults {
   189  		os.RemoveAll(r.dir)
   190  	}
   191  }
   192  
   193  // TestReadDir - test function to run various readDir() tests.
   194  func TestReadDir(t *testing.T) {
   195  	var testResults []result
   196  
   197  	// Setup and capture test results for empty directory.
   198  	testResults = append(testResults, setupTestReadDirEmpty(t)...)
   199  	// Setup and capture test results for directory with only files.
   200  	testResults = append(testResults, setupTestReadDirFiles(t)...)
   201  	// Setup and capture test results for directory with files and directories.
   202  	testResults = append(testResults, setupTestReadDirGeneric(t)...)
   203  	// Setup and capture test results for directory with files and symlink.
   204  	testResults = append(testResults, setupTestReadDirSymlink(t)...)
   205  
   206  	// Remove all dirs once tests are over.
   207  	defer teardown(testResults)
   208  
   209  	// Validate all the results.
   210  	for _, r := range testResults {
   211  		if entries, err := readDir(r.dir); err != nil {
   212  			t.Fatal("failed to run test.", err)
   213  		} else {
   214  			// Keep entries sorted for easier comparison.
   215  			sort.Strings(entries)
   216  			if !checkResult(r.entries, entries) {
   217  				t.Fatalf("expected = %s, got: %s", r.entries, entries)
   218  			}
   219  		}
   220  	}
   221  }
   222  
   223  func TestReadDirN(t *testing.T) {
   224  	testCases := []struct {
   225  		numFiles    int
   226  		n           int
   227  		expectedNum int
   228  	}{
   229  		{0, 0, 0},
   230  		{0, 1, 0},
   231  		{1, 0, 0},
   232  		{0, -1, 0},
   233  		{1, -1, 1},
   234  		{10, -1, 10},
   235  		{1, 1, 1},
   236  		{2, 1, 1},
   237  		{10, 9, 9},
   238  		{10, 10, 10},
   239  		{10, 11, 10},
   240  	}
   241  
   242  	for i, testCase := range testCases {
   243  		dir := mustSetupDir(t)
   244  
   245  		for c := 1; c <= testCase.numFiles; c++ {
   246  			err := ioutil.WriteFile(filepath.Join(dir, fmt.Sprintf("%d", c)), []byte{}, os.ModePerm)
   247  			if err != nil {
   248  				os.RemoveAll(dir)
   249  				t.Fatalf("Unable to create a file, %s", err)
   250  			}
   251  		}
   252  		entries, err := readDirN(dir, testCase.n)
   253  		if err != nil {
   254  			os.RemoveAll(dir)
   255  			t.Fatalf("Unable to read entries, %s", err)
   256  		}
   257  		if len(entries) != testCase.expectedNum {
   258  			os.RemoveAll(dir)
   259  			t.Fatalf("Test %d: unexpected number of entries, waiting for %d, but found %d",
   260  				i+1, testCase.expectedNum, len(entries))
   261  		}
   262  		os.RemoveAll(dir)
   263  	}
   264  }