Files
natsdotnet/tests/NATS.Server.Mqtt.Tests/MqttPersistenceTests.cs
Joseph Doherty a6be5e11ed refactor: extract NATS.Server.Mqtt.Tests project
Move 29 MQTT test files from NATS.Server.Tests into a dedicated
NATS.Server.Mqtt.Tests project. Update namespaces, add
InternalsVisibleTo, and replace Task.Delay calls with
PollHelper.WaitUntilAsync for proper synchronization.
2026-03-12 15:03:12 -04:00

93 lines
3.1 KiB
C#

using NSubstitute;
using NATS.Server.JetStream.Storage;
using NATS.Server.Mqtt;
namespace NATS.Server.Mqtt.Tests;
// Go reference: server/mqtt.go ($MQTT_msgs, $MQTT_sess, $MQTT_rmsgs JetStream streams)
public class MqttPersistenceTests
{
[Fact]
public async Task Session_persists_across_restart()
{
// Go reference: server/mqtt.go mqttStoreSession — session survives restart
var store = MqttSessionStoreTestHelper.CreateWithJetStream();
await store.ConnectAsync("client-1", cleanSession: false);
store.AddSubscription("client-1", "topic/test", qos: 1);
await store.SaveSessionAsync("client-1");
// Simulate restart — new store backed by the same IStreamStore
var recovered = MqttSessionStoreTestHelper.CreateWithJetStream(store.BackingStore!);
await recovered.ConnectAsync("client-1", cleanSession: false);
var subs = recovered.GetSubscriptions("client-1");
subs.ShouldContainKey("topic/test");
}
[Fact]
public async Task Clean_session_deletes_existing()
{
// Go reference: server/mqtt.go cleanSession=true deletes saved state
var store = MqttSessionStoreTestHelper.CreateWithJetStream();
await store.ConnectAsync("client-2", cleanSession: false);
store.AddSubscription("client-2", "persist/me", qos: 1);
await store.SaveSessionAsync("client-2");
// Reconnect with clean session
await store.ConnectAsync("client-2", cleanSession: true);
var subs = store.GetSubscriptions("client-2");
subs.ShouldBeEmpty();
}
[Fact]
public async Task Retained_message_survives_restart()
{
// Go reference: server/mqtt.go retained message persistence via JetStream
var retained = MqttRetainedStoreTestHelper.CreateWithJetStream();
await retained.SetRetainedAsync("sensors/temp", "72.5"u8.ToArray());
// Simulate restart
var recovered = MqttRetainedStoreTestHelper.CreateWithJetStream(retained.BackingStore!);
var msg = await recovered.GetRetainedAsync("sensors/temp");
msg.ShouldNotBeNull();
System.Text.Encoding.UTF8.GetString(msg).ShouldBe("72.5");
}
[Fact]
public async Task Retained_message_cleared_with_empty_payload()
{
// Go reference: server/mqtt.go empty payload clears retained
var retained = MqttRetainedStoreTestHelper.CreateWithJetStream();
await retained.SetRetainedAsync("sensors/temp", "72.5"u8.ToArray());
await retained.SetRetainedAsync("sensors/temp", ReadOnlyMemory<byte>.Empty); // clear
var msg = await retained.GetRetainedAsync("sensors/temp");
msg.ShouldBeNull();
}
}
public static class MqttSessionStoreTestHelper
{
public static MqttSessionStore CreateWithJetStream(IStreamStore? backingStore = null)
{
var store = backingStore ?? new MemStore();
return new MqttSessionStore(store);
}
}
public static class MqttRetainedStoreTestHelper
{
public static MqttRetainedStore CreateWithJetStream(IStreamStore? backingStore = null)
{
var store = backingStore ?? new MemStore();
return new MqttRetainedStore(store);
}
}