mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-18 19:15:19 +00:00
b49f535834
The problem was that a statistics/cleanup run is triggered when the database started and runs concurrently with the test. That cleanup run removes old entries without valid addresses, and one of the test objects matched this. The test object would thus randomly be removed in the middle of the test, causing a failure. This fixes it so the object looks recent when the cleaner-upper looks, and also uses a RAM database (faster).
212 lines
4.4 KiB
Go
212 lines
4.4 KiB
Go
// Copyright (C) 2018 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 main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDatabaseGetSet(t *testing.T) {
|
|
db, err := newMemoryLevelDBStore()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
go db.Serve(ctx)
|
|
defer cancel()
|
|
|
|
// Check missing record
|
|
|
|
rec, err := db.get("abcd")
|
|
if err != nil {
|
|
t.Error("not found should not be an error")
|
|
}
|
|
if len(rec.Addresses) != 0 {
|
|
t.Error("addresses should be empty")
|
|
}
|
|
if rec.Misses != 0 {
|
|
t.Error("missing should be zero")
|
|
}
|
|
|
|
// Set up a clock
|
|
|
|
now := time.Now()
|
|
tc := &testClock{now}
|
|
db.clock = tc
|
|
|
|
// Put a record
|
|
|
|
rec.Addresses = []DatabaseAddress{
|
|
{Address: "tcp://1.2.3.4:5", Expires: tc.Now().Add(time.Minute).UnixNano()},
|
|
}
|
|
if err := db.put("abcd", rec); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Verify it
|
|
|
|
rec, err = db.get("abcd")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(rec.Addresses) != 1 {
|
|
t.Log(rec.Addresses)
|
|
t.Fatal("should have one address")
|
|
}
|
|
if rec.Addresses[0].Address != "tcp://1.2.3.4:5" {
|
|
t.Log(rec.Addresses)
|
|
t.Error("incorrect address")
|
|
}
|
|
|
|
// Wind the clock one half expiry, and merge in a new address
|
|
|
|
tc.wind(30 * time.Second)
|
|
|
|
addrs := []DatabaseAddress{
|
|
{Address: "tcp://6.7.8.9:0", Expires: tc.Now().Add(time.Minute).UnixNano()},
|
|
}
|
|
if err := db.merge("abcd", addrs, tc.Now().UnixNano()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Verify it
|
|
|
|
rec, err = db.get("abcd")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(rec.Addresses) != 2 {
|
|
t.Log(rec.Addresses)
|
|
t.Fatal("should have two addresses")
|
|
}
|
|
if rec.Addresses[0].Address != "tcp://1.2.3.4:5" {
|
|
t.Log(rec.Addresses)
|
|
t.Error("incorrect address[0]")
|
|
}
|
|
if rec.Addresses[1].Address != "tcp://6.7.8.9:0" {
|
|
t.Log(rec.Addresses)
|
|
t.Error("incorrect address[1]")
|
|
}
|
|
|
|
// Pass the first expiry time
|
|
|
|
tc.wind(45 * time.Second)
|
|
|
|
// Verify it
|
|
|
|
rec, err = db.get("abcd")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(rec.Addresses) != 1 {
|
|
t.Log(rec.Addresses)
|
|
t.Fatal("should have one address")
|
|
}
|
|
if rec.Addresses[0].Address != "tcp://6.7.8.9:0" {
|
|
t.Log(rec.Addresses)
|
|
t.Error("incorrect address")
|
|
}
|
|
|
|
// Put a record with misses
|
|
|
|
rec = DatabaseRecord{Misses: 42, Missed: tc.Now().UnixNano()}
|
|
if err := db.put("efgh", rec); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Verify it
|
|
|
|
rec, err = db.get("efgh")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(rec.Addresses) != 0 {
|
|
t.Log(rec.Addresses)
|
|
t.Fatal("should have no addresses")
|
|
}
|
|
if rec.Misses != 42 {
|
|
t.Log(rec.Misses)
|
|
t.Error("incorrect misses")
|
|
}
|
|
|
|
// Set an address
|
|
|
|
addrs = []DatabaseAddress{
|
|
{Address: "tcp://6.7.8.9:0", Expires: tc.Now().Add(time.Minute).UnixNano()},
|
|
}
|
|
if err := db.merge("efgh", addrs, tc.Now().UnixNano()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Verify it
|
|
|
|
rec, err = db.get("efgh")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(rec.Addresses) != 1 {
|
|
t.Log(rec.Addresses)
|
|
t.Fatal("should have one address")
|
|
}
|
|
if rec.Misses != 0 {
|
|
t.Log(rec.Misses)
|
|
t.Error("should have no misses")
|
|
}
|
|
}
|
|
|
|
func TestFilter(t *testing.T) {
|
|
// all cases are expired with t=10
|
|
cases := []struct {
|
|
a []DatabaseAddress
|
|
b []DatabaseAddress
|
|
}{
|
|
{
|
|
a: nil,
|
|
b: nil,
|
|
},
|
|
{
|
|
a: []DatabaseAddress{{Address: "a", Expires: 9}, {Address: "b", Expires: 9}, {Address: "c", Expires: 9}},
|
|
b: []DatabaseAddress{},
|
|
},
|
|
{
|
|
a: []DatabaseAddress{{Address: "a", Expires: 10}},
|
|
b: []DatabaseAddress{{Address: "a", Expires: 10}},
|
|
},
|
|
{
|
|
a: []DatabaseAddress{{Address: "a", Expires: 10}, {Address: "b", Expires: 10}, {Address: "c", Expires: 10}},
|
|
b: []DatabaseAddress{{Address: "a", Expires: 10}, {Address: "b", Expires: 10}, {Address: "c", Expires: 10}},
|
|
},
|
|
{
|
|
a: []DatabaseAddress{{Address: "a", Expires: 5}, {Address: "b", Expires: 15}, {Address: "c", Expires: 5}, {Address: "d", Expires: 15}, {Address: "e", Expires: 5}},
|
|
b: []DatabaseAddress{{Address: "d", Expires: 15}, {Address: "b", Expires: 15}}, // gets reordered
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
res := expire(tc.a, 10)
|
|
if fmt.Sprint(res) != fmt.Sprint(tc.b) {
|
|
t.Errorf("Incorrect result %v, expected %v", res, tc.b)
|
|
}
|
|
}
|
|
}
|
|
|
|
type testClock struct {
|
|
now time.Time
|
|
}
|
|
|
|
func (t *testClock) wind(d time.Duration) {
|
|
t.now = t.now.Add(d)
|
|
}
|
|
|
|
func (t *testClock) Now() time.Time {
|
|
t.now = t.now.Add(time.Nanosecond)
|
|
return t.now
|
|
}
|