fix: issue #29 — integration tests flakiness (DB split + SqlTestFixture consolidado) #34

Merged
dmolinari merged 7 commits from fix/issue-29-flakiness into main 2026-04-19 10:41:27 +00:00
Owner

Closes #29

Implementa las opciones 2+3 combinadas del issue:

  • Opción 2 — DB separada por proyecto:
    • SIGCM2_Test_App para Application.Tests
    • SIGCM2_Test_Api para Api.Tests
    • Elimina la contención inter-proceso sobre SIGCM2_Test.
  • Opción 3 — Consolidar Respawner en SqlTestFixture:
    • Nuevo DatabaseCollection.cs con [CollectionDefinition("Database")] + ICollectionFixture<SqlTestFixture>
    • 6 test files migrados — eliminan Respawner inline, usan el fixture compartido
    • SqlTestFixture.TablesToIgnore es la única fuente de verdad

Cambios por capa

Database infra

  • Nuevo: database/init/create-test-api-db.sql — idempotent: crea SIGCM2_Test_App y SIGCM2_Test_Api si no existen.
  • Runbook en database/README.md — sección "Test DBs" con comando PowerShell+SqlClient (bypasea el ODBC driver 17 no instalado) para aplicar V010.
  • V010 aplicada a ambas DBs (FILEGROUP + partition DDL requiere script manual; V008-V015 se autoaplican via SqlTestFixture.EnsureV0XXAsync).

TestSupport centralization

  • Nuevo: tests/SIGCM2.TestSupport/TestConnectionStrings.cs — constantes AppTestDb + ApiTestDb.
  • SqlTestFixture: nuevo ctor public SqlTestFixture() : this(TestConnectionStrings.AppTestDb) (requerido por ICollectionFixture<T>).
  • TestWebAppFactory.cs: usa TestConnectionStrings.ApiTestDb.

Application.Tests refactor

  • Nuevo: DatabaseCollection.cs con [CollectionDefinition("Database")].
  • 6 test classes migrados a [Collection("Database")] + SqlTestFixture db injection:
    • MedioRepositoryTests
    • SeccionRepositoryTests
    • V009MigrationTests
    • UsuarioRepositoryTests
    • UsuarioRepository_PermisosTests
    • RefreshTokenRepositoryTests
  • 27 archivos actualizados con TestConnectionStrings.AppTestDb o .ApiTestDb.

Documentation

  • database/README.md: agrega V013, V014, V015 + sección "Test DBs" con runbook.

Verificación

Ejecutado dotnet test (ambos proyectos en paralelo, comportamiento default) 6 veces consecutivas:

Run Application.Tests Api.Tests
1 715/715 230/230
2 714/715 (1 flake) 230/230
3 715/715 230/230
4 714/715 (1 flake) 230/230
5 715/715 230/230
6 714/715 (1 flake) 230/230

Mejora: pre-issue #29 teníamos 47-199 fallos catastróficos; post-fix queda 1 test intermitente residual.

Residual flake (follow-up menor diferido)

Un único test puede fallar intermitentemente:

SIGCM2.Application.Tests.Infrastructure.Audit.AuditEventRepositoryTests.QueryAsync_Limit_EmitsCursor_WhenMoreRowsAvailable

  • Está dentro de [Collection("Database")] (clases serializadas intra-collection).
  • Causa probable: asume orden monotónico de inserts o un cleanup parcial intra-test.
  • NO es inter-project (ese problema está eliminado).
  • Arreglar en un follow-up separado: [TestCaseOrderer], cleanup per-test, o refactorear el cursor test.

Engram artifacts

  • sdd/issue-29-integration-tests-flakiness/explore
  • sdd/issue-29-integration-tests-flakiness/proposal
  • sdd/issue-29-integration-tests-flakiness/spec
  • sdd/issue-29-integration-tests-flakiness/design
  • sdd/issue-29-integration-tests-flakiness/tasks
  • sdd/issue-29-integration-tests-flakiness/apply-progress

