package files import ( "fmt" "reflect" "sort" "testing" "github.com/calmh/syncthing/cid" "github.com/calmh/syncthing/lamport" "github.com/calmh/syncthing/protocol" "github.com/calmh/syncthing/scanner" ) type fileList []scanner.File func (l fileList) Len() int { return len(l) } func (l fileList) Less(a, b int) bool { return l[a].Name < l[b].Name } func (l fileList) Swap(a, b int) { l[a], l[b] = l[b], l[a] } func TestGlobalSet(t *testing.T) { m := NewSet() local := []scanner.File{ scanner.File{Name: "a", Version: 1000}, scanner.File{Name: "b", Version: 1000}, scanner.File{Name: "c", Version: 1000}, scanner.File{Name: "d", Version: 1000}, } remote := []scanner.File{ scanner.File{Name: "a", Version: 1000}, scanner.File{Name: "b", Version: 1001}, scanner.File{Name: "c", Version: 1002}, scanner.File{Name: "e", Version: 1000}, } expectedGlobal := []scanner.File{ scanner.File{Name: "a", Version: 1000}, scanner.File{Name: "b", Version: 1001}, scanner.File{Name: "c", Version: 1002}, scanner.File{Name: "d", Version: 1000}, scanner.File{Name: "e", Version: 1000}, } m.ReplaceWithDelete(cid.LocalID, local) m.Replace(1, remote) g := m.Global() sort.Sort(fileList(g)) sort.Sort(fileList(expectedGlobal)) if !reflect.DeepEqual(g, expectedGlobal) { t.Errorf("Global incorrect;\n A: %v !=\n E: %v", g, expectedGlobal) } if lb := len(m.files); lb != 7 { t.Errorf("Num files incorrect %d != 7\n%v", lb, m.files) } } func TestLocalDeleted(t *testing.T) { m := NewSet() lamport.Default = lamport.Clock{} local1 := []scanner.File{ scanner.File{Name: "a", Version: 1000}, scanner.File{Name: "b", Version: 1000}, scanner.File{Name: "c", Version: 1000}, scanner.File{Name: "d", Version: 1000}, scanner.File{Name: "z", Version: 1000, Flags: protocol.FlagDirectory}, } m.ReplaceWithDelete(cid.LocalID, local1) local2 := []scanner.File{ local1[0], local1[2], } expectedGlobal1 := []scanner.File{ local1[0], scanner.File{Name: "b", Version: 1001, Flags: protocol.FlagDeleted}, local1[2], scanner.File{Name: "d", Version: 1002, Flags: protocol.FlagDeleted}, scanner.File{Name: "z", Version: 1003, Flags: protocol.FlagDeleted | protocol.FlagDirectory}, } m.ReplaceWithDelete(cid.LocalID, local2) g := m.Global() sort.Sort(fileList(g)) sort.Sort(fileList(expectedGlobal1)) if !reflect.DeepEqual(g, expectedGlobal1) { t.Errorf("Global incorrect;\n A: %v !=\n E: %v", g, expectedGlobal1) } local3 := []scanner.File{ local1[0], } expectedGlobal2 := []scanner.File{ local1[0], scanner.File{Name: "b", Version: 1001, Flags: protocol.FlagDeleted}, scanner.File{Name: "c", Version: 1004, Flags: protocol.FlagDeleted}, scanner.File{Name: "d", Version: 1002, Flags: protocol.FlagDeleted}, scanner.File{Name: "z", Version: 1003, Flags: protocol.FlagDeleted | protocol.FlagDirectory}, } m.ReplaceWithDelete(cid.LocalID, local3) g = m.Global() sort.Sort(fileList(g)) sort.Sort(fileList(expectedGlobal2)) if !reflect.DeepEqual(g, expectedGlobal2) { t.Errorf("Global incorrect;\n A: %v !=\n E: %v", g, expectedGlobal2) } } func BenchmarkSetLocal10k(b *testing.B) { m := NewSet() var local []scanner.File for i := 0; i < 10000; i++ { local = append(local, scanner.File{Name: fmt.Sprintf("file%d"), Version: 1000}) } var remote []scanner.File for i := 0; i < 10000; i++ { remote = append(remote, scanner.File{Name: fmt.Sprintf("file%d"), Version: 1000}) } m.Replace(1, remote) b.ResetTimer() for i := 0; i < b.N; i++ { m.ReplaceWithDelete(cid.LocalID, local) } } func BenchmarkSetLocal10(b *testing.B) { m := NewSet() var local []scanner.File for i := 0; i < 10; i++ { local = append(local, scanner.File{Name: fmt.Sprintf("file%d"), Version: 1000}) } var remote []scanner.File for i := 0; i < 10000; i++ { remote = append(remote, scanner.File{Name: fmt.Sprintf("file%d"), Version: 1000}) } m.Replace(1, remote) b.ResetTimer() for i := 0; i < b.N; i++ { m.ReplaceWithDelete(cid.LocalID, local) } } func BenchmarkAddLocal10k(b *testing.B) { m := NewSet() var local []scanner.File for i := 0; i < 10000; i++ { local = append(local, scanner.File{Name: fmt.Sprintf("file%d"), Version: 1000}) } var remote []scanner.File for i := 0; i < 10000; i++ { remote = append(remote, scanner.File{Name: fmt.Sprintf("file%d"), Version: 1000}) } m.Replace(1, remote) m.ReplaceWithDelete(cid.LocalID, local) b.ResetTimer() for i := 0; i < b.N; i++ { b.StopTimer() for j := range local { local[j].Version++ } b.StartTimer() m.Update(cid.LocalID, local) } } func BenchmarkAddLocal10(b *testing.B) { m := NewSet() var local []scanner.File for i := 0; i < 10; i++ { local = append(local, scanner.File{Name: fmt.Sprintf("file%d"), Version: 1000}) } var remote []scanner.File for i := 0; i < 10000; i++ { remote = append(remote, scanner.File{Name: fmt.Sprintf("file%d"), Version: 1000}) } m.Replace(1, remote) m.ReplaceWithDelete(cid.LocalID, local) b.ResetTimer() for i := 0; i < b.N; i++ { for j := range local { local[j].Version++ } m.Update(cid.LocalID, local) } } func TestGlobalReset(t *testing.T) { m := NewSet() local := []scanner.File{ scanner.File{Name: "a", Version: 1000}, scanner.File{Name: "b", Version: 1000}, scanner.File{Name: "c", Version: 1000}, scanner.File{Name: "d", Version: 1000}, } remote := []scanner.File{ scanner.File{Name: "a", Version: 1000}, scanner.File{Name: "b", Version: 1001}, scanner.File{Name: "c", Version: 1002}, scanner.File{Name: "e", Version: 1000}, } expectedGlobalKey := map[string]key{ "a": keyFor(local[0]), "b": keyFor(local[1]), "c": keyFor(local[2]), "d": keyFor(local[3]), } m.ReplaceWithDelete(cid.LocalID, local) m.Replace(1, remote) m.Replace(1, nil) if !reflect.DeepEqual(m.globalKey, expectedGlobalKey) { t.Errorf("Global incorrect;\n%v !=\n%v", m.globalKey, expectedGlobalKey) } if lb := len(m.files); lb != 4 { t.Errorf("Num files incorrect %d != 4\n%v", lb, m.files) } } func TestNeed(t *testing.T) { m := NewSet() local := []scanner.File{ scanner.File{Name: "a", Version: 1000}, scanner.File{Name: "b", Version: 1000}, scanner.File{Name: "c", Version: 1000}, scanner.File{Name: "d", Version: 1000}, } remote := []scanner.File{ scanner.File{Name: "a", Version: 1000}, scanner.File{Name: "b", Version: 1001}, scanner.File{Name: "c", Version: 1002}, scanner.File{Name: "e", Version: 1000}, } shouldNeed := []scanner.File{ scanner.File{Name: "b", Version: 1001}, scanner.File{Name: "c", Version: 1002}, scanner.File{Name: "e", Version: 1000}, } m.ReplaceWithDelete(cid.LocalID, local) m.Replace(1, remote) need := m.Need(0) if !reflect.DeepEqual(need, shouldNeed) { t.Errorf("Need incorrect;\n%v !=\n%v", need, shouldNeed) } } func TestChanges(t *testing.T) { m := NewSet() local1 := []scanner.File{ scanner.File{Name: "a", Version: 1000}, scanner.File{Name: "b", Version: 1000}, scanner.File{Name: "c", Version: 1000}, scanner.File{Name: "d", Version: 1000}, } local2 := []scanner.File{ local1[0], // [1] deleted local1[2], scanner.File{Name: "d", Version: 1002}, scanner.File{Name: "e", Version: 1000}, } m.ReplaceWithDelete(cid.LocalID, local1) c0 := m.Changes(cid.LocalID) m.ReplaceWithDelete(cid.LocalID, local2) c1 := m.Changes(cid.LocalID) if !(c1 > c0) { t.Fatal("Change number should have incremented") } m.ReplaceWithDelete(cid.LocalID, local2) c2 := m.Changes(cid.LocalID) if c2 != c1 { t.Fatal("Change number should be unchanged") } }