Strategie testování
merql používá model testování řízený orákulem. Každý testovací scénář určuje známou sadu vstupů (tři stavy databáze), deterministický očekávaný výsledek (orákulum) a porovnává skutečný výstup sloučení s tímto očekáváním. Celkem 32 scénářů pokrývá čistá sloučení, konflikty, určování identity, datové typy, rozsah a okrajové případy.
# Run the full verification suite.
./bin/verify-all
Příkazy na této stránce spusťte z checkoutu repozitáře merql po composer install. Vývojové skripty v bin/, korpus scenarios/ a testy nejsou součástí balíčku Composer. Mezi vývojové závislosti patří PHPUnit 13, který vyžaduje PHP 8.4 nebo novější, přestože samotná knihovna funguje na PHP 8.2.
Testování řízené orákulem
Neexistuje žádný referenční nástroj pro třístranné slučování databází, takže se orákulum vypočítává ze známých vstupů, nikoli pomocí externího nástroje. Každý scénář má deterministický očekávaný výsledek, který lze ověřit logickým postupem:
- Příprava -- vytvořte tři stavy databáze (base, ours, theirs) se známým obsahem.
- Orákulum -- ze známých vstupů vypočítejte očekávaný výsledek sloučení.
- Skutečné provedení -- spusťte sloučení tří stavů pomocí merql.
- Porovnání -- skutečný výsledek se musí přesně shodovat s očekávaným.
Known inputs (base, ours, theirs)
| |
Deterministic merql merge
computation
| |
Expected result Actual result
| |
-----> Compare <-----
|
Pass or Fail
Spouštění testů
Úplné ověření
Skript verify-all je závěrečnou kontrolou. Spouští statickou analýzu, kontrolu standardů kódování, testy PHPUnit a regresní sadu orákula:
./bin/verify-all
Tato kontrola musí projít, než lze jakoukoli práci považovat za dokončenou.
Regresní sada orákula
Spusťte všech 32 scénářů:
./bin/test-regression
Spusťte jednu kategorii:
./bin/test-regression --category clean
./bin/test-regression --category conflict
./bin/test-regression --category identity
Kategorie odpovídají názvům adresářů v scenarios/: clean, conflict, identity, types, scale a edge. Neznámá kategorie vypíše No scenarios found a skončí úspěšně. --category lze opakovat a spustit tak více kategorií.
Skript přijímá také --jobs, ale hodnotu ignoruje a spouští scénáře jeden po druhém (#5).
Spuštění s minimálním výstupem (pouze úspěch/neúspěch):
./bin/test-regression --fast
Jeden scénář
Otestujte jeden scénář celým postupem:
./bin/test-scenario column-level-clean
Jednotlivé kroky orákula
./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
Jednotkové testy
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 spouští pouze PHPUnit. Sada oracle PHPUnit odkazuje na tests/Oracle, který obsahuje třídy spouštěče scénářů, ale žádné testovací případy. Těchto 32 scénářů se proto spouští pouze prostřednictvím composer test:oracle, composer verify nebo ./bin/verify-all.
Integrační testy MySQL se přeskočí, pokud MERQL_MYSQL_HOST, MERQL_MYSQL_DATABASE a MERQL_MYSQL_USER (a případně také MERQL_MYSQL_PASSWORD a MERQL_MYSQL_PORT) neodkazují na testovací databázi.
Kvalita kódu
composer cs # PSR-12 coding standards check
composer cs:fix # Auto-fix coding standards
composer analyse # PHPStan level 10 static analysis
Kategorie scénářů
čisté (8 scénářů)
Čistá sloučení bez konfliktů. Obě strany mohou měnit data, ale nikdy nemění tentýž sloupec stejného řádku.
| Scénář | Test |
|---|---|
insert-only-theirs |
Theirs vložila řádky, ours beze změny. |
update-only-theirs |
Theirs aktualizovala řádky, ours beze změny. |
delete-only-theirs |
Theirs odstranila řádky, ours beze změny. |
insert-only-ours |
Ours vložila řádky, theirs beze změny. |
mixed-no-overlap |
Obě strany změnily různé tabulky nebo řádky. |
both-same-change |
Obě strany provedly stejné změny (bez konfliktu). |
column-level-clean |
Obě strany změnily stejný řádek, ale různé sloupce. |
multi-table |
Změny napříč více tabulkami. |
konflikt (6 scénářů)
Scénáře, které musí vyvolat konflikty.
| Scénář | Testy |
|---|---|
both-update-same-column |
Obě strany změnily stejný sloupec na různé hodnoty. |
update-vs-delete |
Jedna strana aktualizovala řádek, druhá tentýž řádek smazala. |
delete-vs-update |
Opačný směr aktualizace a smazání. |
both-insert-same-pk |
Obě strany vložily řádek se stejným primárním klíčem. |
multiple-conflicts |
Několik konfliktů v jednom sloučení. |
partial-conflict |
Některé sloupce jsou v konfliktu, ostatní se sloučí bez problémů. |
identita (4 scénáře)
Okrajové případy identity řádků.
| Scénář | Testy |
|---|---|
auto-increment |
Nové řádky mají v různých větvích odlišná ID. |
natural-key |
Párování podle jedinečných sloupců místo primárního klíče. |
composite-key |
Primární klíč složený z více sloupců. |
no-key |
Tabulka bez primárního klíče (náhradní řešení pomocí hashe obsahu). |
typy (6 scénářů)
Zpracování všech typů dat ve sloupcích.
| Scénář | Testy |
|---|---|
text-columns |
Hodnoty VARCHAR, TEXT, LONGTEXT. |
numeric-columns |
Hodnoty INT, DECIMAL, FLOAT. |
date-columns |
Hodnoty DATE, DATETIME, TIMESTAMP. |
json-columns |
Sloučení sloupce JSON. |
blob-columns |
Binární data. |
null-handling |
Přechody z NULL na hodnotu a z hodnoty na NULL. |
rozsah (4 scénáře)
Výkon při zátěži.
| Scénář | Testy |
|---|---|
1k-rows |
1,000 řádků. |
10k-rows |
10,000 řádků. |
100k-rows |
100,000 řádků. |
wide-table |
Tabulka s více než 50 sloupci. |
okrajové případy (4 scénáře)
Okrajové případy a mezní podmínky.
| Scénář | Testy |
|---|---|
empty-changeset |
Žádné změny na jedné nebo obou stranách. |
schema-mismatch |
Sloupec přidaný nebo odebraný mezi snímky. |
encoding |
UTF-8, emoji, speciální znaky. |
large-text |
Velmi rozsáhlé hodnoty TEXT/LONGTEXT. |
Struktura scénářů
Každý scénář je adresářem v scenarios/<category>/<name>/ s konfigurací 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"
}
}
U konfliktních scénářů jsou očekávané konflikty podrobně specifikovány:
{
"expectations": {
"conflicts": 1,
"conflict_details": [
{
"table": "test_posts",
"primary_key": {"id": 42},
"column": "title",
"ours_value": "Welcome",
"theirs_value": "Greetings"
}
]
}
}
Průběh ScenarioRunneru
ScenarioRunner::run() řídí jeden scénář:
OracleCapture::compute()vytvoří tři snímky z dat JSON daného scénáře a spustí sloučení.ScenarioComparator::compare()ověří výsledek sloučení podle očekávaných hodnot vscenario.json.- Vrátí výsledek úspěch/neúspěch se seznamem chybových zpráv.
use Merql\Tests\Oracle\ScenarioRunner;
$result = ScenarioRunner::run($scenario);
// ['name' => 'column-level-clean', 'pass' => true, 'failures' => []]
ScenarioRunner::runAll() postupně spustí všechny scénáře:
$results = ScenarioRunner::runAll($scenarios);
Přidání nového scénáře
- Vytvořte adresář:
scenarios/<category>/<name>/. - Vytvořte
scenario.jsons metadaty scénáře a očekávanými výsledky. - Definujte tři stavy databáze v konfiguraci JSON: základní data, změny na naší straně a změny na jejich straně.
- Spusťte scénář:
./bin/test-scenario <name>. - Ověřte celou sadu testů:
./bin/verify-all.
Standardy kvality kódu
merql vynucuje:
- PHPStan úroveň 10 -- přísná statická analýza bez výjimek ze základní konfigurace.
- PSR-12 -- standardy kódování kontroluje
phpcs. - Regresní testy Oracle -- všech 32 scénářů musí projít.
- Jednotkové testy -- izolované testy jednotlivých komponent.
Skript verify-all spustí všechny čtyři kontroly postupně. Částečné schválení se nepřijímá.
Průběžná integrace
CI při každém odeslání změn a pull requestu do main spouští kontrolu standardů kódování, PHPStan, composer test, integrační sadu proti MySQL 8.4 přes mysqli, testy pokrytí primitiv pro slučování a composer audit. Nespouští regresní sadu Oracle (#6), proto před spoléháním na změnu spusťte místně composer test:oracle nebo ./bin/verify-all.