using NATS.Server; using NATS.Server.Auth; using NATS.Server.Imports; namespace NATS.Server.Tests; public class ImportExportTests { [Fact] public void ExportAuth_public_export_authorizes_any_account() { var auth = new ExportAuth(); var account = new Account("test"); auth.IsAuthorized(account).ShouldBeTrue(); } [Fact] public void ExportAuth_approved_accounts_restricts_access() { var auth = new ExportAuth { ApprovedAccounts = ["allowed"] }; var allowed = new Account("allowed"); var denied = new Account("denied"); auth.IsAuthorized(allowed).ShouldBeTrue(); auth.IsAuthorized(denied).ShouldBeFalse(); } [Fact] public void ExportAuth_revoked_account_denied() { var auth = new ExportAuth { ApprovedAccounts = ["test"], RevokedAccounts = new() { ["test"] = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }, }; var account = new Account("test"); auth.IsAuthorized(account).ShouldBeFalse(); } [Fact] public void ServiceResponseType_defaults_to_singleton() { var import = new ServiceImport { DestinationAccount = new Account("dest"), From = "requests.>", To = "api.>", }; import.ResponseType.ShouldBe(ServiceResponseType.Singleton); } [Fact] public void ExportMap_stores_and_retrieves_exports() { var map = new ExportMap(); map.Services["api.>"] = new ServiceExport { Account = new Account("svc") }; map.Streams["events.>"] = new StreamExport(); map.Services.ShouldContainKey("api.>"); map.Streams.ShouldContainKey("events.>"); } [Fact] public void ImportMap_stores_service_imports() { var map = new ImportMap(); var si = new ServiceImport { DestinationAccount = new Account("dest"), From = "requests.>", To = "api.>", }; map.AddServiceImport(si); map.Services.ShouldContainKey("requests.>"); map.Services["requests.>"].Count.ShouldBe(1); } [Fact] public void Account_add_service_export_and_import() { var exporter = new Account("exporter"); var importer = new Account("importer"); exporter.AddServiceExport("api.>", ServiceResponseType.Singleton, null); exporter.Exports.Services.ShouldContainKey("api.>"); var si = importer.AddServiceImport(exporter, "requests.>", "api.>"); si.ShouldNotBeNull(); si.From.ShouldBe("requests.>"); si.To.ShouldBe("api.>"); si.DestinationAccount.ShouldBe(exporter); importer.Imports.Services.ShouldContainKey("requests.>"); } [Fact] public void Account_add_stream_export_and_import() { var exporter = new Account("exporter"); var importer = new Account("importer"); exporter.AddStreamExport("events.>", null); exporter.Exports.Streams.ShouldContainKey("events.>"); importer.AddStreamImport(exporter, "events.>", "imported.events.>"); importer.Imports.Streams.Count.ShouldBe(1); importer.Imports.Streams[0].From.ShouldBe("events.>"); importer.Imports.Streams[0].To.ShouldBe("imported.events.>"); } [Fact] public void Account_service_import_auth_rejected() { var exporter = new Account("exporter"); var importer = new Account("importer"); exporter.AddServiceExport("api.>", ServiceResponseType.Singleton, [new Account("other")]); Should.Throw(() => importer.AddServiceImport(exporter, "requests.>", "api.>")); } [Fact] public void Account_lazy_creates_internal_client() { var account = new Account("test"); var client = account.GetOrCreateInternalClient(99); client.ShouldNotBeNull(); client.Kind.ShouldBe(ClientKind.Account); client.Account.ShouldBe(account); // Second call returns same instance var client2 = account.GetOrCreateInternalClient(100); client2.ShouldBeSameAs(client); } }