db_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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. "testing"
  9. "github.com/syncthing/syncthing/lib/fs"
  10. "github.com/syncthing/syncthing/lib/protocol"
  11. )
  12. func TestIgnoredFiles(t *testing.T) {
  13. ldb, err := openJSONS("testdata/v0.14.48-ignoredfiles.db.jsons")
  14. if err != nil {
  15. t.Fatal(err)
  16. }
  17. db := NewLowlevel(ldb, "<memory>")
  18. UpdateSchema(db)
  19. fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
  20. // The contents of the database are like this:
  21. //
  22. // fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
  23. // fs.Update(protocol.LocalDeviceID, []protocol.FileInfo{
  24. // { // invalid (ignored) file
  25. // Name: "foo",
  26. // Type: protocol.FileInfoTypeFile,
  27. // Invalid: true,
  28. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1000}}},
  29. // },
  30. // { // regular file
  31. // Name: "bar",
  32. // Type: protocol.FileInfoTypeFile,
  33. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1001}}},
  34. // },
  35. // })
  36. // fs.Update(protocol.DeviceID{42}, []protocol.FileInfo{
  37. // { // invalid file
  38. // Name: "baz",
  39. // Type: protocol.FileInfoTypeFile,
  40. // Invalid: true,
  41. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1000}}},
  42. // },
  43. // { // regular file
  44. // Name: "quux",
  45. // Type: protocol.FileInfoTypeFile,
  46. // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1002}}},
  47. // },
  48. // })
  49. // Local files should have the "ignored" bit in addition to just being
  50. // generally invalid if we want to look at the simulation of that bit.
  51. fi, ok := fs.Get(protocol.LocalDeviceID, "foo")
  52. if !ok {
  53. t.Fatal("foo should exist")
  54. }
  55. if !fi.IsInvalid() {
  56. t.Error("foo should be invalid")
  57. }
  58. if !fi.IsIgnored() {
  59. t.Error("foo should be ignored")
  60. }
  61. fi, ok = fs.Get(protocol.LocalDeviceID, "bar")
  62. if !ok {
  63. t.Fatal("bar should exist")
  64. }
  65. if fi.IsInvalid() {
  66. t.Error("bar should not be invalid")
  67. }
  68. if fi.IsIgnored() {
  69. t.Error("bar should not be ignored")
  70. }
  71. // Remote files have the invalid bit as usual, and the IsInvalid() method
  72. // should pick this up too.
  73. fi, ok = fs.Get(protocol.DeviceID{42}, "baz")
  74. if !ok {
  75. t.Fatal("baz should exist")
  76. }
  77. if !fi.IsInvalid() {
  78. t.Error("baz should be invalid")
  79. }
  80. if !fi.IsInvalid() {
  81. t.Error("baz should be invalid")
  82. }
  83. fi, ok = fs.Get(protocol.DeviceID{42}, "quux")
  84. if !ok {
  85. t.Fatal("quux should exist")
  86. }
  87. if fi.IsInvalid() {
  88. t.Error("quux should not be invalid")
  89. }
  90. if fi.IsInvalid() {
  91. t.Error("quux should not be invalid")
  92. }
  93. }
  94. const myID = 1
  95. var (
  96. remoteDevice0, remoteDevice1 protocol.DeviceID
  97. update0to3Folder = "UpdateSchema0to3"
  98. invalid = "invalid"
  99. slashPrefixed = "/notgood"
  100. haveUpdate0to3 map[protocol.DeviceID]fileList
  101. )
  102. func init() {
  103. remoteDevice0, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
  104. remoteDevice1, _ = protocol.DeviceIDFromString("I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU")
  105. haveUpdate0to3 = map[protocol.DeviceID]fileList{
  106. protocol.LocalDeviceID: {
  107. protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
  108. protocol.FileInfo{Name: slashPrefixed, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
  109. },
  110. remoteDevice0: {
  111. protocol.FileInfo{Name: "b", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1001}}}, Blocks: genBlocks(2)},
  112. protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(5), RawInvalid: true},
  113. protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(7)},
  114. },
  115. remoteDevice1: {
  116. protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(7)},
  117. protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(5), RawInvalid: true},
  118. protocol.FileInfo{Name: invalid, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1004}}}, Blocks: genBlocks(5), RawInvalid: true},
  119. },
  120. }
  121. }
  122. func TestUpdate0to3(t *testing.T) {
  123. ldb, err := openJSONS("testdata/v0.14.45-update0to3.db.jsons")
  124. if err != nil {
  125. t.Fatal(err)
  126. }
  127. db := newInstance(NewLowlevel(ldb, "<memory>"))
  128. updater := schemaUpdater{db}
  129. folder := []byte(update0to3Folder)
  130. updater.updateSchema0to1()
  131. if _, ok := db.getFileDirty(folder, protocol.LocalDeviceID[:], []byte(slashPrefixed)); ok {
  132. t.Error("File prefixed by '/' was not removed during transition to schema 1")
  133. }
  134. if _, err := db.Get(db.keyer.GenerateGlobalVersionKey(nil, folder, []byte(invalid)), nil); err != nil {
  135. t.Error("Invalid file wasn't added to global list")
  136. }
  137. updater.updateSchema1to2()
  138. found := false
  139. db.withHaveSequence(folder, 0, func(fi FileIntf) bool {
  140. f := fi.(protocol.FileInfo)
  141. l.Infoln(f)
  142. if found {
  143. t.Error("Unexpected additional file via sequence", f.FileName())
  144. return true
  145. }
  146. if e := haveUpdate0to3[protocol.LocalDeviceID][0]; f.IsEquivalentOptional(e, 0, true, true, 0) {
  147. found = true
  148. } else {
  149. t.Errorf("Wrong file via sequence, got %v, expected %v", f, e)
  150. }
  151. return true
  152. })
  153. if !found {
  154. t.Error("Local file wasn't added to sequence bucket", err)
  155. }
  156. updater.updateSchema2to3()
  157. need := map[string]protocol.FileInfo{
  158. haveUpdate0to3[remoteDevice0][0].Name: haveUpdate0to3[remoteDevice0][0],
  159. haveUpdate0to3[remoteDevice1][0].Name: haveUpdate0to3[remoteDevice1][0],
  160. haveUpdate0to3[remoteDevice0][2].Name: haveUpdate0to3[remoteDevice0][2],
  161. }
  162. db.withNeed(folder, protocol.LocalDeviceID[:], false, func(fi FileIntf) bool {
  163. e, ok := need[fi.FileName()]
  164. if !ok {
  165. t.Error("Got unexpected needed file:", fi.FileName())
  166. }
  167. f := fi.(protocol.FileInfo)
  168. delete(need, f.Name)
  169. if !f.IsEquivalentOptional(e, 0, true, true, 0) {
  170. t.Errorf("Wrong needed file, got %v, expected %v", f, e)
  171. }
  172. return true
  173. })
  174. for n := range need {
  175. t.Errorf(`Missing needed file "%v"`, n)
  176. }
  177. }
  178. func TestDowngrade(t *testing.T) {
  179. db := OpenMemory()
  180. UpdateSchema(db) // sets the min version etc
  181. // Bump the database version to something newer than we actually support
  182. miscDB := NewMiscDataNamespace(db)
  183. miscDB.PutInt64("dbVersion", dbVersion+1)
  184. l.Infoln(dbVersion)
  185. // Pretend we just opened the DB and attempt to update it again
  186. err := UpdateSchema(db)
  187. if err, ok := err.(databaseDowngradeError); !ok {
  188. t.Fatal("Expected error due to database downgrade, got", err)
  189. } else if err.minSyncthingVersion != dbMinSyncthingVersion {
  190. t.Fatalf("Error has %v as min Syncthing version, expected %v", err.minSyncthingVersion, dbMinSyncthingVersion)
  191. }
  192. }