Hoppa till innehåll

Teststrategi

merql använder en oracle-baserad testmodell. Varje testscenario definierar en känd uppsättning indata (tre databastillstånd), ett deterministiskt förväntat resultat (oraclet) och jämför det faktiska resultatet av sammanslagningen med förväntningen. 32 scenarier täcker konfliktfria sammanslagningar, konflikter, identitetslösning, datatyper, skala och specialfall.

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

Kommandona på den här sidan körs från en utcheckning av merql-arkivet efter composer install. Utvecklingsskripten i bin/, korpusen scenarios/ och testerna ingår inte i paketet Composer. Utvecklingsberoendena omfattar PHPUnit 13, som kräver PHP 8.4 eller senare, även om själva biblioteket körs med PHP 8.2.

Oracle-baserad testning

Det finns inget befintligt referensverktyg som utför en trevägssammanslagning av databaser, så oraclet beräknas utifrån kända indata i stället för att genereras av ett externt verktyg. Varje scenario har ett deterministiskt förväntat resultat som kan verifieras logiskt:

  1. Förberedelse -- skapa tre databastillstånd (base, ours, theirs) med känt innehåll.
  2. Oracle -- beräkna det förväntade resultatet av sammanslagningen utifrån de kända indata.
  3. Faktiskt resultat -- kör merql:s sammanslagning av de tre tillstånden.
  4. Jämförelse -- det faktiska resultatet måste exakt matcha det förväntade resultatet.
Kod
Known inputs (base, ours, theirs)
         |                    |
    Deterministic          merql merge
    computation
         |                    |
    Expected result       Actual result
         |                    |
         -----> Compare <-----
                  |
            Pass or Fail

Köra tester

Fullständig verifiering

Skriptet verify-all är den slutliga kontrollen. Det kör statisk analys, kodningsstandarder, tester med PHPUnit och oracle-regressionstestsviten:

Shell
./bin/verify-all

Det här måste godkännas innan något arbete anses vara slutfört.

Oracle-regressionstestsvit

Kör alla 32 scenarier:

Shell
./bin/test-regression

Kör en enskild kategori:

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

Kategorierna är katalognamnen under scenarios/: clean, conflict, identity, types, scale och edge. En okänd kategori skriver ut No scenarios found och avslutas utan fel. --category kan upprepas för att köra flera kategorier.

