kevo/pkg/common/clock/lamport_test.go

155 lines
3.7 KiB
Go

package clock
import (
"testing"
)
func TestLamportClock_Tick(t *testing.T) {
nodeID := NodeID{1, 2, 3}
clock := NewLamportClock(nodeID)
// Initial tick should return 1
ts1 := clock.Tick()
if ts1.Counter != 1 {
t.Errorf("Expected counter to be 1, got %d", ts1.Counter)
}
// Next tick should return 2
ts2 := clock.Tick()
if ts2.Counter != 2 {
t.Errorf("Expected counter to be 2, got %d", ts2.Counter)
}
// NodeID should be preserved
if !ts1.Node.Equal(nodeID) {
t.Errorf("NodeID not preserved in timestamp")
}
}
func TestLamportClock_Update(t *testing.T) {
nodeID1 := NodeID{1, 2, 3}
nodeID2 := NodeID{4, 5, 6}
clock1 := NewLamportClock(nodeID1)
clock2 := NewLamportClock(nodeID2)
// Advance clock1 to 5
for i := 0; i < 5; i++ {
clock1.Tick()
}
// Get current timestamp from clock1
ts1 := clock1.GetCurrent()
if ts1.Counter != 5 {
t.Errorf("Expected counter to be 5, got %d", ts1.Counter)
}
// Update clock2 with timestamp from clock1
ts2 := clock2.Update(ts1)
// Clock2 should now be at least as large as clock1's timestamp + 1
if ts2.Counter <= ts1.Counter {
t.Errorf("Expected clock2 counter > %d, got %d", ts1.Counter, ts2.Counter)
}
// Clock2's NodeID should still be nodeID2
if !ts2.Node.Equal(nodeID2) {
t.Errorf("NodeID not preserved after update")
}
}
func TestLamportClock_Ordering(t *testing.T) {
nodeID1 := NodeID{1, 2, 3}
nodeID2 := NodeID{4, 5, 6}
// Create timestamps with the same counter but different NodeIDs
ts1 := Timestamp{Counter: 5, Node: nodeID1}
ts2 := Timestamp{Counter: 5, Node: nodeID2}
// Compare should break ties using NodeID
if Compare(ts1, ts2) >= 0 {
t.Errorf("Expected ts1 < ts2 when counters are equal")
}
// Create timestamps with different counters
ts3 := Timestamp{Counter: 6, Node: nodeID1}
ts4 := Timestamp{Counter: 5, Node: nodeID2}
// Compare should prioritize counter values
if Compare(ts3, ts4) <= 0 {
t.Errorf("Expected ts3 > ts4 when ts3.Counter > ts4.Counter")
}
}
func TestLamportClock_Serialization(t *testing.T) {
nodeID := NodeID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
ts := Timestamp{Counter: 42, Node: nodeID}
// Serialize
bytes := ts.Bytes()
// Deserialize
ts2, err := TimestampFromBytes(bytes)
if err != nil {
t.Fatalf("Failed to deserialize timestamp: %v", err)
}
// Compare
if ts.Counter != ts2.Counter {
t.Errorf("Counter not preserved in serialization, expected %d got %d", ts.Counter, ts2.Counter)
}
if !ts.Node.Equal(ts2.Node) {
t.Errorf("NodeID not preserved in serialization")
}
}
func TestLamportClock_Concurrent(t *testing.T) {
nodeID := NodeID{1, 2, 3}
clock := NewLamportClock(nodeID)
// Run 100 concurrent ticks
done := make(chan struct{})
for i := 0; i < 100; i++ {
go func() {
clock.Tick()
done <- struct{}{}
}()
}
// Wait for all ticks to complete
for i := 0; i < 100; i++ {
<-done
}
// Counter should be 100
ts := clock.GetCurrent()
if ts.Counter != 100 {
t.Errorf("Expected counter to be 100 after 100 concurrent ticks, got %d", ts.Counter)
}
}
func TestLamportClock_ManualSet(t *testing.T) {
nodeID := NodeID{1, 2, 3}
clock := NewLamportClock(nodeID)
// Set to a high value
clock.ManualSet(1000)
ts := clock.GetCurrent()
if ts.Counter != 1000 {
t.Errorf("Expected counter to be 1000 after ManualSet, got %d", ts.Counter)
}
// Setting to a lower value should have no effect
clock.ManualSet(500)
ts = clock.GetCurrent()
if ts.Counter != 1000 {
t.Errorf("Expected counter to remain 1000 after lower ManualSet, got %d", ts.Counter)
}
// Tick should still increment
ts = clock.Tick()
if ts.Counter != 1001 {
t.Errorf("Expected counter to be 1001 after tick, got %d", ts.Counter)
}
}