feat(S2-b): connect durable MQTT sync to capture workflow
This commit is contained in:
61
tests/FieldLogger.Sync.Tests/FakeMqttTransport.cs
Normal file
61
tests/FieldLogger.Sync.Tests/FakeMqttTransport.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using FieldLogger.Sync;
|
||||
|
||||
namespace FieldLogger.Sync.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// In-memory stand-in for the broker. Records published payloads, lets a test toggle
|
||||
/// connectivity, force publish failures, and inject application-level acks — so the engine's
|
||||
/// durability/ack/backoff behaviour is exercised without MQTTnet or a live broker.
|
||||
/// </summary>
|
||||
public sealed class FakeMqttTransport : IMqttTransport
|
||||
{
|
||||
public bool IsConnected { get; set; } = true;
|
||||
public bool FailNextPublish { get; set; }
|
||||
public List<(string Topic, byte[] Payload)> Published { get; } = new();
|
||||
|
||||
public event Func<AckBatch, Task>? AckReceived;
|
||||
|
||||
public Task ConnectAsync(string ackTopic, CancellationToken ct = default)
|
||||
{
|
||||
IsConnected = true;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task DisconnectAsync()
|
||||
{
|
||||
IsConnected = false;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task PublishAsync(string topic, byte[] payload, string schemaVersion, CancellationToken ct = default)
|
||||
{
|
||||
if (!IsConnected) throw new InvalidOperationException("not connected");
|
||||
if (FailNextPublish)
|
||||
{
|
||||
FailNextPublish = false;
|
||||
throw new InvalidOperationException("simulated broker publish failure");
|
||||
}
|
||||
Published.Add((topic, payload));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>Simulate the cloud emitting an application-level ack for these pointIds.</summary>
|
||||
public async Task InjectAckAsync(params AckItem[] items)
|
||||
{
|
||||
if (AckReceived is { } handlers)
|
||||
{
|
||||
var batch = new AckBatch { Results = items.ToList() };
|
||||
foreach (Func<AckBatch, Task> handler in handlers.GetInvocationList())
|
||||
await handler(batch);
|
||||
}
|
||||
}
|
||||
|
||||
public Task InjectAcceptAsync(string pointId) =>
|
||||
InjectAckAsync(new AckItem { PointId = pointId, Outcome = AckOutcome.ACCEPTED });
|
||||
|
||||
public Task InjectDuplicateAsync(string pointId) =>
|
||||
InjectAckAsync(new AckItem { PointId = pointId, Outcome = AckOutcome.DUPLICATE });
|
||||
|
||||
public Task InjectRejectAsync(string pointId, string reasonCode) =>
|
||||
InjectAckAsync(new AckItem { PointId = pointId, Outcome = AckOutcome.REJECTED, ReasonCode = reasonCode });
|
||||
}
|
||||
Reference in New Issue
Block a user