Skriptet godtar även --jobs, men ignorerar värdet och kör scenarierna efter varandra (#5).

Kör med minimal utdata (endast godkänt/underkänt):

Shell
./bin/test-regression --fast

Enskilt scenario

Testa ett scenario genom hela processen:

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

Enskilda oracle-steg

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

Enhetstester

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ör endast PHPUnit. Testsviten oracle PHPUnit pekar på tests/Oracle, som innehåller scenariokörarens klasser men inga testfall, så de 32 scenarierna körs endast via composer test:oracle, composer verify eller ./bin/verify-all.

MySQL-integrationstesterna hoppas över om inte MERQL_MYSQL_HOST, MERQL_MYSQL_DATABASE och MERQL_MYSQL_USER (samt eventuellt MERQL_MYSQL_PASSWORD och MERQL_MYSQL_PORT) pekar på en testdatabas.

Kodkvalitet

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

Scenariokategorier

clean (8 scenarier)

Konfliktfria sammanslagningar. Båda sidorna kan ändra data, men aldrig samma kolumn i samma rad.

Scenario Testar
insert-only-theirs Rader som theirs infogade; ours oförändrat.
update-only-theirs Rader som theirs uppdaterade; ours oförändrat.
delete-only-theirs Rader som theirs tog bort; ours oförändrat.
insert-only-ours Rader som ours infogade; theirs oförändrat.
mixed-no-overlap Båda ändrade olika tabeller eller rader.
both-same-change Båda gjorde identiska ändringar (ingen konflikt).
column-level-clean Båda ändrade samma rad, men olika kolumner.
multi-table Ändringar i flera tabeller.

conflict (6 scenarier)

Scenarier som måste leda till konflikter.

Scenario Testar
both-update-same-column Båda ändrade samma kolumn till olika värden.
update-vs-delete Den ena uppdaterade och den andra tog bort samma rad.
delete-vs-update Motsatt riktning för uppdatering kontra borttagning.
both-insert-same-pk Båda infogade en rad med samma primärnyckel.
multiple-conflicts Flera konflikter i en sammanslagning.
partial-conflict Vissa kolumner har konflikter, andra slås samman utan problem.

identity (4 scenarier)

Specialfall för radidentitet.

Scenario Testar
auto-increment Nya rader har olika ID:n i olika grenar.
natural-key Matchning via unika kolumner i stället för primärnyckel.
composite-key Primärnyckel med flera kolumner.
no-key Tabell utan primärnyckel (reservlösning med innehållshash).

types (6 scenarier)

Hantering av datatyper för alla kolumntyper.

Scenario Testar
text-columns Värden av typen VARCHAR, TEXT och LONGTEXT.
numeric-columns Värden av typen INT, DECIMAL och FLOAT.
date-columns Värden av typen DATE, DATETIME och TIMESTAMP.
json-columns Sammanslagning av kolumner av typen JSON.
blob-columns Binärdata.
null-handling Övergångar från NULL till värde och från värde till NULL.

scale (4 scenarier)

Prestanda under belastning.

Scenario Testar
1k-rows 1,000 rader.
10k-rows 10,000 rader.
100k-rows 100,000 rader.
wide-table Tabell med 50+ kolumner.

edge (4 scenarier)

Specialfall och gränsvillkor.

Scenario Testar
empty-changeset Inga ändringar på ena eller båda sidorna.
schema-mismatch Kolumn tillagd eller borttagen mellan ögonblicksbilder.
encoding UTF-8, emoji och specialtecken.
large-text Mycket stora värden av typen TEXT/LONGTEXT.

Scenariostruktur

Varje scenario ligger i en katalog under scenarios/<category>/<name>/ med en konfiguration av typen 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"
    }
}

För konfliktscenarier anges de förväntade konflikterna i detalj:

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

ScenarioRunner-processen

ScenarioRunner::run() samordnar ett enskilt scenario:

  1. OracleCapture::compute() bygger tre ögonblicksbilder från scenariots JSON-data och kör sammanslagningen.
  2. ScenarioComparator::compare() kontrollerar sammanslagningens resultat mot de förväntade värdena i scenario.json.
  3. Returnerar godkänt/underkänt med en lista över felmeddelanden.
PHP
use Merql\Tests\Oracle\ScenarioRunner;

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

ScenarioRunner::runAll() kör alla scenarier i följd:

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

Lägga till ett nytt scenario

  1. Skapa en katalog: scenarios/<category>/<name>/.
  2. Skapa scenario.json med scenariots metadata och förväntningar.
  3. Definiera de tre databastillstånden i konfigurationen JSON: basedata, ändringar i ours, ändringar i theirs.
  4. Kör scenariot: ./bin/test-scenario <name>.
  5. Verifiera hela testsviten: ./bin/verify-all.

Kodkvalitetsstandarder

merql tillämpar:

  • PHPStan nivå 10 -- strikt statisk analys utan undantag från baslinjen.
  • PSR-12 -- kodningsstandarder som kontrolleras av phpcs.
  • Oracle-regression -- alla 32 scenarier måste godkännas.
  • Enhetstester -- isolerade tester för varje komponent.

Skriptet verify-all kör alla fyra kontroller i följd. Delvis godkännande accepteras inte.

Kontinuerlig integration

CI kör kontroller av kodningsstandarder, PHPStan, composer test, integrationssviten mot MySQL 8.4 via mysqli, täckning av sammanslagningens grundfunktioner och composer audit vid varje push och pull-begäran till main. Den kör inte oracle-regressionskorpusen (#6), så kör composer test:oracle eller ./bin/verify-all lokalt innan du förlitar dig på en ändring.