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) } }