Files
DodoSSH/tests/DodoSSH.Api.Tests/FlakyCommits.cs
T

44 lines
1.6 KiB
C#

using System.Data.Common;
using Microsoft.EntityFrameworkCore.Diagnostics;
namespace DodoSSH.Api.Tests;
/// <summary>
/// Fails the next commit the way a connection dropped on the way to the server would, when asked to.
/// </summary>
/// <remarks>
/// 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 <see cref="TimeoutException"/>, 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 <c>FreshAttempts</c>.
/// </remarks>
internal sealed class FlakyCommits : DbTransactionInterceptor
{
private int armed;
private int failed;
/// <summary>How many commits this has failed.</summary>
internal int Failed => Volatile.Read(ref failed);
/// <summary>Makes the next commit, whoever's it is, fail once.</summary>
internal void FailNextCommit() => Interlocked.Exchange(ref armed, 1);
/// <inheritdoc />
public override ValueTask<InterceptionResult> 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);
}
}