db_local_test.go 4.6 KB

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