2
0

provider_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. package worker
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "strconv"
  7. "testing"
  8. "time"
  9. . "github.com/smartystreets/goconvey/convey"
  10. )
  11. func TestRsyncProvider(t *testing.T) {
  12. Convey("Rsync Provider should work", t, func() {
  13. tmpDir, err := os.MkdirTemp("", "tunasync")
  14. defer os.RemoveAll(tmpDir)
  15. So(err, ShouldBeNil)
  16. scriptFile := filepath.Join(tmpDir, "myrsync")
  17. tmpFile := filepath.Join(tmpDir, "log_file")
  18. c := rsyncConfig{
  19. name: "tuna",
  20. upstreamURL: "rsync://rsync.tuna.moe/tuna/",
  21. rsyncCmd: scriptFile,
  22. workingDir: tmpDir,
  23. logDir: tmpDir,
  24. logFile: tmpFile,
  25. useIPv6: true,
  26. timeout: 100 * time.Second,
  27. interval: 600 * time.Second,
  28. }
  29. provider, err := newRsyncProvider(c)
  30. So(err, ShouldBeNil)
  31. So(provider.Type(), ShouldEqual, provRsync)
  32. So(provider.Name(), ShouldEqual, c.name)
  33. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  34. So(provider.LogDir(), ShouldEqual, c.logDir)
  35. So(provider.LogFile(), ShouldEqual, c.logFile)
  36. So(provider.Interval(), ShouldEqual, c.interval)
  37. So(provider.Timeout(), ShouldEqual, c.timeout)
  38. Convey("When entering a context (auto exit)", func() {
  39. func() {
  40. ctx := provider.EnterContext()
  41. defer provider.ExitContext()
  42. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  43. newWorkingDir := "/srv/mirror/working/tuna"
  44. ctx.Set(_WorkingDirKey, newWorkingDir)
  45. So(provider.WorkingDir(), ShouldEqual, newWorkingDir)
  46. }()
  47. Convey("After context is done", func() {
  48. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  49. })
  50. })
  51. Convey("When entering a context (manually exit)", func() {
  52. ctx := provider.EnterContext()
  53. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  54. newWorkingDir := "/srv/mirror/working/tuna"
  55. ctx.Set(_WorkingDirKey, newWorkingDir)
  56. So(provider.WorkingDir(), ShouldEqual, newWorkingDir)
  57. Convey("After context is done", func() {
  58. provider.ExitContext()
  59. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  60. })
  61. })
  62. Convey("Let's try a run", func() {
  63. scriptContent := `#!/bin/bash
  64. echo "syncing to $(pwd)"
  65. echo $RSYNC_PASSWORD $@
  66. sleep 1
  67. echo "Total file size: 1.33T bytes"
  68. echo "Done"
  69. exit 0
  70. `
  71. err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
  72. So(err, ShouldBeNil)
  73. targetDir, _ := filepath.EvalSymlinks(provider.WorkingDir())
  74. expectedOutput := fmt.Sprintf(
  75. "syncing to %s\n"+
  76. "%s\n"+
  77. "Total file size: 1.33T bytes\n"+
  78. "Done\n",
  79. targetDir,
  80. fmt.Sprintf(
  81. "-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ "+
  82. "--delete --delete-after --delay-updates --safe-links "+
  83. "--timeout=120 -6 %s %s",
  84. provider.upstreamURL, provider.WorkingDir(),
  85. ),
  86. )
  87. err = provider.Run(make(chan empty, 1))
  88. So(err, ShouldBeNil)
  89. loggedContent, err := os.ReadFile(provider.LogFile())
  90. So(err, ShouldBeNil)
  91. So(string(loggedContent), ShouldEqual, expectedOutput)
  92. // fmt.Println(string(loggedContent))
  93. So(provider.DataSize(), ShouldEqual, "1.33T")
  94. })
  95. })
  96. Convey("If the rsync program fails", t, func() {
  97. tmpDir, err := os.MkdirTemp("", "tunasync")
  98. defer os.RemoveAll(tmpDir)
  99. So(err, ShouldBeNil)
  100. tmpFile := filepath.Join(tmpDir, "log_file")
  101. Convey("in the rsyncProvider", func() {
  102. c := rsyncConfig{
  103. name: "tuna",
  104. upstreamURL: "rsync://rsync.tuna.moe/tuna/",
  105. workingDir: tmpDir,
  106. logDir: tmpDir,
  107. logFile: tmpFile,
  108. extraOptions: []string{"--somethine-invalid"},
  109. interval: 600 * time.Second,
  110. }
  111. provider, err := newRsyncProvider(c)
  112. So(err, ShouldBeNil)
  113. err = provider.Run(make(chan empty, 1))
  114. So(err, ShouldNotBeNil)
  115. loggedContent, err := os.ReadFile(provider.LogFile())
  116. So(err, ShouldBeNil)
  117. So(string(loggedContent), ShouldContainSubstring, "Syntax or usage error")
  118. })
  119. })
  120. }
  121. func TestRsyncProviderWithAuthentication(t *testing.T) {
  122. Convey("Rsync Provider with password should work", t, func() {
  123. tmpDir, err := os.MkdirTemp("", "tunasync")
  124. defer os.RemoveAll(tmpDir)
  125. So(err, ShouldBeNil)
  126. scriptFile := filepath.Join(tmpDir, "myrsync")
  127. tmpFile := filepath.Join(tmpDir, "log_file")
  128. proxyAddr := "127.0.0.1:1233"
  129. c := rsyncConfig{
  130. name: "tuna",
  131. upstreamURL: "rsync://rsync.tuna.moe/tuna/",
  132. rsyncCmd: scriptFile,
  133. username: "tunasync",
  134. password: "tunasyncpassword",
  135. workingDir: tmpDir,
  136. extraOptions: []string{"--delete-excluded"},
  137. rsyncTimeoutValue: 30,
  138. rsyncEnv: map[string]string{"RSYNC_PROXY": proxyAddr},
  139. logDir: tmpDir,
  140. logFile: tmpFile,
  141. useIPv4: true,
  142. interval: 600 * time.Second,
  143. }
  144. provider, err := newRsyncProvider(c)
  145. So(err, ShouldBeNil)
  146. So(provider.Name(), ShouldEqual, c.name)
  147. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  148. So(provider.LogDir(), ShouldEqual, c.logDir)
  149. So(provider.LogFile(), ShouldEqual, c.logFile)
  150. So(provider.Interval(), ShouldEqual, c.interval)
  151. Convey("Let's try a run", func() {
  152. scriptContent := `#!/bin/bash
  153. echo "syncing to $(pwd)"
  154. echo $USER $RSYNC_PASSWORD $RSYNC_PROXY $@
  155. sleep 1
  156. echo "Done"
  157. exit 0
  158. `
  159. err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
  160. So(err, ShouldBeNil)
  161. targetDir, _ := filepath.EvalSymlinks(provider.WorkingDir())
  162. expectedOutput := fmt.Sprintf(
  163. "syncing to %s\n"+
  164. "%s\n"+
  165. "Done\n",
  166. targetDir,
  167. fmt.Sprintf(
  168. "%s %s %s -aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ "+
  169. "--delete --delete-after --delay-updates --safe-links "+
  170. "--timeout=30 -4 --delete-excluded %s %s",
  171. provider.username, provider.password, proxyAddr,
  172. provider.upstreamURL, provider.WorkingDir(),
  173. ),
  174. )
  175. err = provider.Run(make(chan empty, 1))
  176. So(err, ShouldBeNil)
  177. loggedContent, err := os.ReadFile(provider.LogFile())
  178. So(err, ShouldBeNil)
  179. So(string(loggedContent), ShouldEqual, expectedOutput)
  180. // fmt.Println(string(loggedContent))
  181. })
  182. })
  183. }
  184. func TestRsyncProviderWithOverriddenOptions(t *testing.T) {
  185. Convey("Rsync Provider with overridden options should work", t, func() {
  186. tmpDir, err := os.MkdirTemp("", "tunasync")
  187. defer os.RemoveAll(tmpDir)
  188. So(err, ShouldBeNil)
  189. scriptFile := filepath.Join(tmpDir, "myrsync")
  190. tmpFile := filepath.Join(tmpDir, "log_file")
  191. c := rsyncConfig{
  192. name: "tuna",
  193. upstreamURL: "rsync://rsync.tuna.moe/tuna/",
  194. rsyncCmd: scriptFile,
  195. workingDir: tmpDir,
  196. rsyncNeverTimeout: true,
  197. overriddenOptions: []string{"-aHvh", "--no-o", "--no-g", "--stats"},
  198. extraOptions: []string{"--delete-excluded"},
  199. logDir: tmpDir,
  200. logFile: tmpFile,
  201. useIPv6: true,
  202. interval: 600 * time.Second,
  203. }
  204. provider, err := newRsyncProvider(c)
  205. So(err, ShouldBeNil)
  206. So(provider.Name(), ShouldEqual, c.name)
  207. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  208. So(provider.LogDir(), ShouldEqual, c.logDir)
  209. So(provider.LogFile(), ShouldEqual, c.logFile)
  210. So(provider.Interval(), ShouldEqual, c.interval)
  211. Convey("Let's try a run", func() {
  212. scriptContent := `#!/bin/bash
  213. echo "syncing to $(pwd)"
  214. echo $@
  215. sleep 1
  216. echo "Done"
  217. exit 0
  218. `
  219. err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
  220. So(err, ShouldBeNil)
  221. targetDir, _ := filepath.EvalSymlinks(provider.WorkingDir())
  222. expectedOutput := fmt.Sprintf(
  223. "syncing to %s\n"+
  224. "-aHvh --no-o --no-g --stats -6 --delete-excluded %s %s\n"+
  225. "Done\n",
  226. targetDir,
  227. provider.upstreamURL,
  228. provider.WorkingDir(),
  229. )
  230. err = provider.Run(make(chan empty, 1))
  231. So(err, ShouldBeNil)
  232. loggedContent, err := os.ReadFile(provider.LogFile())
  233. So(err, ShouldBeNil)
  234. So(string(loggedContent), ShouldEqual, expectedOutput)
  235. // fmt.Println(string(loggedContent))
  236. })
  237. })
  238. }
  239. func TestRsyncProviderWithDocker(t *testing.T) {
  240. Convey("Rsync in Docker should work", t, func() {
  241. tmpDir, err := os.MkdirTemp("", "tunasync")
  242. defer os.RemoveAll(tmpDir)
  243. So(err, ShouldBeNil)
  244. scriptFile := filepath.Join(tmpDir, "myrsync")
  245. excludeFile := filepath.Join(tmpDir, "exclude.txt")
  246. g := &Config{
  247. Global: globalConfig{
  248. Retry: 2,
  249. },
  250. Docker: dockerConfig{
  251. Enable: true,
  252. Volumes: []string{
  253. scriptFile + ":/bin/myrsync",
  254. "/etc/gai.conf:/etc/gai.conf:ro",
  255. },
  256. },
  257. }
  258. c := mirrorConfig{
  259. Name: "tuna",
  260. Provider: provRsync,
  261. Upstream: "rsync://rsync.tuna.moe/tuna/",
  262. Command: "/bin/myrsync",
  263. ExcludeFile: excludeFile,
  264. DockerImage: "alpine:3.8",
  265. LogDir: tmpDir,
  266. MirrorDir: tmpDir,
  267. UseIPv6: true,
  268. Timeout: 100,
  269. Interval: 600,
  270. }
  271. provider := newMirrorProvider(c, g)
  272. So(provider.Type(), ShouldEqual, provRsync)
  273. So(provider.Name(), ShouldEqual, c.Name)
  274. So(provider.WorkingDir(), ShouldEqual, c.MirrorDir)
  275. So(provider.LogDir(), ShouldEqual, c.LogDir)
  276. cmdScriptContent := `#!/bin/sh
  277. #echo "$@"
  278. while [[ $# -gt 0 ]]; do
  279. if [[ "$1" = "--exclude-from" ]]; then
  280. cat "$2"
  281. shift
  282. fi
  283. shift
  284. done
  285. `
  286. err = os.WriteFile(scriptFile, []byte(cmdScriptContent), 0755)
  287. So(err, ShouldBeNil)
  288. err = os.WriteFile(excludeFile, []byte("__some_pattern"), 0755)
  289. So(err, ShouldBeNil)
  290. for _, hook := range provider.Hooks() {
  291. err = hook.preExec()
  292. So(err, ShouldBeNil)
  293. }
  294. err = provider.Run(make(chan empty, 1))
  295. So(err, ShouldBeNil)
  296. for _, hook := range provider.Hooks() {
  297. err = hook.postExec()
  298. So(err, ShouldBeNil)
  299. }
  300. loggedContent, err := os.ReadFile(provider.LogFile())
  301. So(err, ShouldBeNil)
  302. So(string(loggedContent), ShouldEqual, "__some_pattern")
  303. })
  304. }
  305. func TestCmdProvider(t *testing.T) {
  306. Convey("Command Provider should work", t, func(ctx C) {
  307. tmpDir, err := os.MkdirTemp("", "tunasync")
  308. defer os.RemoveAll(tmpDir)
  309. So(err, ShouldBeNil)
  310. scriptFile := filepath.Join(tmpDir, "cmd.sh")
  311. tmpFile := filepath.Join(tmpDir, "log_file")
  312. c := cmdConfig{
  313. name: "tuna-cmd",
  314. upstreamURL: "http://mirrors.tuna.moe/",
  315. command: "bash " + scriptFile,
  316. workingDir: tmpDir,
  317. logDir: tmpDir,
  318. logFile: tmpFile,
  319. interval: 600 * time.Second,
  320. env: map[string]string{
  321. "AOSP_REPO_BIN": "/usr/local/bin/repo",
  322. },
  323. }
  324. provider, err := newCmdProvider(c)
  325. So(err, ShouldBeNil)
  326. So(provider.Type(), ShouldEqual, provCommand)
  327. So(provider.Name(), ShouldEqual, c.name)
  328. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  329. So(provider.LogDir(), ShouldEqual, c.logDir)
  330. So(provider.LogFile(), ShouldEqual, c.logFile)
  331. So(provider.Interval(), ShouldEqual, c.interval)
  332. Convey("Let's try to run a simple command", func() {
  333. scriptContent := `#!/bin/bash
  334. echo $TUNASYNC_WORKING_DIR
  335. echo $TUNASYNC_MIRROR_NAME
  336. echo $TUNASYNC_UPSTREAM_URL
  337. echo $TUNASYNC_LOG_FILE
  338. echo $AOSP_REPO_BIN
  339. `
  340. expectedOutput := fmt.Sprintf(
  341. "%s\n%s\n%s\n%s\n%s\n",
  342. provider.WorkingDir(),
  343. provider.Name(),
  344. provider.upstreamURL,
  345. provider.LogFile(),
  346. "/usr/local/bin/repo",
  347. )
  348. err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
  349. So(err, ShouldBeNil)
  350. readedScriptContent, err := os.ReadFile(scriptFile)
  351. So(err, ShouldBeNil)
  352. So(readedScriptContent, ShouldResemble, []byte(scriptContent))
  353. err = provider.Run(make(chan empty, 1))
  354. So(err, ShouldBeNil)
  355. loggedContent, err := os.ReadFile(provider.LogFile())
  356. So(err, ShouldBeNil)
  357. So(string(loggedContent), ShouldEqual, expectedOutput)
  358. })
  359. Convey("If a command fails", func() {
  360. scriptContent := `exit 1`
  361. err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
  362. So(err, ShouldBeNil)
  363. readedScriptContent, err := os.ReadFile(scriptFile)
  364. So(err, ShouldBeNil)
  365. So(readedScriptContent, ShouldResemble, []byte(scriptContent))
  366. err = provider.Run(make(chan empty, 1))
  367. So(err, ShouldNotBeNil)
  368. })
  369. Convey("If a long job is killed", func(ctx C) {
  370. scriptContent := `#!/bin/bash
  371. sleep 10
  372. `
  373. err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
  374. So(err, ShouldBeNil)
  375. started := make(chan empty, 1)
  376. go func() {
  377. err := provider.Run(started)
  378. ctx.So(err, ShouldNotBeNil)
  379. }()
  380. <-started
  381. So(provider.IsRunning(), ShouldBeTrue)
  382. time.Sleep(1 * time.Second)
  383. err = provider.Terminate()
  384. So(err, ShouldBeNil)
  385. })
  386. })
  387. Convey("Command Provider without log file should work", t, func(ctx C) {
  388. tmpDir, err := os.MkdirTemp("", "tunasync")
  389. defer os.RemoveAll(tmpDir)
  390. So(err, ShouldBeNil)
  391. c := cmdConfig{
  392. name: "run-ls",
  393. upstreamURL: "http://mirrors.tuna.moe/",
  394. command: "ls",
  395. workingDir: tmpDir,
  396. logDir: tmpDir,
  397. logFile: "/dev/null",
  398. interval: 600 * time.Second,
  399. }
  400. provider, err := newCmdProvider(c)
  401. So(err, ShouldBeNil)
  402. So(provider.IsMaster(), ShouldEqual, false)
  403. So(provider.ZFS(), ShouldBeNil)
  404. So(provider.Type(), ShouldEqual, provCommand)
  405. So(provider.Name(), ShouldEqual, c.name)
  406. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  407. So(provider.LogDir(), ShouldEqual, c.logDir)
  408. So(provider.LogFile(), ShouldEqual, c.logFile)
  409. So(provider.Interval(), ShouldEqual, c.interval)
  410. Convey("Run the command", func() {
  411. err = provider.Run(make(chan empty, 1))
  412. So(err, ShouldBeNil)
  413. })
  414. })
  415. Convey("Command Provider with RegExprs should work", t, func(ctx C) {
  416. tmpDir, err := os.MkdirTemp("", "tunasync")
  417. defer os.RemoveAll(tmpDir)
  418. So(err, ShouldBeNil)
  419. tmpFile := filepath.Join(tmpDir, "log_file")
  420. c := cmdConfig{
  421. name: "run-uptime",
  422. upstreamURL: "http://mirrors.tuna.moe/",
  423. command: "uptime",
  424. failOnMatch: "",
  425. sizePattern: "",
  426. workingDir: tmpDir,
  427. logDir: tmpDir,
  428. logFile: tmpFile,
  429. interval: 600 * time.Second,
  430. }
  431. Convey("when fail-on-match regexp matches", func() {
  432. c.failOnMatch = `[a-z]+`
  433. provider, err := newCmdProvider(c)
  434. So(err, ShouldBeNil)
  435. err = provider.Run(make(chan empty, 1))
  436. So(err, ShouldNotBeNil)
  437. So(provider.DataSize(), ShouldBeEmpty)
  438. })
  439. Convey("when fail-on-match regexp does not match", func() {
  440. c.failOnMatch = `load average_`
  441. provider, err := newCmdProvider(c)
  442. So(err, ShouldBeNil)
  443. err = provider.Run(make(chan empty, 1))
  444. So(err, ShouldBeNil)
  445. })
  446. Convey("when fail-on-match regexp meets /dev/null", func() {
  447. c.failOnMatch = `load average_`
  448. c.logFile = "/dev/null"
  449. provider, err := newCmdProvider(c)
  450. So(err, ShouldBeNil)
  451. err = provider.Run(make(chan empty, 1))
  452. So(err, ShouldNotBeNil)
  453. })
  454. Convey("when size-pattern regexp matches", func() {
  455. c.sizePattern = `load average: ([\d\.]+)`
  456. provider, err := newCmdProvider(c)
  457. So(err, ShouldBeNil)
  458. err = provider.Run(make(chan empty, 1))
  459. So(err, ShouldBeNil)
  460. So(provider.DataSize(), ShouldNotBeEmpty)
  461. _, err = strconv.ParseFloat(provider.DataSize(), 32)
  462. So(err, ShouldBeNil)
  463. })
  464. Convey("when size-pattern regexp does not match", func() {
  465. c.sizePattern = `load ave: ([\d\.]+)`
  466. provider, err := newCmdProvider(c)
  467. So(err, ShouldBeNil)
  468. err = provider.Run(make(chan empty, 1))
  469. So(err, ShouldBeNil)
  470. So(provider.DataSize(), ShouldBeEmpty)
  471. })
  472. Convey("when size-pattern regexp meets /dev/null", func() {
  473. c.sizePattern = `load ave: ([\d\.]+)`
  474. c.logFile = "/dev/null"
  475. provider, err := newCmdProvider(c)
  476. So(err, ShouldBeNil)
  477. err = provider.Run(make(chan empty, 1))
  478. So(err, ShouldNotBeNil)
  479. So(provider.DataSize(), ShouldBeEmpty)
  480. })
  481. })
  482. }
  483. func TestTwoStageRsyncProvider(t *testing.T) {
  484. Convey("TwoStageRsync Provider should work", t, func(ctx C) {
  485. tmpDir, err := os.MkdirTemp("", "tunasync")
  486. defer os.RemoveAll(tmpDir)
  487. So(err, ShouldBeNil)
  488. scriptFile := filepath.Join(tmpDir, "myrsync")
  489. tmpFile := filepath.Join(tmpDir, "log_file")
  490. c := twoStageRsyncConfig{
  491. name: "tuna-two-stage-rsync",
  492. upstreamURL: "rsync://mirrors.tuna.moe/",
  493. stage1Profile: "debian",
  494. rsyncCmd: scriptFile,
  495. workingDir: tmpDir,
  496. logDir: tmpDir,
  497. logFile: tmpFile,
  498. useIPv6: true,
  499. excludeFile: tmpFile,
  500. rsyncTimeoutValue: 30,
  501. extraOptions: []string{"--delete-excluded", "--cache"},
  502. username: "hello",
  503. password: "world",
  504. }
  505. provider, err := newTwoStageRsyncProvider(c)
  506. So(err, ShouldBeNil)
  507. So(provider.Type(), ShouldEqual, provTwoStageRsync)
  508. So(provider.Name(), ShouldEqual, c.name)
  509. So(provider.WorkingDir(), ShouldEqual, c.workingDir)
  510. So(provider.LogDir(), ShouldEqual, c.logDir)
  511. So(provider.LogFile(), ShouldEqual, c.logFile)
  512. So(provider.Interval(), ShouldEqual, c.interval)
  513. Convey("Try a command", func(ctx C) {
  514. scriptContent := `#!/bin/bash
  515. echo "syncing to $(pwd)"
  516. echo $@
  517. sleep 1
  518. echo "Done"
  519. exit 0
  520. `
  521. err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
  522. So(err, ShouldBeNil)
  523. err = provider.Run(make(chan empty, 2))
  524. So(err, ShouldBeNil)
  525. targetDir, _ := filepath.EvalSymlinks(provider.WorkingDir())
  526. expectedOutput := fmt.Sprintf(
  527. "syncing to %s\n"+
  528. "%s\n"+
  529. "Done\n"+
  530. "syncing to %s\n"+
  531. "%s\n"+
  532. "Done\n",
  533. targetDir,
  534. fmt.Sprintf(
  535. "-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ --safe-links "+
  536. "--include=*.diff/ --include=by-hash/ --exclude=*.diff/Index --exclude=Contents* --exclude=Packages* --exclude=Sources* --exclude=Release* --exclude=InRelease --exclude=i18n/* --exclude=dep11/* --exclude=installer-*/current --exclude=ls-lR* --timeout=30 -6 "+
  537. "--exclude-from %s %s %s",
  538. provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
  539. ),
  540. targetDir,
  541. fmt.Sprintf(
  542. "-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ "+
  543. "--delete --delete-after --delay-updates --safe-links "+
  544. "--delete-excluded --cache --timeout=30 -6 --exclude-from %s %s %s",
  545. provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
  546. ),
  547. )
  548. loggedContent, err := os.ReadFile(provider.LogFile())
  549. So(err, ShouldBeNil)
  550. So(string(loggedContent), ShouldEqual, expectedOutput)
  551. // fmt.Println(string(loggedContent))
  552. })
  553. Convey("Try terminating", func(ctx C) {
  554. scriptContent := `#!/bin/bash
  555. echo $@
  556. sleep 10
  557. exit 0
  558. `
  559. err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
  560. So(err, ShouldBeNil)
  561. started := make(chan empty, 2)
  562. go func() {
  563. err := provider.Run(started)
  564. ctx.So(err, ShouldNotBeNil)
  565. }()
  566. <-started
  567. So(provider.IsRunning(), ShouldBeTrue)
  568. time.Sleep(1 * time.Second)
  569. err = provider.Terminate()
  570. So(err, ShouldBeNil)
  571. expectedOutput := fmt.Sprintf(
  572. "-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ --safe-links "+
  573. "--include=*.diff/ --include=by-hash/ --exclude=*.diff/Index --exclude=Contents* --exclude=Packages* --exclude=Sources* --exclude=Release* --exclude=InRelease --exclude=i18n/* --exclude=dep11/* --exclude=installer-*/current --exclude=ls-lR* --timeout=30 -6 "+
  574. "--exclude-from %s %s %s\n",
  575. provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
  576. )
  577. loggedContent, err := os.ReadFile(provider.LogFile())
  578. So(err, ShouldBeNil)
  579. So(string(loggedContent), ShouldStartWith, expectedOutput)
  580. // fmt.Println(string(loggedContent))
  581. })
  582. })
  583. Convey("If the rsync program fails", t, func(ctx C) {
  584. tmpDir, err := os.MkdirTemp("", "tunasync")
  585. defer os.RemoveAll(tmpDir)
  586. So(err, ShouldBeNil)
  587. tmpFile := filepath.Join(tmpDir, "log_file")
  588. Convey("in the twoStageRsyncProvider", func() {
  589. c := twoStageRsyncConfig{
  590. name: "tuna-two-stage-rsync",
  591. upstreamURL: "rsync://0.0.0.1/",
  592. stage1Profile: "debian",
  593. workingDir: tmpDir,
  594. logDir: tmpDir,
  595. logFile: tmpFile,
  596. excludeFile: tmpFile,
  597. }
  598. provider, err := newTwoStageRsyncProvider(c)
  599. So(err, ShouldBeNil)
  600. err = provider.Run(make(chan empty, 2))
  601. So(err, ShouldNotBeNil)
  602. loggedContent, err := os.ReadFile(provider.LogFile())
  603. So(err, ShouldBeNil)
  604. So(string(loggedContent), ShouldContainSubstring, "Error in socket I/O")
  605. })
  606. })
  607. }