chore(udt-010): bootstrap rama + spike anti-MSDTC
Validates design decision #D-1 (TransactionScope ambient over IUnitOfWork):
TransactionScope with TransactionScopeAsyncFlowOption.Enabled does NOT
escalate to MSDTC when multiple SqlConnections share the same connection
string. Test passes (DistributedIdentifier == Guid.Empty).
Unblocks UDT-010 batches B1-B14.
Refs: sdd/udt-010-auditoria-trazabilidad/{design,tasks}
This commit is contained in:
58
tests/SIGCM2.Api.Tests/Audit/TransactionScopeSpikeTests.cs
Normal file
58
tests/SIGCM2.Api.Tests/Audit/TransactionScopeSpikeTests.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System.Transactions;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace SIGCM2.Api.Tests.Audit;
|
||||||
|
|
||||||
|
/// UDT-010 Batch 0 — anti-MSDTC spike. Validates design decision #D-1:
|
||||||
|
/// TransactionScope with AsyncFlowEnabled must NOT escalate to MSDTC when
|
||||||
|
/// multiple SqlConnections share a single connection string. If this fails,
|
||||||
|
/// UDT-010 must pivot to explicit IUnitOfWork.
|
||||||
|
public sealed class TransactionScopeSpikeTests
|
||||||
|
{
|
||||||
|
private const string ConnectionString =
|
||||||
|
"Server=TECNICA3;Database=SIGCM2_Test;User Id=desarrollo;Password=desarrollo2026;TrustServerCertificate=True;";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TransactionScope_DoesNotEscalateToMSDTC_WithSingleConnectionString()
|
||||||
|
{
|
||||||
|
var txOptions = new TransactionOptions
|
||||||
|
{
|
||||||
|
IsolationLevel = IsolationLevel.ReadCommitted
|
||||||
|
};
|
||||||
|
|
||||||
|
using var tx = new TransactionScope(
|
||||||
|
TransactionScopeOption.Required,
|
||||||
|
txOptions,
|
||||||
|
TransactionScopeAsyncFlowOption.Enabled);
|
||||||
|
|
||||||
|
await using (var conn1 = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
await conn1.OpenAsync();
|
||||||
|
using var cmd1 = conn1.CreateCommand();
|
||||||
|
cmd1.CommandText = "SELECT 1";
|
||||||
|
var result1 = await cmd1.ExecuteScalarAsync();
|
||||||
|
result1.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
await using (var conn2 = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
await conn2.OpenAsync();
|
||||||
|
using var cmd2 = conn2.CreateCommand();
|
||||||
|
cmd2.CommandText = "SELECT 1";
|
||||||
|
var result2 = await cmd2.ExecuteScalarAsync();
|
||||||
|
result2.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var current = Transaction.Current;
|
||||||
|
current.Should().NotBeNull("TransactionScope must set an ambient transaction");
|
||||||
|
current!.TransactionInformation.DistributedIdentifier
|
||||||
|
.Should().Be(Guid.Empty,
|
||||||
|
"SQL Server with a single connection string must NOT escalate to MSDTC. " +
|
||||||
|
"If this assertion fails, UDT-010 design must pivot to explicit IUnitOfWork " +
|
||||||
|
"(see sdd/udt-010-auditoria-trazabilidad/design #D-1).");
|
||||||
|
|
||||||
|
tx.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user