using System.Data.Common; using Microsoft.EntityFrameworkCore.Diagnostics; namespace DodoSSH.Api.Tests; /// /// Fails the next commit the way a connection dropped on the way to the server would, when asked to. /// /// /// Before the commit reaches the database, so the transaction is rolled back — which is what a lost commit /// looks like from the server's side — and with a , which the retrying /// execution strategy treats as transient. That is the only way to watch a retry happen against a real /// database, and the retry is the thing worth watching: see FreshAttempts. /// internal sealed class FlakyCommits : DbTransactionInterceptor { private int armed; private int failed; /// How many commits this has failed. internal int Failed => Volatile.Read(ref failed); /// Makes the next commit, whoever's it is, fail once. internal void FailNextCommit() => Interlocked.Exchange(ref armed, 1); /// public override ValueTask TransactionCommittingAsync( DbTransaction transaction, TransactionEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) { if (Interlocked.Exchange(ref armed, 0) == 1) { Interlocked.Increment(ref failed); throw new TimeoutException("The commit was lost on its way to the server."); } return base.TransactionCommittingAsync(transaction, eventData, result, cancellationToken); } }