config_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  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. package config
  7. import (
  8. "bytes"
  9. "encoding/json"
  10. "fmt"
  11. "io/ioutil"
  12. "os"
  13. "path/filepath"
  14. "reflect"
  15. "runtime"
  16. "sort"
  17. "strings"
  18. "testing"
  19. "github.com/d4l3k/messagediff"
  20. "github.com/syncthing/syncthing/lib/fs"
  21. "github.com/syncthing/syncthing/lib/osutil"
  22. "github.com/syncthing/syncthing/lib/protocol"
  23. )
  24. var device1, device2, device3, device4 protocol.DeviceID
  25. func init() {
  26. device1, _ = protocol.DeviceIDFromString("AIR6LPZ7K4PTTUXQSMUUCPQ5YWOEDFIIQJUG7772YQXXR5YD6AWQ")
  27. device2, _ = protocol.DeviceIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
  28. device3, _ = protocol.DeviceIDFromString("LGFPDIT-7SKNNJL-VJZA4FC-7QNCRKA-CE753K7-2BW5QDK-2FOZ7FR-FEP57QJ")
  29. device4, _ = protocol.DeviceIDFromString("P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2")
  30. }
  31. func TestDefaultValues(t *testing.T) {
  32. expected := OptionsConfiguration{
  33. ListenAddresses: []string{"default"},
  34. GlobalAnnServers: []string{"default"},
  35. GlobalAnnEnabled: true,
  36. LocalAnnEnabled: true,
  37. LocalAnnPort: 21027,
  38. LocalAnnMCAddr: "[ff12::8384]:21027",
  39. MaxSendKbps: 0,
  40. MaxRecvKbps: 0,
  41. ReconnectIntervalS: 60,
  42. RelaysEnabled: true,
  43. RelayReconnectIntervalM: 10,
  44. StartBrowser: true,
  45. NATEnabled: true,
  46. NATLeaseM: 60,
  47. NATRenewalM: 30,
  48. NATTimeoutS: 10,
  49. RestartOnWakeup: true,
  50. AutoUpgradeIntervalH: 12,
  51. KeepTemporariesH: 24,
  52. CacheIgnoredFiles: false,
  53. ProgressUpdateIntervalS: 5,
  54. LimitBandwidthInLan: false,
  55. MinHomeDiskFree: Size{1, "%"},
  56. URURL: "https://data.syncthing.net/newdata",
  57. URInitialDelayS: 1800,
  58. URPostInsecurely: false,
  59. ReleasesURL: "https://upgrades.syncthing.net/meta.json",
  60. AlwaysLocalNets: []string{},
  61. OverwriteRemoteDevNames: false,
  62. TempIndexMinBlocks: 10,
  63. UnackedNotificationIDs: []string{},
  64. WeakHashSelectionMethod: WeakHashAuto,
  65. StunKeepaliveS: 24,
  66. StunServers: []string{"default"},
  67. KCPCongestionControl: true,
  68. KCPReceiveWindowSize: 128,
  69. KCPSendWindowSize: 128,
  70. KCPUpdateIntervalMs: 25,
  71. KCPFastResend: false,
  72. DefaultFolderPath: "~",
  73. SetLowPriority: true,
  74. }
  75. cfg := New(device1)
  76. if diff, equal := messagediff.PrettyDiff(expected, cfg.Options); !equal {
  77. t.Errorf("Default config differs. Diff:\n%s", diff)
  78. }
  79. }
  80. func TestDeviceConfig(t *testing.T) {
  81. for i := OldestHandledVersion; i <= CurrentVersion; i++ {
  82. os.RemoveAll(filepath.Join("testdata", DefaultMarkerName))
  83. wr, err := Load(fmt.Sprintf("testdata/v%d.xml", i), device1)
  84. if err != nil {
  85. t.Fatal(err)
  86. }
  87. _, err = os.Stat(filepath.Join("testdata", DefaultMarkerName))
  88. if i < 6 && err != nil {
  89. t.Fatal(err)
  90. } else if i >= 6 && err == nil {
  91. t.Fatal("Unexpected file")
  92. }
  93. cfg := wr.cfg
  94. expectedFolders := []FolderConfiguration{
  95. {
  96. ID: "test",
  97. FilesystemType: fs.FilesystemTypeBasic,
  98. Path: "testdata",
  99. Devices: []FolderDeviceConfiguration{{DeviceID: device1}, {DeviceID: device4}},
  100. Type: FolderTypeSendOnly,
  101. RescanIntervalS: 600,
  102. FSWatcherEnabled: false,
  103. FSWatcherDelayS: 10,
  104. Copiers: 0,
  105. Pullers: 0,
  106. Hashers: 0,
  107. AutoNormalize: true,
  108. MinDiskFree: Size{1, "%"},
  109. MaxConflicts: -1,
  110. Versioning: VersioningConfiguration{
  111. Params: map[string]string{},
  112. },
  113. WeakHashThresholdPct: 25,
  114. MarkerName: DefaultMarkerName,
  115. },
  116. }
  117. // The cachedFilesystem will have been resolved to an absolute path,
  118. // depending on where the tests are running. Zero it out so we don't
  119. // fail based on that.
  120. for i := range cfg.Folders {
  121. cfg.Folders[i].cachedFilesystem = nil
  122. }
  123. expectedDevices := []DeviceConfiguration{
  124. {
  125. DeviceID: device1,
  126. Name: "node one",
  127. Addresses: []string{"tcp://a"},
  128. Compression: protocol.CompressMetadata,
  129. AllowedNetworks: []string{},
  130. },
  131. {
  132. DeviceID: device4,
  133. Name: "node two",
  134. Addresses: []string{"tcp://b"},
  135. Compression: protocol.CompressMetadata,
  136. AllowedNetworks: []string{},
  137. },
  138. }
  139. expectedDeviceIDs := []protocol.DeviceID{device1, device4}
  140. if cfg.Version != CurrentVersion {
  141. t.Errorf("%d: Incorrect version %d != %d", i, cfg.Version, CurrentVersion)
  142. }
  143. if diff, equal := messagediff.PrettyDiff(expectedFolders, cfg.Folders); !equal {
  144. t.Errorf("%d: Incorrect Folders. Diff:\n%s", i, diff)
  145. }
  146. if diff, equal := messagediff.PrettyDiff(expectedDevices, cfg.Devices); !equal {
  147. t.Errorf("%d: Incorrect Devices. Diff:\n%s", i, diff)
  148. }
  149. if diff, equal := messagediff.PrettyDiff(expectedDeviceIDs, cfg.Folders[0].DeviceIDs()); !equal {
  150. t.Errorf("%d: Incorrect DeviceIDs. Diff:\n%s", i, diff)
  151. }
  152. }
  153. }
  154. func TestNoListenAddresses(t *testing.T) {
  155. cfg, err := Load("testdata/nolistenaddress.xml", device1)
  156. if err != nil {
  157. t.Error(err)
  158. }
  159. expected := []string{""}
  160. actual := cfg.Options().ListenAddresses
  161. if diff, equal := messagediff.PrettyDiff(expected, actual); !equal {
  162. t.Errorf("Unexpected ListenAddresses. Diff:\n%s", diff)
  163. }
  164. }
  165. func TestOverriddenValues(t *testing.T) {
  166. expected := OptionsConfiguration{
  167. ListenAddresses: []string{"tcp://:23000"},
  168. GlobalAnnServers: []string{"udp4://syncthing.nym.se:22026"},
  169. GlobalAnnEnabled: false,
  170. LocalAnnEnabled: false,
  171. LocalAnnPort: 42123,
  172. LocalAnnMCAddr: "quux:3232",
  173. MaxSendKbps: 1234,
  174. MaxRecvKbps: 2341,
  175. ReconnectIntervalS: 6000,
  176. RelaysEnabled: false,
  177. RelayReconnectIntervalM: 20,
  178. StartBrowser: false,
  179. NATEnabled: false,
  180. NATLeaseM: 90,
  181. NATRenewalM: 15,
  182. NATTimeoutS: 15,
  183. RestartOnWakeup: false,
  184. AutoUpgradeIntervalH: 24,
  185. KeepTemporariesH: 48,
  186. CacheIgnoredFiles: true,
  187. ProgressUpdateIntervalS: 10,
  188. LimitBandwidthInLan: true,
  189. MinHomeDiskFree: Size{5.2, "%"},
  190. URSeen: 2,
  191. URURL: "https://localhost/newdata",
  192. URInitialDelayS: 800,
  193. URPostInsecurely: true,
  194. ReleasesURL: "https://localhost/releases",
  195. AlwaysLocalNets: []string{},
  196. OverwriteRemoteDevNames: true,
  197. TempIndexMinBlocks: 100,
  198. UnackedNotificationIDs: []string{
  199. "channelNotification", // added in 17->18 migration
  200. },
  201. WeakHashSelectionMethod: WeakHashNever,
  202. StunKeepaliveS: 10,
  203. StunServers: []string{"a.stun.com", "b.stun.com"},
  204. KCPCongestionControl: false,
  205. KCPReceiveWindowSize: 1280,
  206. KCPSendWindowSize: 1280,
  207. KCPUpdateIntervalMs: 1000,
  208. KCPFastResend: true,
  209. DefaultFolderPath: "/media/syncthing",
  210. SetLowPriority: false,
  211. }
  212. os.Unsetenv("STNOUPGRADE")
  213. cfg, err := Load("testdata/overridenvalues.xml", device1)
  214. if err != nil {
  215. t.Error(err)
  216. }
  217. if diff, equal := messagediff.PrettyDiff(expected, cfg.Options()); !equal {
  218. t.Errorf("Overridden config differs. Diff:\n%s", diff)
  219. }
  220. }
  221. func TestDeviceAddressesDynamic(t *testing.T) {
  222. name, _ := os.Hostname()
  223. expected := map[protocol.DeviceID]DeviceConfiguration{
  224. device1: {
  225. DeviceID: device1,
  226. Addresses: []string{"dynamic"},
  227. AllowedNetworks: []string{},
  228. },
  229. device2: {
  230. DeviceID: device2,
  231. Addresses: []string{"dynamic"},
  232. AllowedNetworks: []string{},
  233. },
  234. device3: {
  235. DeviceID: device3,
  236. Addresses: []string{"dynamic"},
  237. AllowedNetworks: []string{},
  238. },
  239. device4: {
  240. DeviceID: device4,
  241. Name: name, // Set when auto created
  242. Addresses: []string{"dynamic"},
  243. Compression: protocol.CompressMetadata,
  244. AllowedNetworks: []string{},
  245. },
  246. }
  247. cfg, err := Load("testdata/deviceaddressesdynamic.xml", device4)
  248. if err != nil {
  249. t.Error(err)
  250. }
  251. actual := cfg.Devices()
  252. if diff, equal := messagediff.PrettyDiff(expected, actual); !equal {
  253. t.Errorf("Devices differ. Diff:\n%s", diff)
  254. }
  255. }
  256. func TestDeviceCompression(t *testing.T) {
  257. name, _ := os.Hostname()
  258. expected := map[protocol.DeviceID]DeviceConfiguration{
  259. device1: {
  260. DeviceID: device1,
  261. Addresses: []string{"dynamic"},
  262. Compression: protocol.CompressMetadata,
  263. AllowedNetworks: []string{},
  264. },
  265. device2: {
  266. DeviceID: device2,
  267. Addresses: []string{"dynamic"},
  268. Compression: protocol.CompressMetadata,
  269. AllowedNetworks: []string{},
  270. },
  271. device3: {
  272. DeviceID: device3,
  273. Addresses: []string{"dynamic"},
  274. Compression: protocol.CompressNever,
  275. AllowedNetworks: []string{},
  276. },
  277. device4: {
  278. DeviceID: device4,
  279. Name: name, // Set when auto created
  280. Addresses: []string{"dynamic"},
  281. Compression: protocol.CompressMetadata,
  282. AllowedNetworks: []string{},
  283. },
  284. }
  285. cfg, err := Load("testdata/devicecompression.xml", device4)
  286. if err != nil {
  287. t.Error(err)
  288. }
  289. actual := cfg.Devices()
  290. if diff, equal := messagediff.PrettyDiff(expected, actual); !equal {
  291. t.Errorf("Devices differ. Diff:\n%s", diff)
  292. }
  293. }
  294. func TestDeviceAddressesStatic(t *testing.T) {
  295. name, _ := os.Hostname()
  296. expected := map[protocol.DeviceID]DeviceConfiguration{
  297. device1: {
  298. DeviceID: device1,
  299. Addresses: []string{"tcp://192.0.2.1", "tcp://192.0.2.2"},
  300. AllowedNetworks: []string{},
  301. },
  302. device2: {
  303. DeviceID: device2,
  304. Addresses: []string{"tcp://192.0.2.3:6070", "tcp://[2001:db8::42]:4242"},
  305. AllowedNetworks: []string{},
  306. },
  307. device3: {
  308. DeviceID: device3,
  309. Addresses: []string{"tcp://[2001:db8::44]:4444", "tcp://192.0.2.4:6090"},
  310. AllowedNetworks: []string{},
  311. },
  312. device4: {
  313. DeviceID: device4,
  314. Name: name, // Set when auto created
  315. Addresses: []string{"dynamic"},
  316. Compression: protocol.CompressMetadata,
  317. AllowedNetworks: []string{},
  318. },
  319. }
  320. cfg, err := Load("testdata/deviceaddressesstatic.xml", device4)
  321. if err != nil {
  322. t.Error(err)
  323. }
  324. actual := cfg.Devices()
  325. if diff, equal := messagediff.PrettyDiff(expected, actual); !equal {
  326. t.Errorf("Devices differ. Diff:\n%s", diff)
  327. }
  328. }
  329. func TestVersioningConfig(t *testing.T) {
  330. cfg, err := Load("testdata/versioningconfig.xml", device4)
  331. if err != nil {
  332. t.Error(err)
  333. }
  334. vc := cfg.Folders()["test"].Versioning
  335. if vc.Type != "simple" {
  336. t.Errorf(`vc.Type %q != "simple"`, vc.Type)
  337. }
  338. if l := len(vc.Params); l != 2 {
  339. t.Errorf("len(vc.Params) %d != 2", l)
  340. }
  341. expected := map[string]string{
  342. "foo": "bar",
  343. "baz": "quux",
  344. }
  345. if diff, equal := messagediff.PrettyDiff(expected, vc.Params); !equal {
  346. t.Errorf("vc.Params differ. Diff:\n%s", diff)
  347. }
  348. }
  349. func TestIssue1262(t *testing.T) {
  350. if runtime.GOOS != "windows" {
  351. t.Skipf("path gets converted to absolute as part of the filesystem initialization on linux")
  352. }
  353. cfg, err := Load("testdata/issue-1262.xml", device4)
  354. if err != nil {
  355. t.Fatal(err)
  356. }
  357. actual := cfg.Folders()["test"].Filesystem().URI()
  358. expected := `e:\`
  359. if actual != expected {
  360. t.Errorf("%q != %q", actual, expected)
  361. }
  362. }
  363. func TestIssue1750(t *testing.T) {
  364. cfg, err := Load("testdata/issue-1750.xml", device4)
  365. if err != nil {
  366. t.Fatal(err)
  367. }
  368. if cfg.Options().ListenAddresses[0] != "tcp://:23000" {
  369. t.Errorf("%q != %q", cfg.Options().ListenAddresses[0], "tcp://:23000")
  370. }
  371. if cfg.Options().ListenAddresses[1] != "tcp://:23001" {
  372. t.Errorf("%q != %q", cfg.Options().ListenAddresses[1], "tcp://:23001")
  373. }
  374. if cfg.Options().GlobalAnnServers[0] != "udp4://syncthing.nym.se:22026" {
  375. t.Errorf("%q != %q", cfg.Options().GlobalAnnServers[0], "udp4://syncthing.nym.se:22026")
  376. }
  377. if cfg.Options().GlobalAnnServers[1] != "udp4://syncthing.nym.se:22027" {
  378. t.Errorf("%q != %q", cfg.Options().GlobalAnnServers[1], "udp4://syncthing.nym.se:22027")
  379. }
  380. }
  381. func TestFolderPath(t *testing.T) {
  382. folder := FolderConfiguration{
  383. Path: "~/tmp",
  384. }
  385. realPath := folder.Filesystem().URI()
  386. if !filepath.IsAbs(realPath) {
  387. t.Error(realPath, "should be absolute")
  388. }
  389. if strings.Contains(realPath, "~") {
  390. t.Error(realPath, "should not contain ~")
  391. }
  392. }
  393. func TestFolderCheckPath(t *testing.T) {
  394. n, err := ioutil.TempDir("", "")
  395. if err != nil {
  396. t.Fatal(err)
  397. }
  398. err = os.MkdirAll(filepath.Join(n, "dir", ".stfolder"), os.FileMode(0777))
  399. if err != nil {
  400. t.Fatal(err)
  401. }
  402. testcases := []struct {
  403. path string
  404. err error
  405. }{
  406. {
  407. path: "",
  408. err: errMarkerMissing,
  409. },
  410. {
  411. path: "does not exist",
  412. err: errPathMissing,
  413. },
  414. {
  415. path: "dir",
  416. err: nil,
  417. },
  418. }
  419. err = osutil.DebugSymlinkForTestsOnly(filepath.Join(n, "dir"), filepath.Join(n, "link"))
  420. if err == nil {
  421. t.Log("running with symlink check")
  422. testcases = append(testcases, struct {
  423. path string
  424. err error
  425. }{
  426. path: "link",
  427. err: nil,
  428. })
  429. } else if runtime.GOOS != "windows" {
  430. t.Log("running without symlink check")
  431. t.Fatal(err)
  432. }
  433. for _, testcase := range testcases {
  434. cfg := FolderConfiguration{
  435. Path: filepath.Join(n, testcase.path),
  436. MarkerName: DefaultMarkerName,
  437. }
  438. if err := cfg.CheckPath(); testcase.err != err {
  439. t.Errorf("unexpected error in case %s: %s != %s", testcase.path, err, testcase.err)
  440. }
  441. }
  442. }
  443. func TestNewSaveLoad(t *testing.T) {
  444. path := "testdata/temp.xml"
  445. os.Remove(path)
  446. exists := func(path string) bool {
  447. _, err := os.Stat(path)
  448. return err == nil
  449. }
  450. intCfg := New(device1)
  451. cfg := Wrap(path, intCfg)
  452. // To make the equality pass later
  453. cfg.cfg.XMLName.Local = "configuration"
  454. if exists(path) {
  455. t.Error(path, "exists")
  456. }
  457. err := cfg.Save()
  458. if err != nil {
  459. t.Error(err)
  460. }
  461. if !exists(path) {
  462. t.Error(path, "does not exist")
  463. }
  464. cfg2, err := Load(path, device1)
  465. if err != nil {
  466. t.Error(err)
  467. }
  468. if diff, equal := messagediff.PrettyDiff(cfg.RawCopy(), cfg2.RawCopy()); !equal {
  469. t.Errorf("Configs are not equal. Diff:\n%s", diff)
  470. }
  471. os.Remove(path)
  472. }
  473. func TestPrepare(t *testing.T) {
  474. var cfg Configuration
  475. if cfg.Folders != nil || cfg.Devices != nil || cfg.Options.ListenAddresses != nil {
  476. t.Error("Expected nil")
  477. }
  478. cfg.prepare(device1)
  479. if cfg.Folders == nil || cfg.Devices == nil || cfg.Options.ListenAddresses == nil {
  480. t.Error("Unexpected nil")
  481. }
  482. }
  483. func TestCopy(t *testing.T) {
  484. wrapper, err := Load("testdata/example.xml", device1)
  485. if err != nil {
  486. t.Fatal(err)
  487. }
  488. cfg := wrapper.RawCopy()
  489. bsOrig, err := json.MarshalIndent(cfg, "", " ")
  490. if err != nil {
  491. t.Fatal(err)
  492. }
  493. copy := cfg.Copy()
  494. cfg.Devices[0].Addresses[0] = "wrong"
  495. cfg.Folders[0].Devices[0].DeviceID = protocol.DeviceID{0, 1, 2, 3}
  496. cfg.Options.ListenAddresses[0] = "wrong"
  497. cfg.GUI.APIKey = "wrong"
  498. bsChanged, err := json.MarshalIndent(cfg, "", " ")
  499. if err != nil {
  500. t.Fatal(err)
  501. }
  502. bsCopy, err := json.MarshalIndent(copy, "", " ")
  503. if err != nil {
  504. t.Fatal(err)
  505. }
  506. if bytes.Equal(bsOrig, bsChanged) {
  507. t.Error("Config should have changed")
  508. }
  509. if !bytes.Equal(bsOrig, bsCopy) {
  510. //ioutil.WriteFile("a", bsOrig, 0644)
  511. //ioutil.WriteFile("b", bsCopy, 0644)
  512. t.Error("Copy should be unchanged")
  513. }
  514. }
  515. func TestPullOrder(t *testing.T) {
  516. wrapper, err := Load("testdata/pullorder.xml", device1)
  517. if err != nil {
  518. t.Fatal(err)
  519. }
  520. folders := wrapper.Folders()
  521. expected := []struct {
  522. name string
  523. order PullOrder
  524. }{
  525. {"f1", OrderRandom}, // empty value, default
  526. {"f2", OrderRandom}, // explicit
  527. {"f3", OrderAlphabetic}, // explicit
  528. {"f4", OrderRandom}, // unknown value, default
  529. {"f5", OrderSmallestFirst}, // explicit
  530. {"f6", OrderLargestFirst}, // explicit
  531. {"f7", OrderOldestFirst}, // explicit
  532. {"f8", OrderNewestFirst}, // explicit
  533. }
  534. // Verify values are deserialized correctly
  535. for _, tc := range expected {
  536. if actual := folders[tc.name].Order; actual != tc.order {
  537. t.Errorf("Incorrect pull order for %q: %v != %v", tc.name, actual, tc.order)
  538. }
  539. }
  540. // Serialize and deserialize again to verify it survives the transformation
  541. buf := new(bytes.Buffer)
  542. cfg := wrapper.RawCopy()
  543. cfg.WriteXML(buf)
  544. t.Logf("%s", buf.Bytes())
  545. cfg, err = ReadXML(buf, device1)
  546. if err != nil {
  547. t.Fatal(err)
  548. }
  549. wrapper = Wrap("testdata/pullorder.xml", cfg)
  550. folders = wrapper.Folders()
  551. for _, tc := range expected {
  552. if actual := folders[tc.name].Order; actual != tc.order {
  553. t.Errorf("Incorrect pull order for %q: %v != %v", tc.name, actual, tc.order)
  554. }
  555. }
  556. }
  557. func TestLargeRescanInterval(t *testing.T) {
  558. wrapper, err := Load("testdata/largeinterval.xml", device1)
  559. if err != nil {
  560. t.Fatal(err)
  561. }
  562. if wrapper.Folders()["l1"].RescanIntervalS != MaxRescanIntervalS {
  563. t.Error("too large rescan interval should be maxed out")
  564. }
  565. if wrapper.Folders()["l2"].RescanIntervalS != 0 {
  566. t.Error("negative rescan interval should become zero")
  567. }
  568. }
  569. func TestGUIConfigURL(t *testing.T) {
  570. testcases := [][2]string{
  571. {"192.0.2.42:8080", "http://192.0.2.42:8080/"},
  572. {":8080", "http://127.0.0.1:8080/"},
  573. {"0.0.0.0:8080", "http://127.0.0.1:8080/"},
  574. {"127.0.0.1:8080", "http://127.0.0.1:8080/"},
  575. {"127.0.0.2:8080", "http://127.0.0.2:8080/"},
  576. {"[::]:8080", "http://[::1]:8080/"},
  577. {"[2001::42]:8080", "http://[2001::42]:8080/"},
  578. }
  579. for _, tc := range testcases {
  580. c := GUIConfiguration{
  581. RawAddress: tc[0],
  582. }
  583. u := c.URL()
  584. if u != tc[1] {
  585. t.Errorf("Incorrect URL %s != %s for addr %s", u, tc[1], tc[0])
  586. }
  587. }
  588. }
  589. func TestDuplicateDevices(t *testing.T) {
  590. // Duplicate devices should be removed
  591. wrapper, err := Load("testdata/dupdevices.xml", device1)
  592. if err != nil {
  593. t.Fatal(err)
  594. }
  595. if l := len(wrapper.RawCopy().Devices); l != 3 {
  596. t.Errorf("Incorrect number of devices, %d != 3", l)
  597. }
  598. f := wrapper.Folders()["f2"]
  599. if l := len(f.Devices); l != 2 {
  600. t.Errorf("Incorrect number of folder devices, %d != 2", l)
  601. }
  602. }
  603. func TestDuplicateFolders(t *testing.T) {
  604. // Duplicate folders are a loading error
  605. _, err := Load("testdata/dupfolders.xml", device1)
  606. if err == nil || !strings.HasPrefix(err.Error(), "duplicate folder ID") {
  607. t.Fatal(`Expected error to mention "duplicate folder ID":`, err)
  608. }
  609. }
  610. func TestEmptyFolderPaths(t *testing.T) {
  611. // Empty folder paths are allowed at the loading stage, and should not
  612. // get messed up by the prepare steps (e.g., become the current dir or
  613. // get a slash added so that it becomes the root directory or similar).
  614. wrapper, err := Load("testdata/nopath.xml", device1)
  615. if err != nil {
  616. t.Fatal(err)
  617. }
  618. folder := wrapper.Folders()["f1"]
  619. if folder.cachedFilesystem != nil {
  620. t.Errorf("Expected %q to be empty", folder.cachedFilesystem)
  621. }
  622. }
  623. func TestV14ListenAddressesMigration(t *testing.T) {
  624. tcs := [][3][]string{
  625. // Default listen plus default relays is now "default"
  626. {
  627. {"tcp://0.0.0.0:22000"},
  628. {"dynamic+https://relays.syncthing.net/endpoint"},
  629. {"default"},
  630. },
  631. // Default listen address without any relay addresses gets converted
  632. // to just the listen address. It's easier this way, and frankly the
  633. // user has gone to some trouble to get the empty string in the
  634. // config to start with...
  635. {
  636. {"tcp://0.0.0.0:22000"}, // old listen addrs
  637. {""}, // old relay addrs
  638. {"tcp://0.0.0.0:22000"}, // new listen addrs
  639. },
  640. // Default listen plus non-default relays gets copied verbatim
  641. {
  642. {"tcp://0.0.0.0:22000"},
  643. {"dynamic+https://other.example.com"},
  644. {"tcp://0.0.0.0:22000", "dynamic+https://other.example.com"},
  645. },
  646. // Non-default listen plus default relays gets copied verbatim
  647. {
  648. {"tcp://1.2.3.4:22000"},
  649. {"dynamic+https://relays.syncthing.net/endpoint"},
  650. {"tcp://1.2.3.4:22000", "dynamic+https://relays.syncthing.net/endpoint"},
  651. },
  652. // Default stuff gets sucked into "default", the rest gets copied
  653. {
  654. {"tcp://0.0.0.0:22000", "tcp://1.2.3.4:22000"},
  655. {"dynamic+https://relays.syncthing.net/endpoint", "relay://other.example.com"},
  656. {"default", "tcp://1.2.3.4:22000", "relay://other.example.com"},
  657. },
  658. }
  659. for _, tc := range tcs {
  660. cfg := Configuration{
  661. Version: 13,
  662. Options: OptionsConfiguration{
  663. ListenAddresses: tc[0],
  664. DeprecatedRelayServers: tc[1],
  665. },
  666. }
  667. convertV13V14(&cfg)
  668. if cfg.Version != 14 {
  669. t.Error("Configuration was not converted")
  670. }
  671. sort.Strings(tc[2])
  672. if !reflect.DeepEqual(cfg.Options.ListenAddresses, tc[2]) {
  673. t.Errorf("Migration error; actual %#v != expected %#v", cfg.Options.ListenAddresses, tc[2])
  674. }
  675. }
  676. }
  677. func TestIgnoredDevices(t *testing.T) {
  678. // Verify that ignored devices that are also present in the
  679. // configuration are not in fact ignored.
  680. wrapper, err := Load("testdata/ignoreddevices.xml", device1)
  681. if err != nil {
  682. t.Fatal(err)
  683. }
  684. if wrapper.IgnoredDevice(device1) {
  685. t.Errorf("Device %v should not be ignored", device1)
  686. }
  687. if !wrapper.IgnoredDevice(device3) {
  688. t.Errorf("Device %v should be ignored", device3)
  689. }
  690. }
  691. func TestGetDevice(t *testing.T) {
  692. // Verify that the Device() call does the right thing
  693. wrapper, err := Load("testdata/ignoreddevices.xml", device1)
  694. if err != nil {
  695. t.Fatal(err)
  696. }
  697. // device1 is mentioned in the config
  698. device, ok := wrapper.Device(device1)
  699. if !ok {
  700. t.Error(device1, "should exist")
  701. }
  702. if device.DeviceID != device1 {
  703. t.Error("Should have returned", device1, "not", device.DeviceID)
  704. }
  705. // device3 is not
  706. device, ok = wrapper.Device(device3)
  707. if ok {
  708. t.Error(device3, "should not exist")
  709. }
  710. if device.DeviceID == device3 {
  711. t.Error("Should not returned ID", device3)
  712. }
  713. }
  714. func TestSharesRemovedOnDeviceRemoval(t *testing.T) {
  715. wrapper, err := Load("testdata/example.xml", device1)
  716. if err != nil {
  717. t.Errorf("Failed: %s", err)
  718. }
  719. raw := wrapper.RawCopy()
  720. raw.Devices = raw.Devices[:len(raw.Devices)-1]
  721. if len(raw.Folders[0].Devices) <= len(raw.Devices) {
  722. t.Error("Should have less devices")
  723. }
  724. _, err = wrapper.Replace(raw)
  725. if err != nil {
  726. t.Errorf("Failed: %s", err)
  727. }
  728. raw = wrapper.RawCopy()
  729. if len(raw.Folders[0].Devices) > len(raw.Devices) {
  730. t.Error("Unexpected extra device")
  731. }
  732. }
  733. func TestIssue4219(t *testing.T) {
  734. // Adding a folder that was previously ignored should make it unignored.
  735. r := bytes.NewReader([]byte(`{
  736. "folders": [
  737. {"id": "abcd123"}
  738. ],
  739. "ignoredFolders": ["t1", "abcd123", "t2"]
  740. }`))
  741. cfg, err := ReadJSON(r, protocol.LocalDeviceID)
  742. if err != nil {
  743. t.Fatal(err)
  744. }
  745. if len(cfg.IgnoredFolders) != 2 {
  746. t.Errorf("There should be two ignored folders, not %d", len(cfg.IgnoredFolders))
  747. }
  748. w := Wrap("/tmp/cfg", cfg)
  749. if !w.IgnoredFolder("t1") {
  750. t.Error("Folder t1 should be ignored")
  751. }
  752. if !w.IgnoredFolder("t2") {
  753. t.Error("Folder t2 should be ignored")
  754. }
  755. if w.IgnoredFolder("abcd123") {
  756. t.Error("Folder abcd123 should not be ignored")
  757. }
  758. }