conflict_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. // Copyright (C) 2015 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. // +build integration
  7. package integration
  8. import (
  9. "bytes"
  10. "io/ioutil"
  11. "log"
  12. "os"
  13. "path/filepath"
  14. "testing"
  15. "time"
  16. "github.com/syncthing/syncthing/lib/rc"
  17. )
  18. func TestConflictsDefault(t *testing.T) {
  19. log.Println("Cleaning...")
  20. err := removeAll("s1", "s2", "h1/index*", "h2/index*")
  21. if err != nil {
  22. t.Fatal(err)
  23. }
  24. log.Println("Generating files...")
  25. err = generateFiles("s1", 100, 20, "../LICENSE")
  26. if err != nil {
  27. t.Fatal(err)
  28. }
  29. fd, err := os.Create("s1/testfile.txt")
  30. if err != nil {
  31. t.Fatal(err)
  32. }
  33. _, err = fd.WriteString("hello\n")
  34. if err != nil {
  35. t.Fatal(err)
  36. }
  37. err = fd.Close()
  38. if err != nil {
  39. t.Fatal(err)
  40. }
  41. expected, err := directoryContents("s1")
  42. if err != nil {
  43. t.Fatal(err)
  44. }
  45. sender := startInstance(t, 1)
  46. defer checkedStop(t, sender)
  47. receiver := startInstance(t, 2)
  48. defer checkedStop(t, receiver)
  49. sender.ResumeAll()
  50. receiver.ResumeAll()
  51. // Rescan with a delay on the next one, so we are not surprised by a
  52. // sudden rescan while we're trying to introduce conflicts.
  53. if err := sender.RescanDelay("default", 86400); err != nil {
  54. t.Fatal(err)
  55. }
  56. if err := receiver.RescanDelay("default", 86400); err != nil {
  57. t.Fatal(err)
  58. }
  59. rc.AwaitSync("default", sender, receiver)
  60. log.Println("Verifying...")
  61. actual, err := directoryContents("s2")
  62. if err != nil {
  63. t.Fatal(err)
  64. }
  65. err = compareDirectoryContents(actual, expected)
  66. if err != nil {
  67. t.Fatal(err)
  68. }
  69. log.Println("Introducing a conflict (simultaneous edit)...")
  70. if err := sender.PauseDevice(receiver.ID()); err != nil {
  71. t.Fatal(err)
  72. }
  73. fd, err = os.OpenFile("s1/testfile.txt", os.O_WRONLY|os.O_APPEND, 0644)
  74. if err != nil {
  75. t.Fatal(err)
  76. }
  77. _, err = fd.WriteString("text added to s1\n")
  78. if err != nil {
  79. t.Fatal(err)
  80. }
  81. err = fd.Close()
  82. if err != nil {
  83. t.Fatal(err)
  84. }
  85. fd, err = os.OpenFile("s2/testfile.txt", os.O_WRONLY|os.O_APPEND, 0644)
  86. if err != nil {
  87. t.Fatal(err)
  88. }
  89. _, err = fd.WriteString("text added to s2\n")
  90. if err != nil {
  91. t.Fatal(err)
  92. }
  93. err = fd.Close()
  94. if err != nil {
  95. t.Fatal(err)
  96. }
  97. if err := sender.ResumeDevice(receiver.ID()); err != nil {
  98. t.Fatal(err)
  99. }
  100. log.Println("Syncing...")
  101. if err := sender.RescanDelay("default", 86400); err != nil {
  102. t.Fatal(err)
  103. }
  104. if err := receiver.RescanDelay("default", 86400); err != nil {
  105. t.Fatal(err)
  106. }
  107. rc.AwaitSync("default", sender, receiver)
  108. // Expect one conflict file, created on either side.
  109. files, err := filepath.Glob("s?/*sync-conflict*")
  110. if err != nil {
  111. t.Fatal(err)
  112. }
  113. if len(files) != 1 {
  114. t.Errorf("Expected 1 conflicted files instead of %d", len(files))
  115. }
  116. log.Println("Introducing a conflict (edit plus delete)...")
  117. if err := sender.PauseDevice(receiver.ID()); err != nil {
  118. t.Fatal(err)
  119. }
  120. err = os.Remove("s1/testfile.txt")
  121. if err != nil {
  122. t.Fatal(err)
  123. }
  124. fd, err = os.OpenFile("s2/testfile.txt", os.O_WRONLY|os.O_APPEND, 0644)
  125. if err != nil {
  126. t.Fatal(err)
  127. }
  128. _, err = fd.WriteString("more text added to s2\n")
  129. if err != nil {
  130. t.Fatal(err)
  131. }
  132. err = fd.Close()
  133. if err != nil {
  134. t.Fatal(err)
  135. }
  136. if err := sender.ResumeDevice(receiver.ID()); err != nil {
  137. t.Fatal(err)
  138. }
  139. log.Println("Syncing...")
  140. if err := sender.RescanDelay("default", 86400); err != nil {
  141. t.Fatal(err)
  142. }
  143. if err := receiver.RescanDelay("default", 86400); err != nil {
  144. t.Fatal(err)
  145. }
  146. rc.AwaitSync("default", sender, receiver)
  147. // The conflict is resolved to the advantage of the edit over the delete.
  148. // As such, we get the edited content synced back to s1 where it was
  149. // removed.
  150. files, err = filepath.Glob("s2/*sync-conflict*")
  151. if err != nil {
  152. t.Fatal(err)
  153. }
  154. if len(files) != 1 {
  155. t.Errorf("Expected 1 conflicted files instead of %d", len(files))
  156. }
  157. bs, err := ioutil.ReadFile("s1/testfile.txt")
  158. if err != nil {
  159. t.Error("reading file:", err)
  160. }
  161. if !bytes.Contains(bs, []byte("more text added to s2")) {
  162. t.Error("s1/testfile.txt should contain data added in s2")
  163. }
  164. }
  165. func TestConflictsInitialMerge(t *testing.T) {
  166. log.Println("Cleaning...")
  167. err := removeAll("s1", "s2", "h1/index*", "h2/index*")
  168. if err != nil {
  169. t.Fatal(err)
  170. }
  171. err = os.Mkdir("s1", 0755)
  172. if err != nil {
  173. t.Fatal(err)
  174. }
  175. err = os.Mkdir("s2", 0755)
  176. if err != nil {
  177. t.Fatal(err)
  178. }
  179. // File 1 is a conflict
  180. err = ioutil.WriteFile("s1/file1", []byte("hello\n"), 0644)
  181. if err != nil {
  182. t.Fatal(err)
  183. }
  184. err = ioutil.WriteFile("s2/file1", []byte("goodbye\n"), 0644)
  185. if err != nil {
  186. t.Fatal(err)
  187. }
  188. // File 2 exists on s1 only
  189. err = ioutil.WriteFile("s1/file2", []byte("hello\n"), 0644)
  190. if err != nil {
  191. t.Fatal(err)
  192. }
  193. // File 3 exists on s2 only
  194. err = ioutil.WriteFile("s2/file3", []byte("goodbye\n"), 0644)
  195. if err != nil {
  196. t.Fatal(err)
  197. }
  198. // Let them sync
  199. sender := startInstance(t, 1)
  200. defer checkedStop(t, sender)
  201. receiver := startInstance(t, 2)
  202. defer checkedStop(t, receiver)
  203. sender.ResumeAll()
  204. receiver.ResumeAll()
  205. log.Println("Syncing...")
  206. rc.AwaitSync("default", sender, receiver)
  207. // Do it once more so the conflict copies propagate to both sides.
  208. sender.Rescan("default")
  209. receiver.Rescan("default")
  210. rc.AwaitSync("default", sender, receiver)
  211. checkedStop(t, sender)
  212. checkedStop(t, receiver)
  213. log.Println("Verifying...")
  214. // s1 should have four files (there's a conflict)
  215. files, err := filepath.Glob("s1/file*")
  216. if err != nil {
  217. t.Fatal(err)
  218. }
  219. if len(files) != 4 {
  220. t.Errorf("Expected 4 files in s1 instead of %d", len(files))
  221. }
  222. // s2 should have four files (there's a conflict)
  223. files, err = filepath.Glob("s2/file*")
  224. if err != nil {
  225. t.Fatal(err)
  226. }
  227. if len(files) != 4 {
  228. t.Errorf("Expected 4 files in s2 instead of %d", len(files))
  229. }
  230. // file1 is in conflict, so there's two versions of that one
  231. files, err = filepath.Glob("s2/file1*")
  232. if err != nil {
  233. t.Fatal(err)
  234. }
  235. if len(files) != 2 {
  236. t.Errorf("Expected 2 'file1' files in s2 instead of %d", len(files))
  237. }
  238. }
  239. func TestConflictsIndexReset(t *testing.T) {
  240. log.Println("Cleaning...")
  241. err := removeAll("s1", "s2", "h1/index*", "h2/index*")
  242. if err != nil {
  243. t.Fatal(err)
  244. }
  245. err = os.Mkdir("s1", 0755)
  246. if err != nil {
  247. t.Fatal(err)
  248. }
  249. err = os.Mkdir("s2", 0755)
  250. if err != nil {
  251. t.Fatal(err)
  252. }
  253. // Three files on s1
  254. err = ioutil.WriteFile("s1/file1", []byte("hello\n"), 0644)
  255. if err != nil {
  256. t.Fatal(err)
  257. }
  258. err = ioutil.WriteFile("s1/file2", []byte("hello\n"), 0644)
  259. if err != nil {
  260. t.Fatal(err)
  261. }
  262. err = ioutil.WriteFile("s2/file3", []byte("hello\n"), 0644)
  263. if err != nil {
  264. t.Fatal(err)
  265. }
  266. // Let them sync
  267. sender := startInstance(t, 1)
  268. defer checkedStop(t, sender)
  269. receiver := startInstance(t, 2)
  270. defer checkedStop(t, receiver)
  271. sender.ResumeAll()
  272. receiver.ResumeAll()
  273. log.Println("Syncing...")
  274. rc.AwaitSync("default", sender, receiver)
  275. log.Println("Verifying...")
  276. // s1 should have three files
  277. files, err := filepath.Glob("s1/file*")
  278. if err != nil {
  279. t.Fatal(err)
  280. }
  281. if len(files) != 3 {
  282. t.Errorf("Expected 3 files in s1 instead of %d", len(files))
  283. }
  284. // s2 should have three files
  285. files, err = filepath.Glob("s2/file*")
  286. if err != nil {
  287. t.Fatal(err)
  288. }
  289. if len(files) != 3 {
  290. t.Errorf("Expected 3 files in s2 instead of %d", len(files))
  291. }
  292. log.Println("Updating...")
  293. // change s2/file2 a few times, so that its version counter increases.
  294. // This will make the file on the cluster look newer than what we have
  295. // locally after we rest the index, unless we have a fix for that.
  296. for i := 0; i < 5; i++ {
  297. err = ioutil.WriteFile("s2/file2", []byte("hello1\n"), 0644)
  298. if err != nil {
  299. t.Fatal(err)
  300. }
  301. err = receiver.Rescan("default")
  302. if err != nil {
  303. t.Fatal(err)
  304. }
  305. time.Sleep(time.Second)
  306. }
  307. rc.AwaitSync("default", sender, receiver)
  308. // Now nuke the index
  309. log.Println("Resetting...")
  310. checkedStop(t, receiver)
  311. removeAll("h2/index*")
  312. // s1/file1 (remote) changes while receiver is down
  313. err = ioutil.WriteFile("s1/file1", []byte("goodbye\n"), 0644)
  314. if err != nil {
  315. t.Fatal(err)
  316. }
  317. // s1 must know about it
  318. err = sender.Rescan("default")
  319. if err != nil {
  320. t.Fatal(err)
  321. }
  322. // s2/file2 (local) changes while receiver is down
  323. err = ioutil.WriteFile("s2/file2", []byte("goodbye\n"), 0644)
  324. if err != nil {
  325. t.Fatal(err)
  326. }
  327. receiver = startInstance(t, 2)
  328. defer checkedStop(t, receiver)
  329. receiver.ResumeAll()
  330. log.Println("Syncing...")
  331. rc.AwaitSync("default", sender, receiver)
  332. // s2 should have five files (three plus two conflicts)
  333. files, err = filepath.Glob("s2/file*")
  334. if err != nil {
  335. t.Fatal(err)
  336. }
  337. if len(files) != 5 {
  338. t.Errorf("Expected 5 files in s2 instead of %d", len(files))
  339. }
  340. // file1 is in conflict, so there's two versions of that one
  341. files, err = filepath.Glob("s2/file1*")
  342. if err != nil {
  343. t.Fatal(err)
  344. }
  345. if len(files) != 2 {
  346. t.Errorf("Expected 2 'file1' files in s2 instead of %d", len(files))
  347. }
  348. // file2 is in conflict, so there's two versions of that one
  349. files, err = filepath.Glob("s2/file2*")
  350. if err != nil {
  351. t.Fatal(err)
  352. }
  353. if len(files) != 2 {
  354. t.Errorf("Expected 2 'file2' files in s2 instead of %d", len(files))
  355. }
  356. }
  357. func TestConflictsSameContent(t *testing.T) {
  358. log.Println("Cleaning...")
  359. err := removeAll("s1", "s2", "h1/index*", "h2/index*")
  360. if err != nil {
  361. t.Fatal(err)
  362. }
  363. err = os.Mkdir("s1", 0755)
  364. if err != nil {
  365. t.Fatal(err)
  366. }
  367. err = os.Mkdir("s2", 0755)
  368. if err != nil {
  369. t.Fatal(err)
  370. }
  371. // Two files on s1
  372. err = ioutil.WriteFile("s1/file1", []byte("hello\n"), 0644)
  373. if err != nil {
  374. t.Fatal(err)
  375. }
  376. err = ioutil.WriteFile("s1/file2", []byte("hello\n"), 0644)
  377. if err != nil {
  378. t.Fatal(err)
  379. }
  380. // Two files on s2, content differs in file1 only, timestamps differ on both.
  381. err = ioutil.WriteFile("s2/file1", []byte("goodbye\n"), 0644)
  382. if err != nil {
  383. t.Fatal(err)
  384. }
  385. err = ioutil.WriteFile("s2/file2", []byte("hello\n"), 0644)
  386. if err != nil {
  387. t.Fatal(err)
  388. }
  389. ts := time.Now().Add(-time.Hour)
  390. os.Chtimes("s2/file1", ts, ts)
  391. os.Chtimes("s2/file2", ts, ts)
  392. // Let them sync
  393. sender := startInstance(t, 1)
  394. defer checkedStop(t, sender)
  395. receiver := startInstance(t, 2)
  396. defer checkedStop(t, receiver)
  397. sender.ResumeAll()
  398. receiver.ResumeAll()
  399. log.Println("Syncing...")
  400. rc.AwaitSync("default", sender, receiver)
  401. // Let conflict copies propagate
  402. sender.Rescan("default")
  403. receiver.Rescan("default")
  404. rc.AwaitSync("default", sender, receiver)
  405. log.Println("Verifying...")
  406. // s1 should have three files
  407. files, err := filepath.Glob("s1/file*")
  408. if err != nil {
  409. t.Fatal(err)
  410. }
  411. if len(files) != 3 {
  412. t.Errorf("Expected 3 files in s1 instead of %d", len(files))
  413. }
  414. // s2 should have three files
  415. files, err = filepath.Glob("s2/file*")
  416. if err != nil {
  417. t.Fatal(err)
  418. }
  419. if len(files) != 3 {
  420. t.Errorf("Expected 3 files in s2 instead of %d", len(files))
  421. }
  422. }