2
0

provider_test.go 19 KB

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