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 }