file_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /*
  2. * Rufs - Remote Union File System
  3. *
  4. * Copyright 2017 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package term
  11. import (
  12. "bytes"
  13. "fmt"
  14. "io/ioutil"
  15. "os"
  16. "testing"
  17. "devt.de/krotik/common/errorutil"
  18. "devt.de/krotik/rufs"
  19. "devt.de/krotik/rufs/config"
  20. )
  21. func TestSimpleFileOperations(t *testing.T) {
  22. var buf bytes.Buffer
  23. // Build up a tree with multiple branches
  24. cfg := map[string]interface{}{
  25. config.TreeSecret: "123",
  26. }
  27. tree, _ := rufs.NewTree(cfg, clientCert)
  28. fooRPC := fmt.Sprintf("%v:%v", branchConfigs["footest"][config.RPCHost], branchConfigs["footest"][config.RPCPort])
  29. fooFP := footest.SSLFingerprint()
  30. barRPC := fmt.Sprintf("%v:%v", branchConfigs["bartest"][config.RPCHost], branchConfigs["bartest"][config.RPCPort])
  31. barFP := bartest.SSLFingerprint()
  32. tmpRPC := fmt.Sprintf("%v:%v", branchConfigs["tmptest"][config.RPCHost], branchConfigs["tmptest"][config.RPCPort])
  33. tmpFP := tmptest.SSLFingerprint()
  34. tree.AddBranch(footest.Name(), fooRPC, fooFP)
  35. tree.AddBranch(bartest.Name(), barRPC, barFP)
  36. tree.AddBranch(tmptest.Name(), tmpRPC, tmpFP)
  37. tree.AddMapping("/", footest.Name(), false)
  38. tree.AddMapping("/backup", bartest.Name(), true)
  39. term := NewTreeTerm(tree, &buf)
  40. if res, err := term.Run("tree"); err != nil || (res != `
  41. /
  42. drwxrwxrwx 0 B backup
  43. drwxrwx--- 4.0 KiB sub1
  44. -rwxrwx--- 10 B test1
  45. -rwxrwx--- 10 B test2
  46. /backup
  47. -rwxrwx--- 10 B test1
  48. /sub1
  49. -rwxrwx--- 17 B test3
  50. `[1:] && res != `
  51. /
  52. drwxrwxrwx 0 B backup
  53. drwxrwxrwx 0 B sub1
  54. -rw-rw-rw- 10 B test1
  55. -rw-rw-rw- 10 B test2
  56. /backup
  57. -rw-rw-rw- 10 B test1
  58. /sub1
  59. -rw-rw-rw- 17 B test3
  60. `[1:]) {
  61. t.Error("Unexpected result: ", res, err)
  62. return
  63. }
  64. res, err := term.Run("cat /sub1/test3")
  65. if err != nil {
  66. t.Error(err)
  67. return
  68. }
  69. res += buf.String()
  70. res += "\n"
  71. buf.Reset()
  72. if res != `
  73. Sub dir test file
  74. `[1:] {
  75. t.Error("Unexpected result: ", res)
  76. return
  77. }
  78. // Read file and store as same filename
  79. res, err = term.Run("get /sub1/test3")
  80. if err != nil || res != "Written file test3" {
  81. t.Error(res, err)
  82. return
  83. }
  84. defer os.Remove("test3")
  85. content, err := ioutil.ReadFile("test3")
  86. if err != nil || string(content) != "Sub dir test file" {
  87. t.Error(string(content), err)
  88. return
  89. }
  90. // Read file and store as same different filename - extra path is ignored
  91. res, err = term.Run("get /sub1/test3 foo42/test123")
  92. if err != nil || res != "Written file test123" {
  93. t.Error(res, err)
  94. return
  95. }
  96. defer os.RemoveAll("test123")
  97. content, err = ioutil.ReadFile("test123")
  98. if err != nil || string(content) != "Sub dir test file" {
  99. t.Error(string(content), err)
  100. return
  101. }
  102. _, err = term.Run("cat /sub1/test4")
  103. if err == nil || (err.Error() != "RufsError: Remote error (stat /sub1/test4: no such file or directory)" &&
  104. err.Error() != `RufsError: Remote error (CreateFile \sub1\test4: The system cannot find the file specified.)`) {
  105. t.Error(err)
  106. return
  107. }
  108. // Try writing files - only backup is mounted as writable
  109. ioutil.WriteFile("testfile66", []byte("write test"), 0660)
  110. defer os.Remove("testfile66")
  111. res, err = term.Run("put testfile66 /testfile66")
  112. if err == nil || err.Error() != "All applicable branches for the requested path were mounted as not writable" {
  113. t.Error(res, err)
  114. return
  115. }
  116. res, err = term.Run("put testfile66 /backup/testfile66")
  117. if err != nil || res != "Written file /backup/testfile66" {
  118. t.Error(res, err)
  119. return
  120. }
  121. if res, err := term.Run("tree /backup"); err != nil || (res != `
  122. /backup
  123. -rwxrwx--- 10 B test1
  124. -rw-r--r-- 10 B testfile66
  125. `[1:] && res != `
  126. /backup
  127. -rw-rw-rw- 10 B test1
  128. -rw-rw-rw- 10 B testfile66
  129. `[1:]) {
  130. t.Error("Unexpected result: ", res, err)
  131. return
  132. }
  133. res, err = term.Run("cat /backup/testfile66")
  134. if err != nil {
  135. t.Error(err)
  136. return
  137. }
  138. res += buf.String()
  139. res += "\n"
  140. buf.Reset()
  141. if res != `
  142. write test
  143. `[1:] {
  144. t.Error("Unexpected result: ", res)
  145. return
  146. }
  147. if res := dirLocal("./bar"); res != `
  148. test1
  149. testfile66
  150. `[1:] {
  151. t.Error("Unexpected result:", res)
  152. return
  153. }
  154. tree.AddMapping("/backup/tmp", tmptest.Name(), true)
  155. if res, err := term.Run("tree /backup"); err != nil || (res != `
  156. /backup
  157. -rwxrwx--- 10 B test1
  158. -rw-r--r-- 10 B testfile66
  159. drwxrwxrwx 0 B tmp
  160. /backup/tmp
  161. `[1:] && res != `
  162. /backup
  163. -rw-rw-rw- 10 B test1
  164. -rw-rw-rw- 10 B testfile66
  165. drwxrwxrwx 0 B tmp
  166. /backup/tmp
  167. `[1:]) {
  168. t.Error("Unexpected result: ", res, err)
  169. return
  170. }
  171. res, err = term.Run("put testfile66 /backup/tmp/foofile66")
  172. if err != nil || res != "Written file /backup/tmp/foofile66" {
  173. t.Error(res, err)
  174. return
  175. }
  176. // Check that tmp has become a real directory as it was created in backup
  177. if res, err := term.Run("tree /backup"); err != nil || (res != `
  178. /backup
  179. -rwxrwx--- 10 B test1
  180. -rw-r--r-- 10 B testfile66
  181. drwxr-xr-x 4.0 KiB tmp
  182. /backup/tmp
  183. -rw-r--r-- 10 B foofile66
  184. `[1:] && res != `
  185. /backup
  186. -rw-rw-rw- 10 B test1
  187. -rw-rw-rw- 10 B testfile66
  188. drwxrwxrwx 0 B tmp
  189. /backup/tmp
  190. -rw-rw-rw- 10 B foofile66
  191. `[1:]) {
  192. t.Error("Unexpected result: ", res, err)
  193. return
  194. }
  195. // The file should have been now written to two files
  196. if res := dirLocal("./bar"); res != `
  197. test1
  198. testfile66
  199. tmp(dir)
  200. `[1:] {
  201. t.Error("Unexpected result:", res)
  202. return
  203. }
  204. if res := dirLocal("./bar/tmp"); res != `
  205. foofile66
  206. `[1:] {
  207. t.Error("Unexpected result:", res)
  208. return
  209. }
  210. if res := dirLocal("./tmp"); res != `
  211. foofile66
  212. `[1:] {
  213. t.Error("Unexpected result:", res)
  214. return
  215. }
  216. // Delete one of the files
  217. os.RemoveAll("bar/tmp")
  218. res, err = term.Run("rm /backup/tmp/foofile66")
  219. if err != nil || res != "" {
  220. t.Error(res, err)
  221. return
  222. }
  223. // See that the file was deleted
  224. if res := dirLocal("./tmp"); res != `
  225. `[1:] {
  226. t.Error("Unexpected result:", res)
  227. return
  228. }
  229. // Recreate the files
  230. res, err = term.Run("put testfile66 /backup/tmp/foofile66")
  231. if err != nil || res != "Written file /backup/tmp/foofile66" {
  232. t.Error(res, err)
  233. return
  234. }
  235. if res := dirLocal("./bar/tmp"); res != `
  236. foofile66
  237. `[1:] {
  238. t.Error("Unexpected result:", res)
  239. return
  240. }
  241. if res := dirLocal("./tmp"); res != `
  242. foofile66
  243. `[1:] {
  244. t.Error("Unexpected result:", res)
  245. return
  246. }
  247. res, err = term.Run("rm /backup/tmp1/")
  248. if err == nil || err.Error() != "RufsError: Remote error (file does not exist)" {
  249. t.Error("Unexpected result:", res, err)
  250. return
  251. }
  252. res, err = term.Run("rm /backup/tmp1")
  253. if err == nil || err.Error() != "RufsError: Remote error (file does not exist)" {
  254. t.Error("Unexpected result:", res, err)
  255. return
  256. }
  257. res, err = term.Run("rm /backup/*")
  258. if err != nil || res != "" {
  259. t.Error(res, err)
  260. return
  261. }
  262. if res, err := term.Run("tree /backup"); err != nil || (res != `
  263. /backup
  264. drwxrwxrwx 0 B tmp
  265. /backup/tmp
  266. -rw-r--r-- 10 B foofile66
  267. `[1:] && res != `
  268. /backup
  269. drwxrwxrwx 0 B tmp
  270. /backup/tmp
  271. -rw-rw-rw- 10 B foofile66
  272. `[1:]) {
  273. t.Error("Unexpected result: ", res, err)
  274. return
  275. }
  276. // Now try to delete recursive
  277. res, err = term.Run("rm /backup/**")
  278. if err != nil || res != "" {
  279. t.Error(res, err)
  280. return
  281. }
  282. if res, err := term.Run("tree /backup"); err != nil || (res != `
  283. /backup
  284. drwxrwxrwx 0 B tmp
  285. /backup/tmp
  286. `[1:] && res != `
  287. /backup
  288. sdrwxrwxrwx 0 KiB tmp
  289. /backup/tmp
  290. `[1:]) {
  291. t.Error("Unexpected result: ", res, err)
  292. return
  293. }
  294. // Recreate the files
  295. res, err = term.Run("put testfile66 /backup/tmp/foofile66")
  296. if err != nil || res != "Written file /backup/tmp/foofile66" {
  297. t.Error(res, err)
  298. return
  299. }
  300. res, err = term.Run("put testfile66 /backup/foofile66")
  301. if err != nil || res != "Written file /backup/foofile66" {
  302. t.Error(res, err)
  303. return
  304. }
  305. // Delete with wildcard
  306. res, err = term.Run("rm /backup/foo**")
  307. if err != nil || res != "" {
  308. t.Error(res, err)
  309. return
  310. }
  311. // Recreate files
  312. res, err = term.Run("put testfile66 /backup/tmp/foofile66")
  313. if err != nil || res != "Written file /backup/tmp/foofile66" {
  314. t.Error(res, err)
  315. return
  316. }
  317. if res, err := term.Run("tree /backup"); err != nil || (res != `
  318. /backup
  319. drwxr-xr-x 4.0 KiB tmp
  320. /backup/tmp
  321. -rw-r--r-- 10 B foofile66
  322. `[1:] && res != `
  323. /backup
  324. drwxrwxrwx 0 B tmp
  325. /backup/tmp
  326. -rw-rw-rw- 10 B foofile66
  327. `[1:]) {
  328. t.Error("Unexpected result: ", res, err)
  329. return
  330. }
  331. res, err = term.Run("ren /backup/tmp")
  332. if err == nil || err.Error() != "ren requires a filename and a new filename" {
  333. t.Error(res, err)
  334. return
  335. }
  336. res, err = term.Run("ren /backup/tmp /tmp/t")
  337. if err == nil || err.Error() != "new filename must not have a path" {
  338. t.Error(res, err)
  339. return
  340. }
  341. res, err = term.Run("ren /backup/tmp tmp2")
  342. if err != nil || res != "" {
  343. t.Error(res, err)
  344. return
  345. }
  346. res, err = term.Run("ren /backup/tmp2/foofile66/ foofile67")
  347. if err != nil || res != "" {
  348. t.Error(res, err)
  349. return
  350. }
  351. res, err = term.Run("mkdir /backup/tmp2/aaa/bbb/")
  352. if err != nil || res != "" {
  353. t.Error(res, err)
  354. return
  355. }
  356. res, err = term.Run("cp /backup/tmp2/foofile67 /backup/tmp/")
  357. if err != nil || res != "Done" {
  358. t.Error(res, err)
  359. return
  360. }
  361. if buf.String() != "\rCopy /foofile67: 10 B / 10 B (1 of 1)\r \r" {
  362. t.Errorf("Unexpected buffer: %#v", buf.String())
  363. return
  364. }
  365. res, err = term.Run("cp /backup/tmp2/foofile68 /backup/tmp/foofile67")
  366. if err == nil || err.Error() != "Cannot stat /backup/tmp2/foofile68: RufsError: Remote error (file does not exist)" {
  367. t.Error(res, err)
  368. return
  369. }
  370. res, err = term.Run("cp /backup/tmp2/foofile67 /foofile67")
  371. if err == nil || err.Error() != "Cannot copy /backup/tmp2/foofile67 to /foofile67: All applicable branches for the requested path were mounted as not writable" {
  372. t.Error(res, err)
  373. return
  374. }
  375. if res, err := term.Run("tree /backup"); err != nil || (res != `
  376. /backup
  377. drwxr-xr-x 4.0 KiB tmp
  378. drwxr-xr-x 4.0 KiB tmp2
  379. /backup/tmp
  380. -rw-r--r-- 10 B foofile66
  381. -rw-r--r-- 10 B foofile67
  382. /backup/tmp2
  383. drwxr-xr-x 4.0 KiB aaa
  384. -rw-r--r-- 10 B foofile67
  385. /backup/tmp2/aaa
  386. drwxr-xr-x 4.0 KiB bbb
  387. /backup/tmp2/aaa/bbb
  388. `[1:] && res != `
  389. /backup
  390. drwxrwxrwx 0 B tmp
  391. drwxrwxrwx 0 B tmp2
  392. /backup/tmp
  393. -rw-rw-rw- 10 B foofile66
  394. -rw-rw-rw- 10 B foofile67
  395. /backup/tmp2
  396. drwxrwxrwx 0 B aaa
  397. -rw-rw-rw- 10 B foofile67
  398. /backup/tmp2/aaa
  399. drwxrwxrwx 0 B bbb
  400. /backup/tmp2/aaa/bbb
  401. `[1:]) {
  402. t.Error("Unexpected result: ", res, err)
  403. return
  404. }
  405. os.Remove("./tmp/foofile66")
  406. os.Remove("./tmp/foofile67")
  407. if res := dirLocal("./tmp"); res != `
  408. `[1:] {
  409. t.Error("Unexpected result:", res)
  410. return
  411. }
  412. if res := dirLocal("./foo"); res != `
  413. sub1(dir)
  414. test1
  415. test2
  416. `[1:] {
  417. t.Error("Unexpected result:", res)
  418. return
  419. }
  420. if res := dirLocal("./foo/sub1"); res != `
  421. test3
  422. `[1:] {
  423. t.Error("Unexpected result:", res)
  424. return
  425. }
  426. os.RemoveAll("./bar/tmp")
  427. os.RemoveAll("./bar/tmp2")
  428. ioutil.WriteFile("bar/test1", []byte("Test3 file"), 0770)
  429. if res := dirLocal("./bar"); res != `
  430. test1
  431. `[1:] {
  432. t.Error("Unexpected result:", res)
  433. return
  434. }
  435. }
  436. /*
  437. dirLocal reads a local directory and returns all found file names as a string.
  438. */
  439. func dirLocal(dir string) string {
  440. var buf bytes.Buffer
  441. fis, err := ioutil.ReadDir(dir)
  442. errorutil.AssertOk(err)
  443. for _, fi := range fis {
  444. buf.WriteString(fi.Name())
  445. if fi.IsDir() {
  446. buf.WriteString("(dir)")
  447. }
  448. buf.WriteString(fmt.Sprintln())
  449. }
  450. return buf.String()
  451. }