conflict_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  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. //go:build integration
  7. // +build integration
  8. package integration
  9. import (
  10. "bytes"
  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) != 2 {
  114. t.Errorf("Expected 1 conflicted file on each side, instead of totally %d", len(files))
  115. } else if filepath.Base(files[0]) != filepath.Base(files[1]) {
  116. t.Errorf(`Expected same conflicted file on both sides, got "%v" and "%v"`, files[0], files[1])
  117. }
  118. log.Println("Introducing a conflict (edit plus delete)...")
  119. if err := sender.PauseDevice(receiver.ID()); err != nil {
  120. t.Fatal(err)
  121. }
  122. err = os.Remove("s1/testfile.txt")
  123. if err != nil {
  124. t.Fatal(err)
  125. }
  126. fd, err = os.OpenFile("s2/testfile.txt", os.O_WRONLY|os.O_APPEND, 0644)
  127. if err != nil {
  128. t.Fatal(err)
  129. }
  130. _, err = fd.WriteString("more text added to s2\n")
  131. if err != nil {
  132. t.Fatal(err)
  133. }
  134. err = fd.Close()
  135. if err != nil {
  136. t.Fatal(err)
  137. }
  138. if err := sender.ResumeDevice(receiver.ID()); err != nil {
  139. t.Fatal(err)
  140. }
  141. log.Println("Syncing...")
  142. if err := sender.RescanDelay("default", 86400); err != nil {
  143. t.Fatal(err)
  144. }
  145. if err := receiver.RescanDelay("default", 86400); err != nil {
  146. t.Fatal(err)
  147. }
  148. rc.AwaitSync("default", sender, receiver)
  149. // The conflict is resolved to the advantage of the edit over the delete.
  150. // As such, we get the edited content synced back to s1 where it was
  151. // removed.
  152. files, err = filepath.Glob("s2/*sync-conflict*")
  153. if err != nil {
  154. t.Fatal(err)
  155. }
  156. if len(files) != 1 {
  157. t.Errorf("Expected 1 conflicted files instead of %d", len(files))
  158. }
  159. bs, err := os.ReadFile("s1/testfile.txt")
  160. if err != nil {
  161. t.Error("reading file:", err)
  162. }
  163. if !bytes.Contains(bs, []byte("more text added to s2")) {
  164. t.Error("s1/testfile.txt should contain data added in s2")
  165. }
  166. }
  167. func TestConflictsInitialMerge(t *testing.T) {
  168. log.Println("Cleaning...")
  169. err := removeAll("s1", "s2", "h1/index*", "h2/index*")
  170. if err != nil {
  171. t.Fatal(err)
  172. }
  173. err = os.Mkdir("s1", 0755)
  174. if err != nil {
  175. t.Fatal(err)
  176. }
  177. err = os.Mkdir("s2", 0755)
  178. if err != nil {
  179. t.Fatal(err)
  180. }
  181. // File 1 is a conflict
  182. err = os.WriteFile("s1/file1", []byte("hello\n"), 0644)
  183. if err != nil {
  184. t.Fatal(err)
  185. }
  186. err = os.WriteFile("s2/file1", []byte("goodbye\n"), 0644)
  187. if err != nil {
  188. t.Fatal(err)
  189. }
  190. // File 2 exists on s1 only
  191. err = os.WriteFile("s1/file2", []byte("hello\n"), 0644)
  192. if err != nil {
  193. t.Fatal(err)
  194. }
  195. // File 3 exists on s2 only
  196. err = os.WriteFile("s2/file3", []byte("goodbye\n"), 0644)
  197. if err != nil {
  198. t.Fatal(err)
  199. }
  200. // Let them sync
  201. sender := startInstance(t, 1)
  202. defer checkedStop(t, sender)
  203. receiver := startInstance(t, 2)
  204. defer checkedStop(t, receiver)
  205. sender.ResumeAll()
  206. receiver.ResumeAll()
  207. log.Println("Syncing...")
  208. rc.AwaitSync("default", sender, receiver)
  209. // Do it once more so the conflict copies propagate to both sides.
  210. sender.Rescan("default")
  211. receiver.Rescan("default")
  212. rc.AwaitSync("default", sender, receiver)
  213. checkedStop(t, sender)
  214. checkedStop(t, receiver)
  215. log.Println("Verifying...")
  216. // s1 should have four files (there's a conflict)
  217. files, err := filepath.Glob("s1/file*")
  218. if err != nil {
  219. t.Fatal(err)
  220. }
  221. if len(files) != 4 {
  222. t.Errorf("Expected 4 files in s1 instead of %d", len(files))
  223. }
  224. // s2 should have four files (there's a conflict)
  225. files, err = filepath.Glob("s2/file*")
  226. if err != nil {
  227. t.Fatal(err)
  228. }
  229. if len(files) != 4 {
  230. t.Errorf("Expected 4 files in s2 instead of %d", len(files))
  231. }
  232. // file1 is in conflict, so there's two versions of that one
  233. files, err = filepath.Glob("s2/file1*")
  234. if err != nil {
  235. t.Fatal(err)
  236. }
  237. if len(files) != 2 {
  238. t.Errorf("Expected 2 'file1' files in s2 instead of %d", len(files))
  239. }
  240. }
  241. func TestConflictsIndexReset(t *testing.T) {
  242. log.Println("Cleaning...")
  243. err := removeAll("s1", "s2", "h1/index*", "h2/index*")
  244. if err != nil {
  245. t.Fatal(err)
  246. }
  247. err = os.Mkdir("s1", 0755)
  248. if err != nil {
  249. t.Fatal(err)
  250. }
  251. err = os.Mkdir("s2", 0755)
  252. if err != nil {
  253. t.Fatal(err)
  254. }
  255. // Three files on s1
  256. err = os.WriteFile("s1/file1", []byte("hello\n"), 0644)
  257. if err != nil {
  258. t.Fatal(err)
  259. }
  260. err = os.WriteFile("s1/file2", []byte("hello\n"), 0644)
  261. if err != nil {
  262. t.Fatal(err)
  263. }
  264. err = os.WriteFile("s2/file3", []byte("hello\n"), 0644)
  265. if err != nil {
  266. t.Fatal(err)
  267. }
  268. // Let them sync
  269. sender := startInstance(t, 1)
  270. defer checkedStop(t, sender)
  271. receiver := startInstance(t, 2)
  272. defer checkedStop(t, receiver)
  273. sender.ResumeAll()
  274. receiver.ResumeAll()
  275. log.Println("Syncing...")
  276. rc.AwaitSync("default", sender, receiver)
  277. log.Println("Verifying...")
  278. // s1 should have three files
  279. files, err := filepath.Glob("s1/file*")
  280. if err != nil {
  281. t.Fatal(err)
  282. }
  283. if len(files) != 3 {
  284. t.Errorf("Expected 3 files in s1 instead of %d", len(files))
  285. }
  286. // s2 should have three files
  287. files, err = filepath.Glob("s2/file*")
  288. if err != nil {
  289. t.Fatal(err)
  290. }
  291. if len(files) != 3 {
  292. t.Errorf("Expected 3 files in s2 instead of %d", len(files))
  293. }
  294. log.Println("Updating...")
  295. // change s2/file2 a few times, so that its version counter increases.
  296. // This will make the file on the cluster look newer than what we have
  297. // locally after we rest the index, unless we have a fix for that.
  298. for i := 0; i < 5; i++ {
  299. err = os.WriteFile("s2/file2", []byte("hello1\n"), 0644)
  300. if err != nil {
  301. t.Fatal(err)
  302. }
  303. err = receiver.Rescan("default")
  304. if err != nil {
  305. t.Fatal(err)
  306. }
  307. time.Sleep(time.Second)
  308. }
  309. rc.AwaitSync("default", sender, receiver)
  310. // Now nuke the index
  311. log.Println("Resetting...")
  312. checkedStop(t, receiver)
  313. removeAll("h2/index*")
  314. // s1/file1 (remote) changes while receiver is down
  315. err = os.WriteFile("s1/file1", []byte("goodbye\n"), 0644)
  316. if err != nil {
  317. t.Fatal(err)
  318. }
  319. // s1 must know about it
  320. err = sender.Rescan("default")
  321. if err != nil {
  322. t.Fatal(err)
  323. }
  324. // s2/file2 (local) changes while receiver is down
  325. err = os.WriteFile("s2/file2", []byte("goodbye\n"), 0644)
  326. if err != nil {
  327. t.Fatal(err)
  328. }
  329. receiver = startInstance(t, 2)
  330. defer checkedStop(t, receiver)
  331. receiver.ResumeAll()
  332. log.Println("Syncing...")
  333. rc.AwaitSync("default", sender, receiver)
  334. // s2 should have five files (three plus two conflicts)
  335. files, err = filepath.Glob("s2/file*")
  336. if err != nil {
  337. t.Fatal(err)
  338. }
  339. if len(files) != 5 {
  340. t.Errorf("Expected 5 files in s2 instead of %d", len(files))
  341. }
  342. // file1 is in conflict, so there's two versions of that one
  343. files, err = filepath.Glob("s2/file1*")
  344. if err != nil {
  345. t.Fatal(err)
  346. }
  347. if len(files) != 2 {
  348. t.Errorf("Expected 2 'file1' files in s2 instead of %d", len(files))
  349. }
  350. // file2 is in conflict, so there's two versions of that one
  351. files, err = filepath.Glob("s2/file2*")
  352. if err != nil {
  353. t.Fatal(err)
  354. }
  355. if len(files) != 2 {
  356. t.Errorf("Expected 2 'file2' files in s2 instead of %d", len(files))
  357. }
  358. }
  359. func TestConflictsSameContent(t *testing.T) {
  360. log.Println("Cleaning...")
  361. err := removeAll("s1", "s2", "h1/index*", "h2/index*")
  362. if err != nil {
  363. t.Fatal(err)
  364. }
  365. err = os.Mkdir("s1", 0755)
  366. if err != nil {
  367. t.Fatal(err)
  368. }
  369. err = os.Mkdir("s2", 0755)
  370. if err != nil {
  371. t.Fatal(err)
  372. }
  373. // Two files on s1
  374. err = os.WriteFile("s1/file1", []byte("hello\n"), 0644)
  375. if err != nil {
  376. t.Fatal(err)
  377. }
  378. err = os.WriteFile("s1/file2", []byte("hello\n"), 0644)
  379. if err != nil {
  380. t.Fatal(err)
  381. }
  382. // Two files on s2, content differs in file1 only, timestamps differ on both.
  383. err = os.WriteFile("s2/file1", []byte("goodbye\n"), 0644)
  384. if err != nil {
  385. t.Fatal(err)
  386. }
  387. err = os.WriteFile("s2/file2", []byte("hello\n"), 0644)
  388. if err != nil {
  389. t.Fatal(err)
  390. }
  391. ts := time.Now().Add(-time.Hour)
  392. os.Chtimes("s2/file1", ts, ts)
  393. os.Chtimes("s2/file2", ts, ts)
  394. // Let them sync
  395. sender := startInstance(t, 1)
  396. defer checkedStop(t, sender)
  397. receiver := startInstance(t, 2)
  398. defer checkedStop(t, receiver)
  399. sender.ResumeAll()
  400. receiver.ResumeAll()
  401. log.Println("Syncing...")
  402. rc.AwaitSync("default", sender, receiver)
  403. // Let conflict copies propagate
  404. sender.Rescan("default")
  405. receiver.Rescan("default")
  406. rc.AwaitSync("default", sender, receiver)
  407. log.Println("Verifying...")
  408. // s1 should have three files
  409. files, err := filepath.Glob("s1/file*")
  410. if err != nil {
  411. t.Fatal(err)
  412. }
  413. if len(files) != 3 {
  414. t.Errorf("Expected 3 files in s1 instead of %d", len(files))
  415. }
  416. // s2 should have three files
  417. files, err = filepath.Glob("s2/file*")
  418. if err != nil {
  419. t.Fatal(err)
  420. }
  421. if len(files) != 3 {
  422. t.Errorf("Expected 3 files in s2 instead of %d", len(files))
  423. }
  424. }