sync_test.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. //go:build integration
  7. // +build integration
  8. package integration
  9. import (
  10. "fmt"
  11. "log"
  12. "math/rand"
  13. "os"
  14. "testing"
  15. "time"
  16. "github.com/syncthing/syncthing/lib/rc"
  17. )
  18. const (
  19. longTimeLimit = 1 * time.Minute
  20. shortTimeLimit = 25 * time.Second
  21. s12Folder = `¯\_(ツ)_/¯ Räksmörgås 动作 Адрес` // This was renamed to ensure arbitrary folder IDs are fine.
  22. )
  23. func TestSyncCluster(t *testing.T) {
  24. // This tests syncing files back and forth between three cluster members.
  25. // Their configs are in h1, h2 and h3. The folder "default" is shared
  26. // between all and stored in s1, s2 and s3 respectively.
  27. //
  28. // Another folder is shared between 1 and 2 only, in s12-1 and s12-2. A
  29. // third folders is shared between 2 and 3, in s23-2 and s23-3.
  30. // When -short is passed, keep it more reasonable.
  31. timeLimit := longTimeLimit
  32. if testing.Short() {
  33. timeLimit = shortTimeLimit
  34. }
  35. const (
  36. numFiles = 100
  37. fileSizeExp = 20
  38. )
  39. rand.Seed(42)
  40. log.Printf("Testing with numFiles=%d, fileSizeExp=%d, timeLimit=%v", numFiles, fileSizeExp, timeLimit)
  41. log.Println("Cleaning...")
  42. err := removeAll("s1", "s12-1",
  43. "s2", "s12-2", "s23-2",
  44. "s3", "s23-3",
  45. "h1/index*", "h2/index*", "h3/index*")
  46. if err != nil {
  47. t.Fatal(err)
  48. }
  49. // Create initial folder contents. All three devices have stuff in
  50. // "default", which should be merged. The other two folders are initially
  51. // empty on one side.
  52. log.Println("Generating files...")
  53. err = generateFiles("s1", numFiles, fileSizeExp, "../LICENSE")
  54. if err != nil {
  55. t.Fatal(err)
  56. }
  57. err = generateFiles("s12-1", numFiles, fileSizeExp, "../LICENSE")
  58. if err != nil {
  59. t.Fatal(err)
  60. }
  61. // We'll use this file for appending data without modifying the time stamp.
  62. fd, err := os.Create("s1/test-appendfile")
  63. if err != nil {
  64. t.Fatal(err)
  65. }
  66. _, err = fd.WriteString("hello\n")
  67. if err != nil {
  68. t.Fatal(err)
  69. }
  70. err = fd.Close()
  71. if err != nil {
  72. t.Fatal(err)
  73. }
  74. err = generateFiles("s2", numFiles, fileSizeExp, "../LICENSE")
  75. if err != nil {
  76. t.Fatal(err)
  77. }
  78. err = generateFiles("s23-2", numFiles, fileSizeExp, "../LICENSE")
  79. if err != nil {
  80. t.Fatal(err)
  81. }
  82. err = generateFiles("s3", numFiles, fileSizeExp, "../LICENSE")
  83. if err != nil {
  84. t.Fatal(err)
  85. }
  86. // Prepare the expected state of folders after the sync
  87. c1, err := directoryContents("s1")
  88. if err != nil {
  89. t.Fatal(err)
  90. }
  91. c2, err := directoryContents("s2")
  92. if err != nil {
  93. t.Fatal(err)
  94. }
  95. c3, err := directoryContents("s3")
  96. if err != nil {
  97. t.Fatal(err)
  98. }
  99. e1 := mergeDirectoryContents(c1, c2, c3)
  100. e2, err := directoryContents("s12-1")
  101. if err != nil {
  102. t.Fatal(err)
  103. }
  104. e3, err := directoryContents("s23-2")
  105. if err != nil {
  106. t.Fatal(err)
  107. }
  108. expected := [][]fileInfo{e1, e2, e3}
  109. // Start the syncers
  110. log.Println("Starting Syncthing...")
  111. p0 := startInstance(t, 1)
  112. defer checkedStop(t, p0)
  113. p1 := startInstance(t, 2)
  114. defer checkedStop(t, p1)
  115. p2 := startInstance(t, 3)
  116. defer checkedStop(t, p2)
  117. p0.ResumeAll()
  118. p1.ResumeAll()
  119. p2.ResumeAll()
  120. p := []*rc.Process{p0, p1, p2}
  121. start := time.Now()
  122. iteration := 0
  123. for time.Since(start) < timeLimit {
  124. iteration++
  125. log.Println("Iteration", iteration)
  126. log.Println("Forcing rescan...")
  127. // Force rescan of folders
  128. for i, device := range p {
  129. if err := device.RescanDelay("default", 86400); err != nil {
  130. t.Fatal(err)
  131. }
  132. if i == 0 || i == 1 {
  133. if err := device.RescanDelay(s12Folder, 86400); err != nil {
  134. t.Fatal(err)
  135. }
  136. }
  137. if i == 1 || i == 2 {
  138. if err := device.RescanDelay("s23", 86400); err != nil {
  139. t.Fatal(err)
  140. }
  141. }
  142. }
  143. // Sync stuff and verify it looks right
  144. err = scSyncAndCompare(p, expected)
  145. if err != nil {
  146. t.Error(err)
  147. break
  148. }
  149. // Sleep for a little over a second to ensure that this round of
  150. // alterations ends up in a different second than the previous one,
  151. // even if the sync was quick. This is to give Syncthing a visible
  152. // mtime change even on filesystem with whole second resolution.
  153. time.Sleep(1100 * time.Millisecond)
  154. log.Println("Altering...")
  155. // Alter the source files for another round
  156. err = alterFiles("s1")
  157. if err != nil {
  158. t.Error(err)
  159. break
  160. }
  161. err = alterFiles("s12-1")
  162. if err != nil {
  163. t.Error(err)
  164. break
  165. }
  166. err = alterFiles("s23-2")
  167. if err != nil {
  168. t.Error(err)
  169. break
  170. }
  171. // Alter the "test-appendfile" without changing its modification time. Sneaky!
  172. fi, err := os.Stat("s1/test-appendfile")
  173. if err != nil {
  174. t.Fatal(err)
  175. }
  176. fd, err := os.OpenFile("s1/test-appendfile", os.O_APPEND|os.O_WRONLY, 0644)
  177. if err != nil {
  178. t.Fatal(err)
  179. }
  180. _, err = fd.Seek(0, os.SEEK_END)
  181. if err != nil {
  182. t.Fatal(err)
  183. }
  184. _, err = fd.WriteString("more data\n")
  185. if err != nil {
  186. t.Fatal(err)
  187. }
  188. err = fd.Close()
  189. if err != nil {
  190. t.Fatal(err)
  191. }
  192. err = os.Chtimes("s1/test-appendfile", fi.ModTime(), fi.ModTime())
  193. if err != nil {
  194. t.Fatal(err)
  195. }
  196. // Prepare the expected state of folders after the sync
  197. e1, err = directoryContents("s1")
  198. if err != nil {
  199. t.Fatal(err)
  200. }
  201. e2, err = directoryContents("s12-1")
  202. if err != nil {
  203. t.Fatal(err)
  204. }
  205. e3, err = directoryContents("s23-2")
  206. if err != nil {
  207. t.Fatal(err)
  208. }
  209. expected = [][]fileInfo{e1, e2, e3}
  210. }
  211. }
  212. func scSyncAndCompare(p []*rc.Process, expected [][]fileInfo) error {
  213. log.Println("Syncing...")
  214. for {
  215. time.Sleep(250 * time.Millisecond)
  216. if !rc.InSync("default", p...) {
  217. continue
  218. }
  219. if !rc.InSync(s12Folder, p[0], p[1]) {
  220. continue
  221. }
  222. if !rc.InSync("s23", p[1], p[2]) {
  223. continue
  224. }
  225. break
  226. }
  227. log.Println("Checking...")
  228. for _, dir := range []string{"s1", "s2", "s3"} {
  229. actual, err := directoryContents(dir)
  230. if err != nil {
  231. return err
  232. }
  233. if err := compareDirectoryContents(actual, expected[0]); err != nil {
  234. return fmt.Errorf("%s: %w", dir, err)
  235. }
  236. }
  237. if len(expected) > 1 {
  238. for _, dir := range []string{"s12-1", "s12-2"} {
  239. actual, err := directoryContents(dir)
  240. if err != nil {
  241. return err
  242. }
  243. if err := compareDirectoryContents(actual, expected[1]); err != nil {
  244. return fmt.Errorf("%s: %w", dir, err)
  245. }
  246. }
  247. }
  248. if len(expected) > 2 {
  249. for _, dir := range []string{"s23-2", "s23-3"} {
  250. actual, err := directoryContents(dir)
  251. if err != nil {
  252. return err
  253. }
  254. if err := compareDirectoryContents(actual, expected[2]); err != nil {
  255. return fmt.Errorf("%s: %w", dir, err)
  256. }
  257. }
  258. }
  259. if err := checkRemoteInSync("default", p[0], p[1]); err != nil {
  260. return err
  261. }
  262. if err := checkRemoteInSync("default", p[0], p[2]); err != nil {
  263. return err
  264. }
  265. if err := checkRemoteInSync(s12Folder, p[0], p[1]); err != nil {
  266. return err
  267. }
  268. if err := checkRemoteInSync("s23", p[1], p[2]); err != nil {
  269. return err
  270. }
  271. return nil
  272. }
  273. func TestSyncSparseFile(t *testing.T) {
  274. // This test verifies that when syncing a file that consists mostly of
  275. // zeroes, those blocks are not transferred. It doesn't verify whether
  276. // the resulting file is actually *sparse* or not.
  277. log.Println("Cleaning...")
  278. err := removeAll("s1", "s12-1",
  279. "s2", "s12-2", "s23-2",
  280. "s3", "s23-3",
  281. "h1/index*", "h2/index*", "h3/index*")
  282. if err != nil {
  283. t.Fatal(err)
  284. }
  285. log.Println("Generating files...")
  286. if err := os.Mkdir("s1", 0755); err != nil {
  287. t.Fatal(err)
  288. }
  289. fd, err := os.Create("s1/testfile")
  290. if err != nil {
  291. t.Fatal(err)
  292. }
  293. if _, err := fd.Write([]byte("Start")); err != nil {
  294. t.Fatal(err)
  295. }
  296. kib := make([]byte, 1024)
  297. for i := 0; i < 8192; i++ {
  298. if _, err := fd.Write(kib); err != nil {
  299. t.Fatal(err)
  300. }
  301. }
  302. if _, err := fd.Write([]byte("End")); err != nil {
  303. t.Fatal(err)
  304. }
  305. fd.Close()
  306. // Start the syncers
  307. log.Println("Syncing...")
  308. p0 := startInstance(t, 1)
  309. defer checkedStop(t, p0)
  310. p1 := startInstance(t, 2)
  311. defer checkedStop(t, p1)
  312. p0.ResumeAll()
  313. p1.ResumeAll()
  314. rc.AwaitSync("default", p0, p1)
  315. log.Println("Comparing...")
  316. if err := compareDirectories("s1", "s2"); err != nil {
  317. t.Fatal(err)
  318. }
  319. conns, err := p0.Connections()
  320. if err != nil {
  321. t.Fatal(err)
  322. }
  323. tot := conns["total"]
  324. if tot.OutBytesTotal > 256<<10 {
  325. t.Fatal("Sending side has sent", tot.OutBytesTotal, "bytes, which is too much")
  326. }
  327. }