Přejít k obsahu

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.

Shell
# 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:

  1. Příprava -- vytvořte tři stavy databáze (base, ours, theirs) se známým obsahem.
  2. Orákulum -- ze známých vstupů vypočítejte očekávaný výsledek sloučení.
  3. Skutečné provedení -- spusťte sloučení tří stavů pomocí merql.
  4. Porovnání -- skutečný výsledek se musí přesně shodovat s očekávaným.
Kód
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:

Shell
./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ářů:

Shell
./bin/test-regression

Spusťte jednu kategorii:

Shell
./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):

Shell
./bin/test-regression --fast

Jeden scénář

Otestujte jeden scénář celým postupem:

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

Jednotlivé kroky orákula

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

Jednotkové testy

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

Shell
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:

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:

JSON
{
    "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ář:

  1. OracleCapture::compute() vytvoří tři snímky z dat JSON daného scénáře a spustí sloučení.
  2. ScenarioComparator::compare() ověří výsledek sloučení podle očekávaných hodnot v scenario.json.
  3. Vrátí výsledek úspěch/neúspěch se seznamem chybových zpráv.
PHP
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:

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

Přidání nového scénáře

  1. Vytvořte adresář: scenarios/<category>/<name>/.
  2. Vytvořte scenario.json s metadaty scénáře a očekávanými výsledky.
  3. Definujte tři stavy databáze v konfiguraci JSON: základní data, změny na naší straně a změny na jejich straně.
  4. Spusťte scénář: ./bin/test-scenario <name>.
  5. 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.