Files
SIG-CM2.0/tests/SIGCM2.Api.Tests/Audit/TransactionScopeSpikeTests.cs
dmolinari c95bc7fe01 fix(tests): extend Respawn + collection config for UDT-010 temporal tables
Follow-up of B1 (V010 migration). Issues found when running the full suite
cross-assembly:

1. Respawn 'Cannot delete rows from a temporal history table' error:
   4 per-class Respawner configs in SIGCM2.Application.Tests did not
   include the newly-created *_History tables introduced by V010
   (Usuario_History / Rol_History / Permiso_History / RolPermiso_History).
   The engine rejects direct DELETE on system-versioned history tables.
   Extended TablesToIgnore in all 4 configs.

2. FK_RefreshToken_Usuario violation in RolRepositoryTests.InitializeAsync:
   Manual 'DELETE FROM Usuario' failed when residual RefreshTokens from
   prior suites existed. Added 'DELETE FROM RefreshToken' before the
   Usuario cleanup to respect FK order. Latent bug surfaced by a new
   test-run ordering — not UDT-010 specific, but fixed in scope.

3. UQ_Usuario_Username duplicate admin race:
   TransactionScopeSpikeTests (B0) and V010MigrationTests (B1) were
   missing [Collection("ApiIntegration")], causing them to run in
   parallel with the rest of SIGCM2.Api.Tests and race on SeedAdmin.
   Serialized by adding the Collection attribute.

Suite now passes cross-assembly: 130/130 Api.Tests + 336/336 Application.Tests.

Refs: sdd/udt-010-auditoria-trazabilidad/apply-progress (B1 follow-up)
2026-04-16 13:22:56 -03:00

60 lines
2.2 KiB
C#

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.
[Collection("ApiIntegration")]
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();
}
}