|
|
@ -1,11 +1,12 @@
|
|
|
|
package clock
|
|
|
|
package clock
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
import (
|
|
|
|
|
|
|
|
"math"
|
|
|
|
"reflect"
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
func assertClocksEqual(t testing.TB, got, want []uint) {
|
|
|
|
func assertClocksEqual[T Uint](t testing.TB, got, want []T) {
|
|
|
|
t.Helper()
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(got, want) {
|
|
|
|
if !reflect.DeepEqual(got, want) {
|
|
|
@ -16,24 +17,51 @@ func assertClocksEqual(t testing.TB, got, want []uint) {
|
|
|
|
|
|
|
|
|
|
|
|
func TestVectorClock(t *testing.T) {
|
|
|
|
func TestVectorClock(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("start value sync", func(t *testing.T) {
|
|
|
|
t.Run("test cases for uint32 type", func(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
testCases := []struct {
|
|
|
|
a []uint
|
|
|
|
a []uint32
|
|
|
|
b []uint
|
|
|
|
b []uint32
|
|
|
|
expected []uint
|
|
|
|
expected []uint32
|
|
|
|
}{
|
|
|
|
}{
|
|
|
|
{[]uint{0, 0}, []uint{0, 0}, []uint{0, 0}},
|
|
|
|
{[]uint32{0, 0}, []uint32{0, 0}, []uint32{0, 0}},
|
|
|
|
{[]uint{2, 0}, []uint{0, 2}, []uint{2, 2}},
|
|
|
|
{[]uint32{2, 0}, []uint32{0, 2}, []uint32{2, 2}},
|
|
|
|
{[]uint{4, 11}, []uint{3, 10}, []uint{4, 11}},
|
|
|
|
{[]uint32{4, 11}, []uint32{3, 10}, []uint32{4, 11}},
|
|
|
|
{[]uint{5, 9}, []uint{8, 12}, []uint{8, 12}},
|
|
|
|
{[]uint32{5, 9}, []uint32{8, 12}, []uint32{8, 12}},
|
|
|
|
{[]uint{1, 1}, []uint{1, 1}, []uint{1, 1}},
|
|
|
|
{[]uint32{1, 1}, []uint32{1, 1}, []uint32{1, 1}},
|
|
|
|
// {[]uint{math.MaxUint32, 1}, []uint{(math.MaxUint32 + 1), 1}, []uint{1, 1}},
|
|
|
|
{[]uint32{math.MaxUint32, 1}, []uint32{2, 1}, []uint32{4294967295, 1}},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
for _, tc := range testCases {
|
|
|
|
vc := VectorClock{clock: tc.a}
|
|
|
|
vc := VectorClock[uint32]{clock: tc.a}
|
|
|
|
|
|
|
|
|
|
|
|
clock, err := vc.Sync(VectorClock{clock: tc.b})
|
|
|
|
clock, err := vc.Sync(VectorClock[uint32]{clock: tc.b})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
t.Errorf("Sync should not have errored")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, clock, tc.expected)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("test cases for uint64 type", func(t *testing.T) {
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
|
|
|
|
a []uint64
|
|
|
|
|
|
|
|
b []uint64
|
|
|
|
|
|
|
|
expected []uint64
|
|
|
|
|
|
|
|
}{
|
|
|
|
|
|
|
|
{[]uint64{0, 0}, []uint64{0, 0}, []uint64{0, 0}},
|
|
|
|
|
|
|
|
{[]uint64{2, 0}, []uint64{0, 2}, []uint64{2, 2}},
|
|
|
|
|
|
|
|
{[]uint64{4, 11}, []uint64{3, 10}, []uint64{4, 11}},
|
|
|
|
|
|
|
|
{[]uint64{5, 9}, []uint64{8, 12}, []uint64{8, 12}},
|
|
|
|
|
|
|
|
{[]uint64{1, 1}, []uint64{1, 1}, []uint64{1, 1}},
|
|
|
|
|
|
|
|
{[]uint64{math.MaxUint64, 1}, []uint64{2, 1}, []uint64{18446744073709551615, 1}},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
|
|
|
|
vc := VectorClock[uint64]{clock: tc.a}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
clock, err := vc.Sync(VectorClock[uint64]{clock: tc.b})
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Sync should not have errored")
|
|
|
|
t.Errorf("Sync should not have errored")
|
|
|
@ -44,51 +72,89 @@ func TestVectorClock(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("basic sync 2", func(t *testing.T) {
|
|
|
|
t.Run("test empty new", func(t *testing.T) {
|
|
|
|
vc := VectorClock{clock: []uint{4, 11}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
clock, err := vc.Sync(VectorClock{clock: []uint{4, 10}})
|
|
|
|
got := NewVectorClock[uint32](2)
|
|
|
|
|
|
|
|
want := VectorClock[uint32]{clock: []uint32{0, 0}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("test new vc for uint32", func(t *testing.T) {
|
|
|
|
|
|
|
|
vc := VectorClock[uint32]{clock: []uint32{4, 11}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
clock, err := vc.Increment(0)
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Sync should not have errored")
|
|
|
|
t.Errorf("Increment should not have errored")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, clock, []uint{4, 11})
|
|
|
|
assertClocksEqual(t, clock, []uint32{5, 11})
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
clock, err = vc.Increment(1)
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("basic sync", func(t *testing.T) {
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
t.Errorf("Increment should not have errored")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, clock, []uint32{5, 12})
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
t.Run("basic sync", func(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("test overflow condition", func(t *testing.T) {
|
|
|
|
|
|
|
|
vc := VectorClock[uint32]{clock: []uint32{math.MaxUint32, 11}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
clock, err := vc.Increment(0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
t.Errorf("Increment should not have errored")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, clock, []uint32{0, 11})
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
vc := VectorClock{clock: []uint{2, 0}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
clock, err := vc.Sync(VectorClock{clock: []uint{0, 2}})
|
|
|
|
t.Run("test index cannot be incremented", func(t *testing.T) {
|
|
|
|
|
|
|
|
vc := VectorClock[uint64]{}
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
clock, err := vc.Increment(0)
|
|
|
|
t.Errorf("Sync should not have errored")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, clock, []uint{2, 2})
|
|
|
|
if clock != nil {
|
|
|
|
|
|
|
|
t.Errorf("Clock should be nil")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
t.Errorf("There should have been an error")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestNewVectorClock(t *testing.T) {
|
|
|
|
func TestNewVectorClock(t *testing.T) {
|
|
|
|
got := NewVectorClock(2)
|
|
|
|
t.Run("test new vc for uint32", func(t *testing.T) {
|
|
|
|
want := VectorClock{clock: []uint{0, 0}}
|
|
|
|
|
|
|
|
|
|
|
|
got := NewVectorClock[uint32](2)
|
|
|
|
|
|
|
|
want := VectorClock[uint32]{clock: []uint32{0, 0}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("test new vc for uint64", func(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
got := NewVectorClock[uint64](2)
|
|
|
|
|
|
|
|
want := VectorClock[uint64]{clock: []uint64{0, 0}}
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestArrayToVectorClock(t *testing.T) {
|
|
|
|
func TestArrayToVectorClock(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("from empty slice", func(t *testing.T) {
|
|
|
|
t.Run("from empty slice", func(t *testing.T) {
|
|
|
|
got := ArrayToVectorClock([]uint{})
|
|
|
|
got := ArrayToVectorClock([]uint32{})
|
|
|
|
want := VectorClock{
|
|
|
|
want := VectorClock[uint32]{
|
|
|
|
clock: []uint{},
|
|
|
|
clock: []uint32{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if len(got.GetClock()) != 0 {
|
|
|
|
if len(got.GetClock()) != 0 {
|
|
|
@ -101,34 +167,34 @@ func TestArrayToVectorClock(t *testing.T) {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("from zero slice", func(t *testing.T) {
|
|
|
|
t.Run("from zero slice", func(t *testing.T) {
|
|
|
|
got := ArrayToVectorClock(make([]uint, 6))
|
|
|
|
got := ArrayToVectorClock(make([]uint64, 6))
|
|
|
|
want := VectorClock{
|
|
|
|
want := VectorClock[uint64]{
|
|
|
|
clock: []uint{0, 0, 0, 0, 0, 0},
|
|
|
|
clock: []uint64{0, 0, 0, 0, 0, 0},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("from start clock", func(t *testing.T) {
|
|
|
|
t.Run("from start clock", func(t *testing.T) {
|
|
|
|
want := NewVectorClock(3)
|
|
|
|
want := NewVectorClock[uint64](3)
|
|
|
|
got := ArrayToVectorClock(want.GetClock())
|
|
|
|
got := ArrayToVectorClock(want.GetClock())
|
|
|
|
|
|
|
|
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("from a populated clock", func(t *testing.T) {
|
|
|
|
t.Run("from a populated clock", func(t *testing.T) {
|
|
|
|
want := VectorClock{
|
|
|
|
want := VectorClock[uint32]{
|
|
|
|
clock: []uint{2, 3},
|
|
|
|
clock: []uint32{2, 3},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
got := ArrayToVectorClock(want.GetClock())
|
|
|
|
got := ArrayToVectorClock(want.GetClock())
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
assertClocksEqual(t, got.GetClock(), want.GetClock())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
t.Run("from a slice that is then modified", func(t *testing.T) {
|
|
|
|
t.Run("from a slice that is then modified", func(t *testing.T) {
|
|
|
|
initial_a := []uint{1, 2, 3, 4}
|
|
|
|
initial_a := []uint64{1, 2, 3, 4}
|
|
|
|
got := ArrayToVectorClock(initial_a)
|
|
|
|
got := ArrayToVectorClock(initial_a)
|
|
|
|
|
|
|
|
|
|
|
|
want := make([]uint, len(initial_a))
|
|
|
|
want := make([]uint64, len(initial_a))
|
|
|
|
copy(want, initial_a)
|
|
|
|
copy(want, initial_a)
|
|
|
|
|
|
|
|
|
|
|
|
initial_a[0] = 12
|
|
|
|
initial_a[0] = 12
|
|
|
|