2021-04-18 15:41:13 -04:00
|
|
|
// Copyright (c) 2015-2021 MinIO, Inc.
|
|
|
|
//
|
|
|
|
// This file is part of MinIO Object Storage stack
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2016-06-24 17:32:08 -04:00
|
|
|
|
2016-08-18 19:23:42 -04:00
|
|
|
package cmd
|
2016-06-24 17:32:08 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2019-03-05 20:28:14 -05:00
|
|
|
"path"
|
2016-06-24 17:32:08 -04:00
|
|
|
"path/filepath"
|
2016-06-26 22:31:53 -04:00
|
|
|
"runtime"
|
2016-06-24 17:32:08 -04:00
|
|
|
"sort"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Test to check for different input arguments.
|
2016-06-26 22:31:53 -04:00
|
|
|
func TestReadDirFail(t *testing.T) {
|
2016-06-24 17:32:08 -04:00
|
|
|
// Check non existent directory.
|
|
|
|
if _, err := readDir("/tmp/non-existent-directory"); err != errFileNotFound {
|
|
|
|
t.Fatalf("expected = %s, got: %s", errFileNotFound, err)
|
|
|
|
}
|
|
|
|
|
2019-03-05 20:28:14 -05:00
|
|
|
file := path.Join(os.TempDir(), "issue")
|
2022-01-02 12:15:06 -05:00
|
|
|
if err := ioutil.WriteFile(file, []byte(""), 0o644); err != nil {
|
2019-03-05 20:28:14 -05:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(file)
|
|
|
|
|
2016-06-24 17:32:08 -04:00
|
|
|
// Check if file is given.
|
2019-03-05 20:28:14 -05:00
|
|
|
if _, err := readDir(path.Join(file, "mydir")); err != errFileNotFound {
|
2016-06-24 17:32:08 -04:00
|
|
|
t.Fatalf("expected = %s, got: %s", errFileNotFound, err)
|
|
|
|
}
|
|
|
|
|
2016-06-26 22:31:53 -04:00
|
|
|
// Only valid for linux.
|
|
|
|
if runtime.GOOS == "linux" {
|
2019-03-05 20:28:14 -05:00
|
|
|
permDir := path.Join(os.TempDir(), "perm-dir")
|
2022-01-02 12:15:06 -05:00
|
|
|
if err := os.MkdirAll(permDir, os.FileMode(0o200)); err != nil {
|
2019-03-05 20:28:14 -05:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(permDir)
|
|
|
|
|
2016-06-26 22:31:53 -04:00
|
|
|
// Check if permission denied.
|
2019-03-05 20:28:14 -05:00
|
|
|
if _, err := readDir(permDir); err == nil {
|
2016-06-26 22:31:53 -04:00
|
|
|
t.Fatalf("expected = an error, got: nil")
|
|
|
|
}
|
2016-06-24 17:32:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-26 22:31:53 -04:00
|
|
|
// Represents data type for all the test results.
|
2016-06-24 17:32:08 -04:00
|
|
|
type result struct {
|
|
|
|
dir string
|
|
|
|
entries []string
|
|
|
|
}
|
|
|
|
|
2016-06-26 22:31:53 -04:00
|
|
|
// Test to read empty directory.
|
|
|
|
func setupTestReadDirEmpty(t *testing.T) (testResults []result) {
|
|
|
|
// Add empty entry slice for this test directory.
|
2022-07-25 15:37:26 -04:00
|
|
|
testResults = append(testResults, result{t.TempDir(), []string{}})
|
2016-06-26 22:31:53 -04:00
|
|
|
return testResults
|
|
|
|
}
|
2016-06-24 17:32:08 -04:00
|
|
|
|
2016-06-26 22:31:53 -04:00
|
|
|
// Test to read non-empty directory with only files.
|
|
|
|
func setupTestReadDirFiles(t *testing.T) (testResults []result) {
|
2022-07-25 15:37:26 -04:00
|
|
|
dir := t.TempDir()
|
2016-06-26 22:31:53 -04:00
|
|
|
entries := []string{}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
name := fmt.Sprintf("file-%d", i)
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(dir, name), []byte{}, os.ModePerm); err != nil {
|
|
|
|
// For cleanup, its required to add these entries into test results.
|
|
|
|
testResults = append(testResults, result{dir, entries})
|
|
|
|
t.Fatalf("Unable to create file, %s", err)
|
2016-06-24 17:32:08 -04:00
|
|
|
}
|
2016-06-26 22:31:53 -04:00
|
|
|
entries = append(entries, name)
|
|
|
|
}
|
2016-06-24 17:32:08 -04:00
|
|
|
|
2016-06-26 22:31:53 -04:00
|
|
|
// Keep entries sorted for easier comparison.
|
|
|
|
sort.Strings(entries)
|
2016-06-24 17:32:08 -04:00
|
|
|
|
2016-06-26 22:31:53 -04:00
|
|
|
// Add entries slice for this test directory.
|
|
|
|
testResults = append(testResults, result{dir, entries})
|
|
|
|
return testResults
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test to read non-empty directory with directories and files.
|
|
|
|
func setupTestReadDirGeneric(t *testing.T) (testResults []result) {
|
2022-07-25 15:37:26 -04:00
|
|
|
dir := t.TempDir()
|
2022-01-02 12:15:06 -05:00
|
|
|
if err := os.MkdirAll(filepath.Join(dir, "mydir"), 0o777); err != nil {
|
2016-06-26 22:31:53 -04:00
|
|
|
t.Fatalf("Unable to create prefix directory \"mydir\", %s", err)
|
|
|
|
}
|
|
|
|
entries := []string{"mydir/"}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
name := fmt.Sprintf("file-%d", i)
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(dir, "mydir", name), []byte{}, os.ModePerm); err != nil {
|
|
|
|
// For cleanup, its required to add these entries into test results.
|
|
|
|
testResults = append(testResults, result{dir, entries})
|
|
|
|
t.Fatalf("Unable to write file, %s", err)
|
|
|
|
}
|
2016-06-24 17:32:08 -04:00
|
|
|
}
|
2016-06-26 22:31:53 -04:00
|
|
|
// Keep entries sorted for easier comparison.
|
|
|
|
sort.Strings(entries)
|
|
|
|
|
|
|
|
// Add entries slice for this test directory.
|
|
|
|
testResults = append(testResults, result{dir, entries})
|
|
|
|
return testResults
|
2016-06-24 17:32:08 -04:00
|
|
|
}
|
|
|
|
|
2016-06-26 22:31:53 -04:00
|
|
|
// Test to read non-empty directory with symlinks.
|
|
|
|
func setupTestReadDirSymlink(t *testing.T) (testResults []result) {
|
2019-10-14 12:44:51 -04:00
|
|
|
if runtime.GOOS == globalWindowsOSName {
|
|
|
|
t.Skip("symlinks not available on windows")
|
2019-09-26 02:08:24 -04:00
|
|
|
return nil
|
|
|
|
}
|
2022-07-25 15:37:26 -04:00
|
|
|
dir := t.TempDir()
|
2016-06-26 22:31:53 -04:00
|
|
|
entries := []string{}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
name1 := fmt.Sprintf("file-%d", i)
|
|
|
|
name2 := fmt.Sprintf("file-%d", i+10)
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(dir, name1), []byte{}, os.ModePerm); err != nil {
|
|
|
|
// For cleanup, its required to add these entries into test results.
|
|
|
|
testResults = append(testResults, result{dir, entries})
|
|
|
|
t.Fatalf("Unable to create a file, %s", err)
|
|
|
|
}
|
|
|
|
// Symlink will not be added to entries.
|
|
|
|
if err := os.Symlink(filepath.Join(dir, name1), filepath.Join(dir, name2)); err != nil {
|
|
|
|
t.Fatalf("Unable to create a symlink, %s", err)
|
|
|
|
}
|
|
|
|
// Add to entries.
|
|
|
|
entries = append(entries, name1)
|
2021-02-20 03:30:12 -05:00
|
|
|
// Symlinks are preserved for regular files
|
|
|
|
entries = append(entries, name2)
|
2016-06-24 17:32:08 -04:00
|
|
|
}
|
2022-01-02 12:15:06 -05:00
|
|
|
if err := os.MkdirAll(filepath.Join(dir, "mydir"), 0o777); err != nil {
|
2016-06-26 22:31:53 -04:00
|
|
|
t.Fatalf("Unable to create \"mydir\", %s", err)
|
|
|
|
}
|
|
|
|
entries = append(entries, "mydir/")
|
|
|
|
|
|
|
|
// Keep entries sorted for easier comparison.
|
|
|
|
sort.Strings(entries)
|
|
|
|
|
|
|
|
// Add entries slice for this test directory.
|
|
|
|
testResults = append(testResults, result{dir, entries})
|
|
|
|
return testResults
|
2016-06-24 17:32:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// checkResult - checks whether entries are got are same as expected entries.
|
|
|
|
func checkResult(expected []string, got []string) bool {
|
|
|
|
// If length of expected and got slice are different, the test actually failed.
|
|
|
|
if len(expected) != len(got) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range expected {
|
|
|
|
// If entry in expected is not same as entry it got, the test is failed.
|
|
|
|
if expected[i] != got[i] {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// expected and got have same entries.
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2016-06-26 22:31:53 -04:00
|
|
|
// teardown - cleans up test directories.
|
|
|
|
func teardown(testResults []result) {
|
|
|
|
for _, r := range testResults {
|
|
|
|
os.RemoveAll(r.dir)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-24 17:32:08 -04:00
|
|
|
// TestReadDir - test function to run various readDir() tests.
|
|
|
|
func TestReadDir(t *testing.T) {
|
2016-06-26 22:31:53 -04:00
|
|
|
var testResults []result
|
|
|
|
|
|
|
|
// Setup and capture test results for empty directory.
|
|
|
|
testResults = append(testResults, setupTestReadDirEmpty(t)...)
|
|
|
|
// Setup and capture test results for directory with only files.
|
|
|
|
testResults = append(testResults, setupTestReadDirFiles(t)...)
|
|
|
|
// Setup and capture test results for directory with files and directories.
|
|
|
|
testResults = append(testResults, setupTestReadDirGeneric(t)...)
|
|
|
|
// Setup and capture test results for directory with files and symlink.
|
|
|
|
testResults = append(testResults, setupTestReadDirSymlink(t)...)
|
|
|
|
|
|
|
|
// Remove all dirs once tests are over.
|
|
|
|
defer teardown(testResults)
|
|
|
|
|
|
|
|
// Validate all the results.
|
2016-06-24 17:32:08 -04:00
|
|
|
for _, r := range testResults {
|
|
|
|
if entries, err := readDir(r.dir); err != nil {
|
|
|
|
t.Fatal("failed to run test.", err)
|
|
|
|
} else {
|
|
|
|
// Keep entries sorted for easier comparison.
|
|
|
|
sort.Strings(entries)
|
|
|
|
if !checkResult(r.entries, entries) {
|
|
|
|
t.Fatalf("expected = %s, got: %s", r.entries, entries)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-05-08 22:08:21 -04:00
|
|
|
|
|
|
|
func TestReadDirN(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
numFiles int
|
|
|
|
n int
|
|
|
|
expectedNum int
|
|
|
|
}{
|
|
|
|
{0, 0, 0},
|
|
|
|
{0, 1, 0},
|
2019-08-09 11:54:11 -04:00
|
|
|
{1, 0, 0},
|
2018-05-08 22:08:21 -04:00
|
|
|
{0, -1, 0},
|
|
|
|
{1, -1, 1},
|
|
|
|
{10, -1, 10},
|
|
|
|
{1, 1, 1},
|
|
|
|
{2, 1, 1},
|
|
|
|
{10, 9, 9},
|
|
|
|
{10, 10, 10},
|
|
|
|
{10, 11, 10},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, testCase := range testCases {
|
2022-07-25 15:37:26 -04:00
|
|
|
dir := t.TempDir()
|
2018-05-08 22:08:21 -04:00
|
|
|
|
|
|
|
for c := 1; c <= testCase.numFiles; c++ {
|
2019-08-09 11:54:11 -04:00
|
|
|
err := ioutil.WriteFile(filepath.Join(dir, fmt.Sprintf("%d", c)), []byte{}, os.ModePerm)
|
|
|
|
if err != nil {
|
|
|
|
os.RemoveAll(dir)
|
2018-05-08 22:08:21 -04:00
|
|
|
t.Fatalf("Unable to create a file, %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
entries, err := readDirN(dir, testCase.n)
|
|
|
|
if err != nil {
|
2019-08-09 11:54:11 -04:00
|
|
|
os.RemoveAll(dir)
|
2018-05-08 22:08:21 -04:00
|
|
|
t.Fatalf("Unable to read entries, %s", err)
|
|
|
|
}
|
|
|
|
if len(entries) != testCase.expectedNum {
|
2019-08-09 11:54:11 -04:00
|
|
|
os.RemoveAll(dir)
|
|
|
|
t.Fatalf("Test %d: unexpected number of entries, waiting for %d, but found %d",
|
|
|
|
i+1, testCase.expectedNum, len(entries))
|
2018-05-08 22:08:21 -04:00
|
|
|
}
|
2019-08-09 11:54:11 -04:00
|
|
|
os.RemoveAll(dir)
|
2018-05-08 22:08:21 -04:00
|
|
|
}
|
|
|
|
}
|