Gå til indhold

Teststrategi

merql bruger en oracle-drevet testmodel. Hvert testscenarie definerer et kendt sæt input (tre databasetilstande), et deterministisk forventet resultat (oracle) og sammenligner det faktiske resultat af sammenfletningen med forventningen. 32 scenarier dækker rene sammenfletninger, konflikter, identitetsafklaring, datatyper, skala og kanttilfælde.

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

Kommandoerne på denne side køres fra en checkout af merql-arkivet efter composer install. Udviklingsscripts i bin/, scenarios/ testmaterialet og testene er ikke en del af pakken Composer. Udviklingsafhængighederne omfatter PHPUnit 13, som kræver PHP 8.4 eller nyere, selv om selve biblioteket kører på PHP 8.2.

Oracle-drevet test

Der findes ikke noget eksisterende referenceværktøj, der udfører en trevejs-databasesammenfletning, så oracle-resultatet beregnes ud fra kendte input i stedet for at blive genereret af et eksternt værktøj. Hvert scenarie har et deterministisk forventet resultat, som kan verificeres logisk:

  1. Opsætning -- opret tre databasetilstande (base, ours, theirs) med kendt indhold.
  2. Oracle -- beregn det forventede resultat af sammenfletningen ud fra de kendte input.
  3. Faktisk resultat -- kør merqls sammenfletning på de tre tilstande.
  4. Sammenlign -- det faktiske resultat skal svare nøjagtigt til det forventede.
Kode
Known inputs (base, ours, theirs)
         |                    |
    Deterministic          merql merge
    computation
         |                    |
    Expected result       Actual result
         |                    |
         -----> Compare <-----
                  |
            Pass or Fail

Kørsel af test

Fuld verifikation

Scriptet verify-all er den sidste kontrol. Det kører statisk analyse, kodningsstandarder, PHPUnit-test og oracle-regressionspakken:

Shell
./bin/verify-all

Dette skal bestås, før arbejdet kan betragtes som færdigt.

Oracle-regressionspakke

Kør alle 32 scenarier:

Shell
./bin/test-regression

Kør en enkelt kategori:

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

Kategorierne er mappenavnene under scenarios/: clean, conflict, identity, types, scale og edge. En ukendt kategori udskriver No scenarios found og afslutter uden fejl. --category kan gentages for at køre flere kategorier.

