using System.Data.Common; using Data.SeaHavenIndustries; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using SeaHaven.DataServices.Implementation; namespace SeaHavenIndustries.Tests; public sealed class UpliftDataServiceTransactionTests { [Fact] public async Task ExecuteWorkOrderMutationAsync_ReleasesGate_WhenTransactionInitializationFails() { await using var connection = new SqliteConnection("DataSource=:memory:"); await connection.OpenAsync(); var failingOptions = new DbContextOptionsBuilder() .UseSqlite(connection) .AddInterceptors(new ThrowOnceTransactionInterceptor()) .Options; await using (var failedContext = new ApplicationDbContext(failingOptions)) { var failedService = new UpliftDataService(failedContext); await Assert.ThrowsAsync(() => failedService.ExecuteWorkOrderMutationAsync( 387, _ => Task.FromResult(true), CancellationToken.None)); } var retryOptions = new DbContextOptionsBuilder() .UseSqlite(connection) .Options; await using var retryContext = new ApplicationDbContext(retryOptions); var retryService = new UpliftDataService(retryContext); var retry = retryService.ExecuteWorkOrderMutationAsync( 387, _ => Task.FromResult("entered"), CancellationToken.None); Assert.Equal("entered", await retry.WaitAsync(TimeSpan.FromSeconds(1))); } private sealed class ThrowOnceTransactionInterceptor : DbTransactionInterceptor { private int _remaining = 1; public override InterceptionResult TransactionStarting( DbConnection connection, TransactionStartingEventData eventData, InterceptionResult result) { ThrowOnce(); return base.TransactionStarting(connection, eventData, result); } public override ValueTask> TransactionStartingAsync( DbConnection connection, TransactionStartingEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) { ThrowOnce(); return base.TransactionStartingAsync(connection, eventData, result, cancellationToken); } private void ThrowOnce() { if (Interlocked.Exchange(ref _remaining, 0) == 1) throw new InvalidOperationException("Forced transaction initialization failure"); } } }