Saltar al contenido

Estrategia de pruebas

merql utiliza un modelo de pruebas basado en un oráculo. Cada escenario de prueba define un conjunto conocido de entradas (tres estados de la base de datos), un resultado esperado determinista (el oráculo) y compara el resultado real de la fusión con esa expectativa. 32 escenarios cubren fusiones sin conflictos, conflictos, resolución de identidades, tipos de datos, escala y casos límite.

Shell
# Run the full verification suite.
./bin/verify-all

Los comandos de esta página se ejecutan desde una copia local del repositorio merql después de composer install. Los scripts de desarrollo de bin/, el corpus de scenarios/ y las pruebas no forman parte del paquete Composer. Las dependencias de desarrollo incluyen PHPUnit 13, que requiere PHP 8.4 o posterior, aunque la biblioteca funciona con PHP 8.2.

Pruebas basadas en un oráculo

No existe una herramienta de referencia que realice fusiones de bases de datos de tres vías, por lo que el oráculo se calcula a partir de entradas conocidas en lugar de generarse con una herramienta externa. Cada escenario tiene un resultado esperado determinista que puede verificarse mediante lógica:

  1. Configuración -- crear tres estados de la base de datos (base, nuestro y suyo) con contenido conocido.
  2. Oráculo -- calcular el resultado esperado de la fusión a partir de las entradas conocidas.
  3. Resultado real -- ejecutar la fusión de merql en los tres estados.
  4. Comparación -- el resultado real debe coincidir exactamente con el resultado esperado.
Código
Known inputs (base, ours, theirs)
         |                    |
    Deterministic          merql merge
    computation
         |                    |
    Expected result       Actual result
         |                    |
         -----> Compare <-----
                  |
            Pass or Fail

Ejecutar las pruebas

Verificación completa

El script verify-all es la comprobación final. Ejecuta el análisis estático, las normas de código, las pruebas PHPUnit y la suite de regresión del oráculo:

Shell
./bin/verify-all

Debe superarse antes de considerar terminado cualquier trabajo.

Suite de regresión del oráculo

Ejecuta los 32 escenarios:

Shell
./bin/test-regression

Ejecuta una sola categoría:

Shell
./bin/test-regression --category clean
./bin/test-regression --category conflict
./bin/test-regression --category identity

Las categorías son los nombres de directorio bajo scenarios/: clean, conflict, identity, types, scale y edge. Una categoría desconocida muestra No scenarios found y termina correctamente. Se puede repetir --category para ejecutar varias categorías.

