| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- // Copyright (C) 2014 The Syncthing Authors.
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
- // You can obtain one at https://mozilla.org/MPL/2.0/.
- package db
- import (
- "bytes"
- "os"
- "testing"
- "github.com/syncthing/syncthing/lib/fs"
- "github.com/syncthing/syncthing/lib/protocol"
- )
- func TestDeviceKey(t *testing.T) {
- fld := []byte("folder6789012345678901234567890123456789012345678901234567890123")
- dev := []byte("device67890123456789012345678901")
- name := []byte("name")
- db := OpenMemory()
- db.folderIdx.ID(fld)
- db.deviceIdx.ID(dev)
- key := db.deviceKey(fld, dev, name)
- fld2 := db.deviceKeyFolder(key)
- if !bytes.Equal(fld2, fld) {
- t.Errorf("wrong folder %q != %q", fld2, fld)
- }
- dev2 := db.deviceKeyDevice(key)
- if !bytes.Equal(dev2, dev) {
- t.Errorf("wrong device %q != %q", dev2, dev)
- }
- name2 := db.deviceKeyName(key)
- if !bytes.Equal(name2, name) {
- t.Errorf("wrong name %q != %q", name2, name)
- }
- }
- func TestGlobalKey(t *testing.T) {
- fld := []byte("folder6789012345678901234567890123456789012345678901234567890123")
- name := []byte("name")
- db := OpenMemory()
- db.folderIdx.ID(fld)
- key := db.globalKey(fld, name)
- fld2, ok := db.globalKeyFolder(key)
- if !ok {
- t.Error("should have been found")
- }
- if !bytes.Equal(fld2, fld) {
- t.Errorf("wrong folder %q != %q", fld2, fld)
- }
- name2 := db.globalKeyName(key)
- if !bytes.Equal(name2, name) {
- t.Errorf("wrong name %q != %q", name2, name)
- }
- _, ok = db.globalKeyFolder([]byte{1, 2, 3, 4, 5})
- if ok {
- t.Error("should not have been found")
- }
- }
- func TestDropIndexIDs(t *testing.T) {
- db := OpenMemory()
- d1 := []byte("device67890123456789012345678901")
- d2 := []byte("device12345678901234567890123456")
- // Set some index IDs
- db.setIndexID(protocol.LocalDeviceID[:], []byte("foo"), 1)
- db.setIndexID(protocol.LocalDeviceID[:], []byte("bar"), 2)
- db.setIndexID(d1, []byte("foo"), 3)
- db.setIndexID(d1, []byte("bar"), 4)
- db.setIndexID(d2, []byte("foo"), 5)
- db.setIndexID(d2, []byte("bar"), 6)
- // Verify them
- if db.getIndexID(protocol.LocalDeviceID[:], []byte("foo")) != 1 {
- t.Fatal("fail local 1")
- }
- if db.getIndexID(protocol.LocalDeviceID[:], []byte("bar")) != 2 {
- t.Fatal("fail local 2")
- }
- if db.getIndexID(d1, []byte("foo")) != 3 {
- t.Fatal("fail remote 1")
- }
- if db.getIndexID(d1, []byte("bar")) != 4 {
- t.Fatal("fail remote 2")
- }
- if db.getIndexID(d2, []byte("foo")) != 5 {
- t.Fatal("fail remote 3")
- }
- if db.getIndexID(d2, []byte("bar")) != 6 {
- t.Fatal("fail remote 4")
- }
- // Drop the local ones, verify only they got dropped
- db.DropLocalDeltaIndexIDs()
- if db.getIndexID(protocol.LocalDeviceID[:], []byte("foo")) != 0 {
- t.Fatal("fail local 1")
- }
- if db.getIndexID(protocol.LocalDeviceID[:], []byte("bar")) != 0 {
- t.Fatal("fail local 2")
- }
- if db.getIndexID(d1, []byte("foo")) != 3 {
- t.Fatal("fail remote 1")
- }
- if db.getIndexID(d1, []byte("bar")) != 4 {
- t.Fatal("fail remote 2")
- }
- if db.getIndexID(d2, []byte("foo")) != 5 {
- t.Fatal("fail remote 3")
- }
- if db.getIndexID(d2, []byte("bar")) != 6 {
- t.Fatal("fail remote 4")
- }
- // Set local ones again
- db.setIndexID(protocol.LocalDeviceID[:], []byte("foo"), 1)
- db.setIndexID(protocol.LocalDeviceID[:], []byte("bar"), 2)
- // Drop the remote ones, verify only they got dropped
- db.DropRemoteDeltaIndexIDs()
- if db.getIndexID(protocol.LocalDeviceID[:], []byte("foo")) != 1 {
- t.Fatal("fail local 1")
- }
- if db.getIndexID(protocol.LocalDeviceID[:], []byte("bar")) != 2 {
- t.Fatal("fail local 2")
- }
- if db.getIndexID(d1, []byte("foo")) != 0 {
- t.Fatal("fail remote 1")
- }
- if db.getIndexID(d1, []byte("bar")) != 0 {
- t.Fatal("fail remote 2")
- }
- if db.getIndexID(d2, []byte("foo")) != 0 {
- t.Fatal("fail remote 3")
- }
- if db.getIndexID(d2, []byte("bar")) != 0 {
- t.Fatal("fail remote 4")
- }
- }
- func TestIgnoredFiles(t *testing.T) {
- ldb, err := openJSONS("testdata/v0.14.48-ignoredfiles.db.jsons")
- if err != nil {
- t.Fatal(err)
- }
- db, _ := newDBInstance(ldb, "<memory>")
- fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
- // The contents of the database are like this:
- //
- // fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeBasic, "."), db)
- // fs.Update(protocol.LocalDeviceID, []protocol.FileInfo{
- // { // invalid (ignored) file
- // Name: "foo",
- // Type: protocol.FileInfoTypeFile,
- // Invalid: true,
- // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1000}}},
- // },
- // { // regular file
- // Name: "bar",
- // Type: protocol.FileInfoTypeFile,
- // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1001}}},
- // },
- // })
- // fs.Update(protocol.DeviceID{42}, []protocol.FileInfo{
- // { // invalid file
- // Name: "baz",
- // Type: protocol.FileInfoTypeFile,
- // Invalid: true,
- // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1000}}},
- // },
- // { // regular file
- // Name: "quux",
- // Type: protocol.FileInfoTypeFile,
- // Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: 1002}}},
- // },
- // })
- // Local files should have the "ignored" bit in addition to just being
- // generally invalid if we want to look at the simulation of that bit.
- fi, ok := fs.Get(protocol.LocalDeviceID, "foo")
- if !ok {
- t.Fatal("foo should exist")
- }
- if !fi.IsInvalid() {
- t.Error("foo should be invalid")
- }
- if !fi.IsIgnored() {
- t.Error("foo should be ignored")
- }
- fi, ok = fs.Get(protocol.LocalDeviceID, "bar")
- if !ok {
- t.Fatal("bar should exist")
- }
- if fi.IsInvalid() {
- t.Error("bar should not be invalid")
- }
- if fi.IsIgnored() {
- t.Error("bar should not be ignored")
- }
- // Remote files have the invalid bit as usual, and the IsInvalid() method
- // should pick this up too.
- fi, ok = fs.Get(protocol.DeviceID{42}, "baz")
- if !ok {
- t.Fatal("baz should exist")
- }
- if !fi.IsInvalid() {
- t.Error("baz should be invalid")
- }
- if !fi.IsInvalid() {
- t.Error("baz should be invalid")
- }
- fi, ok = fs.Get(protocol.DeviceID{42}, "quux")
- if !ok {
- t.Fatal("quux should exist")
- }
- if fi.IsInvalid() {
- t.Error("quux should not be invalid")
- }
- if fi.IsInvalid() {
- t.Error("quux should not be invalid")
- }
- }
- const myID = 1
- var (
- remoteDevice0, remoteDevice1 protocol.DeviceID
- update0to3Folder = "UpdateSchema0to3"
- invalid = "invalid"
- slashPrefixed = "/notgood"
- haveUpdate0to3 map[protocol.DeviceID]fileList
- )
- func init() {
- remoteDevice0, _ = protocol.DeviceIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
- remoteDevice1, _ = protocol.DeviceIDFromString("I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU")
- haveUpdate0to3 = map[protocol.DeviceID]fileList{
- protocol.LocalDeviceID: {
- protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
- protocol.FileInfo{Name: slashPrefixed, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
- },
- remoteDevice0: {
- protocol.FileInfo{Name: "b", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1001}}}, Blocks: genBlocks(2)},
- protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(5), RawInvalid: true},
- protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(7)},
- },
- remoteDevice1: {
- protocol.FileInfo{Name: "c", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1002}}}, Blocks: genBlocks(7)},
- protocol.FileInfo{Name: "d", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1003}}}, Blocks: genBlocks(5), RawInvalid: true},
- protocol.FileInfo{Name: invalid, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1004}}}, Blocks: genBlocks(5), RawInvalid: true},
- },
- }
- }
- func TestUpdate0to3(t *testing.T) {
- ldb, err := openJSONS("testdata/v0.14.45-update0to3.db.jsons")
- if err != nil {
- t.Fatal(err)
- }
- db, _ := newDBInstance(ldb, "<memory>")
- folder := []byte(update0to3Folder)
- db.updateSchema0to1()
- if _, ok := db.getFile(db.deviceKey(folder, protocol.LocalDeviceID[:], []byte(slashPrefixed))); ok {
- t.Error("File prefixed by '/' was not removed during transition to schema 1")
- }
- if _, err := db.Get(db.globalKey(folder, []byte(invalid)), nil); err != nil {
- t.Error("Invalid file wasn't added to global list")
- }
- db.updateSchema1to2()
- found := false
- db.withHaveSequence(folder, 0, func(fi FileIntf) bool {
- f := fi.(protocol.FileInfo)
- l.Infoln(f)
- if found {
- t.Error("Unexpected additional file via sequence", f.FileName())
- return true
- }
- if e := haveUpdate0to3[protocol.LocalDeviceID][0]; f.IsEquivalentOptional(e, true, true, 0) {
- found = true
- } else {
- t.Errorf("Wrong file via sequence, got %v, expected %v", f, e)
- }
- return true
- })
- if !found {
- t.Error("Local file wasn't added to sequence bucket", err)
- }
- db.updateSchema2to3()
- need := map[string]protocol.FileInfo{
- haveUpdate0to3[remoteDevice0][0].Name: haveUpdate0to3[remoteDevice0][0],
- haveUpdate0to3[remoteDevice1][0].Name: haveUpdate0to3[remoteDevice1][0],
- haveUpdate0to3[remoteDevice0][2].Name: haveUpdate0to3[remoteDevice0][2],
- }
- db.withNeed(folder, protocol.LocalDeviceID[:], false, func(fi FileIntf) bool {
- e, ok := need[fi.FileName()]
- if !ok {
- t.Error("Got unexpected needed file:", fi.FileName())
- }
- f := fi.(protocol.FileInfo)
- delete(need, f.Name)
- if !f.IsEquivalentOptional(e, true, true, 0) {
- t.Errorf("Wrong needed file, got %v, expected %v", f, e)
- }
- return true
- })
- for n := range need {
- t.Errorf(`Missing needed file "%v"`, n)
- }
- }
- func TestDowngrade(t *testing.T) {
- loc := "testdata/downgrade.db"
- db, err := Open(loc)
- if err != nil {
- t.Fatal(err)
- }
- defer func() {
- db.Close()
- os.RemoveAll(loc)
- }()
- miscDB := NewNamespacedKV(db, string(KeyTypeMiscData))
- miscDB.PutInt64("dbVersion", dbVersion+1)
- l.Infoln(dbVersion)
- db.Close()
- db, err = Open(loc)
- if err, ok := err.(databaseDowngradeError); !ok {
- t.Fatal("Expected error due to database downgrade, got", err)
- } else if err.minSyncthingVersion != dbMinSyncthingVersion {
- t.Fatalf("Error has %v as min Syncthing version, expected %v", err.minSyncthingVersion, dbMinSyncthingVersion)
- }
- }
|