using NATS.Client.Core; using NATS.E2E.Tests.Infrastructure; namespace NATS.E2E.Tests; public class AdvancedTests { [Fact] public async Task ConfigFile_FullConfig_ServerStartsAndAcceptsConnections() { var config = """ server_name: e2e-config-test max_payload: 2048 max_connections: 100 """; await using var server = NatsServerProcess.WithConfig(config); await server.StartAsync(); await using var client = new NatsConnection(new NatsOpts { Url = $"nats://127.0.0.1:{server.Port}" }); await client.ConnectAsync(); await client.PingAsync(); client.ConnectionState.ShouldBe(NatsConnectionState.Open); client.ServerInfo.ShouldNotBeNull(); client.ServerInfo!.MaxPayload.ShouldBe(2048); } [Fact] public async Task MaxConnections_ExceedsLimit_Rejected() { var config = """ max_connections: 2 """; await using var server = NatsServerProcess.WithConfig(config); await server.StartAsync(); var url = $"nats://127.0.0.1:{server.Port}"; await using var c1 = new NatsConnection(new NatsOpts { Url = url }); await using var c2 = new NatsConnection(new NatsOpts { Url = url }); await c1.ConnectAsync(); await c1.PingAsync(); await c2.ConnectAsync(); await c2.PingAsync(); await using var c3 = new NatsConnection(new NatsOpts { Url = url, MaxReconnectRetry = 0, }); var ex = await Should.ThrowAsync(async () => { await c3.ConnectAsync(); await c3.PingAsync(); }); ex.ShouldNotBeNull(); } [Fact(Skip = "system_account promotion not yet wired: events route through internal $SYS account, not user-defined account")] [SlopwatchSuppress("SW001", "User-defined system_account SubList is not bridged to the internal event system; tracked as a future milestone")] public async Task SystemEvents_ClientConnect_EventPublished() { var config = """ accounts { SYS { users = [{ user: "sys", password: "sys" }] } APP { users = [{ user: "app", password: "app" }] } } system_account: SYS """; await using var server = NatsServerProcess.WithConfig(config); await server.StartAsync(); var url = $"nats://127.0.0.1:{server.Port}"; await using var sysClient = new NatsConnection(new NatsOpts { Url = url, AuthOpts = new NatsAuthOpts { Username = "sys", Password = "sys" }, }); await sysClient.ConnectAsync(); await using var subscription = await sysClient.SubscribeCoreAsync("$SYS.ACCOUNT.*.CONNECT"); await sysClient.PingAsync(); await using var appClient = new NatsConnection(new NatsOpts { Url = url, AuthOpts = new NatsAuthOpts { Username = "app", Password = "app" }, }); await appClient.ConnectAsync(); await appClient.PingAsync(); using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var msg = await subscription.Msgs.ReadAsync(cts.Token); msg.Subject.ShouldContain("CONNECT"); } [Fact(Skip = "Cross-account service routing not yet implemented in message dispatch path")] [SlopwatchSuppress("SW001", "Cross-account service import routing is not yet wired in the message dispatch path; tracked as a future milestone")] public async Task AccountImportExport_CrossAccountServiceCall() { var config = """ accounts { PROVIDER { users = [{ user: "provider", password: "prov" }] exports = [ { service: "svc.echo" } ] } CONSUMER { users = [{ user: "consumer", password: "cons" }] imports = [ { service: { account: PROVIDER, subject: "svc.echo" } } ] } } """; await using var server = NatsServerProcess.WithConfig(config); await server.StartAsync(); var url = $"nats://127.0.0.1:{server.Port}"; await using var provider = new NatsConnection(new NatsOpts { Url = url, AuthOpts = new NatsAuthOpts { Username = "provider", Password = "prov" }, }); await provider.ConnectAsync(); await using var svcSub = await provider.SubscribeCoreAsync("svc.echo"); await provider.PingAsync(); var responderTask = Task.Run(async () => { using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var msg = await svcSub.Msgs.ReadAsync(cts.Token); await provider.PublishAsync(msg.ReplyTo!, $"echo: {msg.Data}"); }); await using var consumer = new NatsConnection(new NatsOpts { Url = url, AuthOpts = new NatsAuthOpts { Username = "consumer", Password = "cons" }, }); await consumer.ConnectAsync(); using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var reply = await consumer.RequestAsync("svc.echo", "hello", cancellationToken: cts.Token); reply.Data.ShouldBe("echo: hello"); await responderTask; } [Fact(Skip = "Subject transforms not yet implemented in config parsing")] [SlopwatchSuppress("SW001", "Subject transform config parsing is not yet implemented; tracked for future milestone")] public Task SubjectTransforms_MappedSubject_ReceivedOnTarget() { return Task.CompletedTask; } [Fact(Skip = "JWT operator mode not yet implemented in config parsing")] [SlopwatchSuppress("SW001", "JWT operator mode config parsing is not yet implemented; tracked for future milestone")] public Task JwtAuth_ValidJwt_Connects() { return Task.CompletedTask; } }