Scriptet accepterer også --jobs, men ignorerer værdien og kører scenarierne ét ad gangen (#5).

Kør med minimal output (kun bestået/ikke bestået):

Shell
./bin/test-regression --fast

Enkelt scenarie

Test ét scenarie gennem hele forløbet:

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

Individuelle oracle-trin

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

Enhedstest

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 kører kun PHPUnit. oracle-pakken PHPUnit peger på tests/Oracle, som indeholder scenarierunner-klasserne, men ingen testtilfælde, så de 32 scenarier køres kun via composer test:oracle, composer verify eller ./bin/verify-all.

MySQL-integrationstestene springes over, medmindre MERQL_MYSQL_HOST, MERQL_MYSQL_DATABASE og MERQL_MYSQL_USER (samt eventuelt MERQL_MYSQL_PASSWORD og MERQL_MYSQL_PORT) peger på en testdatabase.

Kodekvalitet

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

Scenariekategorier

clean (8 scenarier)

Rene sammenfletninger uden konflikter. Begge sider kan ændre data, men aldrig den samme kolonne i den samme række.

Scenarie Test
insert-only-theirs De indsatte rækker hos dem, vores uændrede.
update-only-theirs De opdaterede rækker hos dem, vores uændrede.
delete-only-theirs De slettede rækker hos dem, vores uændrede.
insert-only-ours Vores indsatte rækker, deres uændrede.
mixed-no-overlap Begge ændrede forskellige tabeller eller rækker.
both-same-change Begge foretog identiske ændringer (ingen konflikt).
column-level-clean Begge ændrede samme række, men forskellige kolonner.
multi-table Ændringer på tværs af flere tabeller.

conflict (6 scenarier)

Scenarier, der skal skabe konflikter.

Scenarie Test
both-update-same-column Begge ændrede samme kolonne til forskellige værdier.
update-vs-delete Den ene opdaterede, den anden slettede samme række.
delete-vs-update Omvendt retning af opdatering kontra sletning.
both-insert-same-pk Begge indsatte en række med samme primærnøgle.
multiple-conflicts Flere konflikter i én sammenfletning.
partial-conflict Nogle kolonner er i konflikt, andre sammenflettes uden konflikt.

identity (4 scenarier)

Kanttilfælde for rækkeidentitet.

Scenarie Test
auto-increment Nye rækker har forskellige ID'er på tværs af grene.
natural-key Match via unikke kolonner i stedet for PK.
composite-key Primærnøgle med flere kolonner.
no-key Tabel uden primærnøgle (fallback til indholdshash).

types (6 scenarier)

Håndtering af datatyper for alle kolonnetyper.

Scenarie Test
text-columns VARCHAR-, TEXT- og LONGTEXT-værdier.
numeric-columns INT-, DECIMAL- og FLOAT-værdier.
date-columns DATE-, DATETIME- og TIMESTAMP-værdier.
json-columns JSON-kolonnesammenfletning.
blob-columns Binære data.
null-handling Overgange fra NULL til værdi og fra værdi til NULL.

scale (4 scenarier)

Ydeevne under belastning.

Scenarie Test
1k-rows 1,000 rækker.
10k-rows 10,000 rækker.
100k-rows 100,000 rækker.
wide-table Tabel med over 50 kolonner.

edge (4 scenarier)

Kanttilfælde og grænsebetingelser.

Scenarie Test
empty-changeset Ingen ændringer på den ene eller begge sider.
schema-mismatch Kolonne tilføjet eller fjernet mellem snapshots.
encoding UTF-8, emoji, specialtegn.
large-text Meget store TEXT/LONGTEXT-værdier.

Scenariestruktur

Hvert scenarie er en mappe under scenarios/<category>/<name>/ med en scenario.json-konfiguration:

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"
    }
}

For konfliktscenarier angives de forventede konflikter i detaljer:

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

ScenarioRunner-forløbet

ScenarioRunner::run() styrer et enkelt scenarie:

  1. OracleCapture::compute() opbygger tre snapshots ud fra scenariets data i JSON og kører sammenfletningen.
  2. ScenarioComparator::compare() kontrollerer sammenfletningsresultatet mod de forventede værdier i scenario.json.
  3. Returnerer bestået/ikke bestået med en liste over fejlmeddelelser.
PHP
use Merql\Tests\Oracle\ScenarioRunner;

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

ScenarioRunner::runAll() kører alle scenarier efter hinanden:

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

Tilføjelse af et nyt scenarie

  1. Opret en mappe: scenarios/<category>/<name>/.
  2. Opret scenario.json med scenariemetadata og forventninger.
  3. Definér de tre databasetilstande i JSON-konfigurationen: basedata, vores ændringer, deres ændringer.
  4. Kør scenariet: ./bin/test-scenario <name>.
  5. Verificér hele pakken: ./bin/verify-all.

Standarder for kodekvalitet

merql håndhæver:

  • PHPStan niveau 10 -- streng statisk analyse uden undtagelser fra baseline.
  • PSR-12 -- kodningsstandarder kontrolleret af phpcs.
  • Oracle-regression -- alle 32 scenarier skal bestås.
  • Enhedstest -- isolerede test af hver komponent.

Scriptet verify-all kører alle fire kontroller efter hinanden. Delvis godkendelse accepteres ikke.

Kontinuerlig integration

CI kører kodningsstandarder, PHPStan, composer test, integrationspakken mod MySQL 8.4 via mysqli, dækning af sammenfletningsprimitive og composer audit ved hver push og pull request til main. Den kører ikke oracle-regressionspakken (#6), så kør composer test:oracle eller ./bin/verify-all lokalt, før du stoler på en ændring.