restore_test.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. package backup
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "syscall"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. cosylogger "github.com/uozi-tech/cosy/logger"
  10. )
  11. func init() {
  12. // Initialize logging system to avoid nil pointer exceptions during tests
  13. cosylogger.Init("debug")
  14. }
  15. // TestIsDeviceBusyError tests the device busy error detection
  16. func TestIsDeviceBusyError(t *testing.T) {
  17. tests := []struct {
  18. name string
  19. err error
  20. expected bool
  21. }{
  22. {
  23. name: "nil error",
  24. err: nil,
  25. expected: false,
  26. },
  27. {
  28. name: "EBUSY syscall error",
  29. err: syscall.EBUSY,
  30. expected: true,
  31. },
  32. {
  33. name: "device or resource busy string",
  34. err: fmt.Errorf("device or resource busy"),
  35. expected: true,
  36. },
  37. {
  38. name: "resource busy string",
  39. err: fmt.Errorf("resource busy"),
  40. expected: true,
  41. },
  42. {
  43. name: "other error",
  44. err: fmt.Errorf("permission denied"),
  45. expected: false,
  46. },
  47. }
  48. for _, tt := range tests {
  49. t.Run(tt.name, func(t *testing.T) {
  50. result := isDeviceBusyError(tt.err)
  51. assert.Equal(t, tt.expected, result)
  52. })
  53. }
  54. }
  55. // TestUnescapeOctal tests the octal escape sequence unescaping
  56. func TestUnescapeOctal(t *testing.T) {
  57. tests := []struct {
  58. name string
  59. input string
  60. expected string
  61. }{
  62. {
  63. name: "no escape sequences",
  64. input: "/mnt/data",
  65. expected: "/mnt/data",
  66. },
  67. {
  68. name: "space escape \\040",
  69. input: "/mnt/my\\040folder",
  70. expected: "/mnt/my folder",
  71. },
  72. {
  73. name: "multiple escapes",
  74. input: "/mnt\\040test\\040dir",
  75. expected: "/mnt test dir",
  76. },
  77. {
  78. name: "incomplete escape at end",
  79. input: "/mnt\\04",
  80. expected: "/mnt\\04",
  81. },
  82. }
  83. for _, tt := range tests {
  84. t.Run(tt.name, func(t *testing.T) {
  85. result := unescapeOctal(tt.input)
  86. assert.Equal(t, tt.expected, result)
  87. })
  88. }
  89. }
  90. // TestIsMountPoint tests mount point detection
  91. func TestIsMountPoint(t *testing.T) {
  92. // Create a temporary directory for testing
  93. tempDir, err := os.MkdirTemp("", "mount-test-*")
  94. assert.NoError(t, err)
  95. defer os.RemoveAll(tempDir)
  96. // Create a subdirectory
  97. subDir := filepath.Join(tempDir, "subdir")
  98. err = os.MkdirAll(subDir, 0755)
  99. assert.NoError(t, err)
  100. // Test regular directory (should not be a mount point)
  101. isMountResult := isMountPoint(subDir)
  102. assert.False(t, isMountResult, "Regular subdirectory should not be detected as mount point")
  103. // Test root directory
  104. // Root is typically a mount point on Linux
  105. rootIsMountResult := isMountPoint("/")
  106. // We don't assert true here because it depends on the system
  107. // But we verify the function doesn't panic
  108. t.Logf("Root directory mount check result: %v", rootIsMountResult)
  109. // Test non-existent path
  110. nonExistentIsMountResult := isMountPoint("/non/existent/path")
  111. assert.False(t, nonExistentIsMountResult, "Non-existent path should return false")
  112. }
  113. // TestClearDirectoryContents tests the directory contents clearing
  114. func TestClearDirectoryContents(t *testing.T) {
  115. // Create a temporary directory structure
  116. tempDir, err := os.MkdirTemp("", "clear-test-*")
  117. assert.NoError(t, err)
  118. defer os.RemoveAll(tempDir)
  119. // Create files and subdirectories
  120. testFile1 := filepath.Join(tempDir, "file1.txt")
  121. testFile2 := filepath.Join(tempDir, "file2.txt")
  122. subDir := filepath.Join(tempDir, "subdir")
  123. subFile := filepath.Join(subDir, "subfile.txt")
  124. err = os.WriteFile(testFile1, []byte("test content 1"), 0644)
  125. assert.NoError(t, err)
  126. err = os.WriteFile(testFile2, []byte("test content 2"), 0644)
  127. assert.NoError(t, err)
  128. err = os.MkdirAll(subDir, 0755)
  129. assert.NoError(t, err)
  130. err = os.WriteFile(subFile, []byte("sub content"), 0644)
  131. assert.NoError(t, err)
  132. // Verify files exist before clearing
  133. assert.FileExists(t, testFile1)
  134. assert.FileExists(t, testFile2)
  135. assert.FileExists(t, subFile)
  136. assert.DirExists(t, subDir)
  137. // Clear directory contents
  138. err = clearDirectoryContents(tempDir)
  139. assert.NoError(t, err)
  140. // Verify directory still exists
  141. assert.DirExists(t, tempDir)
  142. // Verify all contents are removed
  143. entries, err := os.ReadDir(tempDir)
  144. assert.NoError(t, err)
  145. assert.Empty(t, entries, "Directory should be empty after clearing")
  146. }
  147. // TestClearDirectoryContentsWithNestedDirs tests clearing nested directory structures
  148. func TestClearDirectoryContentsWithNestedDirs(t *testing.T) {
  149. tempDir, err := os.MkdirTemp("", "clear-nested-test-*")
  150. assert.NoError(t, err)
  151. defer os.RemoveAll(tempDir)
  152. // Create nested structure: tempDir/level1/level2/level3
  153. level1 := filepath.Join(tempDir, "level1")
  154. level2 := filepath.Join(level1, "level2")
  155. level3 := filepath.Join(level2, "level3")
  156. err = os.MkdirAll(level3, 0755)
  157. assert.NoError(t, err)
  158. // Add files at each level
  159. err = os.WriteFile(filepath.Join(level1, "file1.txt"), []byte("level1"), 0644)
  160. assert.NoError(t, err)
  161. err = os.WriteFile(filepath.Join(level2, "file2.txt"), []byte("level2"), 0644)
  162. assert.NoError(t, err)
  163. err = os.WriteFile(filepath.Join(level3, "file3.txt"), []byte("level3"), 0644)
  164. assert.NoError(t, err)
  165. // Clear contents
  166. err = clearDirectoryContents(tempDir)
  167. assert.NoError(t, err)
  168. // Verify root directory exists but is empty
  169. assert.DirExists(t, tempDir)
  170. entries, err := os.ReadDir(tempDir)
  171. assert.NoError(t, err)
  172. assert.Empty(t, entries)
  173. }
  174. // TestCleanDirectoryPreservingStructure tests the main cleaning function
  175. func TestCleanDirectoryPreservingStructure(t *testing.T) {
  176. tempDir, err := os.MkdirTemp("", "clean-structure-test-*")
  177. assert.NoError(t, err)
  178. defer os.RemoveAll(tempDir)
  179. // Create a complex directory structure
  180. dir1 := filepath.Join(tempDir, "dir1")
  181. dir2 := filepath.Join(tempDir, "dir2")
  182. file1 := filepath.Join(tempDir, "file1.txt")
  183. file2 := filepath.Join(dir1, "file2.txt")
  184. err = os.MkdirAll(dir1, 0755)
  185. assert.NoError(t, err)
  186. err = os.MkdirAll(dir2, 0755)
  187. assert.NoError(t, err)
  188. err = os.WriteFile(file1, []byte("content1"), 0644)
  189. assert.NoError(t, err)
  190. err = os.WriteFile(file2, []byte("content2"), 0644)
  191. assert.NoError(t, err)
  192. // Clean the directory
  193. err = cleanDirectoryPreservingStructure(tempDir)
  194. assert.NoError(t, err)
  195. // Verify root directory exists
  196. assert.DirExists(t, tempDir)
  197. // Verify all contents are removed
  198. entries, err := os.ReadDir(tempDir)
  199. assert.NoError(t, err)
  200. assert.Empty(t, entries, "Directory should be empty after cleaning")
  201. }
  202. // TestCleanDirectoryPreservingStructureEmptyDir tests cleaning an already empty directory
  203. func TestCleanDirectoryPreservingStructureEmptyDir(t *testing.T) {
  204. tempDir, err := os.MkdirTemp("", "clean-empty-test-*")
  205. assert.NoError(t, err)
  206. defer os.RemoveAll(tempDir)
  207. // Clean already empty directory
  208. err = cleanDirectoryPreservingStructure(tempDir)
  209. assert.NoError(t, err)
  210. // Verify directory still exists
  211. assert.DirExists(t, tempDir)
  212. }
  213. // TestCleanDirectoryPreservingStructureWithSymlinks tests cleaning with symbolic links
  214. func TestCleanDirectoryPreservingStructureWithSymlinks(t *testing.T) {
  215. tempDir, err := os.MkdirTemp("", "clean-symlink-test-*")
  216. assert.NoError(t, err)
  217. defer os.RemoveAll(tempDir)
  218. // Create a target file
  219. targetFile := filepath.Join(tempDir, "target.txt")
  220. err = os.WriteFile(targetFile, []byte("target content"), 0644)
  221. assert.NoError(t, err)
  222. // Create a symlink
  223. symlinkPath := filepath.Join(tempDir, "link.txt")
  224. err = os.Symlink(targetFile, symlinkPath)
  225. assert.NoError(t, err)
  226. // Verify symlink exists
  227. _, err = os.Lstat(symlinkPath)
  228. assert.NoError(t, err)
  229. // Clean directory
  230. err = cleanDirectoryPreservingStructure(tempDir)
  231. assert.NoError(t, err)
  232. // Verify directory exists and is empty
  233. assert.DirExists(t, tempDir)
  234. entries, err := os.ReadDir(tempDir)
  235. assert.NoError(t, err)
  236. assert.Empty(t, entries)
  237. }
  238. // TestCleanDirectoryPreservingStructureNonExistent tests error handling for non-existent directory
  239. func TestCleanDirectoryPreservingStructureNonExistent(t *testing.T) {
  240. nonExistentDir := "/tmp/non-existent-dir-12345"
  241. err := cleanDirectoryPreservingStructure(nonExistentDir)
  242. assert.Error(t, err, "Should return error for non-existent directory")
  243. }