using Xunit; namespace ScadaLink.ConfigurationDatabase.Tests.Migrations; /// /// Audit Log #23 (ExecutionId Task 5) integration test for the /// AddNotificationOriginExecutionId 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 /// OriginExecutionId 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 AddNotificationOriginExecutionIdMigrationTests : IClassFixture { private readonly MsSqlMigrationFixture _fixture; public AddNotificationOriginExecutionIdMigrationTests(MsSqlMigrationFixture fixture) { _fixture = fixture; } [SkippableFact] public async Task AppliesMigration_AddsOriginExecutionIdColumn_ToNotifications() { Skip.IfNot(_fixture.Available, _fixture.SkipReason); var present = await ScalarAsync( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS " + "WHERE TABLE_NAME = 'Notifications' AND COLUMN_NAME = 'OriginExecutionId' " + "AND TABLE_SCHEMA = 'dbo';"); Assert.Equal(1, present); } [SkippableFact] public async Task OriginExecutionIdColumn_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 = 'OriginExecutionId';"); Assert.Equal("uniqueidentifier", dataType); var isNullable = await ScalarAsync( "SELECT IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS " + "WHERE TABLE_NAME = 'Notifications' AND COLUMN_NAME = 'OriginExecutionId';"); 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))!; } }