El script también acepta --jobs, pero ignora su valor y ejecuta los escenarios uno tras otro (#5).

Ejecuta con una salida mínima (solo aprobado/reprobado):

Shell
./bin/test-regression --fast

Escenario individual

Prueba un escenario mediante el flujo completo:

Shell
./bin/test-scenario column-level-clean

Pasos individuales del oráculo

Shell
./bin/oracle column-level-clean    # Compute expected result
./bin/actual column-level-clean    # Run merql, capture output
./bin/compare column-level-clean   # Diff oracle vs actual

Pruebas unitarias

Shell
composer test:unit         # Isolated component tests
composer test:integration  # Integration tests (SQLite, plus MySQL when configured)
composer test              # All PHPUnit suites
composer test:oracle       # Oracle regression corpus (bin/test-regression)
composer verify            # analyse + cs + test + test:oracle

composer test ejecuta solo PHPUnit. La suite oracle PHPUnit apunta a tests/Oracle, que contiene las clases del ejecutor de escenarios, pero ningún caso de prueba, por lo que los 32 escenarios solo se ejecutan mediante composer test:oracle, composer verify o ./bin/verify-all.

Las pruebas de integración MySQL se omiten salvo que MERQL_MYSQL_HOST, MERQL_MYSQL_DATABASE y MERQL_MYSQL_USER (además de, opcionalmente, MERQL_MYSQL_PASSWORD y MERQL_MYSQL_PORT) apunten a una base de datos de prueba.

Calidad del código

Shell
composer cs            # PSR-12 coding standards check
composer cs:fix        # Auto-fix coding standards
composer analyse       # PHPStan level 10 static analysis

Categorías de escenarios

clean (8 escenarios)

Fusiones sin conflictos. Ambos lados pueden cambiar datos, pero nunca la misma columna de la misma fila.

Escenario Pruebas
insert-only-theirs theirs insertó filas; ours no cambió.
update-only-theirs theirs actualizó filas; ours no cambió.
delete-only-theirs theirs eliminó filas; ours no cambió.
insert-only-ours ours insertó filas; theirs no cambió.
mixed-no-overlap Ambos cambiaron tablas o filas distintas.
both-same-change Ambos hicieron los mismos cambios (sin conflicto).
column-level-clean Ambos cambiaron la misma fila, pero distintas columnas.
multi-table Cambios en varias tablas.

conflict (6 escenarios)

Escenarios que deben generar conflictos.

Escenario Pruebas
both-update-same-column Ambos cambiaron la misma columna a valores distintos.
update-vs-delete Uno actualizó y el otro eliminó la misma fila.
delete-vs-update Dirección inversa de actualización frente a eliminación.
both-insert-same-pk Ambos insertaron una fila con la misma clave principal.
multiple-conflicts Varios conflictos en una fusión.
partial-conflict Algunas columnas entran en conflicto y otras se fusionan sin problemas.

identity (4 escenarios)

Casos límite de identidad de filas.

Escenario Pruebas
auto-increment Las filas nuevas tienen distintos ID entre ramas.
natural-key Coincidencia mediante columnas únicas en lugar de la PK.
composite-key Clave principal de varias columnas.
no-key Tabla sin clave principal (alternativa de hash del contenido).

types (6 escenarios)

Gestión de tipos de datos en todos los tipos de columna.

Escenario Pruebas
text-columns Valores VARCHAR, TEXT y LONGTEXT.
numeric-columns Valores INT, DECIMAL y FLOAT.
date-columns Valores DATE, DATETIME y TIMESTAMP.
json-columns Fusión de columnas JSON.
blob-columns Datos binarios.
null-handling Transiciones de NULL a un valor y de un valor a NULL.

scale (4 escenarios)

Rendimiento con carga.

Escenario Pruebas
1k-rows 1,000 filas.
10k-rows 10,000 filas.
100k-rows 100,000 filas.
wide-table Tabla con más de 50 columnas.

edge (4 escenarios)

Casos límite y condiciones de borde.

Escenario Pruebas
empty-changeset Sin cambios en uno o ambos lados.
schema-mismatch Columna añadida o eliminada entre instantáneas.
encoding UTF-8, emojis y caracteres especiales.
large-text Valores TEXT/LONGTEXT muy grandes.

Estructura de los escenarios

Cada escenario es un directorio bajo scenarios/<category>/<name>/ con una configuración scenario.json:

JSON
{
    "name": "column-level-clean",
    "category": "clean",
    "description": "Both sides modify same row but different columns",
    "tables": ["test_posts"],
    "expectations": {
        "conflicts": 0,
        "operations": 3,
        "changeset_match": "exact",
        "merge_match": "exact",
        "sql_match": "semantic"
    }
}

En los escenarios con conflictos, los conflictos esperados se especifican en detalle:

JSON
{
    "expectations": {
        "conflicts": 1,
        "conflict_details": [
            {
                "table": "test_posts",
                "primary_key": {"id": 42},
                "column": "title",
                "ours_value": "Welcome",
                "theirs_value": "Greetings"
            }
        ]
    }
}

Flujo de ScenarioRunner

ScenarioRunner::run() coordina un escenario individual:

  1. OracleCapture::compute() crea tres instantáneas a partir de los datos JSON del escenario y ejecuta la fusión.
  2. ScenarioComparator::compare() comprueba el resultado de la fusión frente a los valores esperados en scenario.json.
  3. Devuelve aprobado/reprobado junto con una lista de mensajes de error.
PHP
use Merql\Tests\Oracle\ScenarioRunner;

$result = ScenarioRunner::run($scenario);
// ['name' => 'column-level-clean', 'pass' => true, 'failures' => []]

ScenarioRunner::runAll() ejecuta todos los escenarios en secuencia:

PHP
$results = ScenarioRunner::runAll($scenarios);

Añadir un escenario nuevo

  1. Crea un directorio: scenarios/<category>/<name>/.
  2. Crea scenario.json con los metadatos y las expectativas del escenario.
  3. Define los tres estados de la base de datos en la configuración JSON: datos base, modificaciones nuestras y modificaciones suyas.
  4. Ejecuta el escenario: ./bin/test-scenario <name>.
  5. Verifica la suite completa: ./bin/verify-all.

Estándares de calidad del código

merql aplica:

  • PHPStan nivel 10 -- análisis estático estricto sin excepciones de referencia.
  • PSR-12 -- normas de código verificadas por phpcs.
  • Regresión del oráculo -- deben superarse los 32 escenarios.
  • Pruebas unitarias -- pruebas aisladas para cada componente.

El script verify-all ejecuta las cuatro comprobaciones en secuencia. No se acepta una aprobación parcial.

Integración continua

CI ejecuta las normas de código, PHPStan, composer test, la suite de integración con MySQL 8.4 mediante mysqli, la cobertura de primitivas de fusión y composer audit en cada envío y solicitud de incorporación a main. No ejecuta el corpus de regresión del oráculo (#6), así que antes de confiar en un cambio, ejecuta localmente composer test:oracle o ./bin/verify-all.