Teststrategie
merql gebruikt een oraclegestuurd testmodel. Elk testscenario definieert een bekende set invoer (drie databasetoestanden), een deterministisch verwacht resultaat (de oracle) en vergelijkt de werkelijke uitvoer van de merge met die verwachting. 32 scenario's bestrijken schone merges, conflicten, identiteitsbepaling, gegevenstypen, schaal en uitzonderingsgevallen.
# Run the full verification suite.
./bin/verify-all
De opdrachten op deze pagina worden uitgevoerd vanuit een checkout van de merql-repository na
composer install. De ontwikkelscripts in bin/, het corpus van scenarios/
en de tests maken geen deel uit van het Composer-pakket. De ontwikkelafhankelijkheden omvatten
PHPUnit 13, waarvoor PHP 8.4 of hoger vereist is, hoewel de
bibliotheek zelf draait op PHP 8.2.
Oraclegestuurd testen
Er bestaat geen referentietool voor het uitvoeren van een drieweg-databasemerge. Daarom wordt de oracle berekend op basis van bekende invoer, niet gegenereerd door een externe tool. Elk scenario heeft een deterministisch verwacht resultaat dat aan de hand van logica kan worden gecontroleerd:
- Setup -- maak drie databasetoestanden (base, ours, theirs) met bekende inhoud.
- Oracle -- bereken het verwachte mergeresultaat op basis van de bekende invoer.
- Werkelijke uitvoering -- voer de merge van merql uit op de drie toestanden.
- Vergelijking -- het werkelijke resultaat moet exact overeenkomen met het verwachte resultaat.
Known inputs (base, ours, theirs)
| |
Deterministic merql merge
computation
| |
Expected result Actual result
| |
-----> Compare <-----
|
Pass or Fail
Tests uitvoeren
Volledige verificatie
Het verify-all-script is de laatste controle. Het voert statische analyse, coderingsstandaarden, PHPUnit-tests en de oracle-regressiesuite uit:
./bin/verify-all
Dit moet slagen voordat werk als voltooid wordt beschouwd.
Oracle-regressiesuite
Voer alle 32 scenario's uit:
./bin/test-regression
Voer één categorie uit:
./bin/test-regression --category clean
./bin/test-regression --category conflict
./bin/test-regression --category identity
Categorieën zijn de mapnamen onder scenarios/: clean, conflict,
identity, types, scale en edge. Bij een onbekende categorie wordt No scenarios found weergegeven en eindigt het script succesvol. --category kan worden herhaald om
meerdere categorieën uit te voeren.
Het script accepteert ook --jobs, maar negeert de waarde en voert scenario's
na elkaar uit (#5).
Uitvoeren met minimale uitvoer (alleen geslaagd/mislukt):
./bin/test-regression --fast
Eén scenario
Test één scenario via de volledige pipeline:
./bin/test-scenario column-level-clean
Afzonderlijke oracle-stappen
./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
Unittests
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 voert alleen PHPUnit uit. De oracle-suite van PHPUnit verwijst naar
tests/Oracle, met de klassen van de scenariorunner maar zonder testgevallen. Daarom worden de 32 scenario's alleen uitgevoerd via composer test:oracle, composer verify of
./bin/verify-all.
De MySQL-integratietests worden overgeslagen tenzij MERQL_MYSQL_HOST,
MERQL_MYSQL_DATABASE en MERQL_MYSQL_USER (en eventueel ook
MERQL_MYSQL_PASSWORD en MERQL_MYSQL_PORT) naar een testdatabase verwijzen.
Codekwaliteit
composer cs # PSR-12 coding standards check
composer cs:fix # Auto-fix coding standards
composer analyse # PHPStan level 10 static analysis
Scenariocategorieën
clean (8 scenario's)
Schone merges zonder conflicten. Beide zijden kunnen gegevens wijzigen, maar nooit dezelfde kolom van dezelfde rij.
| Scenario | Tests |
|---|---|
insert-only-theirs |
Theirs heeft rijen ingevoegd, ours is ongewijzigd. |
update-only-theirs |
Theirs heeft rijen bijgewerkt, ours is ongewijzigd. |
delete-only-theirs |
Theirs heeft rijen verwijderd, ours is ongewijzigd. |
insert-only-ours |
Ours heeft rijen ingevoegd, theirs is ongewijzigd. |
mixed-no-overlap |
Beide hebben verschillende tabellen of rijen gewijzigd. |
both-same-change |
Beide hebben identieke wijzigingen aangebracht (geen conflict). |
column-level-clean |
Beide hebben dezelfde rij gewijzigd, maar verschillende kolommen. |
multi-table |
Wijzigingen in meerdere tabellen. |
conflict (6 scenario's)
Scenario's die conflicten moeten opleveren.
| Scenario | Tests |
|---|---|
both-update-same-column |
Beide hebben dezelfde kolom gewijzigd in verschillende waarden. |
update-vs-delete |
De ene heeft dezelfde rij bijgewerkt en de andere verwijderd. |
delete-vs-update |
Omgekeerde richting van update versus verwijdering. |
both-insert-same-pk |
Beide hebben een rij met dezelfde primaire sleutel ingevoegd. |
multiple-conflicts |
Meerdere conflicten in één merge. |
partial-conflict |
Sommige kolommen conflicteren, andere worden zonder conflict samengevoegd. |
identity (4 scenario's)
Randgevallen rond rij-identiteit.
| Scenario | Tests |
|---|---|
auto-increment |
Nieuwe rijen hebben verschillende ID's in verschillende branches. |
natural-key |
Koppelen op basis van unieke kolommen in plaats van PK. |
composite-key |
Primaire sleutel met meerdere kolommen. |
no-key |
Tabel zonder primaire sleutel (terugvaloptie op basis van inhoudshash). |
types (6 scenario's)
Verwerking van gegevenstypen voor alle kolomtypen.
| Scenario | Tests |
|---|---|
text-columns |
Waarden van het type VARCHAR, TEXT en LONGTEXT. |
numeric-columns |
Waarden van het type INT, DECIMAL en FLOAT. |
date-columns |
Waarden van het type DATE, DATETIME en TIMESTAMP. |
json-columns |
JSON-kolommerge. |
blob-columns |
Binaire gegevens. |
null-handling |
Overgangen van NULL naar een waarde en van een waarde naar NULL. |
scale (4 scenario's)
Prestaties onder belasting.
| Scenario | Tests |
|---|---|
1k-rows |
1,000 rijen. |
10k-rows |
10,000 rijen. |
100k-rows |
100,000 rijen. |
wide-table |
Tabel met 50+ kolommen. |
edge (4 scenario's)
Uitzonderingsgevallen en randvoorwaarden.
| Scenario | Tests |
|---|---|
empty-changeset |
Geen wijzigingen aan één of beide zijden. |
schema-mismatch |
Kolom toegevoegd of verwijderd tussen snapshots. |
encoding |
UTF-8, emoji en speciale tekens. |
large-text |
Zeer grote TEXT/LONGTEXT-waarden. |
Scenariostructuur
Elk scenario is een map onder scenarios/<category>/<name>/ met een configuratie scenario.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"
}
}
Voor conflictscenario's worden de verwachte conflicten gedetailleerd opgegeven:
{
"expectations": {
"conflicts": 1,
"conflict_details": [
{
"table": "test_posts",
"primary_key": {"id": 42},
"column": "title",
"ours_value": "Welcome",
"theirs_value": "Greetings"
}
]
}
}
De ScenarioRunner-pipeline
ScenarioRunner::run() coördineert één scenario:
OracleCapture::compute()bouwt drie snapshots op basis van de gegevens van JSON en voert de merge uit.ScenarioComparator::compare()controleert het mergeresultaat aan de hand van de verwachte waarden inscenario.json.- Retourneert geslaagd/mislukt met een lijst foutmeldingen.
use Merql\Tests\Oracle\ScenarioRunner;
$result = ScenarioRunner::run($scenario);
// ['name' => 'column-level-clean', 'pass' => true, 'failures' => []]
ScenarioRunner::runAll() voert elk scenario achtereenvolgens uit:
$results = ScenarioRunner::runAll($scenarios);
Een nieuw scenario toevoegen
- Maak een map:
scenarios/<category>/<name>/. - Maak
scenario.jsonmet de scenariometagegevens en verwachtingen. - Definieer de drie databasestatussen in de configuratie van JSON: basisgegevens, wijzigingen van ours en wijzigingen van theirs.
- Voer het scenario uit:
./bin/test-scenario <name>. - Controleer de volledige suite:
./bin/verify-all.
Codekwaliteitsnormen
merql hanteert:
- PHPStan niveau 10 -- strikte statische analyse zonder uitzonderingen op basis van een baseline.
- PSR-12 -- coderingsnormen gecontroleerd door
phpcs. - Oracle-regressie -- alle 32 scenario's moeten slagen.
- Unit-tests -- geïsoleerde tests voor elk onderdeel.
Het script verify-all voert alle vier controles achter elkaar uit. Gedeeltelijke goedkeuring wordt niet geaccepteerd.
Continue integratie
CI voert bij elke push en pull request naar main de controles voor coderingsnormen, PHPStan, composer test, de integratiesuite met MySQL 8.4 via mysqli, de dekking van merge-primitieven en composer audit uit. De oracle-regressiecorpus wordt niet uitgevoerd (#6); voer daarom lokaal composer test:oracle of ./bin/verify-all uit voordat u op een wijziging vertrouwt.