using Xunit; namespace ScadaLink.ConfigurationDatabase.Tests.Migrations; /// /// Audit Log ParentExecutionId integration test for the /// AddNotificationOriginParentExecutionId migration: applies the EF /// migrations to a freshly-created MSSQL test database on the running /// infra/mssql container and asserts that the Notifications table carries /// the new OriginParentExecutionId column as a nullable /// uniqueidentifier. /// /// /// Unlike AuditLog, the Notifications table is not partitioned, so /// the column is a plain metadata-only ALTER TABLE … ADD with no index. /// Tests pair with Skip.IfNot(...) so /// the runner reports them as Skipped (not Passed) when MSSQL is unreachable. The /// fixture applies the migrations once at construction time. /// public class AddNotificationOriginParentExecutionIdMigrationTests : IClassFixture { private readonly MsSqlMigrationFixture _fixture; public AddNotificationOriginParentExecutionIdMigrationTests(MsSqlMigrationFixture fixture) { _fixture = fixture; } [SkippableFact] public async Task AppliesMigration_AddsOriginParentExecutionIdColumn_ToNotifications() { Skip.IfNot(_fixture.Available, _fixture.SkipReason); var present = await ScalarAsync( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS " + "WHERE TABLE_NAME = 'Notifications' AND COLUMN_NAME = 'OriginParentExecutionId' " + "AND TABLE_SCHEMA = 'dbo';"); Assert.Equal(1, present); } [SkippableFact] public async Task OriginParentExecutionIdColumn_IsNullableUniqueIdentifier() { Skip.IfNot(_fixture.Available, _fixture.SkipReason); var dataType = await ScalarAsync( "SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS " + "WHERE TABLE_NAME = 'Notifications' AND COLUMN_NAME = 'OriginParentExecutionId';"); Assert.Equal("uniqueidentifier", dataType); var isNullable = await ScalarAsync( "SELECT IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS " + "WHERE TABLE_NAME = 'Notifications' AND COLUMN_NAME = 'OriginParentExecutionId';"); Assert.Equal("YES", isNullable); } // --- helpers ------------------------------------------------------------ private async Task ScalarAsync(string sql) { await using var conn = _fixture.OpenConnection(); await using var cmd = conn.CreateCommand(); cmd.CommandText = sql; var result = await cmd.ExecuteScalarAsync(); if (result is null || result is DBNull) { return default!; } return (T)Convert.ChangeType(result, typeof(T) == typeof(string) ? typeof(string) : Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T))!; } }