using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using StellaOps.Infrastructure.Postgres.Testing; using StellaOps.Scanner.Storage; using StellaOps.Scanner.Surface.Validation; using StellaOps.Scanner.WebService.Diagnostics; namespace StellaOps.Scanner.WebService.Tests; public sealed class ScannerApplicationFactory : WebApplicationFactory { private readonly ScannerWebServicePostgresFixture postgresFixture; private readonly Dictionary configuration = new() { ["scanner:storage:driver"] = "postgres", ["scanner:storage:dsn"] = string.Empty, ["scanner:storage:database"] = string.Empty, ["scanner:queue:driver"] = "redis", ["scanner:queue:dsn"] = "redis://localhost:6379", ["scanner:artifactStore:driver"] = "rustfs", ["scanner:artifactStore:endpoint"] = "https://rustfs.local/api/v1/", ["scanner:artifactStore:accessKey"] = "test-access", ["scanner:artifactStore:secretKey"] = "test-secret", ["scanner:artifactStore:bucket"] = "scanner-artifacts", ["scanner:artifactStore:timeoutSeconds"] = "30", ["scanner:telemetry:minimumLogLevel"] = "Information", ["scanner:telemetry:enableRequestLogging"] = "false", ["scanner:events:enabled"] = "false", ["scanner:features:enableSignedReports"] = "false" }; private readonly Action>? configureConfiguration; private readonly Action? configureServices; public ScannerApplicationFactory( Action>? configureConfiguration = null, Action? configureServices = null) { postgresFixture = new ScannerWebServicePostgresFixture(); postgresFixture.InitializeAsync().GetAwaiter().GetResult(); configuration["scanner:storage:dsn"] = postgresFixture.ConnectionString; configuration["scanner:storage:database"] = postgresFixture.SchemaName; this.configureConfiguration = configureConfiguration; this.configureServices = configureServices; } protected override void ConfigureWebHost(IWebHostBuilder builder) { configureConfiguration?.Invoke(configuration); builder.UseEnvironment("Testing"); Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__ENABLED", null); Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__ALLOWANONYMOUSFALLBACK", null); Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__ISSUER", null); Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__AUDIENCES__0", null); Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__CLIENTID", null); Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__CLIENTSECRET", null); Environment.SetEnvironmentVariable("SCANNER__STORAGE__DSN", configuration["scanner:storage:dsn"]); Environment.SetEnvironmentVariable("SCANNER__STORAGE__DATABASE", configuration["scanner:storage:database"]); Environment.SetEnvironmentVariable("SCANNER__QUEUE__DSN", configuration["scanner:queue:dsn"]); Environment.SetEnvironmentVariable("SCANNER__ARTIFACTSTORE__ENDPOINT", configuration["scanner:artifactStore:endpoint"]); Environment.SetEnvironmentVariable("SCANNER__ARTIFACTSTORE__ACCESSKEY", configuration["scanner:artifactStore:accessKey"]); Environment.SetEnvironmentVariable("SCANNER__ARTIFACTSTORE__SECRETKEY", configuration["scanner:artifactStore:secretKey"]); Environment.SetEnvironmentVariable("SCANNER_SURFACE_FS_ENDPOINT", "https://surface.local"); Environment.SetEnvironmentVariable("SCANNER_SURFACE_FS_BUCKET", configuration["scanner:artifactStore:bucket"]); Environment.SetEnvironmentVariable("SCANNER_SURFACE_PREFETCH_ENABLED", "false"); Environment.SetEnvironmentVariable("SCANNER_SURFACE_SECRETS_PROVIDER", "file"); Environment.SetEnvironmentVariable("SCANNER_SURFACE_SECRETS_ROOT", Path.GetTempPath()); Environment.SetEnvironmentVariable("SCANNER_SURFACE_SECRETS_TENANT", "tenant-a"); if (configuration.TryGetValue("scanner:events:enabled", out var eventsEnabled)) { Environment.SetEnvironmentVariable("SCANNER__EVENTS__ENABLED", eventsEnabled); } if (configuration.TryGetValue("scanner:authority:enabled", out var authorityEnabled)) { Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__ENABLED", authorityEnabled); } if (configuration.TryGetValue("scanner:authority:allowAnonymousFallback", out var allowAnonymous)) { Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__ALLOWANONYMOUSFALLBACK", allowAnonymous); } if (configuration.TryGetValue("scanner:authority:issuer", out var authorityIssuer)) { Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__ISSUER", authorityIssuer); } if (configuration.TryGetValue("scanner:authority:audiences:0", out var primaryAudience)) { Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__AUDIENCES__0", primaryAudience); } if (configuration.TryGetValue("scanner:authority:clientId", out var clientId)) { Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__CLIENTID", clientId); } if (configuration.TryGetValue("scanner:authority:clientSecret", out var clientSecret)) { Environment.SetEnvironmentVariable("SCANNER__AUTHORITY__CLIENTSECRET", clientSecret); } builder.ConfigureAppConfiguration((_, configBuilder) => { configBuilder.AddInMemoryCollection(configuration); }); builder.ConfigureTestServices(services => { configureServices?.Invoke(services); services.RemoveAll(); services.AddSingleton(); }); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { postgresFixture.DisposeAsync().GetAwaiter().GetResult(); } } private sealed class TestSurfaceValidatorRunner : ISurfaceValidatorRunner { public ValueTask RunAllAsync( SurfaceValidationContext context, CancellationToken cancellationToken = default) => ValueTask.FromResult(SurfaceValidationResult.Success()); public ValueTask EnsureAsync( SurfaceValidationContext context, CancellationToken cancellationToken = default) => ValueTask.CompletedTask; } private sealed class ScannerWebServicePostgresFixture : PostgresIntegrationFixture { protected override System.Reflection.Assembly? GetMigrationAssembly() => typeof(ScannerStorageOptions).Assembly; protected override string GetModuleName() => "Scanner.Storage.WebService.Tests"; } }