Reformat/cleanup
All checks were successful
NuGet Package Publish / nuget (push) Successful in 1m10s
All checks were successful
NuGet Package Publish / nuget (push) Successful in 1m10s
This commit is contained in:
@@ -1,17 +1,13 @@
|
||||
using ZB.MOM.WW.CBDDC.Core;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace ZB.MOM.WW.CBDDC.Core.Tests;
|
||||
|
||||
public class VectorClockTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verifies an empty vector clock returns the default timestamp for unknown nodes.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void EmptyVectorClock_ShouldReturnDefaultTimestamp()
|
||||
{
|
||||
public class VectorClockTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verifies an empty vector clock returns the default timestamp for unknown nodes.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void EmptyVectorClock_ShouldReturnDefaultTimestamp()
|
||||
{
|
||||
// Arrange
|
||||
var vc = new VectorClock();
|
||||
|
||||
@@ -19,15 +15,15 @@ public class VectorClockTests
|
||||
var ts = vc.GetTimestamp("node1");
|
||||
|
||||
// Assert
|
||||
ts.ShouldBe(default(HlcTimestamp));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies setting a timestamp stores it for the specified node.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void SetTimestamp_ShouldStoreTimestamp()
|
||||
{
|
||||
ts.ShouldBe(default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies setting a timestamp stores it for the specified node.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void SetTimestamp_ShouldStoreTimestamp()
|
||||
{
|
||||
// Arrange
|
||||
var vc = new VectorClock();
|
||||
var ts = new HlcTimestamp(100, 1, "node1");
|
||||
@@ -36,15 +32,15 @@ public class VectorClockTests
|
||||
vc.SetTimestamp("node1", ts);
|
||||
|
||||
// Assert
|
||||
vc.GetTimestamp("node1").ShouldBe(ts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies node identifiers are returned for all known nodes.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void NodeIds_ShouldReturnAllNodes()
|
||||
{
|
||||
vc.GetTimestamp("node1").ShouldBe(ts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies node identifiers are returned for all known nodes.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void NodeIds_ShouldReturnAllNodes()
|
||||
{
|
||||
// Arrange
|
||||
var vc = new VectorClock();
|
||||
vc.SetTimestamp("node1", new HlcTimestamp(100, 1, "node1"));
|
||||
@@ -56,15 +52,15 @@ public class VectorClockTests
|
||||
// Assert
|
||||
nodeIds.Count.ShouldBe(2);
|
||||
nodeIds.ShouldContain("node1");
|
||||
nodeIds.ShouldContain("node2");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies equal vector clocks are compared as equal.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CompareTo_EqualClocks_ShouldReturnEqual()
|
||||
{
|
||||
nodeIds.ShouldContain("node2");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies equal vector clocks are compared as equal.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CompareTo_EqualClocks_ShouldReturnEqual()
|
||||
{
|
||||
// Arrange
|
||||
var vc1 = new VectorClock();
|
||||
vc1.SetTimestamp("node1", new HlcTimestamp(100, 1, "node1"));
|
||||
@@ -78,15 +74,15 @@ public class VectorClockTests
|
||||
var result = vc1.CompareTo(vc2);
|
||||
|
||||
// Assert
|
||||
result.ShouldBe(CausalityRelation.Equal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies a clock strictly ahead of another is reported as strictly ahead.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CompareTo_StrictlyAhead_ShouldReturnStrictlyAhead()
|
||||
{
|
||||
result.ShouldBe(CausalityRelation.Equal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies a clock strictly ahead of another is reported as strictly ahead.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CompareTo_StrictlyAhead_ShouldReturnStrictlyAhead()
|
||||
{
|
||||
// Arrange
|
||||
var vc1 = new VectorClock();
|
||||
vc1.SetTimestamp("node1", new HlcTimestamp(200, 1, "node1")); // Ahead
|
||||
@@ -100,15 +96,15 @@ public class VectorClockTests
|
||||
var result = vc1.CompareTo(vc2);
|
||||
|
||||
// Assert
|
||||
result.ShouldBe(CausalityRelation.StrictlyAhead);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies a clock strictly behind another is reported as strictly behind.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CompareTo_StrictlyBehind_ShouldReturnStrictlyBehind()
|
||||
{
|
||||
result.ShouldBe(CausalityRelation.StrictlyAhead);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies a clock strictly behind another is reported as strictly behind.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CompareTo_StrictlyBehind_ShouldReturnStrictlyBehind()
|
||||
{
|
||||
// Arrange
|
||||
var vc1 = new VectorClock();
|
||||
vc1.SetTimestamp("node1", new HlcTimestamp(100, 1, "node1")); // Behind
|
||||
@@ -122,15 +118,15 @@ public class VectorClockTests
|
||||
var result = vc1.CompareTo(vc2);
|
||||
|
||||
// Assert
|
||||
result.ShouldBe(CausalityRelation.StrictlyBehind);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies divergent per-node progress is reported as concurrent.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CompareTo_Concurrent_ShouldReturnConcurrent()
|
||||
{
|
||||
result.ShouldBe(CausalityRelation.StrictlyBehind);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies divergent per-node progress is reported as concurrent.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CompareTo_Concurrent_ShouldReturnConcurrent()
|
||||
{
|
||||
// Arrange - Split brain scenario
|
||||
var vc1 = new VectorClock();
|
||||
vc1.SetTimestamp("node1", new HlcTimestamp(200, 1, "node1")); // Node1 ahead
|
||||
@@ -144,15 +140,15 @@ public class VectorClockTests
|
||||
var result = vc1.CompareTo(vc2);
|
||||
|
||||
// Assert
|
||||
result.ShouldBe(CausalityRelation.Concurrent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies pull candidates include nodes where the other clock is ahead.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetNodesWithUpdates_ShouldReturnNodesWhereOtherIsAhead()
|
||||
{
|
||||
result.ShouldBe(CausalityRelation.Concurrent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies pull candidates include nodes where the other clock is ahead.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetNodesWithUpdates_ShouldReturnNodesWhereOtherIsAhead()
|
||||
{
|
||||
// Arrange
|
||||
var vc1 = new VectorClock();
|
||||
vc1.SetTimestamp("node1", new HlcTimestamp(100, 1, "node1"));
|
||||
@@ -167,15 +163,15 @@ public class VectorClockTests
|
||||
|
||||
// Assert
|
||||
nodesToPull.Count().ShouldBe(1);
|
||||
nodesToPull.ShouldContain("node1");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies push candidates include nodes where this clock is ahead.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetNodesToPush_ShouldReturnNodesWhereThisIsAhead()
|
||||
{
|
||||
nodesToPull.ShouldContain("node1");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies push candidates include nodes where this clock is ahead.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetNodesToPush_ShouldReturnNodesWhereThisIsAhead()
|
||||
{
|
||||
// Arrange
|
||||
var vc1 = new VectorClock();
|
||||
vc1.SetTimestamp("node1", new HlcTimestamp(200, 1, "node1")); // Ahead
|
||||
@@ -190,15 +186,15 @@ public class VectorClockTests
|
||||
|
||||
// Assert
|
||||
nodesToPush.Count().ShouldBe(1);
|
||||
nodesToPush.ShouldContain("node1");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies a newly introduced remote node is included in pull candidates.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetNodesWithUpdates_WhenNewNodeAppearsInOther_ShouldReturnIt()
|
||||
{
|
||||
nodesToPush.ShouldContain("node1");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies a newly introduced remote node is included in pull candidates.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetNodesWithUpdates_WhenNewNodeAppearsInOther_ShouldReturnIt()
|
||||
{
|
||||
// Arrange - Simulates a new node joining the cluster
|
||||
var vc1 = new VectorClock();
|
||||
vc1.SetTimestamp("node1", new HlcTimestamp(100, 1, "node1"));
|
||||
@@ -212,15 +208,15 @@ public class VectorClockTests
|
||||
|
||||
// Assert
|
||||
nodesToPull.Count().ShouldBe(1);
|
||||
nodesToPull.ShouldContain("node3");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies merge keeps the maximum timestamp per node.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Merge_ShouldTakeMaximumForEachNode()
|
||||
{
|
||||
nodesToPull.ShouldContain("node3");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies merge keeps the maximum timestamp per node.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Merge_ShouldTakeMaximumForEachNode()
|
||||
{
|
||||
// Arrange
|
||||
var vc1 = new VectorClock();
|
||||
vc1.SetTimestamp("node1", new HlcTimestamp(200, 1, "node1"));
|
||||
@@ -234,18 +230,18 @@ public class VectorClockTests
|
||||
// Act
|
||||
vc1.Merge(vc2);
|
||||
|
||||
// Assert
|
||||
vc1.GetTimestamp("node1").ShouldBe(new HlcTimestamp(200, 1, "node1")); // Kept max
|
||||
vc1.GetTimestamp("node2").ShouldBe(new HlcTimestamp(200, 2, "node2")); // Merged max
|
||||
vc1.GetTimestamp("node3").ShouldBe(new HlcTimestamp(150, 1, "node3")); // Added new
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies cloning creates an independent copy of the vector clock.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Clone_ShouldCreateIndependentCopy()
|
||||
{
|
||||
// Assert
|
||||
vc1.GetTimestamp("node1").ShouldBe(new HlcTimestamp(200, 1, "node1")); // Kept max
|
||||
vc1.GetTimestamp("node2").ShouldBe(new HlcTimestamp(200, 2, "node2")); // Merged max
|
||||
vc1.GetTimestamp("node3").ShouldBe(new HlcTimestamp(150, 1, "node3")); // Added new
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies cloning creates an independent copy of the vector clock.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Clone_ShouldCreateIndependentCopy()
|
||||
{
|
||||
// Arrange
|
||||
var vc1 = new VectorClock();
|
||||
vc1.SetTimestamp("node1", new HlcTimestamp(100, 1, "node1"));
|
||||
@@ -256,15 +252,15 @@ public class VectorClockTests
|
||||
|
||||
// Assert
|
||||
vc1.NodeIds.Count().ShouldBe(1);
|
||||
vc2.NodeIds.Count().ShouldBe(2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the string representation includes serialized node timestamps.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ToString_ShouldReturnReadableFormat()
|
||||
{
|
||||
vc2.NodeIds.Count().ShouldBe(2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the string representation includes serialized node timestamps.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ToString_ShouldReturnReadableFormat()
|
||||
{
|
||||
// Arrange
|
||||
var vc = new VectorClock();
|
||||
vc.SetTimestamp("node1", new HlcTimestamp(100, 1, "node1"));
|
||||
@@ -275,15 +271,15 @@ public class VectorClockTests
|
||||
|
||||
// Assert
|
||||
str.ShouldContain("node1:100:1:node1");
|
||||
str.ShouldContain("node2:200:2:node2");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies split-brain updates are detected as concurrent.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void SplitBrainScenario_ShouldDetectConcurrency()
|
||||
{
|
||||
str.ShouldContain("node2:200:2:node2");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies split-brain updates are detected as concurrent.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void SplitBrainScenario_ShouldDetectConcurrency()
|
||||
{
|
||||
// Arrange - Simulating a network partition scenario
|
||||
// Partition 1: node1 and node2 are alive
|
||||
var vcPartition1 = new VectorClock();
|
||||
@@ -310,4 +306,4 @@ public class VectorClockTests
|
||||
partition1NeedsToPush.ShouldContain("node1");
|
||||
partition1NeedsToPush.ShouldContain("node2");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user