db_local_test.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright (C) 2025 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 sqlite
  7. import (
  8. "testing"
  9. "github.com/syncthing/syncthing/internal/itererr"
  10. "github.com/syncthing/syncthing/lib/protocol"
  11. )
  12. func TestBlocks(t *testing.T) {
  13. t.Parallel()
  14. db, err := Open(t.TempDir())
  15. if err != nil {
  16. t.Fatal()
  17. }
  18. t.Cleanup(func() {
  19. if err := db.Close(); err != nil {
  20. t.Fatal(err)
  21. }
  22. })
  23. files := []protocol.FileInfo{
  24. {
  25. Name: "file1",
  26. Blocks: []protocol.BlockInfo{
  27. {Hash: []byte{1, 2, 3}, Offset: 0, Size: 42},
  28. {Hash: []byte{2, 3, 4}, Offset: 42, Size: 42},
  29. {Hash: []byte{3, 4, 5}, Offset: 84, Size: 42},
  30. },
  31. },
  32. {
  33. Name: "file2",
  34. Blocks: []protocol.BlockInfo{
  35. {Hash: []byte{2, 3, 4}, Offset: 0, Size: 42},
  36. {Hash: []byte{3, 4, 5}, Offset: 42, Size: 42},
  37. {Hash: []byte{4, 5, 6}, Offset: 84, Size: 42},
  38. },
  39. },
  40. }
  41. if err := db.Update("test", protocol.LocalDeviceID, files); err != nil {
  42. t.Fatal(err)
  43. }
  44. // Search for blocks
  45. vals, err := itererr.Collect(db.AllLocalBlocksWithHash(folderID, []byte{1, 2, 3}))
  46. if err != nil {
  47. t.Fatal(err)
  48. }
  49. if len(vals) != 1 {
  50. t.Log(vals)
  51. t.Fatal("expected one hit")
  52. } else if vals[0].BlockIndex != 0 || vals[0].Offset != 0 || vals[0].Size != 42 {
  53. t.Log(vals[0])
  54. t.Fatal("bad entry")
  55. }
  56. if vals[0].FileName != "file1" {
  57. t.Fatal("should be file1")
  58. }
  59. // Get the other blocks
  60. vals, err = itererr.Collect(db.AllLocalBlocksWithHash(folderID, []byte{3, 4, 5}))
  61. if err != nil {
  62. t.Fatal(err)
  63. }
  64. if len(vals) != 2 {
  65. t.Log(vals)
  66. t.Fatal("expected two hits")
  67. }
  68. // if vals[0].Index != 2 || vals[0].Offset != 84 || vals[0].Size != 42 {
  69. // t.Log(vals[0])
  70. // t.Fatal("bad entry 1")
  71. // }
  72. // if vals[1].Index != 1 || vals[1].Offset != 42 || vals[1].Size != 42 {
  73. // t.Log(vals[1])
  74. // t.Fatal("bad entry 2")
  75. // }
  76. }
  77. func TestBlocksDeleted(t *testing.T) {
  78. t.Parallel()
  79. sdb, err := Open(t.TempDir())
  80. if err != nil {
  81. t.Fatal()
  82. }
  83. t.Cleanup(func() {
  84. if err := sdb.Close(); err != nil {
  85. t.Fatal(err)
  86. }
  87. })
  88. // Insert a file
  89. file := genFile("foo", 1, 0)
  90. if err := sdb.Update(folderID, protocol.LocalDeviceID, []protocol.FileInfo{file}); err != nil {
  91. t.Fatal()
  92. }
  93. // We should find one entry for the block hash
  94. search := file.Blocks[0].Hash
  95. es, err := itererr.Collect(sdb.AllLocalBlocksWithHash(folderID, search))
  96. if err != nil {
  97. t.Fatal(err)
  98. }
  99. if len(es) != 1 {
  100. t.Fatal("expected one hit")
  101. }
  102. // Update the file with a new block hash
  103. file.Blocks = genBlocks("foo", 42, 1)
  104. if err := sdb.Update(folderID, protocol.LocalDeviceID, []protocol.FileInfo{file}); err != nil {
  105. t.Fatal()
  106. }
  107. // Searching for the old hash should yield no hits
  108. if hits, err := itererr.Collect(sdb.AllLocalBlocksWithHash(folderID, search)); err != nil {
  109. t.Fatal(err)
  110. } else if len(hits) != 0 {
  111. t.Log(hits)
  112. t.Error("expected no hits")
  113. }
  114. // Searching for the new hash should yield one hits
  115. if hits, err := itererr.Collect(sdb.AllLocalBlocksWithHash(folderID, file.Blocks[0].Hash)); err != nil {
  116. t.Fatal(err)
  117. } else if len(hits) != 1 {
  118. t.Log(hits)
  119. t.Error("expected one hit")
  120. }
  121. }
  122. func TestRemoteSequence(t *testing.T) {
  123. t.Parallel()
  124. sdb, err := Open(t.TempDir())
  125. if err != nil {
  126. t.Fatal()
  127. }
  128. t.Cleanup(func() {
  129. if err := sdb.Close(); err != nil {
  130. t.Fatal(err)
  131. }
  132. })
  133. // Insert a local file
  134. file := genFile("foo", 1, 0)
  135. if err := sdb.Update(folderID, protocol.LocalDeviceID, []protocol.FileInfo{file}); err != nil {
  136. t.Fatal()
  137. }
  138. // Insert several remote files
  139. file = genFile("foo1", 1, 42)
  140. if err := sdb.Update(folderID, protocol.DeviceID{42}, []protocol.FileInfo{file}); err != nil {
  141. t.Fatal()
  142. }
  143. if err := sdb.Update(folderID, protocol.DeviceID{43}, []protocol.FileInfo{file}); err != nil {
  144. t.Fatal()
  145. }
  146. file = genFile("foo2", 1, 43)
  147. if err := sdb.Update(folderID, protocol.DeviceID{43}, []protocol.FileInfo{file}); err != nil {
  148. t.Fatal()
  149. }
  150. if err := sdb.Update(folderID, protocol.DeviceID{44}, []protocol.FileInfo{file}); err != nil {
  151. t.Fatal()
  152. }
  153. file = genFile("foo3", 1, 44)
  154. if err := sdb.Update(folderID, protocol.DeviceID{44}, []protocol.FileInfo{file}); err != nil {
  155. t.Fatal()
  156. }
  157. // Verify remote sequences
  158. seqs, err := sdb.RemoteSequences(folderID)
  159. if err != nil {
  160. t.Fatal(err)
  161. }
  162. if len(seqs) != 3 || seqs[protocol.DeviceID{42}] != 42 ||
  163. seqs[protocol.DeviceID{43}] != 43 ||
  164. seqs[protocol.DeviceID{44}] != 44 {
  165. t.Log(seqs)
  166. t.Error("bad seqs")
  167. }
  168. }