using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Xunit; using ZB.MOM.WW.OtOpcUa.Configuration; namespace ZB.MOM.WW.OtOpcUa.Configuration.Tests; /// /// Spins up a dedicated test database, applies the EF migrations against it, and exposes a /// factory. Disposed at collection teardown (drops the DB). /// Gated by the OTOPCUA_CONFIG_TEST_SERVER env var so CI runs can opt in explicitly; /// local runs default to the dev container on localhost:14330. /// public sealed class SchemaComplianceFixture : IDisposable { private const string DefaultServer = "localhost,14330"; private const string DefaultSaPassword = "OtOpcUaDev_2026!"; public string DatabaseName { get; } public string ConnectionString { get; } public SchemaComplianceFixture() { var server = Environment.GetEnvironmentVariable("OTOPCUA_CONFIG_TEST_SERVER") ?? DefaultServer; var saPassword = Environment.GetEnvironmentVariable("OTOPCUA_CONFIG_TEST_SA_PASSWORD") ?? DefaultSaPassword; DatabaseName = $"OtOpcUaConfig_Test_{DateTime.UtcNow:yyyyMMddHHmmss}_{Guid.NewGuid():N}"; ConnectionString = $"Server={server};Database={DatabaseName};User Id=sa;Password={saPassword};TrustServerCertificate=True;Encrypt=False;"; var options = new DbContextOptionsBuilder() .UseSqlServer(ConnectionString) .Options; using var ctx = new OtOpcUaConfigDbContext(options); ctx.Database.Migrate(); } public SqlConnection OpenConnection() { var conn = new SqlConnection(ConnectionString); conn.Open(); return conn; } public void Dispose() { var masterConnection = new SqlConnectionStringBuilder(ConnectionString) { InitialCatalog = "master" }.ConnectionString; using var conn = new SqlConnection(masterConnection); conn.Open(); using var cmd = conn.CreateCommand(); cmd.CommandText = $@" IF DB_ID(N'{DatabaseName}') IS NOT NULL BEGIN ALTER DATABASE [{DatabaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [{DatabaseName}]; END"; cmd.ExecuteNonQuery(); } } [CollectionDefinition(nameof(SchemaComplianceCollection))] public sealed class SchemaComplianceCollection : ICollectionFixture { }