fix tests. new product advisories enhancements
This commit is contained in:
@@ -25,8 +25,7 @@ public class CrossServiceClockSkewTests : IClassFixture<ClockSkewServiceFixture>
|
||||
public CrossServiceClockSkewTests(ClockSkewServiceFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_fixture.ResetAllClocks();
|
||||
_fixture.ClearEventLog();
|
||||
_fixture.ResetAllServices(); // Full reset for test isolation - recreates HLCs with fresh state
|
||||
}
|
||||
|
||||
#region Scanner-Concelier Skew Tests
|
||||
|
||||
@@ -74,7 +74,7 @@ public sealed class ClockSkewServiceFixture : IAsyncLifetime
|
||||
serviceId,
|
||||
stateStore,
|
||||
NullLogger<HybridLogicalClock.HybridLogicalClock>.Instance,
|
||||
TimeSpan.FromMinutes(1));
|
||||
TimeSpan.FromMinutes(5)); // Allow 5 minutes clock skew tolerance for testing extreme scenarios
|
||||
|
||||
var service = new ServiceClock(serviceId, timeProvider, hlc, clockOffset);
|
||||
_services[serviceId] = service;
|
||||
@@ -233,6 +233,8 @@ public sealed class ClockSkewServiceFixture : IAsyncLifetime
|
||||
|
||||
/// <summary>
|
||||
/// Resets all service clocks to base time with no offset.
|
||||
/// Note: This only resets time providers, not HLC internal state.
|
||||
/// For full reset, use ResetAllServices() instead.
|
||||
/// </summary>
|
||||
public void ResetAllClocks()
|
||||
{
|
||||
@@ -244,6 +246,27 @@ public sealed class ClockSkewServiceFixture : IAsyncLifetime
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completely resets all services by recreating them with fresh HLC state.
|
||||
/// Call this between tests to ensure test isolation.
|
||||
/// </summary>
|
||||
public void ResetAllServices()
|
||||
{
|
||||
foreach (var service in _services.Values)
|
||||
{
|
||||
service.Dispose();
|
||||
}
|
||||
_services.Clear();
|
||||
_eventLog.Clear();
|
||||
_globalEventSequence = 0;
|
||||
|
||||
// Recreate default services
|
||||
CreateService("scanner", TimeSpan.Zero);
|
||||
CreateService("concelier", TimeSpan.Zero);
|
||||
CreateService("gateway", TimeSpan.Zero);
|
||||
CreateService("backend", TimeSpan.Zero);
|
||||
}
|
||||
|
||||
private ServiceClock GetService(string serviceId)
|
||||
{
|
||||
return _services.TryGetValue(serviceId, out var service)
|
||||
|
||||
@@ -23,6 +23,7 @@ public class DistributedHlcTests : IClassFixture<MultiNodeHlcFixture>
|
||||
public DistributedHlcTests(MultiNodeHlcFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_fixture.Reset(); // Ensure clean state for each test
|
||||
}
|
||||
|
||||
#region Multi-Node Causal Ordering Tests
|
||||
|
||||
@@ -50,6 +50,18 @@ public sealed class MultiNodeHlcFixture : IAsyncLifetime
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the fixture state for test isolation.
|
||||
/// Call this at the beginning of each test to ensure clean state.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_nodes.Clear();
|
||||
_partitionSimulator.HealAll();
|
||||
_partitionSimulator.ClearLatencies();
|
||||
ClearEventLog();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new node with its own HLC instance.
|
||||
/// </summary>
|
||||
@@ -69,7 +81,7 @@ public sealed class MultiNodeHlcFixture : IAsyncLifetime
|
||||
nodeId,
|
||||
stateStore,
|
||||
NullLogger<HybridLogicalClock.HybridLogicalClock>.Instance,
|
||||
TimeSpan.FromMinutes(1));
|
||||
TimeSpan.FromHours(2)); // Allow 2 hours clock skew tolerance for testing long partition scenarios
|
||||
|
||||
var context = new NodeContext(clock, timeProvider, stateStore, nodeId);
|
||||
_nodes[nodeId] = context;
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed class NetworkPartitionSimulator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partitions communication between two specific nodes.
|
||||
/// Partitions communication between two specific nodes (bidirectional).
|
||||
/// </summary>
|
||||
public void PartitionNodes(string nodeA, string nodeB)
|
||||
{
|
||||
@@ -57,6 +57,39 @@ public sealed class NetworkPartitionSimulator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partitions communication in one direction only (fromNode cannot send to toNode).
|
||||
/// </summary>
|
||||
public void PartitionOneWay(string fromNode, string toNode)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(fromNode);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(toNode);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_partitions.TryGetValue(fromNode, out var partitions))
|
||||
{
|
||||
partitions = [];
|
||||
_partitions[fromNode] = partitions;
|
||||
}
|
||||
partitions.Add(toNode);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Heals a one-way partition (allows fromNode to send to toNode again).
|
||||
/// </summary>
|
||||
public void HealOneWay(string fromNode, string toNode)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_partitions.TryGetValue(fromNode, out var partitions))
|
||||
{
|
||||
partitions.Remove(toNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Heals the partition for a specific node (restores connectivity).
|
||||
/// </summary>
|
||||
@@ -106,13 +139,15 @@ public sealed class NetworkPartitionSimulator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if communication between two nodes is blocked.
|
||||
/// Checks if communication from fromNode to toNode is blocked.
|
||||
/// Note: Partitions are directional - if A has B in its list, A cannot send to B.
|
||||
/// A full isolation (marked with "*") blocks both sending and receiving.
|
||||
/// </summary>
|
||||
public bool IsPartitioned(string fromNode, string toNode)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
// Check if fromNode is fully isolated
|
||||
// Check if fromNode is fully isolated or has toNode in its partition list
|
||||
if (_partitions.TryGetValue(fromNode, out var fromPartitions))
|
||||
{
|
||||
if (fromPartitions.Contains("*") || fromPartitions.Contains(toNode))
|
||||
@@ -121,10 +156,10 @@ public sealed class NetworkPartitionSimulator
|
||||
}
|
||||
}
|
||||
|
||||
// Check if toNode is fully isolated
|
||||
// Check if toNode is fully isolated (cannot receive from anyone)
|
||||
if (_partitions.TryGetValue(toNode, out var toPartitions))
|
||||
{
|
||||
if (toPartitions.Contains("*") || toPartitions.Contains(fromNode))
|
||||
if (toPartitions.Contains("*"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ public class HlcNetworkPartitionTests : IClassFixture<MultiNodeHlcFixture>
|
||||
public HlcNetworkPartitionTests(MultiNodeHlcFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_fixture.Reset(); // Ensure clean state for each test
|
||||
}
|
||||
|
||||
#region Basic Partition Tests
|
||||
@@ -98,9 +99,8 @@ public class HlcNetworkPartitionTests : IClassFixture<MultiNodeHlcFixture>
|
||||
_fixture.CreateNode("asym-a", baseTime);
|
||||
_fixture.CreateNode("asym-b", baseTime);
|
||||
|
||||
// Only partition B -> A direction
|
||||
_fixture.PartitionSimulator.PartitionNodes("asym-b", "asym-a");
|
||||
_fixture.PartitionSimulator.HealPartition("asym-a", "asym-b"); // Allow A -> B
|
||||
// Only partition B -> A direction (B cannot send to A)
|
||||
_fixture.PartitionSimulator.PartitionOneWay("asym-b", "asym-a");
|
||||
|
||||
// Act - A can send to B
|
||||
var tsA = _fixture.Tick("asym-a");
|
||||
|
||||
Reference in New Issue
Block a user