github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/utils/filesys/fs_test.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package filesys
    16  
    17  import (
    18  	"os"
    19  	"path/filepath"
    20  	"reflect"
    21  	"sort"
    22  	"testing"
    23  
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"github.com/dolthub/dolt/go/libraries/utils/osutil"
    27  	"github.com/dolthub/dolt/go/libraries/utils/test"
    28  )
    29  
    30  const (
    31  	testFilename  = "testfile.txt"
    32  	movedFilename = "movedfile.txt"
    33  	testString    = "this is a test"
    34  	testStringLen = int64(len(testString))
    35  )
    36  
    37  var filesysetmsToTest = map[string]Filesys{
    38  	"inmem": EmptyInMemFS("/"),
    39  	"local": LocalFS,
    40  }
    41  
    42  func TestFilesystems(t *testing.T) {
    43  	dir := test.TestDir("filesys_test")
    44  	fp := filepath.Join(dir, testFilename)
    45  	movedFilePath := filepath.Join(dir, movedFilename)
    46  
    47  	for fsName, fs := range filesysetmsToTest {
    48  		t.Run(fsName, func(t *testing.T) {
    49  			// Test file doesn't exist before creation
    50  			exists, _ := fs.Exists(dir)
    51  			require.False(t, exists)
    52  
    53  			// Test creating a directory
    54  			err := fs.MkDirs(dir)
    55  			require.NoError(t, err)
    56  
    57  			// Test directory exists, and is in fact a directory
    58  			exists, isDir := fs.Exists(dir)
    59  			require.True(t, exists)
    60  			require.True(t, isDir)
    61  
    62  			// Test failure to open a directory for read
    63  			_, err = fs.OpenForRead(dir)
    64  			require.Error(t, err)
    65  
    66  			// Test failure to open a directory for write
    67  			_, err = fs.OpenForWrite(dir, os.ModePerm)
    68  			require.Error(t, err)
    69  
    70  			// Test file doesn't exist before creation
    71  			exists, _ = fs.Exists(fp)
    72  			require.False(t, exists)
    73  
    74  			// Test can't open a file that doesn't exist for read
    75  			_, err = fs.OpenForRead(fp)
    76  			require.Error(t, err)
    77  
    78  			data := test.RandomData(256 * 1024)
    79  
    80  			// Test writing file with random data
    81  			err = fs.WriteFile(fp, data)
    82  			require.NoError(t, err)
    83  
    84  			// Test that the data can be read back and hasn't changed
    85  			dataRead, err := fs.ReadFile(fp)
    86  			require.NoError(t, err)
    87  			require.Equal(t, dataRead, data)
    88  
    89  			// Test moving the file
    90  			err = fs.MoveFile(fp, movedFilePath)
    91  			require.NoError(t, err)
    92  
    93  			// Test that there is no longer a file at the initial path
    94  			exists, _ = fs.Exists(fp)
    95  			require.False(t, exists)
    96  
    97  			// Test that a file exists at the new location
    98  			exists, isDir = fs.Exists(movedFilePath)
    99  			require.True(t, exists)
   100  			require.False(t, isDir)
   101  
   102  			// Test that the data can be read back and hasn't changed since being moved
   103  			dataRead, err = fs.ReadFile(movedFilePath)
   104  			require.NoError(t, err)
   105  			require.Equal(t, dataRead, data)
   106  		})
   107  	}
   108  }
   109  
   110  func TestNewInMemFS(t *testing.T) {
   111  	fs := NewInMemFS([]string{"/r1/c1", "r2/c1/gc1"}, map[string][]byte{
   112  		"/r1/c1/file1.txt": []byte(testString),
   113  		"/r3/file2.txt":    []byte(testString),
   114  	}, "/")
   115  
   116  	expectedDirs := []string{
   117  		osutil.PathToNative("/r1"),
   118  		osutil.PathToNative("/r1/c1"),
   119  		osutil.PathToNative("/r2"),
   120  		osutil.PathToNative("/r2/c1"),
   121  		osutil.PathToNative("/r2/c1/gc1"),
   122  		osutil.PathToNative("/r3"),
   123  	}
   124  
   125  	expectedFiles := []string{
   126  		osutil.PathToNative("/r1/c1/file1.txt"),
   127  		osutil.PathToNative("/r3/file2.txt"),
   128  	}
   129  
   130  	actualDirs, actualFiles, err := iterate(fs, "/", true, t)
   131  
   132  	if err != nil {
   133  		t.Error("Error iterating")
   134  	}
   135  
   136  	validate(expectedDirs, expectedFiles, actualDirs, actualFiles, "inmem", t)
   137  }
   138  
   139  func TestRecursiveFSIteration(t *testing.T) {
   140  	dir := test.TestDir("TestRecursiveFSIteration")
   141  
   142  	for fsName, fs := range filesysetmsToTest {
   143  		var expectedDirs []string
   144  		var expectedFiles []string
   145  
   146  		expectedDirs = makeDirsAddExpected(expectedDirs, fs, dir, "child1")
   147  		expectedDirs = makeDirsAddExpected(expectedDirs, fs, dir, "child2", "grandchild1")
   148  		expectedDirs = makeDirsAddExpected(expectedDirs, fs, dir, "child3", "grandchild2")
   149  		expectedDirs = makeDirsAddExpected(expectedDirs, fs, filepath.Join(dir, "child3"), "grandchild3")
   150  
   151  		expectedFiles = writeFileAddToExp(expectedFiles, fs, dir, "child1", "File1.txt")
   152  		expectedFiles = writeFileAddToExp(expectedFiles, fs, dir, "child2", "grandchild1", "File1.txt")
   153  		expectedFiles = writeFileAddToExp(expectedFiles, fs, dir, "child3", "grandchild2", "File1.txt")
   154  		expectedFiles = writeFileAddToExp(expectedFiles, fs, dir, "child3", "grandchild2", "File2.txt")
   155  		expectedFiles = writeFileAddToExp(expectedFiles, fs, dir, "child3", "grandchild3", "File1.txt")
   156  
   157  		actualDirs, actualFiles, err := iterate(fs, dir, true, t)
   158  
   159  		if err != nil {
   160  			t.Error("fs:", fsName, "Failed to iterate.", err.Error())
   161  			continue
   162  		}
   163  
   164  		validate(expectedDirs, expectedFiles, actualDirs, actualFiles, fsName, t)
   165  	}
   166  }
   167  
   168  func TestFSIteration(t *testing.T) {
   169  	dir := test.TestDir("TestFSIteration")
   170  
   171  	for fsName, fs := range filesysetmsToTest {
   172  		var expectedDirs []string
   173  		var expectedFiles []string
   174  		var ignored []string
   175  
   176  		makeDirsAddExpected(ignored, fs, dir, "child1")
   177  		makeDirsAddExpected(ignored, fs, dir, "child2", "grandchild1")
   178  		makeDirsAddExpected(ignored, fs, dir, "child3")
   179  
   180  		child3path := filepath.Join(dir, "child3")
   181  		expectedDirs = makeDirsAddExpected(expectedDirs, fs, child3path, "grandchild2")
   182  		expectedDirs = makeDirsAddExpected(expectedDirs, fs, child3path, "grandchild3")
   183  		expectedFiles = writeFileAddToExp(expectedFiles, fs, child3path, "File1.txt")
   184  
   185  		writeFileAddToExp(ignored, fs, dir, "child1", "File1.txt")
   186  		writeFileAddToExp(ignored, fs, dir, "child2", "grandchild1", "File1.txt")
   187  		writeFileAddToExp(ignored, fs, dir, "child3", "grandchild2", "File1.txt")
   188  		writeFileAddToExp(ignored, fs, dir, "child3", "grandchild2", "File2.txt")
   189  		writeFileAddToExp(ignored, fs, dir, "child3", "grandchild3", "File1.txt")
   190  
   191  		actualDirs, actualFiles, err := iterate(fs, filepath.Join(dir, "child3"), false, t)
   192  
   193  		if err != nil {
   194  			t.Error("fs:", fsName, "Failed to iterate.", err.Error())
   195  			continue
   196  		}
   197  
   198  		validate(expectedDirs, expectedFiles, actualDirs, actualFiles, fsName, t)
   199  	}
   200  }
   201  
   202  func TestDeletes(t *testing.T) {
   203  	dir := test.TestDir("TestDeletes")
   204  
   205  	for fsName, fs := range filesysetmsToTest {
   206  		var ignored []string
   207  
   208  		makeDirsAddExpected(ignored, fs, dir, "child1")
   209  		makeDirsAddExpected(ignored, fs, dir, "child2", "grandchild1")
   210  		makeDirsAddExpected(ignored, fs, dir, "child3")
   211  
   212  		writeFileAddToExp(ignored, fs, dir, "child1", "File1.txt")
   213  		writeFileAddToExp(ignored, fs, dir, "child2", "grandchild1", "File1.txt")
   214  		writeFileAddToExp(ignored, fs, dir, "child3", "grandchild2", "File1.txt")
   215  		writeFileAddToExp(ignored, fs, dir, "child3", "grandchild2", "File2.txt")
   216  		writeFileAddToExp(ignored, fs, dir, "child3", "grandchild3", "File1.txt")
   217  
   218  		var err error
   219  		err = fs.Delete(filepath.Join(dir, "child1"), false)
   220  
   221  		if err == nil {
   222  			t.Error("fs:", fsName, "Should have failed to delete non empty directory without force flag")
   223  		}
   224  
   225  		err = fs.DeleteFile(filepath.Join(dir, "child1", "File1.txt"))
   226  
   227  		if err != nil {
   228  			t.Error("fs:", fsName, "Should have succeeded to delete file")
   229  		}
   230  
   231  		err = fs.DeleteFile(filepath.Join(dir, "child1"))
   232  
   233  		if err == nil {
   234  			t.Error("fs:", fsName, "DeleteFile should not delete directories")
   235  		}
   236  
   237  		err = fs.Delete(filepath.Join(dir, "child1"), false)
   238  
   239  		if err != nil {
   240  			t.Error("fs:", fsName, "Should have succeeded to delete empty directory")
   241  		}
   242  
   243  		err = fs.Delete(filepath.Join(dir, "child2"), true)
   244  
   245  		if err != nil {
   246  			t.Error("fs:", fsName, "Should have succeeded to force delete directory and it")
   247  		}
   248  	}
   249  
   250  }
   251  
   252  func makeDirsAddExpected(expected []string, fs Filesys, root string, descendants ...string) []string {
   253  	currDir := root
   254  	for _, descendant := range descendants {
   255  		currDir = filepath.Join(currDir, descendant)
   256  		expected = append(expected, currDir)
   257  	}
   258  
   259  	err := fs.MkDirs(currDir)
   260  
   261  	if err != nil {
   262  		panic("failed to make dir")
   263  	}
   264  
   265  	return expected
   266  }
   267  
   268  func writeFileAddToExp(expected []string, fs Filesys, root string, pathFromRoot ...string) []string {
   269  	pathElements := append([]string{root}, pathFromRoot...)
   270  
   271  	fp := filepath.Join(pathElements...)
   272  	fs.WriteFile(fp, []byte(testString))
   273  	return append(expected, fp)
   274  }
   275  
   276  func iterate(fs Filesys, dir string, recursive bool, t *testing.T) ([]string, []string, error) {
   277  	actualDirs := make([]string, 0, 10)
   278  	actualFiles := make([]string, 0, 10)
   279  	err := fs.Iter(dir, recursive, func(path string, size int64, isDir bool) (stop bool) {
   280  		if isDir {
   281  			actualDirs = append(actualDirs, path)
   282  		} else {
   283  			actualFiles = append(actualFiles, path)
   284  
   285  			if size != testStringLen {
   286  				t.Error(path, "is not of the expected size.")
   287  			}
   288  		}
   289  
   290  		return false
   291  	})
   292  
   293  	return actualDirs, actualFiles, err
   294  }
   295  
   296  func validate(expectedDirs, expectedFiles, actualDirs, actualFiles []string, fsName string, t *testing.T) {
   297  	sort.Strings(expectedDirs)
   298  	sort.Strings(expectedFiles)
   299  	sort.Strings(actualDirs)
   300  	sort.Strings(actualFiles)
   301  
   302  	if !reflect.DeepEqual(expectedDirs, actualDirs) {
   303  		t.Error("fs:", fsName, "Expected dirs does not match actual dirs.", "\n\tactual  :", actualDirs, "\n\texpected:", expectedDirs)
   304  	}
   305  
   306  	if !reflect.DeepEqual(expectedFiles, actualFiles) {
   307  		t.Error("fs:", fsName, "Expected files does not match actual files.", "\n\tactual  :", actualFiles, "\n\texpected:", expectedFiles)
   308  	}
   309  }