62 lines
2.2 KiB
C#
62 lines
2.2 KiB
C#
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 });
|
|
}
|