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.
This commit is contained in:
Joseph Doherty
2026-03-12 15:03:12 -04:00
parent d2c04fcca5
commit a6be5e11ed
32 changed files with 88 additions and 38 deletions

View File

@@ -7,6 +7,7 @@
<Project Path="tests/NATS.Server.TestUtilities/NATS.Server.TestUtilities.csproj" /> <Project Path="tests/NATS.Server.TestUtilities/NATS.Server.TestUtilities.csproj" />
<Project Path="tests/NATS.Server.Tests/NATS.Server.Tests.csproj" /> <Project Path="tests/NATS.Server.Tests/NATS.Server.Tests.csproj" />
<Project Path="tests/NATS.Server.Transport.Tests/NATS.Server.Transport.Tests.csproj" /> <Project Path="tests/NATS.Server.Transport.Tests/NATS.Server.Transport.Tests.csproj" />
<Project Path="tests/NATS.Server.Mqtt.Tests/NATS.Server.Mqtt.Tests.csproj" />
<Project Path="tests/NATS.E2E.Tests/NATS.E2E.Tests.csproj" /> <Project Path="tests/NATS.E2E.Tests/NATS.E2E.Tests.csproj" />
</Folder> </Folder>
</Solution> </Solution>

View File

@@ -2,6 +2,7 @@
<ItemGroup> <ItemGroup>
<InternalsVisibleTo Include="NATS.Server.Tests" /> <InternalsVisibleTo Include="NATS.Server.Tests" />
<InternalsVisibleTo Include="NATS.Server.Transport.Tests" /> <InternalsVisibleTo Include="NATS.Server.Transport.Tests" />
<InternalsVisibleTo Include="NATS.Server.Mqtt.Tests" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" /> <FrameworkReference Include="Microsoft.AspNetCore.App" />

View File