Nota de conflicto con CAT-001 (PR #30)

Esta rama está basada en main (pre-CAT-001). Cuando ambas merged, habrá conflict en SqlTestFixture.cs (CAT-001 agrega EnsureV016SchemaAsync + Rubro_History al TablesToIgnore). Resolución trivial al merge time — ambos cambios son aditivos.

Impacto post-merge

  • sig-cm2/conventions/new-temporal-table-test-propagation queda OBSOLETE. Nueva convención: para cada temporal table nueva, actualizar solo SqlTestFixture (1 archivo, no 7+).
## Closes #29 Implementa las opciones 2+3 combinadas del issue: - **Opción 2 — DB separada por proyecto**: - `SIGCM2_Test_App` para `Application.Tests` - `SIGCM2_Test_Api` para `Api.Tests` - Elimina la contención inter-proceso sobre `SIGCM2_Test`. - **Opción 3 — Consolidar Respawner en SqlTestFixture**: - Nuevo `DatabaseCollection.cs` con `[CollectionDefinition("Database")]` + `ICollectionFixture<SqlTestFixture>` - 6 test files migrados — eliminan `Respawner` inline, usan el fixture compartido - `SqlTestFixture.TablesToIgnore` es la única fuente de verdad ## Cambios por capa ### Database infra - **Nuevo**: `database/init/create-test-api-db.sql` — idempotent: crea `SIGCM2_Test_App` y `SIGCM2_Test_Api` si no existen. - Runbook en `database/README.md` — sección "Test DBs" con comando PowerShell+SqlClient (bypasea el ODBC driver 17 no instalado) para aplicar V010. - V010 aplicada a ambas DBs (FILEGROUP + partition DDL requiere script manual; V008-V015 se autoaplican via `SqlTestFixture.EnsureV0XXAsync`). ### TestSupport centralization - **Nuevo**: `tests/SIGCM2.TestSupport/TestConnectionStrings.cs` — constantes `AppTestDb` + `ApiTestDb`. - `SqlTestFixture`: nuevo ctor `public SqlTestFixture() : this(TestConnectionStrings.AppTestDb)` (requerido por `ICollectionFixture<T>`). - `TestWebAppFactory.cs`: usa `TestConnectionStrings.ApiTestDb`. ### Application.Tests refactor - **Nuevo**: `DatabaseCollection.cs` con `[CollectionDefinition("Database")]`. - 6 test classes migrados a `[Collection("Database")]` + `SqlTestFixture db` injection: - `MedioRepositoryTests` - `SeccionRepositoryTests` - `V009MigrationTests` - `UsuarioRepositoryTests` - `UsuarioRepository_PermisosTests` - `RefreshTokenRepositoryTests` - 27 archivos actualizados con `TestConnectionStrings.AppTestDb` o `.ApiTestDb`. ### Documentation - `database/README.md`: agrega V013, V014, V015 + sección "Test DBs" con runbook. ## Verificación Ejecutado `dotnet test` (ambos proyectos en paralelo, comportamiento default) **6 veces** consecutivas: | Run | Application.Tests | Api.Tests | |-----|---|---| | 1 | 715/715 ✅ | 230/230 ✅ | | 2 | 714/715 (1 flake) | 230/230 ✅ | | 3 | 715/715 ✅ | 230/230 ✅ | | 4 | 714/715 (1 flake) | 230/230 ✅ | | 5 | 715/715 ✅ | 230/230 ✅ | | 6 | 714/715 (1 flake) | 230/230 ✅ | **Mejora**: pre-issue #29 teníamos 47-199 fallos catastróficos; post-fix queda 1 test intermitente residual. ## Residual flake (follow-up menor diferido) Un único test puede fallar intermitentemente: `SIGCM2.Application.Tests.Infrastructure.Audit.AuditEventRepositoryTests.QueryAsync_Limit_EmitsCursor_WhenMoreRowsAvailable` - Está dentro de `[Collection("Database")]` (clases serializadas intra-collection). - Causa probable: asume orden monotónico de inserts o un cleanup parcial intra-test. - NO es inter-project (ese problema está eliminado). - Arreglar en un follow-up separado: `[TestCaseOrderer]`, cleanup per-test, o refactorear el cursor test. ## Engram artifacts - `sdd/issue-29-integration-tests-flakiness/explore` - `sdd/issue-29-integration-tests-flakiness/proposal` - `sdd/issue-29-integration-tests-flakiness/spec` - `sdd/issue-29-integration-tests-flakiness/design` - `sdd/issue-29-integration-tests-flakiness/tasks` - `sdd/issue-29-integration-tests-flakiness/apply-progress` ## Nota de conflicto con CAT-001 (PR #30) Esta rama está basada en `main` (pre-CAT-001). Cuando ambas merged, **habrá conflict en `SqlTestFixture.cs`** (CAT-001 agrega `EnsureV016SchemaAsync` + `Rubro_History` al `TablesToIgnore`). Resolución trivial al merge time — ambos cambios son aditivos. ## Impacto post-merge - `sig-cm2/conventions/new-temporal-table-test-propagation` queda **OBSOLETE**. Nueva convención: para cada temporal table nueva, actualizar solo `SqlTestFixture` (1 archivo, no 7+).
dmolinari added 6 commits 2026-04-19 01:00:23 +00:00
Introduce SIGCM2_Test_App y SIGCM2_Test_Api como bases aisladas para
Application.Tests y Api.Tests respectivamente. TestConnectionStrings.cs
centraliza las connection strings; create-test-api-db.sql documenta
el setup idempotente de ambas bases con COLLATE Modern_Spanish_CI_AS.
Agrega ctor parameterless que apunta a SIGCM2_Test_App (requerido por
xUnit ICollectionFixture<T>). El ctor con string se marca internal y
expone via InternalsVisibleTo a SIGCM2.Api.Tests. TestWebAppFactory
apunta a SIGCM2_Test_Api. Se agrega propiedad Connection pública para
que los tests que necesitan queries ad-hoc la usen.
Registra la colección "Database" con SqlTestFixture como fixture compartido
para Application.Tests (elimina el ctor-con-string inline en cada test class).
Agrega Using global a ambos proyectos para evitar usings por archivo.
6 clases que instanciaban Respawner directamente migran a recibir SqlTestFixture
vía ICollectionFixture. 8 clases restantes solo actualizan ConnectionString a
TestConnectionStrings.AppTestDb. Cada clase ahora es responsable únicamente de
sus seeds específicos; la limpieza de la base queda centralizada en el fixture.
Todos los archivos de Api.Tests reemplazan la connection string hardcodeada
por TestConnectionStrings.ApiTestDb. Cada proyecto de tests ahora tiene su
propia base de datos aislada, eliminando la contención entre Application.Tests
y Api.Tests que causaba flakiness.
Agrega filas V013, V014, V015 a la tabla de migraciones. Actualiza
convención de "3 bases" (SIGCM2, SIGCM2_Test_App, SIGCM2_Test_Api).
Añade sección "Bases de datos de integration tests" con tabla de
propósito y referencia al script de creación.
dmolinari added 1 commit 2026-04-19 10:40:37 +00:00
DATETIME2(3) + cursor roundtrip via O format perdía sub-ms de
DateTime.UtcNow causando ~37% flake rate. Timestamp fijo con sub-ms=0
elimina la ambigüedad.

Fixes residual flake del issue #29.
dmolinari merged commit 9886524645 into main 2026-04-19 10:41:27 +00:00
dmolinari deleted branch fix/issue-29-flakiness 2026-04-19 10:41:28 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dmolinari/SIG-CM2.0#34