Files
CBDDC/tests/ZB.MOM.WW.CBDDC.Sample.Console.Tests/PeerOplogConfirmationStoreTests.cs

109 lines
4.5 KiB
C#

using Microsoft.Extensions.Logging.Abstractions;
using ZB.MOM.WW.CBDDC.Core;
using ZB.MOM.WW.CBDDC.Core.Network;
using ZB.MOM.WW.CBDDC.Persistence.BLite;
namespace ZB.MOM.WW.CBDDC.Sample.Console.Tests;
public class PeerOplogConfirmationStoreTests : IDisposable
{
private readonly string _testDbPath;
private readonly SampleDbContext _context;
private readonly BLitePeerOplogConfirmationStore<SampleDbContext> _store;
/// <summary>
/// Initializes a new instance of the <see cref="PeerOplogConfirmationStoreTests"/> class.
/// </summary>
public PeerOplogConfirmationStoreTests()
{
_testDbPath = Path.Combine(Path.GetTempPath(), $"test-peer-confirmation-{Guid.NewGuid()}.blite");
_context = new SampleDbContext(_testDbPath);
_store = new BLitePeerOplogConfirmationStore<SampleDbContext>(
_context,
NullLogger<BLitePeerOplogConfirmationStore<SampleDbContext>>.Instance);
}
/// <summary>
/// Verifies that ensuring peer registration multiple times remains idempotent.
/// </summary>
[Fact]
public async Task EnsurePeerRegisteredAsync_IsIdempotent()
{
await _store.EnsurePeerRegisteredAsync("peer-a", "10.0.0.10:5050", PeerType.StaticRemote);
await _store.EnsurePeerRegisteredAsync("peer-a", "10.0.0.10:5050", PeerType.StaticRemote);
var active = (await _store.GetActiveTrackedPeersAsync()).ToList();
var exported = (await _store.ExportAsync()).ToList();
active.Count.ShouldBe(1);
active[0].ShouldBe("peer-a");
exported.Count(x => x.PeerNodeId == "peer-a" && x.SourceNodeId == "__peer_registration__").ShouldBe(1);
}
/// <summary>
/// Verifies create, update, and read flows for peer oplog confirmations.
/// </summary>
[Fact]
public async Task ConfirmationStore_CrudFlow_Works()
{
await _store.EnsurePeerRegisteredAsync("peer-a", "10.0.0.10:5050", PeerType.StaticRemote);
await _store.UpdateConfirmationAsync("peer-a", "source-1", new HlcTimestamp(100, 1, "source-1"), "hash-1");
var firstRead = (await _store.GetConfirmationsForPeerAsync("peer-a")).ToList();
firstRead.Count.ShouldBe(1);
firstRead[0].ConfirmedWall.ShouldBe(100);
firstRead[0].ConfirmedLogic.ShouldBe(1);
firstRead[0].ConfirmedHash.ShouldBe("hash-1");
await _store.UpdateConfirmationAsync("peer-a", "source-1", new HlcTimestamp(120, 2, "source-1"), "hash-2");
await _store.UpdateConfirmationAsync("peer-a", "source-2", new HlcTimestamp(130, 0, "source-2"), "hash-3");
var secondRead = (await _store.GetConfirmationsForPeerAsync("peer-a")).OrderBy(x => x.SourceNodeId).ToList();
var allConfirmations = (await _store.GetConfirmationsAsync()).ToList();
secondRead.Count.ShouldBe(2);
secondRead[0].SourceNodeId.ShouldBe("source-1");
secondRead[0].ConfirmedWall.ShouldBe(120);
secondRead[0].ConfirmedLogic.ShouldBe(2);
secondRead[0].ConfirmedHash.ShouldBe("hash-2");
secondRead[1].SourceNodeId.ShouldBe("source-2");
secondRead[1].ConfirmedWall.ShouldBe(130);
secondRead[1].ConfirmedLogic.ShouldBe(0);
secondRead[1].ConfirmedHash.ShouldBe("hash-3");
allConfirmations.Count.ShouldBe(2);
}
/// <summary>
/// Verifies that removing peer tracking deactivates tracking records for that peer.
/// </summary>
[Fact]
public async Task RemovePeerTrackingAsync_DeactivatesPeerTracking()
{
await _store.EnsurePeerRegisteredAsync("peer-a", "10.0.0.10:5050", PeerType.StaticRemote);
await _store.EnsurePeerRegisteredAsync("peer-b", "10.0.0.11:5050", PeerType.StaticRemote);
await _store.UpdateConfirmationAsync("peer-a", "source-1", new HlcTimestamp(100, 0, "source-1"), "hash-a");
await _store.UpdateConfirmationAsync("peer-b", "source-1", new HlcTimestamp(100, 0, "source-1"), "hash-b");
await _store.RemovePeerTrackingAsync("peer-a");
var activePeers = (await _store.GetActiveTrackedPeersAsync()).ToList();
var exported = (await _store.ExportAsync()).ToList();
var peerARows = exported.Where(x => x.PeerNodeId == "peer-a").ToList();
activePeers.ShouldContain("peer-b");
activePeers.ShouldNotContain("peer-a");
peerARows.ShouldNotBeEmpty();
peerARows.All(x => !x.IsActive).ShouldBeTrue();
}
/// <inheritdoc />
public void Dispose()
{
_context?.Dispose();
if (File.Exists(_testDbPath))
{
try { File.Delete(_testDbPath); } catch { }
}
}
}