protocol_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. // Copyright (C) 2014 The Protocol Authors.
  2. package protocol
  3. import (
  4. "bytes"
  5. "crypto/sha256"
  6. "encoding/hex"
  7. "encoding/json"
  8. "errors"
  9. "io"
  10. "io/ioutil"
  11. "runtime"
  12. "strings"
  13. "testing"
  14. "testing/quick"
  15. "github.com/syncthing/syncthing/lib/rand"
  16. )
  17. var (
  18. c0ID = NewDeviceID([]byte{1})
  19. c1ID = NewDeviceID([]byte{2})
  20. quickCfg = &quick.Config{}
  21. )
  22. func TestPing(t *testing.T) {
  23. ar, aw := io.Pipe()
  24. br, bw := io.Pipe()
  25. c0 := NewConnection(c0ID, ar, bw, newTestModel(), "name", CompressAlways).(wireFormatConnection).Connection.(*rawConnection)
  26. c0.Start()
  27. c1 := NewConnection(c1ID, br, aw, newTestModel(), "name", CompressAlways).(wireFormatConnection).Connection.(*rawConnection)
  28. c1.Start()
  29. c0.ClusterConfig(ClusterConfig{})
  30. c1.ClusterConfig(ClusterConfig{})
  31. if ok := c0.ping(); !ok {
  32. t.Error("c0 ping failed")
  33. }
  34. if ok := c1.ping(); !ok {
  35. t.Error("c1 ping failed")
  36. }
  37. }
  38. func TestClose(t *testing.T) {
  39. m0 := newTestModel()
  40. m1 := newTestModel()
  41. ar, aw := io.Pipe()
  42. br, bw := io.Pipe()
  43. c0 := NewConnection(c0ID, ar, bw, m0, "name", CompressAlways).(wireFormatConnection).Connection.(*rawConnection)
  44. c0.Start()
  45. c1 := NewConnection(c1ID, br, aw, m1, "name", CompressAlways)
  46. c1.Start()
  47. c0.ClusterConfig(ClusterConfig{})
  48. c1.ClusterConfig(ClusterConfig{})
  49. c0.internalClose(errors.New("manual close"))
  50. <-c0.closed
  51. if err := m0.closedError(); err == nil || !strings.Contains(err.Error(), "manual close") {
  52. t.Fatal("Connection should be closed")
  53. }
  54. // None of these should panic, some should return an error
  55. if c0.ping() {
  56. t.Error("Ping should not return true")
  57. }
  58. c0.Index("default", nil)
  59. c0.Index("default", nil)
  60. if _, err := c0.Request("default", "foo", 0, 0, nil, 0, false); err == nil {
  61. t.Error("Request should return an error")
  62. }
  63. }
  64. func TestMarshalIndexMessage(t *testing.T) {
  65. if testing.Short() {
  66. quickCfg.MaxCount = 10
  67. }
  68. f := func(m1 Index) bool {
  69. if len(m1.Files) == 0 {
  70. m1.Files = nil
  71. }
  72. for i, f := range m1.Files {
  73. if len(f.Blocks) == 0 {
  74. m1.Files[i].Blocks = nil
  75. } else {
  76. for j := range f.Blocks {
  77. f.Blocks[j].Offset = 0
  78. if len(f.Blocks[j].Hash) == 0 {
  79. f.Blocks[j].Hash = nil
  80. }
  81. }
  82. }
  83. if len(f.Version.Counters) == 0 {
  84. m1.Files[i].Version.Counters = nil
  85. }
  86. }
  87. return testMarshal(t, "index", &m1, &Index{})
  88. }
  89. if err := quick.Check(f, quickCfg); err != nil {
  90. t.Error(err)
  91. }
  92. }
  93. func TestMarshalRequestMessage(t *testing.T) {
  94. if testing.Short() {
  95. quickCfg.MaxCount = 10
  96. }
  97. f := func(m1 Request) bool {
  98. if len(m1.Hash) == 0 {
  99. m1.Hash = nil
  100. }
  101. return testMarshal(t, "request", &m1, &Request{})
  102. }
  103. if err := quick.Check(f, quickCfg); err != nil {
  104. t.Error(err)
  105. }
  106. }
  107. func TestMarshalResponseMessage(t *testing.T) {
  108. if testing.Short() {
  109. quickCfg.MaxCount = 10
  110. }
  111. f := func(m1 Response) bool {
  112. if len(m1.Data) == 0 {
  113. m1.Data = nil
  114. }
  115. return testMarshal(t, "response", &m1, &Response{})
  116. }
  117. if err := quick.Check(f, quickCfg); err != nil {
  118. t.Error(err)
  119. }
  120. }
  121. func TestMarshalClusterConfigMessage(t *testing.T) {
  122. if testing.Short() {
  123. quickCfg.MaxCount = 10
  124. }
  125. f := func(m1 ClusterConfig) bool {
  126. if len(m1.Folders) == 0 {
  127. m1.Folders = nil
  128. }
  129. for i := range m1.Folders {
  130. if len(m1.Folders[i].Devices) == 0 {
  131. m1.Folders[i].Devices = nil
  132. }
  133. }
  134. return testMarshal(t, "clusterconfig", &m1, &ClusterConfig{})
  135. }
  136. if err := quick.Check(f, quickCfg); err != nil {
  137. t.Error(err)
  138. }
  139. }
  140. func TestMarshalCloseMessage(t *testing.T) {
  141. if testing.Short() {
  142. quickCfg.MaxCount = 10
  143. }
  144. f := func(m1 Close) bool {
  145. return testMarshal(t, "close", &m1, &Close{})
  146. }
  147. if err := quick.Check(f, quickCfg); err != nil {
  148. t.Error(err)
  149. }
  150. }
  151. func TestMarshalFDPU(t *testing.T) {
  152. if testing.Short() {
  153. quickCfg.MaxCount = 10
  154. }
  155. f := func(m1 FileDownloadProgressUpdate) bool {
  156. if len(m1.Version.Counters) == 0 {
  157. m1.Version.Counters = nil
  158. }
  159. return testMarshal(t, "close", &m1, &FileDownloadProgressUpdate{})
  160. }
  161. if err := quick.Check(f, quickCfg); err != nil {
  162. t.Error(err)
  163. }
  164. }
  165. func TestUnmarshalFDPUv16v17(t *testing.T) {
  166. var fdpu FileDownloadProgressUpdate
  167. m0, _ := hex.DecodeString("08cda1e2e3011278f3918787f3b89b8af2958887f0aa9389f3a08588f3aa8f96f39aa8a5f48b9188f19286a0f3848da4f3aba799f3beb489f0a285b9f487b684f2a3bda2f48598b4f2938a89f2a28badf187a0a2f2aebdbdf4849494f4808fbbf2b3a2adf2bb95bff0a6ada4f198ab9af29a9c8bf1abb793f3baabb2f188a6ba1a0020bb9390f60220f6d9e42220b0c7e2b2fdffffffff0120fdb2dfcdfbffffffff0120cedab1d50120bd8784c0feffffffff0120ace99591fdffffffff0120eed7d09af9ffffffff01")
  168. if err := fdpu.Unmarshal(m0); err != nil {
  169. t.Fatal("Unmarshalling message from v0.14.16:", err)
  170. }
  171. m1, _ := hex.DecodeString("0880f1969905128401f099b192f0abb1b9f3b280aff19e9aa2f3b89e84f484b39df1a7a6b0f1aea4b1f0adac94f3b39caaf1939281f1928a8af0abb1b0f0a8b3b3f3a88e94f2bd85acf29c97a9f2969da6f0b7a188f1908ea2f09a9c9bf19d86a6f29aada8f389bb95f0bf9d88f1a09d89f1b1a4b5f29b9eabf298a59df1b2a589f2979ebdf0b69880f18986b21a440a1508c7d8fb8897ca93d90910e8c4d8e8f2f8f0ccee010a1508afa8ffd8c085b393c50110e5bdedc3bddefe9b0b0a1408a1bedddba4cac5da3c10b8e5d9958ca7e3ec19225ae2f88cb2f8ffffffff018ceda99cfbffffffff01b9c298a407e295e8e9fcffffffff01f3b9ade5fcffffffff01c08bfea9fdffffffff01a2c2e5e1ffffffffff0186dcc5dafdffffffff01e9ffc7e507c9d89db8fdffffffff01")
  172. if err := fdpu.Unmarshal(m1); err != nil {
  173. t.Fatal("Unmarshalling message from v0.14.16:", err)
  174. }
  175. }
  176. func testMarshal(t *testing.T, prefix string, m1, m2 message) bool {
  177. buf, err := m1.Marshal()
  178. if err != nil {
  179. t.Fatal(err)
  180. }
  181. err = m2.Unmarshal(buf)
  182. if err != nil {
  183. t.Fatal(err)
  184. }
  185. bs1, _ := json.MarshalIndent(m1, "", " ")
  186. bs2, _ := json.MarshalIndent(m2, "", " ")
  187. if !bytes.Equal(bs1, bs2) {
  188. ioutil.WriteFile(prefix+"-1.txt", bs1, 0644)
  189. ioutil.WriteFile(prefix+"-2.txt", bs2, 0644)
  190. return false
  191. }
  192. return true
  193. }
  194. func TestLZ4Compression(t *testing.T) {
  195. c := new(rawConnection)
  196. for i := 0; i < 10; i++ {
  197. dataLen := 150 + rand.Intn(150)
  198. data := make([]byte, dataLen)
  199. _, err := io.ReadFull(rand.Reader, data[100:])
  200. if err != nil {
  201. t.Fatal(err)
  202. }
  203. comp, err := c.lz4Compress(data)
  204. if err != nil {
  205. t.Errorf("compressing %d bytes: %v", dataLen, err)
  206. continue
  207. }
  208. res, err := c.lz4Decompress(comp)
  209. if err != nil {
  210. t.Errorf("decompressing %d bytes to %d: %v", len(comp), dataLen, err)
  211. continue
  212. }
  213. if len(res) != len(data) {
  214. t.Errorf("Incorrect len %d != expected %d", len(res), len(data))
  215. }
  216. if !bytes.Equal(data, res) {
  217. t.Error("Incorrect decompressed data")
  218. }
  219. t.Logf("OK #%d, %d -> %d -> %d", i, dataLen, len(comp), dataLen)
  220. }
  221. }
  222. func TestCheckFilename(t *testing.T) {
  223. cases := []struct {
  224. name string
  225. ok bool
  226. }{
  227. // Valid filenames
  228. {"foo", true},
  229. {"foo/bar/baz", true},
  230. {"foo/bar:baz", true}, // colon is ok in general, will be filtered on windows
  231. {`\`, true}, // path separator on the wire is forward slash, so as above
  232. {`\.`, true},
  233. {`\..`, true},
  234. {".foo", true},
  235. {"foo..", true},
  236. // Invalid filenames
  237. {"foo/..", false},
  238. {"foo/../bar", false},
  239. {"../foo/../bar", false},
  240. {"", false},
  241. {".", false},
  242. {"..", false},
  243. {"/", false},
  244. {"/.", false},
  245. {"/..", false},
  246. {"/foo", false},
  247. {"./foo", false},
  248. {"foo./", false},
  249. {"foo/.", false},
  250. {"foo/", false},
  251. }
  252. for _, tc := range cases {
  253. err := checkFilename(tc.name)
  254. if (err == nil) != tc.ok {
  255. t.Errorf("Unexpected result for checkFilename(%q): %v", tc.name, err)
  256. }
  257. }
  258. }
  259. func TestCheckConsistency(t *testing.T) {
  260. cases := []struct {
  261. fi FileInfo
  262. ok bool
  263. }{
  264. {
  265. // valid
  266. fi: FileInfo{
  267. Name: "foo",
  268. Type: FileInfoTypeFile,
  269. Blocks: []BlockInfo{{Size: 1234, Offset: 0, Hash: []byte{1, 2, 3, 4}}},
  270. },
  271. ok: true,
  272. },
  273. {
  274. // deleted with blocks
  275. fi: FileInfo{
  276. Name: "foo",
  277. Deleted: true,
  278. Type: FileInfoTypeFile,
  279. Blocks: []BlockInfo{{Size: 1234, Offset: 0, Hash: []byte{1, 2, 3, 4}}},
  280. },
  281. ok: false,
  282. },
  283. {
  284. // no blocks
  285. fi: FileInfo{
  286. Name: "foo",
  287. Type: FileInfoTypeFile,
  288. },
  289. ok: false,
  290. },
  291. {
  292. // directory with blocks
  293. fi: FileInfo{
  294. Name: "foo",
  295. Type: FileInfoTypeDirectory,
  296. Blocks: []BlockInfo{{Size: 1234, Offset: 0, Hash: []byte{1, 2, 3, 4}}},
  297. },
  298. ok: false,
  299. },
  300. }
  301. for _, tc := range cases {
  302. err := checkFileInfoConsistency(tc.fi)
  303. if tc.ok && err != nil {
  304. t.Errorf("Unexpected error %v (want nil) for %v", err, tc.fi)
  305. }
  306. if !tc.ok && err == nil {
  307. t.Errorf("Unexpected nil error for %v", tc.fi)
  308. }
  309. }
  310. }
  311. func TestBlockSize(t *testing.T) {
  312. cases := []struct {
  313. fileSize int64
  314. blockSize int
  315. }{
  316. {1 << KiB, 128 << KiB},
  317. {1 << MiB, 128 << KiB},
  318. {499 << MiB, 256 << KiB},
  319. {500 << MiB, 512 << KiB},
  320. {501 << MiB, 512 << KiB},
  321. {1 << GiB, 1 << MiB},
  322. {2 << GiB, 2 << MiB},
  323. {3 << GiB, 2 << MiB},
  324. {500 << GiB, 16 << MiB},
  325. {50000 << GiB, 16 << MiB},
  326. }
  327. for _, tc := range cases {
  328. size := BlockSize(tc.fileSize)
  329. if size != tc.blockSize {
  330. t.Errorf("BlockSize(%d), size=%d, expected %d", tc.fileSize, size, tc.blockSize)
  331. }
  332. }
  333. }
  334. var blockSize int
  335. func BenchmarkBlockSize(b *testing.B) {
  336. for i := 0; i < b.N; i++ {
  337. blockSize = BlockSize(16 << 30)
  338. }
  339. }
  340. func TestLocalFlagBits(t *testing.T) {
  341. var f FileInfo
  342. if f.IsIgnored() || f.MustRescan() || f.IsInvalid() {
  343. t.Error("file should have no weird bits set by default")
  344. }
  345. f.SetIgnored(42)
  346. if !f.IsIgnored() || f.MustRescan() || !f.IsInvalid() {
  347. t.Error("file should be ignored and invalid")
  348. }
  349. f.SetMustRescan(42)
  350. if f.IsIgnored() || !f.MustRescan() || !f.IsInvalid() {
  351. t.Error("file should be must-rescan and invalid")
  352. }
  353. f.SetUnsupported(42)
  354. if f.IsIgnored() || f.MustRescan() || !f.IsInvalid() {
  355. t.Error("file should be invalid")
  356. }
  357. }
  358. func TestIsEquivalent(t *testing.T) {
  359. b := func(v bool) *bool {
  360. return &v
  361. }
  362. type testCase struct {
  363. a FileInfo
  364. b FileInfo
  365. ignPerms *bool // nil means should not matter, we'll test both variants
  366. ignBlocks *bool
  367. ignFlags uint32
  368. eq bool
  369. }
  370. cases := []testCase{
  371. // Empty FileInfos are equivalent
  372. {eq: true},
  373. // Various basic attributes, all of which cause ineqality when
  374. // they differ
  375. {
  376. a: FileInfo{Name: "foo"},
  377. b: FileInfo{Name: "bar"},
  378. eq: false,
  379. },
  380. {
  381. a: FileInfo{Type: FileInfoTypeFile},
  382. b: FileInfo{Type: FileInfoTypeDirectory},
  383. eq: false,
  384. },
  385. {
  386. a: FileInfo{Size: 1234},
  387. b: FileInfo{Size: 2345},
  388. eq: false,
  389. },
  390. {
  391. a: FileInfo{Deleted: false},
  392. b: FileInfo{Deleted: true},
  393. eq: false,
  394. },
  395. {
  396. a: FileInfo{RawInvalid: false},
  397. b: FileInfo{RawInvalid: true},
  398. eq: false,
  399. },
  400. {
  401. a: FileInfo{ModifiedS: 1234},
  402. b: FileInfo{ModifiedS: 2345},
  403. eq: false,
  404. },
  405. {
  406. a: FileInfo{ModifiedNs: 1234},
  407. b: FileInfo{ModifiedNs: 2345},
  408. eq: false,
  409. },
  410. // Special handling of local flags and invalidity. "MustRescan"
  411. // files are never equivalent to each other. Otherwise, equivalence
  412. // is based just on whether the file becomes IsInvalid() or not, not
  413. // the specific reason or flag bits.
  414. {
  415. a: FileInfo{LocalFlags: FlagLocalMustRescan},
  416. b: FileInfo{LocalFlags: FlagLocalMustRescan},
  417. eq: false,
  418. },
  419. {
  420. a: FileInfo{RawInvalid: true},
  421. b: FileInfo{RawInvalid: true},
  422. eq: true,
  423. },
  424. {
  425. a: FileInfo{LocalFlags: FlagLocalUnsupported},
  426. b: FileInfo{LocalFlags: FlagLocalUnsupported},
  427. eq: true,
  428. },
  429. {
  430. a: FileInfo{RawInvalid: true},
  431. b: FileInfo{LocalFlags: FlagLocalUnsupported},
  432. eq: true,
  433. },
  434. {
  435. a: FileInfo{LocalFlags: 0},
  436. b: FileInfo{LocalFlags: FlagLocalReceiveOnly},
  437. eq: false,
  438. },
  439. {
  440. a: FileInfo{LocalFlags: 0},
  441. b: FileInfo{LocalFlags: FlagLocalReceiveOnly},
  442. ignFlags: FlagLocalReceiveOnly,
  443. eq: true,
  444. },
  445. // Difference in blocks is not OK
  446. {
  447. a: FileInfo{Blocks: []BlockInfo{{Hash: []byte{1, 2, 3, 4}}}},
  448. b: FileInfo{Blocks: []BlockInfo{{Hash: []byte{2, 3, 4, 5}}}},
  449. ignBlocks: b(false),
  450. eq: false,
  451. },
  452. // ... unless we say it is
  453. {
  454. a: FileInfo{Blocks: []BlockInfo{{Hash: []byte{1, 2, 3, 4}}}},
  455. b: FileInfo{Blocks: []BlockInfo{{Hash: []byte{2, 3, 4, 5}}}},
  456. ignBlocks: b(true),
  457. eq: true,
  458. },
  459. // Difference in permissions is not OK.
  460. {
  461. a: FileInfo{Permissions: 0444},
  462. b: FileInfo{Permissions: 0666},
  463. ignPerms: b(false),
  464. eq: false,
  465. },
  466. // ... unless we say it is
  467. {
  468. a: FileInfo{Permissions: 0666},
  469. b: FileInfo{Permissions: 0444},
  470. ignPerms: b(true),
  471. eq: true,
  472. },
  473. // These attributes are not checked at all
  474. {
  475. a: FileInfo{NoPermissions: false},
  476. b: FileInfo{NoPermissions: true},
  477. eq: true,
  478. },
  479. {
  480. a: FileInfo{Version: Vector{Counters: []Counter{{ID: 1, Value: 42}}}},
  481. b: FileInfo{Version: Vector{Counters: []Counter{{ID: 42, Value: 1}}}},
  482. eq: true,
  483. },
  484. {
  485. a: FileInfo{Sequence: 1},
  486. b: FileInfo{Sequence: 2},
  487. eq: true,
  488. },
  489. // The block size is not checked (but this would fail the blocks
  490. // check in real world)
  491. {
  492. a: FileInfo{RawBlockSize: 1},
  493. b: FileInfo{RawBlockSize: 2},
  494. eq: true,
  495. },
  496. // The symlink target is checked for symlinks
  497. {
  498. a: FileInfo{Type: FileInfoTypeSymlink, SymlinkTarget: "a"},
  499. b: FileInfo{Type: FileInfoTypeSymlink, SymlinkTarget: "b"},
  500. eq: false,
  501. },
  502. // ... but not for non-symlinks
  503. {
  504. a: FileInfo{Type: FileInfoTypeFile, SymlinkTarget: "a"},
  505. b: FileInfo{Type: FileInfoTypeFile, SymlinkTarget: "b"},
  506. eq: true,
  507. },
  508. }
  509. if runtime.GOOS == "windows" {
  510. // On windows we only check the user writable bit of the permission
  511. // set, so these are equivalent.
  512. cases = append(cases, testCase{
  513. a: FileInfo{Permissions: 0777},
  514. b: FileInfo{Permissions: 0600},
  515. ignPerms: b(false),
  516. eq: true,
  517. })
  518. }
  519. for i, tc := range cases {
  520. // Check the standard attributes with all permutations of the
  521. // special ignore flags, unless the value of those flags are given
  522. // in the tests.
  523. for _, ignPerms := range []bool{true, false} {
  524. for _, ignBlocks := range []bool{true, false} {
  525. if tc.ignPerms != nil && *tc.ignPerms != ignPerms {
  526. continue
  527. }
  528. if tc.ignBlocks != nil && *tc.ignBlocks != ignBlocks {
  529. continue
  530. }
  531. if res := tc.a.isEquivalent(tc.b, ignPerms, ignBlocks, tc.ignFlags); res != tc.eq {
  532. t.Errorf("Case %d:\na: %v\nb: %v\na.IsEquivalent(b, %v, %v) => %v, expected %v", i, tc.a, tc.b, ignPerms, ignBlocks, res, tc.eq)
  533. }
  534. if res := tc.b.isEquivalent(tc.a, ignPerms, ignBlocks, tc.ignFlags); res != tc.eq {
  535. t.Errorf("Case %d:\na: %v\nb: %v\nb.IsEquivalent(a, %v, %v) => %v, expected %v", i, tc.a, tc.b, ignPerms, ignBlocks, res, tc.eq)
  536. }
  537. }
  538. }
  539. }
  540. }
  541. func TestSha256OfEmptyBlock(t *testing.T) {
  542. // every block size should have a correct entry in sha256OfEmptyBlock
  543. for blockSize := MinBlockSize; blockSize <= MaxBlockSize; blockSize *= 2 {
  544. expected := sha256.Sum256(make([]byte, blockSize))
  545. if sha256OfEmptyBlock[blockSize] != expected {
  546. t.Error("missing or wrong hash for block of size", blockSize)
  547. }
  548. }
  549. }