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.
# 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:
- Opsætning -- opret tre databasetilstande (base, ours, theirs) med kendt indhold.
- Oracle -- beregn det forventede resultat af sammenfletningen ud fra de kendte input.
- Faktisk resultat -- kør merqls sammenfletning på de tre tilstande.
- Sammenlign -- det faktiske resultat skal svare nøjagtigt til det forventede.
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:
./bin/verify-all
Dette skal bestås, før arbejdet kan betragtes som færdigt.
Oracle-regressionspakke
Kør alle 32 scenarier:
./bin/test-regression
Kør en enkelt kategori:
./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):
./bin/test-regression --fast
Enkelt scenarie
Test ét scenarie gennem hele forløbet:
./bin/test-scenario column-level-clean
Individuelle oracle-trin
./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
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
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:
{
"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:
{
"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:
OracleCapture::compute()opbygger tre snapshots ud fra scenariets data i JSON og kører sammenfletningen.ScenarioComparator::compare()kontrollerer sammenfletningsresultatet mod de forventede værdier iscenario.json.- Returnerer bestået/ikke bestået med en liste over fejlmeddelelser.
use Merql\Tests\Oracle\ScenarioRunner;
$result = ScenarioRunner::run($scenario);
// ['name' => 'column-level-clean', 'pass' => true, 'failures' => []]
ScenarioRunner::runAll() kører alle scenarier efter hinanden:
$results = ScenarioRunner::runAll($scenarios);
Tilføjelse af et nyt scenarie
- Opret en mappe:
scenarios/<category>/<name>/. - Opret
scenario.jsonmed scenariemetadata og forventninger. - Definér de tre databasetilstande i JSON-konfigurationen: basedata, vores ændringer, deres ændringer.
- Kør scenariet:
./bin/test-scenario <name>. - 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.