testutils_test.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright (C) 2016 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. package model
  7. import (
  8. "io/ioutil"
  9. "os"
  10. "testing"
  11. "time"
  12. "github.com/syncthing/syncthing/lib/config"
  13. "github.com/syncthing/syncthing/lib/db"
  14. "github.com/syncthing/syncthing/lib/db/backend"
  15. "github.com/syncthing/syncthing/lib/events"
  16. "github.com/syncthing/syncthing/lib/fs"
  17. "github.com/syncthing/syncthing/lib/ignore"
  18. "github.com/syncthing/syncthing/lib/protocol"
  19. "github.com/syncthing/syncthing/lib/rand"
  20. )
  21. var (
  22. myID, device1, device2 protocol.DeviceID
  23. defaultCfgWrapper config.Wrapper
  24. defaultFolderConfig config.FolderConfiguration
  25. defaultFs fs.Filesystem
  26. defaultCfg config.Configuration
  27. defaultAutoAcceptCfg config.Configuration
  28. )
  29. func init() {
  30. myID, _ = protocol.DeviceIDFromString("ZNWFSWE-RWRV2BD-45BLMCV-LTDE2UR-4LJDW6J-R5BPWEB-TXD27XJ-IZF5RA4")
  31. device1, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
  32. device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
  33. defaultFs = fs.NewFilesystem(fs.FilesystemTypeBasic, "testdata")
  34. defaultFolderConfig = testFolderConfig("testdata")
  35. defaultCfgWrapper = createTmpWrapper(config.New(myID))
  36. _, _ = defaultCfgWrapper.SetDevice(config.NewDeviceConfiguration(device1, "device1"))
  37. _, _ = defaultCfgWrapper.SetFolder(defaultFolderConfig)
  38. opts := defaultCfgWrapper.Options()
  39. opts.KeepTemporariesH = 1
  40. _, _ = defaultCfgWrapper.SetOptions(opts)
  41. defaultCfg = defaultCfgWrapper.RawCopy()
  42. defaultAutoAcceptCfg = config.Configuration{
  43. Devices: []config.DeviceConfiguration{
  44. {
  45. DeviceID: myID, // self
  46. },
  47. {
  48. DeviceID: device1,
  49. AutoAcceptFolders: true,
  50. },
  51. {
  52. DeviceID: device2,
  53. AutoAcceptFolders: true,
  54. },
  55. },
  56. Options: config.OptionsConfiguration{
  57. DefaultFolderPath: ".",
  58. },
  59. }
  60. }
  61. func tmpDefaultWrapper() (config.Wrapper, config.FolderConfiguration) {
  62. w := createTmpWrapper(defaultCfgWrapper.RawCopy())
  63. fcfg := testFolderConfigTmp()
  64. _, _ = w.SetFolder(fcfg)
  65. return w, fcfg
  66. }
  67. func testFolderConfigTmp() config.FolderConfiguration {
  68. tmpDir := createTmpDir()
  69. return testFolderConfig(tmpDir)
  70. }
  71. func testFolderConfig(path string) config.FolderConfiguration {
  72. cfg := config.NewFolderConfiguration(myID, "default", "default", fs.FilesystemTypeBasic, path)
  73. cfg.FSWatcherEnabled = false
  74. cfg.Devices = append(cfg.Devices, config.FolderDeviceConfiguration{DeviceID: device1})
  75. return cfg
  76. }
  77. func testFolderConfigFake() config.FolderConfiguration {
  78. cfg := config.NewFolderConfiguration(myID, "default", "default", fs.FilesystemTypeFake, rand.String(32)+"?content=true")
  79. cfg.FSWatcherEnabled = false
  80. cfg.Devices = append(cfg.Devices, config.FolderDeviceConfiguration{DeviceID: device1})
  81. return cfg
  82. }
  83. func setupModelWithConnection() (*model, *fakeConnection, config.FolderConfiguration) {
  84. w, fcfg := tmpDefaultWrapper()
  85. m, fc := setupModelWithConnectionFromWrapper(w)
  86. return m, fc, fcfg
  87. }
  88. func setupModelWithConnectionFromWrapper(w config.Wrapper) (*model, *fakeConnection) {
  89. m := setupModel(w)
  90. fc := addFakeConn(m, device1)
  91. fc.folder = "default"
  92. _ = m.ScanFolder("default")
  93. return m, fc
  94. }
  95. func setupModel(w config.Wrapper) *model {
  96. db := db.NewLowlevel(backend.OpenMemory())
  97. m := newModel(w, myID, "syncthing", "dev", db, nil)
  98. m.ServeBackground()
  99. m.ScanFolders()
  100. return m
  101. }
  102. func newModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersion string, ldb *db.Lowlevel, protectedFiles []string) *model {
  103. evLogger := events.NewLogger()
  104. m := NewModel(cfg, id, clientName, clientVersion, ldb, protectedFiles, evLogger).(*model)
  105. go evLogger.Serve()
  106. return m
  107. }
  108. func cleanupModel(m *model) {
  109. m.Stop()
  110. m.db.Close()
  111. m.evLogger.Stop()
  112. os.Remove(m.cfg.ConfigPath())
  113. }
  114. func cleanupModelAndRemoveDir(m *model, dir string) {
  115. cleanupModel(m)
  116. os.RemoveAll(dir)
  117. }
  118. func createTmpDir() string {
  119. tmpDir, err := ioutil.TempDir("", "syncthing_testFolder-")
  120. if err != nil {
  121. panic("Failed to create temporary testing dir")
  122. }
  123. return tmpDir
  124. }
  125. type alwaysChangedKey struct {
  126. fs fs.Filesystem
  127. name string
  128. }
  129. // alwaysChanges is an ignore.ChangeDetector that always returns true on Changed()
  130. type alwaysChanged struct {
  131. seen map[alwaysChangedKey]struct{}
  132. }
  133. func newAlwaysChanged() *alwaysChanged {
  134. return &alwaysChanged{
  135. seen: make(map[alwaysChangedKey]struct{}),
  136. }
  137. }
  138. func (c *alwaysChanged) Remember(fs fs.Filesystem, name string, _ time.Time) {
  139. c.seen[alwaysChangedKey{fs, name}] = struct{}{}
  140. }
  141. func (c *alwaysChanged) Reset() {
  142. c.seen = make(map[alwaysChangedKey]struct{})
  143. }
  144. func (c *alwaysChanged) Seen(fs fs.Filesystem, name string) bool {
  145. _, ok := c.seen[alwaysChangedKey{fs, name}]
  146. return ok
  147. }
  148. func (c *alwaysChanged) Changed() bool {
  149. return true
  150. }
  151. func localSize(t *testing.T, m Model, folder string) db.Counts {
  152. t.Helper()
  153. snap := dbSnapshot(t, m, folder)
  154. defer snap.Release()
  155. return snap.LocalSize()
  156. }
  157. func globalSize(t *testing.T, m Model, folder string) db.Counts {
  158. t.Helper()
  159. snap := dbSnapshot(t, m, folder)
  160. defer snap.Release()
  161. return snap.GlobalSize()
  162. }
  163. func receiveOnlyChangedSize(t *testing.T, m Model, folder string) db.Counts {
  164. t.Helper()
  165. snap := dbSnapshot(t, m, folder)
  166. defer snap.Release()
  167. return snap.ReceiveOnlyChangedSize()
  168. }
  169. func needSize(t *testing.T, m Model, folder string) db.Counts {
  170. t.Helper()
  171. snap := dbSnapshot(t, m, folder)
  172. defer snap.Release()
  173. return snap.NeedSize(protocol.LocalDeviceID)
  174. }
  175. func dbSnapshot(t *testing.T, m Model, folder string) *db.Snapshot {
  176. t.Helper()
  177. snap, err := m.DBSnapshot(folder)
  178. if err != nil {
  179. t.Fatal(err)
  180. }
  181. return snap
  182. }
  183. // Reach in and update the ignore matcher to one that always does
  184. // reloads when asked to, instead of checking file mtimes. This is
  185. // because we will be changing the files on disk often enough that the
  186. // mtimes will be unreliable to determine change status.
  187. func folderIgnoresAlwaysReload(m *model, fcfg config.FolderConfiguration) {
  188. m.removeFolder(fcfg)
  189. fset := db.NewFileSet(fcfg.ID, fcfg.Filesystem(), m.db)
  190. ignores := ignore.New(fcfg.Filesystem(), ignore.WithCache(true), ignore.WithChangeDetector(newAlwaysChanged()))
  191. m.fmut.Lock()
  192. m.addAndStartFolderLockedWithIgnores(fcfg, fset, ignores)
  193. m.fmut.Unlock()
  194. }