feat: add resilient reconnect and catch-up replay
This commit is contained in:
@@ -169,12 +169,56 @@ public sealed class SuiteLinkSessionTests
|
||||
Assert.Equal("callback failure", callbackException.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryDispatchUpdate_WithExplicitSource_UsesProvidedSource()
|
||||
{
|
||||
var session = new SuiteLinkSession();
|
||||
SuiteLinkTagUpdate? callbackUpdate = null;
|
||||
|
||||
session.RegisterSubscription("Pump001.Run", 0x1234, update => callbackUpdate = update);
|
||||
|
||||
var decoded = new DecodedUpdate(
|
||||
TagId: 0x1234,
|
||||
Quality: 0x00C0,
|
||||
ElapsedMilliseconds: 10,
|
||||
Value: SuiteLinkValue.FromBoolean(true));
|
||||
|
||||
var dispatched = session.TryDispatchUpdate(
|
||||
decoded,
|
||||
DateTimeOffset.UtcNow,
|
||||
SuiteLinkUpdateSource.CatchUpReplay,
|
||||
out var dispatchedUpdate,
|
||||
out _);
|
||||
|
||||
Assert.True(dispatched);
|
||||
Assert.NotNull(dispatchedUpdate);
|
||||
Assert.Equal(SuiteLinkUpdateSource.CatchUpReplay, dispatchedUpdate.Source);
|
||||
Assert.Equal(dispatchedUpdate, callbackUpdate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClearSubscriptions_RemovesAllMappings()
|
||||
{
|
||||
var session = new SuiteLinkSession();
|
||||
|
||||
session.RegisterSubscription("Pump001.Run", 0x1234, _ => { });
|
||||
session.RegisterSubscription("Pump001.Speed", 0x5678, _ => { });
|
||||
|
||||
session.ClearSubscriptions();
|
||||
|
||||
Assert.False(session.TryGetTagId("Pump001.Run", out _));
|
||||
Assert.False(session.TryGetTagId("Pump001.Speed", out _));
|
||||
Assert.False(session.TryGetItemName(0x1234, out _));
|
||||
Assert.False(session.TryGetItemName(0x5678, out _));
|
||||
Assert.Equal(0, session.SubscriptionCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetState_InvalidTransition_ThrowsInvalidOperationException()
|
||||
{
|
||||
var session = new SuiteLinkSession();
|
||||
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => session.SetState(SuiteLinkSessionState.SessionConnected));
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => session.SetState(SuiteLinkSessionState.Ready));
|
||||
|
||||
Assert.Contains("Invalid state transition", ex.Message);
|
||||
Assert.Equal(SuiteLinkSessionState.Disconnected, session.State);
|
||||
@@ -191,4 +235,17 @@ public sealed class SuiteLinkSessionTests
|
||||
Assert.False(session.TryTransitionState(SuiteLinkSessionState.Disconnected, SuiteLinkSessionState.HandshakeComplete));
|
||||
Assert.Equal(SuiteLinkSessionState.TcpConnected, session.State);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetState_ReconnectAttemptStartupFailure_CanReturnToReconnecting()
|
||||
{
|
||||
var session = new SuiteLinkSession();
|
||||
|
||||
session.SetState(SuiteLinkSessionState.TcpConnected);
|
||||
session.SetState(SuiteLinkSessionState.HandshakeComplete);
|
||||
session.SetState(SuiteLinkSessionState.ConnectSent);
|
||||
session.SetState(SuiteLinkSessionState.Reconnecting);
|
||||
|
||||
Assert.Equal(SuiteLinkSessionState.Reconnecting, session.State);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user