directory_operations_test.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. package fuse_test
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "sort"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/require"
  10. )
  11. // TestDirectoryOperations tests fundamental FUSE directory operations
  12. func TestDirectoryOperations(t *testing.T) {
  13. framework := NewFuseTestFramework(t, DefaultTestConfig())
  14. defer framework.Cleanup()
  15. require.NoError(t, framework.Setup(DefaultTestConfig()))
  16. t.Run("CreateDirectory", func(t *testing.T) {
  17. testCreateDirectory(t, framework)
  18. })
  19. t.Run("RemoveDirectory", func(t *testing.T) {
  20. testRemoveDirectory(t, framework)
  21. })
  22. t.Run("ReadDirectory", func(t *testing.T) {
  23. testReadDirectory(t, framework)
  24. })
  25. t.Run("NestedDirectories", func(t *testing.T) {
  26. testNestedDirectories(t, framework)
  27. })
  28. t.Run("DirectoryPermissions", func(t *testing.T) {
  29. testDirectoryPermissions(t, framework)
  30. })
  31. t.Run("DirectoryRename", func(t *testing.T) {
  32. testDirectoryRename(t, framework)
  33. })
  34. }
  35. // testCreateDirectory tests creating directories
  36. func testCreateDirectory(t *testing.T, framework *FuseTestFramework) {
  37. dirName := "test_directory"
  38. mountPath := filepath.Join(framework.GetMountPoint(), dirName)
  39. // Create directory
  40. require.NoError(t, os.Mkdir(mountPath, 0755))
  41. // Verify directory exists
  42. info, err := os.Stat(mountPath)
  43. require.NoError(t, err)
  44. assert.True(t, info.IsDir())
  45. assert.Equal(t, os.FileMode(0755), info.Mode().Perm())
  46. }
  47. // testRemoveDirectory tests removing directories
  48. func testRemoveDirectory(t *testing.T, framework *FuseTestFramework) {
  49. dirName := "test_remove_dir"
  50. mountPath := filepath.Join(framework.GetMountPoint(), dirName)
  51. // Create directory
  52. require.NoError(t, os.Mkdir(mountPath, 0755))
  53. // Verify it exists
  54. _, err := os.Stat(mountPath)
  55. require.NoError(t, err)
  56. // Remove directory
  57. require.NoError(t, os.Remove(mountPath))
  58. // Verify it's gone
  59. _, err = os.Stat(mountPath)
  60. require.True(t, os.IsNotExist(err))
  61. }
  62. // testReadDirectory tests reading directory contents
  63. func testReadDirectory(t *testing.T, framework *FuseTestFramework) {
  64. testDir := "test_read_dir"
  65. framework.CreateTestDir(testDir)
  66. // Create various types of entries
  67. entries := []string{
  68. "file1.txt",
  69. "file2.log",
  70. "subdir1",
  71. "subdir2",
  72. "script.sh",
  73. }
  74. // Create files and subdirectories
  75. for _, entry := range entries {
  76. entryPath := filepath.Join(testDir, entry)
  77. if entry == "subdir1" || entry == "subdir2" {
  78. framework.CreateTestDir(entryPath)
  79. } else {
  80. framework.CreateTestFile(entryPath, []byte("content of "+entry))
  81. }
  82. }
  83. // Read directory
  84. mountPath := filepath.Join(framework.GetMountPoint(), testDir)
  85. dirEntries, err := os.ReadDir(mountPath)
  86. require.NoError(t, err)
  87. // Verify all entries are present
  88. var actualNames []string
  89. for _, entry := range dirEntries {
  90. actualNames = append(actualNames, entry.Name())
  91. }
  92. sort.Strings(entries)
  93. sort.Strings(actualNames)
  94. assert.Equal(t, entries, actualNames)
  95. // Verify entry types
  96. for _, entry := range dirEntries {
  97. if entry.Name() == "subdir1" || entry.Name() == "subdir2" {
  98. assert.True(t, entry.IsDir())
  99. } else {
  100. assert.False(t, entry.IsDir())
  101. }
  102. }
  103. }
  104. // testNestedDirectories tests operations on nested directory structures
  105. func testNestedDirectories(t *testing.T, framework *FuseTestFramework) {
  106. // Create nested structure: parent/child1/grandchild/child2
  107. structure := []string{
  108. "parent",
  109. "parent/child1",
  110. "parent/child1/grandchild",
  111. "parent/child2",
  112. }
  113. // Create directories
  114. for _, dir := range structure {
  115. framework.CreateTestDir(dir)
  116. }
  117. // Create files at various levels
  118. files := map[string][]byte{
  119. "parent/root_file.txt": []byte("root level"),
  120. "parent/child1/child_file.txt": []byte("child level"),
  121. "parent/child1/grandchild/deep_file.txt": []byte("deep level"),
  122. "parent/child2/another_file.txt": []byte("another child"),
  123. }
  124. for path, content := range files {
  125. framework.CreateTestFile(path, content)
  126. }
  127. // Verify structure by walking
  128. mountPath := filepath.Join(framework.GetMountPoint(), "parent")
  129. var foundPaths []string
  130. err := filepath.Walk(mountPath, func(path string, info os.FileInfo, err error) error {
  131. if err != nil {
  132. return err
  133. }
  134. // Get relative path from mount point
  135. relPath, _ := filepath.Rel(framework.GetMountPoint(), path)
  136. foundPaths = append(foundPaths, relPath)
  137. return nil
  138. })
  139. require.NoError(t, err)
  140. // Verify all expected paths were found
  141. expectedPaths := []string{
  142. "parent",
  143. "parent/child1",
  144. "parent/child1/grandchild",
  145. "parent/child1/grandchild/deep_file.txt",
  146. "parent/child1/child_file.txt",
  147. "parent/child2",
  148. "parent/child2/another_file.txt",
  149. "parent/root_file.txt",
  150. }
  151. sort.Strings(expectedPaths)
  152. sort.Strings(foundPaths)
  153. assert.Equal(t, expectedPaths, foundPaths)
  154. // Verify file contents
  155. for path, expectedContent := range files {
  156. framework.AssertFileContent(path, expectedContent)
  157. }
  158. }
  159. // testDirectoryPermissions tests directory permission operations
  160. func testDirectoryPermissions(t *testing.T, framework *FuseTestFramework) {
  161. dirName := "test_permissions_dir"
  162. mountPath := filepath.Join(framework.GetMountPoint(), dirName)
  163. // Create directory with specific permissions
  164. require.NoError(t, os.Mkdir(mountPath, 0700))
  165. // Check initial permissions
  166. info, err := os.Stat(mountPath)
  167. require.NoError(t, err)
  168. assert.Equal(t, os.FileMode(0700), info.Mode().Perm())
  169. // Change permissions
  170. require.NoError(t, os.Chmod(mountPath, 0755))
  171. // Verify permission change
  172. info, err = os.Stat(mountPath)
  173. require.NoError(t, err)
  174. assert.Equal(t, os.FileMode(0755), info.Mode().Perm())
  175. }
  176. // testDirectoryRename tests renaming directories
  177. func testDirectoryRename(t *testing.T, framework *FuseTestFramework) {
  178. oldName := "old_directory"
  179. newName := "new_directory"
  180. // Create directory with content
  181. framework.CreateTestDir(oldName)
  182. framework.CreateTestFile(filepath.Join(oldName, "test_file.txt"), []byte("test content"))
  183. oldPath := filepath.Join(framework.GetMountPoint(), oldName)
  184. newPath := filepath.Join(framework.GetMountPoint(), newName)
  185. // Rename directory
  186. require.NoError(t, os.Rename(oldPath, newPath))
  187. // Verify old path doesn't exist
  188. _, err := os.Stat(oldPath)
  189. require.True(t, os.IsNotExist(err))
  190. // Verify new path exists and is a directory
  191. info, err := os.Stat(newPath)
  192. require.NoError(t, err)
  193. assert.True(t, info.IsDir())
  194. // Verify content still exists
  195. framework.AssertFileContent(filepath.Join(newName, "test_file.txt"), []byte("test content"))
  196. }
  197. // TestComplexDirectoryOperations tests more complex directory scenarios
  198. func TestComplexDirectoryOperations(t *testing.T) {
  199. framework := NewFuseTestFramework(t, DefaultTestConfig())
  200. defer framework.Cleanup()
  201. require.NoError(t, framework.Setup(DefaultTestConfig()))
  202. t.Run("RemoveNonEmptyDirectory", func(t *testing.T) {
  203. testRemoveNonEmptyDirectory(t, framework)
  204. })
  205. t.Run("DirectoryWithManyFiles", func(t *testing.T) {
  206. testDirectoryWithManyFiles(t, framework)
  207. })
  208. t.Run("DeepDirectoryNesting", func(t *testing.T) {
  209. testDeepDirectoryNesting(t, framework)
  210. })
  211. }
  212. // testRemoveNonEmptyDirectory tests behavior when trying to remove non-empty directories
  213. func testRemoveNonEmptyDirectory(t *testing.T, framework *FuseTestFramework) {
  214. dirName := "non_empty_dir"
  215. framework.CreateTestDir(dirName)
  216. // Add content to directory
  217. framework.CreateTestFile(filepath.Join(dirName, "file.txt"), []byte("content"))
  218. framework.CreateTestDir(filepath.Join(dirName, "subdir"))
  219. mountPath := filepath.Join(framework.GetMountPoint(), dirName)
  220. // Try to remove non-empty directory (should fail)
  221. err := os.Remove(mountPath)
  222. require.Error(t, err)
  223. // Directory should still exist
  224. info, err := os.Stat(mountPath)
  225. require.NoError(t, err)
  226. assert.True(t, info.IsDir())
  227. // Remove with RemoveAll should work
  228. require.NoError(t, os.RemoveAll(mountPath))
  229. // Verify it's gone
  230. _, err = os.Stat(mountPath)
  231. require.True(t, os.IsNotExist(err))
  232. }
  233. // testDirectoryWithManyFiles tests directories with large numbers of files
  234. func testDirectoryWithManyFiles(t *testing.T, framework *FuseTestFramework) {
  235. dirName := "many_files_dir"
  236. framework.CreateTestDir(dirName)
  237. // Create many files
  238. numFiles := 100
  239. for i := 0; i < numFiles; i++ {
  240. filename := filepath.Join(dirName, fmt.Sprintf("file_%03d.txt", i))
  241. content := []byte(fmt.Sprintf("Content of file %d", i))
  242. framework.CreateTestFile(filename, content)
  243. }
  244. // Read directory
  245. mountPath := filepath.Join(framework.GetMountPoint(), dirName)
  246. entries, err := os.ReadDir(mountPath)
  247. require.NoError(t, err)
  248. // Verify count
  249. assert.Equal(t, numFiles, len(entries))
  250. // Verify some random files
  251. testIndices := []int{0, 10, 50, 99}
  252. for _, i := range testIndices {
  253. filename := filepath.Join(dirName, fmt.Sprintf("file_%03d.txt", i))
  254. expectedContent := []byte(fmt.Sprintf("Content of file %d", i))
  255. framework.AssertFileContent(filename, expectedContent)
  256. }
  257. }
  258. // testDeepDirectoryNesting tests very deep directory structures
  259. func testDeepDirectoryNesting(t *testing.T, framework *FuseTestFramework) {
  260. // Create deep nesting (20 levels)
  261. depth := 20
  262. currentPath := ""
  263. for i := 0; i < depth; i++ {
  264. if i == 0 {
  265. currentPath = fmt.Sprintf("level_%02d", i)
  266. } else {
  267. currentPath = filepath.Join(currentPath, fmt.Sprintf("level_%02d", i))
  268. }
  269. framework.CreateTestDir(currentPath)
  270. }
  271. // Create a file at the deepest level
  272. deepFile := filepath.Join(currentPath, "deep_file.txt")
  273. deepContent := []byte("This is very deep!")
  274. framework.CreateTestFile(deepFile, deepContent)
  275. // Verify file exists and has correct content
  276. framework.AssertFileContent(deepFile, deepContent)
  277. // Verify we can navigate the full structure
  278. mountPath := filepath.Join(framework.GetMountPoint(), currentPath)
  279. info, err := os.Stat(mountPath)
  280. require.NoError(t, err)
  281. assert.True(t, info.IsDir())
  282. }