file_test.go 12 KB

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