Spaces:
Running
Running
// _ _ | |
// __ _____ __ ___ ___ __ _| |_ ___ | |
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
// \ V V / __/ (_| |\ V /| | (_| | || __/ | |
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
// | |
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
// | |
// CONTACT: [email protected] | |
// | |
package backup | |
import ( | |
"sort" | |
"testing" | |
"time" | |
"github.com/stretchr/testify/assert" | |
) | |
func TestExcludeClasses(t *testing.T) { | |
tests := []struct { | |
in BackupDescriptor | |
xs []string | |
out []string | |
}{ | |
{in: BackupDescriptor{}, xs: []string{}, out: []string{}}, | |
{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{}, out: []string{"a"}}, | |
{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{"a"}, out: []string{}}, | |
{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}, {Name: "4"}}}, xs: []string{"2", "3"}, out: []string{"1", "4"}}, | |
{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}}}, xs: []string{"1", "3"}, out: []string{"2"}}, | |
// {in: []BackupDescriptor{"1", "2", "3", "4"}, xs: []string{"2", "3"}, out: []string{"1", "4"}}, | |
// {in: []BackupDescriptor{"1", "2", "3"}, xs: []string{"1", "3"}, out: []string{"2"}}, | |
} | |
for _, tc := range tests { | |
tc.in.Exclude(tc.xs) | |
lst := tc.in.List() | |
assert.Equal(t, tc.out, lst) | |
} | |
} | |
func TestIncludeClasses(t *testing.T) { | |
tests := []struct { | |
in BackupDescriptor | |
xs []string | |
out []string | |
}{ | |
{in: BackupDescriptor{}, xs: []string{}, out: []string{}}, | |
{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{}, out: []string{"a"}}, | |
{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}}, xs: []string{"a"}, out: []string{"a"}}, | |
{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}, {Name: "4"}}}, xs: []string{"2", "3"}, out: []string{"2", "3"}}, | |
{in: BackupDescriptor{Classes: []ClassDescriptor{{Name: "1"}, {Name: "2"}, {Name: "3"}}}, xs: []string{"1", "3"}, out: []string{"1", "3"}}, | |
} | |
for _, tc := range tests { | |
tc.in.Include(tc.xs) | |
lst := tc.in.List() | |
assert.Equal(t, tc.out, lst) | |
} | |
} | |
func TestAllExist(t *testing.T) { | |
x := BackupDescriptor{Classes: []ClassDescriptor{{Name: "a"}}} | |
if y := x.AllExist(nil); y != "" { | |
t.Errorf("x.AllExists(nil) got=%v want=%v", y, "") | |
} | |
if y := x.AllExist([]string{"a"}); y != "" { | |
t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "") | |
} | |
if y := x.AllExist([]string{"b"}); y != "b" { | |
t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "b") | |
} | |
} | |
func TestValidateBackup(t *testing.T) { | |
timept := time.Now().UTC() | |
bytes := []byte("hello") | |
tests := []struct { | |
desc BackupDescriptor | |
successV1 bool | |
successV2 bool | |
}{ | |
// first level check | |
{desc: BackupDescriptor{}}, | |
{desc: BackupDescriptor{ID: "1"}}, | |
{desc: BackupDescriptor{ID: "1", Version: "1"}}, | |
{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1"}}, | |
{ | |
desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept}, | |
successV1: true, successV2: true, | |
}, | |
{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, Error: "err"}}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{}}, | |
}}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{Name: "n"}}, | |
}}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{Name: "n", Schema: bytes}}, | |
}}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{Name: "n", Schema: bytes, ShardingState: bytes}}, | |
}, successV1: true, successV2: true}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", Schema: bytes, ShardingState: bytes, | |
Shards: []*ShardDescriptor{{Name: ""}}, | |
}}, | |
}}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", Schema: bytes, ShardingState: bytes, | |
Shards: []*ShardDescriptor{{Name: "n", Node: ""}}, | |
}}, | |
}}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", Schema: bytes, ShardingState: bytes, | |
Shards: []*ShardDescriptor{{Name: "n", Node: "n"}}, | |
}}, | |
}, successV2: true}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", Schema: bytes, ShardingState: bytes, | |
Shards: []*ShardDescriptor{{ | |
Name: "n", Node: "n", | |
PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", | |
}}, | |
}}, | |
}, successV1: true, successV2: true}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", Schema: bytes, ShardingState: bytes, | |
Shards: []*ShardDescriptor{{ | |
Name: "n", Node: "n", | |
PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", | |
Files: []string{"file"}, | |
}}, | |
}}, | |
}, successV2: true}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", Schema: bytes, ShardingState: bytes, | |
Shards: []*ShardDescriptor{{ | |
Name: "n", Node: "n", | |
PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", | |
DocIDCounter: bytes, Files: []string{"file"}, | |
}}, | |
}}, | |
}, successV2: true}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", Schema: bytes, ShardingState: bytes, | |
Shards: []*ShardDescriptor{{ | |
Name: "n", Node: "n", | |
PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", | |
DocIDCounter: bytes, Version: bytes, PropLengthTracker: bytes, Files: []string{""}, | |
}}, | |
}}, | |
}, successV2: true}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", Schema: bytes, ShardingState: bytes, | |
Shards: []*ShardDescriptor{{ | |
Name: "n", Node: "n", | |
PropLengthTrackerPath: "n", DocIDCounterPath: "n", ShardVersionPath: "n", | |
DocIDCounter: bytes, Version: bytes, PropLengthTracker: bytes, Files: []string{"file"}, | |
}}, | |
}}, | |
}, successV1: true, successV2: true}, | |
} | |
for i, tc := range tests { | |
err := tc.desc.Validate(false) | |
if got := err == nil; got != tc.successV1 { | |
t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.successV1, got, err) | |
} | |
err = tc.desc.Validate(true) | |
if got := err == nil; got != tc.successV2 { | |
t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.successV1, got, err) | |
} | |
} | |
} | |
func TestBackwardCompatibility(t *testing.T) { | |
timept := time.Now().UTC() | |
tests := []struct { | |
desc BackupDescriptor | |
success bool | |
}{ | |
// first level check | |
{desc: BackupDescriptor{}}, | |
{desc: BackupDescriptor{ID: "1"}}, | |
{desc: BackupDescriptor{ID: "1", Version: "1"}}, | |
{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1"}}, | |
{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept}}, | |
{desc: BackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, Error: "err"}}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", | |
Shards: []*ShardDescriptor{{Name: "n", Node: ""}}, | |
}}, | |
}}, | |
{desc: BackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Classes: []ClassDescriptor{{ | |
Name: "n", | |
Shards: []*ShardDescriptor{{ | |
Name: "n", Node: "n", | |
}}, | |
}}, | |
}, success: true}, | |
} | |
for i, tc := range tests { | |
desc := tc.desc.ToDistributed() | |
err := desc.Validate() | |
if got := err == nil; got != tc.success { | |
t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.success, got, err) | |
} | |
} | |
} | |
func TestDistributedBackup(t *testing.T) { | |
d := DistributedBackupDescriptor{ | |
Nodes: map[string]*NodeDescriptor{ | |
"N1": {Classes: []string{"1", "2"}}, | |
"N2": {Classes: []string{"3", "4"}}, | |
}, | |
} | |
if n := d.Len(); n != 2 { | |
t.Errorf("#nodes got:%v want:%v", n, 2) | |
} | |
if n := d.Count(); n != 4 { | |
t.Errorf("#classes got:%v want:%v", n, 4) | |
} | |
d.Exclude([]string{"3", "4"}) | |
d.RemoveEmpty() | |
if n := d.Len(); n != 1 { | |
t.Errorf("#nodes got:%v want:%v", n, 2) | |
} | |
if n := d.Count(); n != 2 { | |
t.Errorf("#classes got:%v want:%v", n, 4) | |
} | |
} | |
func TestDistributedBackupExcludeClasses(t *testing.T) { | |
tests := []struct { | |
in DistributedBackupDescriptor | |
xs []string | |
out []string | |
}{ | |
{ | |
in: DistributedBackupDescriptor{}, | |
xs: []string{}, | |
out: []string{}, | |
}, | |
{ | |
in: DistributedBackupDescriptor{ | |
Nodes: map[string]*NodeDescriptor{ | |
"N1": {Classes: []string{"a"}}, | |
}, | |
}, | |
xs: []string{}, | |
out: []string{"a"}, | |
}, | |
{ | |
in: DistributedBackupDescriptor{ | |
Nodes: map[string]*NodeDescriptor{ | |
"N1": {Classes: []string{"a"}}, | |
}, | |
}, | |
xs: []string{"a"}, | |
out: []string{}, | |
}, | |
{ | |
in: DistributedBackupDescriptor{ | |
Nodes: map[string]*NodeDescriptor{ | |
"N1": {Classes: []string{"1", "2"}}, | |
"N2": {Classes: []string{"3", "4"}}, | |
}, | |
}, | |
xs: []string{"2", "3"}, | |
out: []string{"1", "4"}, | |
}, | |
{ | |
in: DistributedBackupDescriptor{ | |
Nodes: map[string]*NodeDescriptor{ | |
"N1": {Classes: []string{"1", "2"}}, | |
"N2": {Classes: []string{"3"}}, | |
}, | |
}, | |
xs: []string{"1", "3"}, | |
out: []string{"2"}, | |
}, | |
} | |
for _, tc := range tests { | |
tc.in.Exclude(tc.xs) | |
lst := tc.in.Classes() | |
sort.Strings(lst) | |
assert.Equal(t, tc.out, lst) | |
} | |
} | |
func TestDistributedBackupIncludeClasses(t *testing.T) { | |
tests := []struct { | |
in DistributedBackupDescriptor | |
xs []string | |
out []string | |
}{ | |
{ | |
in: DistributedBackupDescriptor{}, | |
xs: []string{}, | |
out: []string{}, | |
}, | |
{ | |
in: DistributedBackupDescriptor{ | |
Nodes: map[string]*NodeDescriptor{ | |
"N1": {Classes: []string{"a"}}, | |
}, | |
}, | |
xs: []string{}, | |
out: []string{"a"}, | |
}, | |
{ | |
in: DistributedBackupDescriptor{ | |
Nodes: map[string]*NodeDescriptor{ | |
"N1": {Classes: []string{"a"}}, | |
}, | |
}, | |
xs: []string{"a"}, | |
out: []string{"a"}, | |
}, | |
{ | |
in: DistributedBackupDescriptor{ | |
Nodes: map[string]*NodeDescriptor{ | |
"N1": {Classes: []string{"1", "2"}}, | |
"N2": {Classes: []string{"3", "4"}}, | |
}, | |
}, | |
xs: []string{"2", "3"}, | |
out: []string{"2", "3"}, | |
}, | |
{ | |
in: DistributedBackupDescriptor{ | |
Nodes: map[string]*NodeDescriptor{ | |
"N1": {Classes: []string{"1", "2"}}, | |
"N2": {Classes: []string{"3"}}, | |
}, | |
}, | |
xs: []string{"1", "3"}, | |
out: []string{"1", "3"}, | |
}, | |
} | |
for _, tc := range tests { | |
tc.in.Include(tc.xs) | |
lst := tc.in.Classes() | |
sort.Strings(lst) | |
assert.Equal(t, tc.out, lst) | |
} | |
} | |
func TestDistributedBackupAllExist(t *testing.T) { | |
x := DistributedBackupDescriptor{Nodes: map[string]*NodeDescriptor{"N1": {Classes: []string{"a"}}}} | |
if y := x.AllExist(nil); y != "" { | |
t.Errorf("x.AllExists(nil) got=%v want=%v", y, "") | |
} | |
if y := x.AllExist([]string{"a"}); y != "" { | |
t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "") | |
} | |
if y := x.AllExist([]string{"b"}); y != "b" { | |
t.Errorf("x.AllExists(['a']) got=%v want=%v", y, "b") | |
} | |
} | |
func TestDistributedBackupValidate(t *testing.T) { | |
timept := time.Now().UTC() | |
tests := []struct { | |
desc DistributedBackupDescriptor | |
success bool | |
}{ | |
// first level check | |
{desc: DistributedBackupDescriptor{}}, | |
{desc: DistributedBackupDescriptor{ID: "1"}}, | |
{desc: DistributedBackupDescriptor{ID: "1", Version: "1"}}, | |
{desc: DistributedBackupDescriptor{ID: "1", Version: "1", ServerVersion: "1"}}, | |
{desc: DistributedBackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, Error: "err"}}, | |
{desc: DistributedBackupDescriptor{ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept}}, | |
{desc: DistributedBackupDescriptor{ | |
ID: "1", Version: "1", ServerVersion: "1", StartedAt: timept, | |
Nodes: map[string]*NodeDescriptor{"N": {}}, | |
}, success: true}, | |
} | |
for i, tc := range tests { | |
err := tc.desc.Validate() | |
if got := err == nil; got != tc.success { | |
t.Errorf("%d. validate(%+v): want=%v got=%v err=%v", i, tc.desc, tc.success, got, err) | |
} | |
} | |
} | |
func TestTestDistributedBackupResetStatus(t *testing.T) { | |
begin := time.Now().UTC().Add(-2) | |
desc := DistributedBackupDescriptor{ | |
StartedAt: begin, | |
CompletedAt: begin.Add(2), | |
ID: "1", | |
Version: "1", | |
ServerVersion: "1", | |
Nodes: map[string]*NodeDescriptor{ | |
"1": {}, | |
"2": {Status: Success}, | |
"3": {Error: "error"}, | |
}, | |
Error: "error", | |
} | |
desc.ResetStatus() | |
if !desc.StartedAt.After(begin) { | |
t.Fatalf("!desc.StartedAt.After(begin)") | |
} | |
want := DistributedBackupDescriptor{ | |
StartedAt: desc.StartedAt, | |
ID: "1", | |
Version: "1", | |
ServerVersion: "1", | |
Nodes: map[string]*NodeDescriptor{ | |
"1": {Status: Started}, | |
"2": {Status: Started}, | |
"3": {Status: Started, Error: ""}, | |
}, | |
Status: Started, | |
} | |
assert.Equal(t, want, desc) | |
} | |
func TestShardDescriptorClear(t *testing.T) { | |
s := ShardDescriptor{ | |
Name: "name", | |
Node: "node", | |
PropLengthTrackerPath: "a/b", | |
PropLengthTracker: []byte{1}, | |
DocIDCounterPath: "a/c", | |
DocIDCounter: []byte{2}, | |
ShardVersionPath: "a/d", | |
Version: []byte{3}, | |
Files: []string{"file"}, | |
Chunk: 1, | |
} | |
want := ShardDescriptor{ | |
Name: "name", | |
Node: "node", | |
Files: []string{"file"}, | |
Chunk: 1, | |
} | |
s.ClearTemporary() | |
assert.Equal(t, want, s) | |
} | |