file_test.go 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. package v1
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "mime/multipart"
  8. "net/http"
  9. "os"
  10. "strings"
  11. "testing"
  12. "time"
  13. "devt.de/krotik/common/datautil"
  14. "devt.de/krotik/common/errorutil"
  15. "devt.de/krotik/rufs"
  16. "devt.de/krotik/rufs/api"
  17. "devt.de/krotik/rufs/config"
  18. )
  19. func TestFileSync(t *testing.T) {
  20. queryURL := "http://localhost" + TESTPORT + EndpointFile
  21. dirqueryURL := "http://localhost" + TESTPORT + EndpointDir
  22. progressqueryURL := "http://localhost" + TESTPORT + EndpointProgress
  23. // Setup a tree
  24. defer func() {
  25. // Make sure all trees are removed
  26. api.ResetTrees()
  27. }()
  28. tree, err := rufs.NewTree(api.TreeConfigTemplate, api.TreeCertTemplate)
  29. errorutil.AssertOk(err)
  30. api.AddTree("Hans1", tree)
  31. fooRPC := fmt.Sprintf("%v:%v", branchConfigs["footest"][config.RPCHost], branchConfigs["footest"][config.RPCPort])
  32. fooFP := footest.SSLFingerprint()
  33. err = tree.AddBranch("footest", fooRPC, fooFP)
  34. errorutil.AssertOk(err)
  35. err = tree.AddMapping("/", "footest", true)
  36. errorutil.AssertOk(err)
  37. // Make the target directory
  38. os.Mkdir("foo/sync1", 0755)
  39. defer func() {
  40. errorutil.AssertOk(os.RemoveAll("foo/sync1"))
  41. }()
  42. st, _, res := sendTestRequest(dirqueryURL+"Hans1?recursive=TRUE&checksums=1", "GET", nil)
  43. if st != "200 OK" || res != `
  44. {
  45. "/": [
  46. {
  47. "checksum": "",
  48. "isdir": true,
  49. "name": "sub1",
  50. "size": 4096
  51. },
  52. {
  53. "checksum": "",
  54. "isdir": true,
  55. "name": "sync1",
  56. "size": 4096
  57. },
  58. {
  59. "checksum": "73b8af47",
  60. "isdir": false,
  61. "name": "test1",
  62. "size": 10
  63. },
  64. {
  65. "checksum": "b0c1fadd",
  66. "isdir": false,
  67. "name": "test2",
  68. "size": 10
  69. }
  70. ],
  71. "/sub1": [
  72. {
  73. "checksum": "f89782b1",
  74. "isdir": false,
  75. "name": "test3",
  76. "size": 17
  77. }
  78. ],
  79. "/sync1": null
  80. }`[1:] {
  81. t.Error("Unexpected response:", st, res)
  82. return
  83. }
  84. // Do the sync
  85. st, _, res = sendTestRequest(queryURL+"Hans1/", "PUT", []byte(`
  86. {
  87. "action" : "sync",
  88. "destination" : "/sync1"
  89. }`))
  90. if st != "200 OK" {
  91. t.Error("Unexpected response:", st, res)
  92. return
  93. }
  94. var resMap map[string]interface{}
  95. json.Unmarshal([]byte(res), &resMap)
  96. pid := fmt.Sprint(resMap["progress_id"])
  97. for {
  98. st, _, res = sendTestRequest(progressqueryURL+"Hans1/"+pid, "GET", nil)
  99. json.Unmarshal([]byte(res), &resMap)
  100. if st != "200 OK" ||
  101. len(resMap["errors"].([]interface{})) > 0 ||
  102. (resMap["progress"] == resMap["total_progress"] && resMap["item"] == resMap["total_items"]) {
  103. break
  104. }
  105. }
  106. if st != "200 OK" || res != `
  107. {
  108. "errors": [],
  109. "item": 5,
  110. "operation": "Copy file",
  111. "progress": 17,
  112. "subject": "/sub1/test3",
  113. "total_items": 5,
  114. "total_progress": 17
  115. }`[1:] {
  116. t.Error("Unexpected response:", st, res)
  117. return
  118. }
  119. time.Sleep(5 * time.Millisecond) // Wait a small time so all operations are guaranteed to finish
  120. st, _, res = sendTestRequest(dirqueryURL+"Hans1?recursive=TRUE&checksums=1", "GET", nil)
  121. if st != "200 OK" || res != `
  122. {
  123. "/": [
  124. {
  125. "checksum": "",
  126. "isdir": true,
  127. "name": "sub1",
  128. "size": 4096
  129. },
  130. {
  131. "checksum": "",
  132. "isdir": true,
  133. "name": "sync1",
  134. "size": 4096
  135. },
  136. {
  137. "checksum": "73b8af47",
  138. "isdir": false,
  139. "name": "test1",
  140. "size": 10
  141. },
  142. {
  143. "checksum": "b0c1fadd",
  144. "isdir": false,
  145. "name": "test2",
  146. "size": 10
  147. }
  148. ],
  149. "/sub1": [
  150. {
  151. "checksum": "f89782b1",
  152. "isdir": false,
  153. "name": "test3",
  154. "size": 17
  155. }
  156. ],
  157. "/sync1": [
  158. {
  159. "checksum": "",
  160. "isdir": true,
  161. "name": "sub1",
  162. "size": 4096
  163. },
  164. {
  165. "checksum": "",
  166. "isdir": true,
  167. "name": "sync1",
  168. "size": 4096
  169. },
  170. {
  171. "checksum": "73b8af47",
  172. "isdir": false,
  173. "name": "test1",
  174. "size": 10
  175. },
  176. {
  177. "checksum": "b0c1fadd",
  178. "isdir": false,
  179. "name": "test2",
  180. "size": 10
  181. }
  182. ],
  183. "/sync1/sub1": [
  184. {
  185. "checksum": "f89782b1",
  186. "isdir": false,
  187. "name": "test3",
  188. "size": 17
  189. }
  190. ],
  191. "/sync1/sync1": null
  192. }`[1:] {
  193. t.Error("Unexpected response:", st, res)
  194. return
  195. }
  196. // Test errors
  197. st, _, res = sendTestRequest(queryURL+"Hans1/", "PUT", []byte(`
  198. {
  199. "action" : "sync"
  200. }`))
  201. if st != "400 Bad Request" || res != "Parameter destination is missing from request body" {
  202. t.Error("Unexpected response:", st, res)
  203. return
  204. }
  205. tree.Reset(false)
  206. ProgressMap = datautil.NewMapCache(100, 0)
  207. err = tree.AddMapping("/", "footest", false)
  208. errorutil.AssertOk(err)
  209. st, _, res = sendTestRequest(queryURL+"Hans1/", "PUT", []byte(`
  210. {
  211. "action" : "sync",
  212. "destination" : "/sync1"
  213. }`))
  214. if st != "400 Bad Request" || res != "All applicable branches for the requested path were mounted as not writable" {
  215. t.Error("Unexpected response:", st, res)
  216. return
  217. }
  218. // Check error in ProgressMap
  219. for k := range ProgressMap.GetAll() {
  220. k = strings.Split(k, "#")[1]
  221. _, _, res = sendTestRequest(progressqueryURL+"Hans1/"+k, "GET", nil)
  222. resMap = nil
  223. errorutil.AssertOk(json.Unmarshal([]byte(res), &resMap))
  224. if res := fmt.Sprint(resMap["errors"]); res != "[All applicable branches for the requested path were mounted as not writable]" {
  225. t.Error("Unexpected result:", res)
  226. }
  227. break
  228. }
  229. }
  230. func TestFileUpload(t *testing.T) {
  231. queryURL := "http://localhost" + TESTPORT + EndpointFile
  232. dirqueryURL := "http://localhost" + TESTPORT + EndpointDir
  233. // Setup a tree
  234. defer func() {
  235. // Make sure all trees are removed
  236. api.ResetTrees()
  237. }()
  238. tree, err := rufs.NewTree(api.TreeConfigTemplate, api.TreeCertTemplate)
  239. errorutil.AssertOk(err)
  240. api.AddTree("Hans1", tree)
  241. fooRPC := fmt.Sprintf("%v:%v", branchConfigs["footest"][config.RPCHost], branchConfigs["footest"][config.RPCPort])
  242. fooFP := footest.SSLFingerprint()
  243. err = tree.AddBranch("footest", fooRPC, fooFP)
  244. errorutil.AssertOk(err)
  245. err = tree.AddMapping("/", "footest", true)
  246. errorutil.AssertOk(err)
  247. // Send a file
  248. body := &bytes.Buffer{}
  249. writer := multipart.NewWriter(body)
  250. part, err := writer.CreateFormFile("uploadfile", "foo-upload.txt")
  251. errorutil.AssertOk(err)
  252. part.Write([]byte("footest"))
  253. part, err = writer.CreateFormFile("uploadfile", "bar-upload.txt")
  254. errorutil.AssertOk(err)
  255. part.Write([]byte("bartest"))
  256. writer.WriteField("redirect", "/foo/bar")
  257. writer.Close()
  258. req, err := http.NewRequest("POST", queryURL+"Hans1/", body)
  259. if err != nil {
  260. panic(err)
  261. }
  262. req.Header.Set("Content-Type", writer.FormDataContentType())
  263. client := &http.Client{}
  264. client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
  265. return http.ErrUseLastResponse
  266. }
  267. resp, err := client.Do(req)
  268. if err != nil {
  269. panic(err)
  270. }
  271. defer resp.Body.Close()
  272. respBody, _ := ioutil.ReadAll(resp.Body)
  273. respBodyStr := strings.Trim(string(respBody), " \n")
  274. if l, _ := resp.Location(); resp.Status != "302 Found" || l.String() != "http://localhost:9040/foo/bar" {
  275. t.Error("Unexpected response:", resp.Status, l.String(), respBodyStr)
  276. return
  277. }
  278. defer func() {
  279. // Remove the uploaded files after we are done
  280. os.RemoveAll("foo/foo-upload.txt")
  281. os.RemoveAll("foo/bar-upload.txt")
  282. }()
  283. // Check that the file has been written
  284. st, _, res := sendTestRequest(dirqueryURL+"Hans1?recursive=TRUE&checksums=1", "GET", nil)
  285. if st != "200 OK" || res != `
  286. {
  287. "/": [
  288. {
  289. "checksum": "bab796f6",
  290. "isdir": false,
  291. "name": "bar-upload.txt",
  292. "size": 7
  293. },
  294. {
  295. "checksum": "75f4b6fe",
  296. "isdir": false,
  297. "name": "foo-upload.txt",
  298. "size": 7
  299. },
  300. {
  301. "checksum": "",
  302. "isdir": true,
  303. "name": "sub1",
  304. "size": 4096
  305. },
  306. {
  307. "checksum": "73b8af47",
  308. "isdir": false,
  309. "name": "test1",
  310. "size": 10
  311. },
  312. {
  313. "checksum": "b0c1fadd",
  314. "isdir": false,
  315. "name": "test2",
  316. "size": 10
  317. }
  318. ],
  319. "/sub1": [
  320. {
  321. "checksum": "f89782b1",
  322. "isdir": false,
  323. "name": "test3",
  324. "size": 17
  325. }
  326. ]
  327. }`[1:] {
  328. t.Error("Unexpected response:", st, res)
  329. return
  330. }
  331. // Check the files have been written correctly
  332. txt, err := ioutil.ReadFile("foo/foo-upload.txt")
  333. if err != nil || string(txt) != "footest" {
  334. t.Error("Unexpected result:", string(txt), err)
  335. return
  336. }
  337. txt, err = ioutil.ReadFile("foo/bar-upload.txt")
  338. if err != nil || string(txt) != "bartest" {
  339. t.Error("Unexpected result:", string(txt), err)
  340. return
  341. }
  342. // Test error cases
  343. st, _, res = sendTestRequest(queryURL, "POST", nil)
  344. if st != "400 Bad Request" || res != "Need a tree name and a file path" {
  345. t.Error("Unexpected response:", st, res)
  346. return
  347. }
  348. st, _, res = sendTestRequest(queryURL+"Hans2", "POST", nil)
  349. if st != "400 Bad Request" || res != "Unknown tree: Hans2" {
  350. t.Error("Unexpected response:", st, res)
  351. return
  352. }
  353. st, _, res = sendTestRequest(queryURL+"Hans1", "POST", nil)
  354. if st != "400 Bad Request" || res != "Could not read request body: request Content-Type isn't multipart/form-data" {
  355. t.Error("Unexpected response:", st, res)
  356. return
  357. }
  358. writer = multipart.NewWriter(body)
  359. part, err = writer.CreateFormFile("uploadfile2", "foo-upload.txt")
  360. if err != nil {
  361. panic(err)
  362. }
  363. errorutil.AssertOk(err)
  364. part.Write([]byte("footest"))
  365. writer.Close()
  366. req, err = http.NewRequest("POST", queryURL+"Hans1/", body)
  367. if err != nil {
  368. panic(err)
  369. }
  370. req.Header.Set("Content-Type", writer.FormDataContentType())
  371. client = &http.Client{}
  372. resp, err = client.Do(req)
  373. if err != nil {
  374. panic(err)
  375. }
  376. defer resp.Body.Close()
  377. respBody, _ = ioutil.ReadAll(resp.Body)
  378. respBodyStr = strings.Trim(string(respBody), " \n")
  379. if resp.Status != "400 Bad Request" || respBodyStr != "Could not find 'uploadfile' form field" {
  380. t.Error("Unexpected response:", resp.Status, respBodyStr)
  381. return
  382. }
  383. // Try with a absolute redirect
  384. writer = multipart.NewWriter(body)
  385. part, err = writer.CreateFormFile("uploadfile", "foo-upload.txt")
  386. errorutil.AssertOk(err)
  387. part.Write([]byte("footest"))
  388. writer.WriteField("redirect", "http://bla")
  389. writer.Close()
  390. req, err = http.NewRequest("POST", queryURL+"Hans1/", body)
  391. if err != nil {
  392. panic(err)
  393. }
  394. req.Header.Set("Content-Type", writer.FormDataContentType())
  395. client = &http.Client{}
  396. resp, err = client.Do(req)
  397. if err != nil {
  398. panic(err)
  399. }
  400. defer resp.Body.Close()
  401. respBody, _ = ioutil.ReadAll(resp.Body)
  402. respBodyStr = strings.Trim(string(respBody), " \n")
  403. if resp.Status != "400 Bad Request" || respBodyStr != "Could not redirect: Redirection URL must not be an absolute URL" {
  404. t.Error("Unexpected response:", resp.Status, respBodyStr)
  405. return
  406. }
  407. // Remap branch as read-only
  408. tree.Reset(false)
  409. err = tree.AddMapping("/", "footest", false)
  410. errorutil.AssertOk(err)
  411. writer = multipart.NewWriter(body)
  412. part, err = writer.CreateFormFile("uploadfile", "foo-upload.txt")
  413. errorutil.AssertOk(err)
  414. part.Write([]byte("footest"))
  415. writer.Close()
  416. req, err = http.NewRequest("POST", queryURL+"Hans1/", body)
  417. if err != nil {
  418. panic(err)
  419. }
  420. req.Header.Set("Content-Type", writer.FormDataContentType())
  421. client = &http.Client{}
  422. resp, err = client.Do(req)
  423. if err != nil {
  424. panic(err)
  425. }
  426. defer resp.Body.Close()
  427. respBody, _ = ioutil.ReadAll(resp.Body)
  428. respBodyStr = strings.Trim(string(respBody), " \n")
  429. if resp.Status != "400 Bad Request" || respBodyStr != "Could not write file foo-upload.txt: All applicable branches for the requested path were mounted as not writable" {
  430. t.Error("Unexpected response:", resp.Status, respBodyStr)
  431. return
  432. }
  433. }
  434. func TestFileQuery(t *testing.T) {
  435. queryURL := "http://localhost" + TESTPORT + EndpointFile
  436. dirqueryURL := "http://localhost" + TESTPORT + EndpointDir
  437. progressqueryURL := "http://localhost" + TESTPORT + EndpointProgress
  438. // Setup a tree
  439. defer func() {
  440. // Make sure all trees are removed
  441. api.ResetTrees()
  442. }()
  443. tree, err := rufs.NewTree(api.TreeConfigTemplate, api.TreeCertTemplate)
  444. errorutil.AssertOk(err)
  445. api.AddTree("Hans1", tree)
  446. fooRPC := fmt.Sprintf("%v:%v", branchConfigs["footest"][config.RPCHost], branchConfigs["footest"][config.RPCPort])
  447. fooFP := footest.SSLFingerprint()
  448. err = tree.AddBranch("footest", fooRPC, fooFP)
  449. errorutil.AssertOk(err)
  450. err = tree.AddMapping("/", "footest", false)
  451. errorutil.AssertOk(err)
  452. barRPC := fmt.Sprintf("%v:%v", branchConfigs["bartest"][config.RPCHost], branchConfigs["bartest"][config.RPCPort])
  453. barFP := bartest.SSLFingerprint()
  454. err = tree.AddBranch("bartest", barRPC, barFP)
  455. errorutil.AssertOk(err)
  456. err = tree.AddMapping("/tmp", "bartest", true)
  457. errorutil.AssertOk(err)
  458. // Create a file for renaming and deletion
  459. ioutil.WriteFile("bar/newfile1", []byte("test123"), 0660)
  460. st, _, res := sendTestRequest(dirqueryURL+"Hans1?recursive=TRUE&checksums=1", "GET", nil)
  461. if st != "200 OK" || res != `
  462. {
  463. "/": [
  464. {
  465. "checksum": "",
  466. "isdir": true,
  467. "name": "sub1",
  468. "size": 4096
  469. },
  470. {
  471. "checksum": "73b8af47",
  472. "isdir": false,
  473. "name": "test1",
  474. "size": 10
  475. },
  476. {
  477. "checksum": "b0c1fadd",
  478. "isdir": false,
  479. "name": "test2",
  480. "size": 10
  481. },
  482. {
  483. "checksum": "",
  484. "isdir": true,
  485. "name": "tmp",
  486. "size": 0
  487. }
  488. ],
  489. "/sub1": [
  490. {
  491. "checksum": "f89782b1",
  492. "isdir": false,
  493. "name": "test3",
  494. "size": 17
  495. }
  496. ],
  497. "/tmp": [
  498. {
  499. "checksum": "abcc6601",
  500. "isdir": false,
  501. "name": "newfile1",
  502. "size": 7
  503. },
  504. {
  505. "checksum": "5b62da0f",
  506. "isdir": false,
  507. "name": "test1",
  508. "size": 10
  509. }
  510. ]
  511. }`[1:] {
  512. t.Error("Unexpected response:", st, res)
  513. return
  514. }
  515. // Read a file
  516. st, _, res = sendTestRequest(queryURL+"Hans1/test2", "GET", nil)
  517. if st != "200 OK" || res != `
  518. Test2 file`[1:] {
  519. t.Error("Unexpected response:", st, res)
  520. return
  521. }
  522. // Try to delete a file
  523. st, _, res = sendTestRequest(queryURL+"Hans1/test2", "DELETE", nil)
  524. if st != "400 Bad Request" || res != "All applicable branches for the requested path were mounted as not writable" {
  525. t.Error("Unexpected response:", st, res)
  526. return
  527. }
  528. st, _, res = sendTestRequest(queryURL+"Hans1/test2", "DELETE", []byte(`["1.txt", "2.txt"]`))
  529. if st != "400 Bad Request" || res != "All applicable branches for the requested path were mounted as not writable" {
  530. t.Error("Unexpected response:", st, res)
  531. return
  532. }
  533. // Rename the file
  534. st, _, res = sendTestRequest(queryURL+"Hans1/tmp/newfile1", "PUT", []byte(`
  535. {
  536. "action" : "rename",
  537. "newname" : "newtest1"
  538. }`))
  539. if st != "200 OK" || res != "{}" {
  540. t.Error("Unexpected response:", st, res)
  541. return
  542. }
  543. // Create a directory
  544. st, _, res = sendTestRequest(queryURL+"Hans1/tmp/upload/", "PUT", []byte(`
  545. {
  546. "action" : "mkdir"
  547. }`))
  548. if st != "200 OK" || res != "{}" {
  549. t.Error("Unexpected response:", st, res)
  550. return
  551. }
  552. // Copy a file
  553. st, _, res = sendTestRequest(queryURL+"Hans1/tmp/newtest1", "PUT", []byte(`
  554. {
  555. "action" : "copy",
  556. "destination" : "/tmp/upload/"
  557. }`))
  558. if st != "200 OK" {
  559. t.Error("Unexpected response:", st, res)
  560. return
  561. }
  562. var resMap map[string]interface{}
  563. json.Unmarshal([]byte(res), &resMap)
  564. pid := fmt.Sprint(resMap["progress_id"])
  565. for {
  566. st, _, res = sendTestRequest(progressqueryURL+"Hans1/"+pid, "GET", nil)
  567. json.Unmarshal([]byte(res), &resMap)
  568. if st != "200 OK" || resMap["progress"] == resMap["total_progress"] {
  569. break
  570. }
  571. }
  572. if st != "200 OK" || res != `
  573. {
  574. "errors": [],
  575. "item": 1,
  576. "operation": "Copy",
  577. "progress": 7,
  578. "subject": "/newtest1",
  579. "total_items": 1,
  580. "total_progress": 7
  581. }`[1:] {
  582. t.Error("Unexpected response:", st, res)
  583. return
  584. }
  585. st, _, res = sendTestRequest(queryURL+"Hans1/tmp/upload/newtest1", "PUT", []byte(`
  586. {
  587. "action" : "rename",
  588. "newname" : "bla.txt"
  589. }`))
  590. if st != "200 OK" {
  591. t.Error("Unexpected response:", st, res)
  592. return
  593. }
  594. // Check the directory
  595. st, _, res = sendTestRequest(dirqueryURL+"Hans1/tmp?recursive=1&checksums=1", "GET", nil)
  596. if st != "200 OK" || res != `
  597. {
  598. "/tmp": [
  599. {
  600. "checksum": "abcc6601",
  601. "isdir": false,
  602. "name": "newtest1",
  603. "size": 7
  604. },
  605. {
  606. "checksum": "5b62da0f",
  607. "isdir": false,
  608. "name": "test1",
  609. "size": 10
  610. },
  611. {
  612. "checksum": "",
  613. "isdir": true,
  614. "name": "upload",
  615. "size": 4096
  616. }
  617. ],
  618. "/tmp/upload": [
  619. {
  620. "checksum": "abcc6601",
  621. "isdir": false,
  622. "name": "bla.txt",
  623. "size": 7
  624. }
  625. ]
  626. }`[1:] {
  627. t.Error("Unexpected response:", st, res)
  628. return
  629. }
  630. // Copy multiple files
  631. st, _, res = sendTestRequest(queryURL+"Hans1", "PUT", []byte(`
  632. {
  633. "action" : "copy",
  634. "files" : ["/tmp/newtest1", "/tmp/test1"],
  635. "destination" : "/tmp/upload"
  636. }`))
  637. if st != "200 OK" {
  638. t.Error("Unexpected response:", st, res)
  639. return
  640. }
  641. json.Unmarshal([]byte(res), &resMap)
  642. pid = fmt.Sprint(resMap["progress_id"])
  643. for {
  644. st, _, res = sendTestRequest(progressqueryURL+"Hans1/"+pid, "GET", nil)
  645. json.Unmarshal([]byte(res), &resMap)
  646. if st != "200 OK" || (resMap["progress"] == resMap["total_progress"] &&
  647. resMap["item"] == resMap["total_items"]) {
  648. break
  649. }
  650. }
  651. if st != "200 OK" || res != `
  652. {
  653. "errors": [],
  654. "item": 2,
  655. "operation": "Copy",
  656. "progress": 10,
  657. "subject": "/test1",
  658. "total_items": 2,
  659. "total_progress": 10
  660. }`[1:] {
  661. t.Error("Unexpected response:", st, res)
  662. return
  663. }
  664. // Check the directory
  665. st, _, res = sendTestRequest(dirqueryURL+"Hans1/tmp?recursive=1&checksums=1", "GET", nil)
  666. if st != "200 OK" || res != `
  667. {
  668. "/tmp": [
  669. {
  670. "checksum": "abcc6601",
  671. "isdir": false,
  672. "name": "newtest1",
  673. "size": 7
  674. },
  675. {
  676. "checksum": "5b62da0f",
  677. "isdir": false,
  678. "name": "test1",
  679. "size": 10
  680. },
  681. {
  682. "checksum": "",
  683. "isdir": true,
  684. "name": "upload",
  685. "size": 4096
  686. }
  687. ],
  688. "/tmp/upload": [
  689. {
  690. "checksum": "abcc6601",
  691. "isdir": false,
  692. "name": "bla.txt",
  693. "size": 7
  694. },
  695. {
  696. "checksum": "abcc6601",
  697. "isdir": false,
  698. "name": "newtest1",
  699. "size": 7
  700. },
  701. {
  702. "checksum": "5b62da0f",
  703. "isdir": false,
  704. "name": "test1",
  705. "size": 10
  706. }
  707. ]
  708. }`[1:] {
  709. t.Error("Unexpected response:", st, res)
  710. return
  711. }
  712. // Rename multiple files
  713. st, _, res = sendTestRequest(queryURL+"Hans1", "PUT", []byte(`
  714. {
  715. "action" : "rename",
  716. "files" : ["/tmp/newtest1", "/tmp/upload", "/tmp/upload1/bla.txt"],
  717. "newnames" : ["/tmp/newtest2", "/tmp/upload1", "/tmp/upload1/bla1.txt"]
  718. }`))
  719. if st != "200 OK" {
  720. t.Error("Unexpected response:", st, res)
  721. return
  722. }
  723. // Check the directory
  724. st, _, res = sendTestRequest(dirqueryURL+"Hans1/tmp?recursive=1&checksums=1", "GET", nil)
  725. if st != "200 OK" || res != `
  726. {
  727. "/tmp": [
  728. {
  729. "checksum": "abcc6601",
  730. "isdir": false,
  731. "name": "newtest2",
  732. "size": 7
  733. },
  734. {
  735. "checksum": "5b62da0f",
  736. "isdir": false,
  737. "name": "test1",
  738. "size": 10
  739. },
  740. {
  741. "checksum": "",
  742. "isdir": true,
  743. "name": "upload1",
  744. "size": 4096
  745. }
  746. ],
  747. "/tmp/upload1": [
  748. {
  749. "checksum": "abcc6601",
  750. "isdir": false,
  751. "name": "bla1.txt",
  752. "size": 7
  753. },
  754. {
  755. "checksum": "abcc6601",
  756. "isdir": false,
  757. "name": "newtest1",
  758. "size": 7
  759. },
  760. {
  761. "checksum": "5b62da0f",
  762. "isdir": false,
  763. "name": "test1",
  764. "size": 10
  765. }
  766. ]
  767. }`[1:] {
  768. t.Error("Unexpected response:", st, res)
  769. return
  770. }
  771. // Test error conditions
  772. st, _, res = sendTestRequest(queryURL+"Hans1", "PUT", []byte(`
  773. {
  774. "action" : "rename",
  775. "files" : ["/tmp/newtest1", "/tmp/upload", "/tmp/upload1/bla.txt"],
  776. "newnames" : "/tmp/newtest2"
  777. }`))
  778. if st != "400 Bad Request" || res != "Parameter newnames must be a list of filenames" {
  779. t.Error("Unexpected response:", st, res)
  780. return
  781. }
  782. st, _, res = sendTestRequest(queryURL+"Hans1", "PUT", []byte(`
  783. {
  784. "action" : "rename",
  785. "newnames" : ["/tmp/newtest2"]
  786. }`))
  787. if st != "400 Bad Request" || res != "Parameter files is missing from request body" {
  788. t.Error("Unexpected response:", st, res)
  789. return
  790. }
  791. st, _, res = sendTestRequest(queryURL+"Hans1", "PUT", []byte(`
  792. {
  793. "action" : "rename",
  794. "files" : "/tmp/newtest1",
  795. "newnames" : ["/tmp/newtest2"]
  796. }`))
  797. if st != "400 Bad Request" || res != "Parameter files must be a list of files" {
  798. t.Error("Unexpected response:", st, res)
  799. return
  800. }
  801. st, _, res = sendTestRequest(queryURL+"Hans1", "PUT", []byte(`
  802. {
  803. "action" : "copy",
  804. "files" : "/tmp/newtest1",
  805. "destination" : "/tmp/upload"
  806. }`))
  807. if st != "400 Bad Request" || res != "Parameter files must be a list of files" {
  808. t.Error("Unexpected response:", st, res)
  809. return
  810. }
  811. ProgressMap = datautil.NewMapCache(100, 0)
  812. st, _, res = sendTestRequest(queryURL+"Hans1/tmp/newtest3", "PUT", []byte(`
  813. {
  814. "action" : "copy",
  815. "destination" : "/tmp/upload/bla.txt"
  816. }`))
  817. if st != "400 Bad Request" || res != "Cannot stat /tmp/newtest3: RufsError: Remote error (file does not exist)" {
  818. t.Error("Unexpected response:", st, res)
  819. return
  820. }
  821. // Check error in ProgressMap
  822. for k := range ProgressMap.GetAll() {
  823. k = strings.Split(k, "#")[1]
  824. _, _, res = sendTestRequest(progressqueryURL+"Hans1/"+k, "GET", nil)
  825. resMap = nil
  826. errorutil.AssertOk(json.Unmarshal([]byte(res), &resMap))
  827. if res := fmt.Sprint(resMap["errors"]); res != "[Cannot stat /tmp/newtest3: RufsError: Remote error (file does not exist)]" {
  828. t.Error("Unexpected result:", res)
  829. }
  830. break
  831. }
  832. st, _, res = sendTestRequest(queryURL+"Hans1/", "GET", nil)
  833. if st != "400 Bad Request" || res != "Need a tree name and a file path" {
  834. t.Error("Unexpected response:", st, res)
  835. return
  836. }
  837. st, _, res = sendTestRequest(queryURL+"Hans2/bla", "GET", nil)
  838. if st != "400 Bad Request" || res != "Unknown tree: Hans2" {
  839. t.Error("Unexpected response:", st, res)
  840. return
  841. }
  842. st, _, res = sendTestRequest(queryURL+"Hans1/bla", "GET", nil)
  843. if st != "400 Bad Request" || res != "Could not read file bla: RufsError: Remote error (stat /bla: no such file or directory)" {
  844. t.Error("Unexpected response:", st, res)
  845. return
  846. }
  847. st, _, res = sendTestRequest(progressqueryURL+"Hans1/", "GET", nil)
  848. if st != "400 Bad Request" || res != "Need a tree name and a progress ID" {
  849. t.Error("Unexpected response:", st, res)
  850. return
  851. }
  852. st, _, res = sendTestRequest(progressqueryURL+"Hans2/bla", "GET", nil)
  853. if st != "400 Bad Request" || res != "Unknown tree: Hans2" {
  854. t.Error("Unexpected response:", st, res)
  855. return
  856. }
  857. st, _, res = sendTestRequest(progressqueryURL+"Hans1/bla", "GET", nil)
  858. if st != "400 Bad Request" || res != "Unknown progress ID: bla" {
  859. t.Error("Unexpected response:", st, res)
  860. return
  861. }
  862. st, _, res = sendTestRequest(queryURL, "PUT", []byte(""))
  863. if st != "400 Bad Request" || res != "Need a tree name and a file path" {
  864. t.Error("Unexpected response:", st, res)
  865. return
  866. }
  867. st, _, res = sendTestRequest(queryURL+"Hans2/bla", "PUT", []byte(""))
  868. if st != "400 Bad Request" || res != "Unknown tree: Hans2" {
  869. t.Error("Unexpected response:", st, res)
  870. return
  871. }
  872. st, _, res = sendTestRequest(queryURL+"Hans1/bla", "PUT", []byte(`
  873. aaa{
  874. "action" : "copy",
  875. "destination" : "/tmp/upload/bla.txt"
  876. }`))
  877. if st != "400 Bad Request" || res != "Could not decode request body: invalid character 'a' looking for beginning of value" {
  878. t.Error("Unexpected response:", st, res)
  879. return
  880. }
  881. st, _, res = sendTestRequest(queryURL+"Hans1/bla", "PUT", []byte(`
  882. {
  883. "action2" : "copy",
  884. "destination" : "/tmp/upload/bla.txt"
  885. }`))
  886. if st != "400 Bad Request" || res != "Action command is missing from request body" {
  887. t.Error("Unexpected response:", st, res)
  888. return
  889. }
  890. st, _, res = sendTestRequest(queryURL+"Hans1/bla", "PUT", []byte(`
  891. {
  892. "action" : "copy",
  893. "destination2" : "/tmp/upload/bla.txt"
  894. }`))
  895. if st != "400 Bad Request" || res != "Parameter destination is missing from request body" {
  896. t.Error("Unexpected response:", st, res)
  897. return
  898. }
  899. st, _, res = sendTestRequest(queryURL+"Hans1/bla", "PUT", []byte(`
  900. {
  901. "action" : "copy2",
  902. "destination" : "/tmp/upload/bla.txt"
  903. }`))
  904. if st != "400 Bad Request" || res != "Unknown action: copy2" {
  905. t.Error("Unexpected response:", st, res)
  906. return
  907. }
  908. st, _, res = sendTestRequest(queryURL+"Hans1/bla", "PUT", []byte(`
  909. {
  910. "action" : "rename"
  911. }`))
  912. if st != "400 Bad Request" || res != "Parameter newname is missing from request body" {
  913. t.Error("Unexpected response:", st, res)
  914. return
  915. }
  916. }