leveldb_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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 db
  7. import (
  8. "bytes"
  9. "os"
  10. "testing"
  11. "github.com/syncthing/syncthing/lib/fs"
  12. "github.com/syncthing/syncthing/lib/protocol"
  13. )
  14. func TestDeviceKey(t *testing.T) {
  15. fld := []byte("folder6789012345678901234567890123456789012345678901234567890123")
  16. dev := []byte("device67890123456789012345678901")
  17. name := []byte("name")
  18. db := OpenMemory()
  19. db.folderIdx.ID(fld)
  20. db.deviceIdx.ID(dev)
  21. key := db.deviceKey(fld, dev, name)
  22. fld2 := db.deviceKeyFolder(key)
  23. if !bytes.Equal(fld2, fld) {
  24. t.Errorf("wrong folder %q != %q", fld2, fld)
  25. }
  26. dev2 := db.deviceKeyDevice(key)
  27. if !bytes.Equal(dev2, dev) {
  28. t.Errorf("wrong device %q != %q", dev2, dev)
  29. }
  30. name2 := db.deviceKeyName(key)
  31. if !bytes.Equal(name2, name) {
  32. t.Errorf("wrong name %q != %q", name2, name)
  33. }
  34. }
  35. func TestGlobalKey(t *testing.T) {
  36. fld := []byte("folder6789012345678901234567890123456789012345678901234567890123")
  37. name := []byte("name")
  38. db := OpenMemory()
  39. db.folderIdx.ID(fld)
  40. key := db.globalKey(fld, name)
  41. fld2, ok := db.globalKeyFolder(key)
  42. if !ok {
  43. t.Error("should have been found")
  44. }
  45. if !bytes.Equal(fld2, fld) {
  46. t.Errorf("wrong folder %q != %q", fld2, fld)
  47. }
  48. name2 := db.globalKeyName(key)
  49. if !bytes.Equal(name2, name) {
  50. t.Errorf("wrong name %q != %q", name2, name)
  51. }
  52. _, ok = db.globalKeyFolder([]byte{1, 2, 3, 4, 5})
  53. if ok {
  54. t.Error("should not have been found")
  55. }
  56. }
  57. func TestDropIndexIDs(t *testing.T) {
  58. db := OpenMemory()
  59. d1 := []byte("device67890123456789012345678901")
  60. d2 := []byte("device12345678901234567890123456")
  61. // Set some index IDs
  62. db.setIndexID(protocol.LocalDeviceID[:], []byte("foo"), 1)
  63. db.setIndexID(protocol.LocalDeviceID[:], []byte("bar"), 2)
  64. db.setIndexID(d1, []byte("foo"), 3)
  65. db.setIndexID(d1, []byte("bar"), 4)
  66. db.setIndexID(d2, []byte("foo"), 5)
  67. db.setIndexID(d2, []byte("bar"), 6)
  68. // Verify them
  69. if db.getIndexID(protocol.LocalDeviceID[:], []byte("foo")) != 1 {
  70. t.Fatal("fail local 1")
  71. }
  72. if db.getIndexID(protocol.LocalDeviceID[:], []byte("bar")) != 2 {
  73. t.Fatal("fail local 2")
  74. }
  75. if db.getIndexID(d1, []byte("foo")) != 3 {
  76. t.Fatal("fail remote 1")
  77. }
  78. if db.getIndexID(d1, []byte("bar")) != 4 {
  79. t.Fatal("fail remote 2")
  80. }
  81. if db.getIndexID(d2, []byte("foo")) != 5 {
  82. t.Fatal("fail remote 3")
  83. }
  84. if db.getIndexID(d2, []byte("bar")) != 6 {
  85. t.Fatal("fail remote 4")
  86. }
  87. // Drop the local ones, verify only they got dropped
  88. db.DropLocalDeltaIndexIDs()
  89. if db.getIndexID(protocol.LocalDeviceID[:], []byte("foo")) != 0 {
  90. t.Fatal("fail local 1")
  91. }
  92. if db.getIndexID(protocol.LocalDeviceID[:], []byte("bar")) != 0 {
  93. t.Fatal("fail local 2")
  94. }
  95. if db.getIndexID(d1, []byte("foo")) != 3 {
  96. t.Fatal("fail remote 1")
  97. }
  98. if db.getIndexID(d1, []byte("bar")) != 4 {
  99. t.Fatal("fail remote 2")
  100. }
  101. if db.getIndexID(d2, []byte("foo")) != 5 {
  102. t.Fatal("fail remote 3")
  103. }
  104. if db.getIndexID(d2, []byte("bar")) != 6 {
  105. t.Fatal("fail remote 4")
  106. }
  107. // Set local ones again
  108. db.setIndexID(protocol.LocalDeviceID[:], []byte("foo"), 1)
  109. db.setIndexID(protocol.LocalDeviceID[:], []byte("bar"), 2)
  110. // Drop the remote ones, verify only they got dropped
  111. db.DropRemoteDeltaIndexIDs()
  112. if db.getIndexID(protocol.LocalDeviceID[:], []byte("foo")) != 1 {
  113. t.Fatal("fail local 1")
  114. }
  115. if db.getIndexID(protocol.LocalDeviceID[:], []byte("bar")) != 2 {
  116. t.Fatal("fail local 2")
  117. }
  118. if db.getIndexID(d1, []byte("foo")) != 0 {
  119. t.Fatal("fail remote 1")
  120. }
  121. if db.getIndexID(d1, []byte("bar")) != 0 {
  122. t.Fatal("fail remote 2")
  123. }
  124. if db.getIndexID(d2, []byte("foo")) != 0 {
  125. t.Fatal("fail remote 3")
  126. }
  127. if db.getIndexID(d2, []byte("bar")) != 0 {
  128. t.Fatal("fail remote 4")
  129. }
  130. }
  131. func TestIgnoredFiles(t *testing.T) {
  132. ldb, err := openJSONS("testdata/v0.14.48-ignoredfiles.db.jsons")
  133. if err != nil {
  134. t.Fatal(err)
  135. }
  136. db, _ := newDBInstance(ldb, "<memory>")
  137. fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
  138. // The contents of the database are like this:
  139. //
  140. // fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
  141. // fs.Update(protocol.LocalDeviceID, []protocol.FileInfo{
  142. // { // invalid (ignored) file
  143. // Name: "foo",
  144. // Type: protocol.FileInfoTypeFile,
  145. // Invalid: true,
  146. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1000}}},
  147. // },
  148. // { // regular file
  149. // Name: "bar",
  150. // Type: protocol.FileInfoTypeFile,
  151. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1001}}},
  152. // },
  153. // })
  154. // fs.Update(protocol.DeviceID{42}, []protocol.FileInfo{
  155. // { // invalid file
  156. // Name: "baz",
  157. // Type: protocol.FileInfoTypeFile,
  158. // Invalid: true,
  159. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1000}}},
  160. // },
  161. // { // regular file
  162. // Name: "quux",
  163. // Type: protocol.FileInfoTypeFile,
  164. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1002}}},
  165. // },
  166. // })
  167. // Local files should have the "ignored" bit in addition to just being
  168. // generally invalid if we want to look at the simulation of that bit.
  169. fi, ok := fs.Get(protocol.LocalDeviceID, "foo")
  170. if !ok {
  171. t.Fatal("foo should exist")
  172. }
  173. if !fi.IsInvalid() {
  174. t.Error("foo should be invalid")
  175. }
  176. if !fi.IsIgnored() {
  177. t.Error("foo should be ignored")
  178. }
  179. fi, ok = fs.Get(protocol.LocalDeviceID, "bar")
  180. if !ok {
  181. t.Fatal("bar should exist")
  182. }
  183. if fi.IsInvalid() {
  184. t.Error("bar should not be invalid")
  185. }
  186. if fi.IsIgnored() {
  187. t.Error("bar should not be ignored")
  188. }
  189. // Remote files have the invalid bit as usual, and the IsInvalid() method
  190. // should pick this up too.
  191. fi, ok = fs.Get(protocol.DeviceID{42}, "baz")
  192. if !ok {
  193. t.Fatal("baz should exist")
  194. }
  195. if !fi.IsInvalid() {
  196. t.Error("baz should be invalid")
  197. }
  198. if !fi.IsInvalid() {
  199. t.Error("baz should be invalid")
  200. }
  201. fi, ok = fs.Get(protocol.DeviceID{42}, "quux")
  202. if !ok {
  203. t.Fatal("quux should exist")
  204. }
  205. if fi.IsInvalid() {
  206. t.Error("quux should not be invalid")
  207. }
  208. if fi.IsInvalid() {
  209. t.Error("quux should not be invalid")
  210. }
  211. }
  212. const myID = 1
  213. var (
  214. remoteDevice0, remoteDevice1 protocol.DeviceID
  215. update0to3Folder = "UpdateSchema0to3"
  216. invalid = "invalid"
  217. slashPrefixed = "/notgood"
  218. haveUpdate0to3 map[protocol.DeviceID]fileList
  219. )
  220. func init() {
  221. remoteDevice0, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
  222. remoteDevice1, _ = protocol.DeviceIDFromString("I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU")
  223. haveUpdate0to3 = map[protocol.DeviceID]fileList{
  224. protocol.LocalDeviceID: {
  225. protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
  226. protocol.FileInfo{Name: slashPrefixed, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
  227. },
  228. remoteDevice0: {
  229. protocol.FileInfo{Name: "b", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1001}}}, Blocks: genBlocks(2)},
  230. protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(5), RawInvalid: true},
  231. protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(7)},
  232. },
  233. remoteDevice1: {
  234. protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(7)},
  235. protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(5), RawInvalid: true},
  236. protocol.FileInfo{Name: invalid, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1004}}}, Blocks: genBlocks(5), RawInvalid: true},
  237. },
  238. }
  239. }
  240. func TestUpdate0to3(t *testing.T) {
  241. ldb, err := openJSONS("testdata/v0.14.45-update0to3.db.jsons")
  242. if err != nil {
  243. t.Fatal(err)
  244. }
  245. db, _ := newDBInstance(ldb, "<memory>")
  246. folder := []byte(update0to3Folder)
  247. db.updateSchema0to1()
  248. if _, ok := db.getFile(db.deviceKey(folder, protocol.LocalDeviceID[:], []byte(slashPrefixed))); ok {
  249. t.Error("File prefixed by '/' was not removed during transition to schema 1")
  250. }
  251. if _, err := db.Get(db.globalKey(folder, []byte(invalid)), nil); err != nil {
  252. t.Error("Invalid file wasn't added to global list")
  253. }
  254. db.updateSchema1to2()
  255. found := false
  256. db.withHaveSequence(folder, 0, func(fi FileIntf) bool {
  257. f := fi.(protocol.FileInfo)
  258. l.Infoln(f)
  259. if found {
  260. t.Error("Unexpected additional file via sequence", f.FileName())
  261. return true
  262. }
  263. if e := haveUpdate0to3[protocol.LocalDeviceID][0]; f.IsEquivalentOptional(e, true, true, 0) {
  264. found = true
  265. } else {
  266. t.Errorf("Wrong file via sequence, got %v, expected %v", f, e)
  267. }
  268. return true
  269. })
  270. if !found {
  271. t.Error("Local file wasn't added to sequence bucket", err)
  272. }
  273. db.updateSchema2to3()
  274. need := map[string]protocol.FileInfo{
  275. haveUpdate0to3[remoteDevice0][0].Name: haveUpdate0to3[remoteDevice0][0],
  276. haveUpdate0to3[remoteDevice1][0].Name: haveUpdate0to3[remoteDevice1][0],
  277. haveUpdate0to3[remoteDevice0][2].Name: haveUpdate0to3[remoteDevice0][2],
  278. }
  279. db.withNeed(folder, protocol.LocalDeviceID[:], false, func(fi FileIntf) bool {
  280. e, ok := need[fi.FileName()]
  281. if !ok {
  282. t.Error("Got unexpected needed file:", fi.FileName())
  283. }
  284. f := fi.(protocol.FileInfo)
  285. delete(need, f.Name)
  286. if !f.IsEquivalentOptional(e, true, true, 0) {
  287. t.Errorf("Wrong needed file, got %v, expected %v", f, e)
  288. }
  289. return true
  290. })
  291. for n := range need {
  292. t.Errorf(`Missing needed file "%v"`, n)
  293. }
  294. }
  295. func TestDowngrade(t *testing.T) {
  296. loc := "testdata/downgrade.db"
  297. db, err := Open(loc)
  298. if err != nil {
  299. t.Fatal(err)
  300. }
  301. defer func() {
  302. db.Close()
  303. os.RemoveAll(loc)
  304. }()
  305. miscDB := NewNamespacedKV(db, string(KeyTypeMiscData))
  306. miscDB.PutInt64("dbVersion", dbVersion+1)
  307. l.Infoln(dbVersion)
  308. db.Close()
  309. db, err = Open(loc)
  310. if err, ok := err.(databaseDowngradeError); !ok {
  311. t.Fatal("Expected error due to database downgrade, got", err)
  312. } else if err.minSyncthingVersion != dbMinSyncthingVersion {
  313. t.Fatalf("Error has %v as min Syncthing version, expected %v", err.minSyncthingVersion, dbMinSyncthingVersion)
  314. }
  315. }