@@ -12,8 +12,9 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttAdvancedParityTests public class MqttAdvancedParityTests
{ {
@@ -763,10 +764,22 @@ public class MqttAdvancedParityTests
// Disconnect // Disconnect
client.Dispose(); client.Dispose();
// Server should not crash // Verify server is still operational by polling until it accepts a new connection
await Task.Delay(100); var connected = await PollHelper.WaitUntilAsync(async () =>
{
try
{
using var probe = new TcpClient();
await probe.ConnectAsync(IPAddress.Loopback, listener.Port);
return true;
}
catch
{
return false;
}
}, timeoutMs: 2000, intervalMs: 10);
connected.ShouldBeTrue("Server should still accept connections after client disconnect");
// Verify server is still operational
using var client2 = new TcpClient(); using var client2 = new TcpClient();
await client2.ConnectAsync(IPAddress.Loopback, listener.Port); await client2.ConnectAsync(IPAddress.Loopback, listener.Port);
var s2 = client2.GetStream(); var s2 = client2.GetStream();

View File

@@ -2,7 +2,7 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttAuthIntegrationTests public class MqttAuthIntegrationTests
{ {

View File

@@ -9,8 +9,9 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using NATS.Server.Auth; using NATS.Server.Auth;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttAuthParityTests public class MqttAuthParityTests
{ {
@@ -202,10 +203,13 @@ public class MqttAuthParityTests
await MqttAuthWire.WriteLineAsync(stream, "CONNECT keepalive-client clean=true keepalive=1"); await MqttAuthWire.WriteLineAsync(stream, "CONNECT keepalive-client clean=true keepalive=1");
(await MqttAuthWire.ReadLineAsync(stream, 1000)).ShouldBe("CONNACK"); (await MqttAuthWire.ReadLineAsync(stream, 1000)).ShouldBe("CONNACK");
await Task.Delay(2500); // Poll until the server closes the connection due to keepalive expiry (keepalive=1s)
var disconnected = await PollHelper.WaitUntilAsync(async () =>
var result = await MqttAuthWire.ReadRawAsync(stream, 500); {
(result == null || result == "__timeout__").ShouldBeTrue(); var result = await MqttAuthWire.ReadRawAsync(stream, 200);
return result == null || result == "__timeout__";
}, timeoutMs: 5000, intervalMs: 100);
disconnected.ShouldBeTrue("Server should disconnect idle client after keepalive timeout");
} }
// ========================================================================= // =========================================================================

View File

@@ -8,7 +8,7 @@
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttBinaryParserTests public class MqttBinaryParserTests
{ {

View File

@@ -4,7 +4,7 @@
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
using Shouldly; using Shouldly;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttFlapperDetectionTests public class MqttFlapperDetectionTests
{ {

View File

@@ -3,7 +3,7 @@
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
using Shouldly; using Shouldly;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public sealed class MqttFlowControllerTests public sealed class MqttFlowControllerTests
{ {

View File

@@ -8,7 +8,7 @@
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
/// <summary> /// <summary>
/// Parity tests ported from Go server/mqtt_test.go exercising MQTT binary /// Parity tests ported from Go server/mqtt_test.go exercising MQTT binary

View File

@@ -1,8 +1,9 @@
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
using NATS.Server.TestUtilities;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttKeepAliveTests public class MqttKeepAliveTests
{ {
@@ -20,7 +21,12 @@ public class MqttKeepAliveTests
await MqttRuntimeWire.WriteLineAsync(stream, "CONNECT keepalive-client keepalive=1"); await MqttRuntimeWire.WriteLineAsync(stream, "CONNECT keepalive-client keepalive=1");
(await MqttRuntimeWire.ReadLineAsync(stream, 1000)).ShouldBe("CONNACK"); (await MqttRuntimeWire.ReadLineAsync(stream, 1000)).ShouldBe("CONNACK");
await Task.Delay(2000); // Poll until the server closes the connection due to keepalive expiry (keepalive=1s)
(await MqttRuntimeWire.ReadRawAsync(stream, 1000)).ShouldBeNull(); var disconnected = await PollHelper.WaitUntilAsync(async () =>
{
var result = await MqttRuntimeWire.ReadRawAsync(stream, 200);
return result == null;
}, timeoutMs: 5000, intervalMs: 100);
disconnected.ShouldBeTrue("Server should disconnect idle client after keepalive timeout");
} }
} }

View File

@@ -3,7 +3,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests; namespace NATS.Server.Mqtt.Tests;
public class MqttListenerParityTests public class MqttListenerParityTests
{ {

View File

@@ -1,6 +1,6 @@
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttModelParityBatch3Tests public class MqttModelParityBatch3Tests
{ {

View File

@@ -1,6 +1,6 @@
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttPacketParserTests public class MqttPacketParserTests
{ {

View File

@@ -5,7 +5,7 @@
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttPacketParsingParityTests public class MqttPacketParsingParityTests
{ {

View File

@@ -1,6 +1,6 @@
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttPacketWriterTests public class MqttPacketWriterTests
{ {

View File

@@ -1,7 +1,7 @@
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttProtocolConstantsParityBatch1Tests public class MqttProtocolConstantsParityBatch1Tests
{ {

View File

@@ -1,7 +1,7 @@
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttProtocolConstantsParityBatch2Tests public class MqttProtocolConstantsParityBatch2Tests
{ {

View File

@@ -2,7 +2,7 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests; namespace NATS.Server.Mqtt.Tests;
public class MqttPublishSubscribeParityTests public class MqttPublishSubscribeParityTests
{ {

View File

@@ -4,7 +4,7 @@
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
using Shouldly; using Shouldly;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public sealed class MqttQoSTrackingTests public sealed class MqttQoSTrackingTests
{ {

View File

@@ -2,7 +2,7 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttQosAckRuntimeTests public class MqttQosAckRuntimeTests
{ {

View File

@@ -6,7 +6,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttQosDeliveryParityTests public class MqttQosDeliveryParityTests
{ {

View File

@@ -6,7 +6,7 @@
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttQosTests public class MqttQosTests
{ {

View File

@@ -6,7 +6,7 @@ using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
using Shouldly; using Shouldly;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttRetainedDeliveryTests public class MqttRetainedDeliveryTests
{ {

View File

@@ -8,7 +8,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttRetainedMessageParityTests public class MqttRetainedMessageParityTests
{ {

View File

@@ -7,7 +7,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttSessionParityTests public class MqttSessionParityTests
{ {

View File

@@ -5,7 +5,7 @@
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttSessionPersistenceTests public class MqttSessionPersistenceTests
{ {

View File

@@ -3,7 +3,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttSessionRuntimeTests public class MqttSessionRuntimeTests
{ {

View File

@@ -4,7 +4,7 @@
// golang/nats-server/server/mqtt.go — mqttTopicToNATSPubSubject, mqttFilterToNATSSubject, // golang/nats-server/server/mqtt.go — mqttTopicToNATSPubSubject, mqttFilterToNATSSubject,
// natsSubjectToMQTTTopic, mqttToNATSSubjectConversion // natsSubjectToMQTTTopic, mqttToNATSSubjectConversion
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
/// <summary> /// <summary>
/// Tests MQTT topic to NATS subject conversion and vice versa, porting the /// Tests MQTT topic to NATS subject conversion and vice versa, porting the

View File

@@ -7,7 +7,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttWillMessageParityTests public class MqttWillMessageParityTests
{ {

View File

@@ -5,7 +5,7 @@
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
using Shouldly; using Shouldly;
namespace NATS.Server.Tests.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt;
public class MqttWillMessageTests public class MqttWillMessageTests
{ {

View File

@@ -2,7 +2,7 @@ using NSubstitute;
using NATS.Server.JetStream.Storage; using NATS.Server.JetStream.Storage;
using NATS.Server.Mqtt; using NATS.Server.Mqtt;
namespace NATS.Server.Tests; namespace NATS.Server.Mqtt.Tests;
// Go reference: server/mqtt.go ($MQTT_msgs, $MQTT_sess, $MQTT_rmsgs JetStream streams) // Go reference: server/mqtt.go ($MQTT_msgs, $MQTT_sess, $MQTT_rmsgs JetStream streams)

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NATS.Client.Core" />
<PackageReference Include="NSubstitute" />
<PackageReference Include="Shouldly" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
<Using Include="Shouldly" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NATS.Server\NATS.Server.csproj" />
<ProjectReference Include="..\NATS.Server.TestUtilities\NATS.Server.TestUtilities.csproj" />
</ItemGroup>
</Project>