Move 25 gateway-related test files from NATS.Server.Tests into a dedicated NATS.Server.Gateways.Tests project. Update namespaces, replace private ReadUntilAsync with SocketTestHelper from TestUtilities, inline TestServerFactory usage, add InternalsVisibleTo, and register the project in the solution file. All 261 tests pass.
156 lines
5.2 KiB
C#
156 lines
5.2 KiB
C#
using System.Net;
|
|
using System.Net.Sockets;
|
|
using NATS.Server.Gateways;
|
|
using Shouldly;
|
|
|
|
namespace NATS.Server.Gateways.Tests.Gateways;
|
|
|
|
/// <summary>
|
|
/// Tests for queue group subscription tracking on GatewayConnection.
|
|
/// Go reference: gateway.go — sendQueueSubsToGateway, queueSubscriptions state.
|
|
/// </summary>
|
|
public class QueueGroupPropagationTests : IAsyncDisposable
|
|
{
|
|
private readonly TcpListener _listener;
|
|
private readonly Socket _clientSocket;
|
|
private readonly Socket _serverSocket;
|
|
private readonly GatewayConnection _gw;
|
|
|
|
public QueueGroupPropagationTests()
|
|
{
|
|
_listener = new TcpListener(IPAddress.Loopback, 0);
|
|
_listener.Start();
|
|
var port = ((IPEndPoint)_listener.LocalEndpoint).Port;
|
|
|
|
_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
|
_clientSocket.Connect(IPAddress.Loopback, port);
|
|
_serverSocket = _listener.AcceptSocket();
|
|
|
|
_gw = new GatewayConnection(_serverSocket);
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
await _gw.DisposeAsync();
|
|
_clientSocket.Dispose();
|
|
_listener.Stop();
|
|
}
|
|
|
|
// Go: gateway.go — sendQueueSubsToGateway registers queue group subscriptions per subject
|
|
[Fact]
|
|
public void AddQueueSubscription_registers_group()
|
|
{
|
|
_gw.AddQueueSubscription("orders.new", "workers");
|
|
|
|
_gw.HasQueueSubscription("orders.new", "workers").ShouldBeTrue();
|
|
}
|
|
|
|
// Go: gateway.go — getQueueGroups returns all groups for a subject
|
|
[Fact]
|
|
public void GetQueueGroups_returns_groups_for_subject()
|
|
{
|
|
_gw.AddQueueSubscription("payments.>", "billing");
|
|
_gw.AddQueueSubscription("payments.>", "audit");
|
|
|
|
var groups = _gw.GetQueueGroups("payments.>");
|
|
|
|
groups.ShouldContain("billing");
|
|
groups.ShouldContain("audit");
|
|
groups.Count.ShouldBe(2);
|
|
}
|
|
|
|
// Go: gateway.go — removeQueueSubscription removes a specific queue group
|
|
[Fact]
|
|
public void RemoveQueueSubscription_removes_group()
|
|
{
|
|
_gw.AddQueueSubscription("events.click", "analytics");
|
|
_gw.AddQueueSubscription("events.click", "logging");
|
|
|
|
_gw.RemoveQueueSubscription("events.click", "analytics");
|
|
|
|
_gw.HasQueueSubscription("events.click", "analytics").ShouldBeFalse();
|
|
_gw.HasQueueSubscription("events.click", "logging").ShouldBeTrue();
|
|
}
|
|
|
|
// Go: gateway.go — hasQueueSubscription returns true for registered subject/group pair
|
|
[Fact]
|
|
public void HasQueueSubscription_true_when_registered()
|
|
{
|
|
_gw.AddQueueSubscription("tasks.process", "pool");
|
|
|
|
_gw.HasQueueSubscription("tasks.process", "pool").ShouldBeTrue();
|
|
}
|
|
|
|
// Go: gateway.go — hasQueueSubscription returns false for unknown pair
|
|
[Fact]
|
|
public void HasQueueSubscription_false_when_not_registered()
|
|
{
|
|
_gw.HasQueueSubscription("unknown.subject", "nonexistent-group").ShouldBeFalse();
|
|
}
|
|
|
|
// Go: gateway.go — multiple queue groups can be registered for the same subject
|
|
[Fact]
|
|
public void Multiple_groups_per_subject()
|
|
{
|
|
_gw.AddQueueSubscription("jobs.run", "fast");
|
|
_gw.AddQueueSubscription("jobs.run", "slow");
|
|
_gw.AddQueueSubscription("jobs.run", "batch");
|
|
|
|
var groups = _gw.GetQueueGroups("jobs.run");
|
|
|
|
groups.Count.ShouldBe(3);
|
|
groups.ShouldContain("fast");
|
|
groups.ShouldContain("slow");
|
|
groups.ShouldContain("batch");
|
|
}
|
|
|
|
// Go: gateway.go — subscriptions for different subjects are tracked independently
|
|
[Fact]
|
|
public void Different_subjects_tracked_independently()
|
|
{
|
|
_gw.AddQueueSubscription("subject.a", "group1");
|
|
_gw.AddQueueSubscription("subject.b", "group2");
|
|
|
|
_gw.HasQueueSubscription("subject.a", "group2").ShouldBeFalse();
|
|
_gw.HasQueueSubscription("subject.b", "group1").ShouldBeFalse();
|
|
_gw.HasQueueSubscription("subject.a", "group1").ShouldBeTrue();
|
|
_gw.HasQueueSubscription("subject.b", "group2").ShouldBeTrue();
|
|
}
|
|
|
|
// Go: gateway.go — QueueSubscriptionCount reflects number of distinct subjects with queue groups
|
|
[Fact]
|
|
public void QueueSubscriptionCount_tracks_subjects()
|
|
{
|
|
_gw.QueueSubscriptionCount.ShouldBe(0);
|
|
|
|
_gw.AddQueueSubscription("foo", "g1");
|
|
_gw.QueueSubscriptionCount.ShouldBe(1);
|
|
|
|
_gw.AddQueueSubscription("bar", "g2");
|
|
_gw.QueueSubscriptionCount.ShouldBe(2);
|
|
|
|
// Adding a second group to an existing subject does not increase count
|
|
_gw.AddQueueSubscription("foo", "g3");
|
|
_gw.QueueSubscriptionCount.ShouldBe(2);
|
|
}
|
|
|
|
// Go: gateway.go — removing a queue group that was never added is a no-op
|
|
[Fact]
|
|
public void RemoveQueueSubscription_no_error_for_unknown()
|
|
{
|
|
// Should not throw even though neither subject nor group was registered
|
|
var act = () => _gw.RemoveQueueSubscription("never.registered", "ghost");
|
|
act.ShouldNotThrow();
|
|
}
|
|
|
|
// Go: gateway.go — GetQueueGroups returns empty set for unknown subject
|
|
[Fact]
|
|
public void GetQueueGroups_empty_for_unknown_subject()
|
|
{
|
|
var groups = _gw.GetQueueGroups("nonexistent.subject");
|
|
|
|
groups.ShouldNotBeNull();
|
|
groups.Count.ShouldBe(0);
|
|
}
|
|
}
|