symlink_test.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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 http://mozilla.org/MPL/2.0/.
  6. // +build integration
  7. package integration
  8. import (
  9. "io/ioutil"
  10. "log"
  11. "os"
  12. "path/filepath"
  13. "testing"
  14. "github.com/syncthing/syncthing/lib/config"
  15. "github.com/syncthing/syncthing/lib/protocol"
  16. "github.com/syncthing/syncthing/lib/rc"
  17. "github.com/syncthing/syncthing/lib/symlinks"
  18. )
  19. func symlinksSupported() bool {
  20. tmp, err := ioutil.TempDir("", "symlink-test")
  21. if err != nil {
  22. return false
  23. }
  24. defer os.RemoveAll(tmp)
  25. err = os.Symlink("tmp", filepath.Join(tmp, "link"))
  26. return err == nil
  27. }
  28. func TestSymlinks(t *testing.T) {
  29. if !symlinksSupported() {
  30. t.Skip("symlinks unsupported")
  31. }
  32. // Use no versioning
  33. id, _ := protocol.DeviceIDFromString(id2)
  34. cfg, _ := config.Load("h2/config.xml", id)
  35. fld := cfg.Folders()["default"]
  36. fld.Versioning = config.VersioningConfiguration{}
  37. cfg.SetFolder(fld)
  38. cfg.Save()
  39. testSymlinks(t)
  40. }
  41. func TestSymlinksSimpleVersioning(t *testing.T) {
  42. if !symlinksSupported() {
  43. t.Skip("symlinks unsupported")
  44. }
  45. // Use simple versioning
  46. id, _ := protocol.DeviceIDFromString(id2)
  47. cfg, _ := config.Load("h2/config.xml", id)
  48. fld := cfg.Folders()["default"]
  49. fld.Versioning = config.VersioningConfiguration{
  50. Type: "simple",
  51. Params: map[string]string{"keep": "5"},
  52. }
  53. cfg.SetFolder(fld)
  54. cfg.Save()
  55. testSymlinks(t)
  56. }
  57. func TestSymlinksStaggeredVersioning(t *testing.T) {
  58. if !symlinksSupported() {
  59. t.Skip("symlinks unsupported")
  60. }
  61. // Use staggered versioning
  62. id, _ := protocol.DeviceIDFromString(id2)
  63. cfg, _ := config.Load("h2/config.xml", id)
  64. fld := cfg.Folders()["default"]
  65. fld.Versioning = config.VersioningConfiguration{
  66. Type: "staggered",
  67. }
  68. cfg.SetFolder(fld)
  69. cfg.Save()
  70. testSymlinks(t)
  71. }
  72. func testSymlinks(t *testing.T) {
  73. log.Println("Cleaning...")
  74. err := removeAll("s1", "s2", "h1/index*", "h2/index*")
  75. if err != nil {
  76. t.Fatal(err)
  77. }
  78. log.Println("Generating files...")
  79. err = generateFiles("s1", 100, 20, "../LICENSE")
  80. if err != nil {
  81. t.Fatal(err)
  82. }
  83. // A file that we will replace with a symlink later
  84. fd, err := os.Create("s1/fileToReplace")
  85. if err != nil {
  86. t.Fatal(err)
  87. }
  88. fd.Close()
  89. // A directory that we will replace with a symlink later
  90. err = os.Mkdir("s1/dirToReplace", 0755)
  91. if err != nil {
  92. t.Fatal(err)
  93. }
  94. // A file and a symlink to that file
  95. fd, err = os.Create("s1/file")
  96. if err != nil {
  97. t.Fatal(err)
  98. }
  99. fd.Close()
  100. err = symlinks.Create("s1/fileLink", "file", 0)
  101. if err != nil {
  102. log.Fatal(err)
  103. }
  104. // A directory and a symlink to that directory
  105. err = os.Mkdir("s1/dir", 0755)
  106. if err != nil {
  107. t.Fatal(err)
  108. }
  109. err = symlinks.Create("s1/dirLink", "dir", 0)
  110. if err != nil {
  111. log.Fatal(err)
  112. }
  113. // A link to something in the repo that does not exist
  114. err = symlinks.Create("s1/noneLink", "does/not/exist", 0)
  115. if err != nil {
  116. log.Fatal(err)
  117. }
  118. // A link we will replace with a file later
  119. err = symlinks.Create("s1/repFileLink", "does/not/exist", 0)
  120. if err != nil {
  121. log.Fatal(err)
  122. }
  123. // A link we will replace with a directory later
  124. err = symlinks.Create("s1/repDirLink", "does/not/exist", 0)
  125. if err != nil {
  126. log.Fatal(err)
  127. }
  128. // A link we will remove later
  129. err = symlinks.Create("s1/removeLink", "does/not/exist", 0)
  130. if err != nil {
  131. log.Fatal(err)
  132. }
  133. // Verify that the files and symlinks sync to the other side
  134. sender := startInstance(t, 1)
  135. defer checkedStop(t, sender)
  136. receiver := startInstance(t, 2)
  137. defer checkedStop(t, receiver)
  138. log.Println("Syncing...")
  139. rc.AwaitSync("default", sender, receiver)
  140. log.Println("Comparing directories...")
  141. err = compareDirectories("s1", "s2")
  142. if err != nil {
  143. t.Fatal(err)
  144. }
  145. log.Println("Making some changes...")
  146. // Remove one symlink
  147. err = os.Remove("s1/fileLink")
  148. if err != nil {
  149. log.Fatal(err)
  150. }
  151. // Change the target of another
  152. err = os.Remove("s1/dirLink")
  153. if err != nil {
  154. log.Fatal(err)
  155. }
  156. err = symlinks.Create("s1/dirLink", "file", 0)
  157. if err != nil {
  158. log.Fatal(err)
  159. }
  160. // Replace one with a file
  161. err = os.Remove("s1/repFileLink")
  162. if err != nil {
  163. log.Fatal(err)
  164. }
  165. fd, err = os.Create("s1/repFileLink")
  166. if err != nil {
  167. log.Fatal(err)
  168. }
  169. fd.Close()
  170. // Replace one with a directory
  171. err = os.Remove("s1/repDirLink")
  172. if err != nil {
  173. log.Fatal(err)
  174. }
  175. err = os.Mkdir("s1/repDirLink", 0755)
  176. if err != nil {
  177. log.Fatal(err)
  178. }
  179. // Replace a file with a symlink
  180. err = os.Remove("s1/fileToReplace")
  181. if err != nil {
  182. log.Fatal(err)
  183. }
  184. err = symlinks.Create("s1/fileToReplace", "somewhere/non/existent", 0)
  185. if err != nil {
  186. log.Fatal(err)
  187. }
  188. // Replace a directory with a symlink
  189. err = os.RemoveAll("s1/dirToReplace")
  190. if err != nil {
  191. log.Fatal(err)
  192. }
  193. err = symlinks.Create("s1/dirToReplace", "somewhere/non/existent", 0)
  194. if err != nil {
  195. log.Fatal(err)
  196. }
  197. // Remove a broken symlink
  198. err = os.Remove("s1/removeLink")
  199. if err != nil {
  200. log.Fatal(err)
  201. }
  202. // Sync these changes and recheck
  203. log.Println("Syncing...")
  204. if err := sender.Rescan("default"); err != nil {
  205. t.Fatal(err)
  206. }
  207. rc.AwaitSync("default", sender, receiver)
  208. log.Println("Comparing directories...")
  209. err = compareDirectories("s1", "s2")
  210. if err != nil {
  211. t.Fatal(err)
  212. }
  213. }