- Fix pull consumer fetch: send original stream subject in HMSG (not inbox) so NATS client distinguishes data messages from control messages - Fix MaxAge expiry: add background timer in StreamManager for periodic pruning - Fix JetStream wire format: Go-compatible anonymous objects with string enums, proper offset-based pagination for stream/consumer list APIs - Add 42 E2E black-box tests (core messaging, auth, TLS, accounts, JetStream) - Add ~1000 parity tests across all subsystems (gaps closure) - Update gap inventory docs to reflect implementation status
96 lines
3.1 KiB
C#
96 lines
3.1 KiB
C#
using Microsoft.Extensions.Logging.Abstractions;
|
|
using NATS.Server.Configuration;
|
|
|
|
namespace NATS.Server.Tests.Gateways;
|
|
|
|
public class GatewayConnectionDirectionParityBatch2Tests
|
|
{
|
|
[Fact]
|
|
public async Task Gateway_manager_tracks_inbound_and_outbound_connection_sets()
|
|
{
|
|
var a = await StartServerAsync(MakeGatewayOptions("GW-A"));
|
|
var b = await StartServerAsync(MakeGatewayOptions("GW-B", a.Server.GatewayListen));
|
|
|
|
try
|
|
{
|
|
await WaitForCondition(() =>
|
|
a.Server.NumInboundGateways() == 1 &&
|
|
b.Server.NumOutboundGateways() == 1,
|
|
10000);
|
|
|
|
a.Server.NumInboundGateways().ShouldBe(1);
|
|
a.Server.NumOutboundGateways().ShouldBe(0);
|
|
b.Server.NumOutboundGateways().ShouldBe(1);
|
|
b.Server.NumInboundGateways().ShouldBe(0);
|
|
|
|
var aManager = a.Server.GatewayManager;
|
|
var bManager = b.Server.GatewayManager;
|
|
aManager.ShouldNotBeNull();
|
|
bManager.ShouldNotBeNull();
|
|
|
|
aManager!.HasInbound(b.Server.ServerId).ShouldBeTrue();
|
|
bManager!.HasInbound(a.Server.ServerId).ShouldBeFalse();
|
|
|
|
bManager.GetOutboundGatewayConnection(a.Server.ServerId).ShouldNotBeNull();
|
|
bManager.GetOutboundGatewayConnection("does-not-exist").ShouldBeNull();
|
|
|
|
aManager.GetInboundGatewayConnections().Count.ShouldBe(1);
|
|
aManager.GetOutboundGatewayConnections().Count.ShouldBe(0);
|
|
bManager.GetOutboundGatewayConnections().Count.ShouldBe(1);
|
|
bManager.GetInboundGatewayConnections().Count.ShouldBe(0);
|
|
}
|
|
finally
|
|
{
|
|
await DisposeServers(a, b);
|
|
}
|
|
}
|
|
|
|
private static NatsOptions MakeGatewayOptions(string gatewayName, string? remote = null)
|
|
{
|
|
return new NatsOptions
|
|
{
|
|
Host = "127.0.0.1",
|
|
Port = 0,
|
|
Gateway = new GatewayOptions
|
|
{
|
|
Name = gatewayName,
|
|
Host = "127.0.0.1",
|
|
Port = 0,
|
|
Remotes = remote is null ? [] : [remote],
|
|
},
|
|
};
|
|
}
|
|
|
|
private static async Task<(NatsServer Server, CancellationTokenSource Cts)> StartServerAsync(NatsOptions opts)
|
|
{
|
|
var server = new NatsServer(opts, NullLoggerFactory.Instance);
|
|
var cts = new CancellationTokenSource();
|
|
_ = server.StartAsync(cts.Token);
|
|
await server.WaitForReadyAsync();
|
|
return (server, cts);
|
|
}
|
|
|
|
private static async Task DisposeServers(params (NatsServer Server, CancellationTokenSource Cts)[] servers)
|
|
{
|
|
foreach (var (server, cts) in servers)
|
|
{
|
|
await cts.CancelAsync();
|
|
server.Dispose();
|
|
cts.Dispose();
|
|
}
|
|
}
|
|
|
|
private static async Task WaitForCondition(Func<bool> predicate, int timeoutMs)
|
|
{
|
|
using var cts = new CancellationTokenSource(timeoutMs);
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
if (predicate())
|
|
return;
|
|
await Task.Yield();
|
|
}
|
|
|
|
throw new TimeoutException("Condition not met.");
|
|
}
|
|
}
|