Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 12 additions & 39 deletions test/EFCore.Relational.Tests/RelationalConnectionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,27 +1095,20 @@ public void HandleTransactionCompleted_with_concurrent_ClearTransactions_is_thre
var connection = new FakeRelationalConnection(
CreateOptions(new FakeRelationalOptionsExtension().WithConnectionString("Database=ConcurrencyTest")));

using var scope = new TransactionScope();
var scope = new TransactionScope();
connection.Open();
scope.Complete();

var random = new Random();
var resetFirst = random.Next(0, 1) == 0;
var tasks = new Task[2];
tasks[0] = Task.Run(async () =>
// Start the reset task first, which will yield and then try to reset
var resetTask = Task.Run(async () =>
{
try
{
// Small delay to increase chance of race condition
// Small delay to increase chance of race condition with HandleTransactionCompleted
await Task.Yield();

if (resetFirst)
{
((IResettableService)connection).ResetState();
}
else
{
scope.Complete();
}
// ResetState calls ClearTransactions which might race with HandleTransactionCompleted
((IResettableService)connection).ResetState();
}
catch (Exception ex)
{
Expand All @@ -1126,32 +1119,12 @@ public void HandleTransactionCompleted_with_concurrent_ClearTransactions_is_thre
}
});

tasks[1] = Task.Run(async () =>
{
try
{
// Small delay to increase chance of race condition
await Task.Yield();

if (resetFirst)
{
scope.Complete();
}
else
{
((IResettableService)connection).ResetState();
}
}
catch (Exception ex)
{
lock (exceptions)
{
exceptions.Add(ex);
}
}
});
// Dispose the scope on the main thread, which will trigger the TransactionCompleted event
// The event handler (HandleTransactionCompleted) may execute on a different thread and race
// with the ClearTransactions call in resetTask
scope.Dispose();

Task.WaitAll(tasks, TimeSpan.FromSeconds(10));
Task.WaitAll(new[] { resetTask }, TimeSpan.FromSeconds(10));
}

Assert.Empty(exceptions);
Expand Down