Treci la conținut

Strategia de testare

merql folosește un model de testare bazat pe rezultate de referință. Fiecare scenariu de test definește un set cunoscut de intrări (trei stări ale bazei de date), un rezultat determinist așteptat (referința) și compară rezultatul efectiv al îmbinării cu așteptarea. 32 de scenarii acoperă îmbinări fără conflicte, conflicte, rezolvarea identității, tipuri de date, scară și cazuri limită.

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

Comenzile de pe această pagină se execută dintr-un checkout al depozitului merql după composer install. Scripturile de dezvoltare din bin/, corpusul scenarios/ și testele nu fac parte din pachetul Composer. Dependențele de dezvoltare includ PHPUnit 13, care necesită PHP 8.4 sau o versiune ulterioară, deși biblioteca în sine rulează pe PHP 8.2.

Testare bazată pe rezultate de referință

Nu există un instrument de referință care să efectueze îmbinări tridirecționale ale bazelor de date, așa că rezultatul de referință este calculat din intrări cunoscute, nu generat de un instrument extern. Fiecare scenariu are un rezultat determinist așteptat, care poate fi verificat logic:

  1. Configurare -- creați trei stări ale bazei de date (base, ours, theirs) cu conținut cunoscut.
  2. Referință -- calculați rezultatul așteptat al îmbinării din intrările cunoscute.
  3. Rezultat efectiv -- rulați îmbinarea merql pentru cele trei stări.
  4. Comparare -- rezultatul efectiv trebuie să corespundă exact rezultatului așteptat.
Cod
Known inputs (base, ours, theirs)
         |                    |
    Deterministic          merql merge
    computation
         |                    |
    Expected result       Actual result
         |                    |
         -----> Compare <-----
                  |
            Pass or Fail

Rularea testelor

Verificare completă

Scriptul verify-all este verificarea finală. Rulează analiza statică, verificarea standardelor de cod, testele PHPUnit și suita de regresie bazată pe rezultate de referință:

Shell
./bin/verify-all

Acesta trebuie să treacă înainte ca orice activitate să fie considerată completă.

Suita de regresie bazată pe rezultate de referință

Rulați toate cele 32 de scenarii:

Shell
./bin/test-regression

Rulați o singură categorie:

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

Categoriile sunt numele directoarelor din scenarios/: clean, conflict, identity, types, scale și edge. O categorie necunoscută afișează No scenarios found și se închide cu succes. --category se poate repeta pentru a rula mai multe categorii.

Scriptul acceptă și --jobs, dar ignoră valoarea și rulează scenariile unul după altul (#5).

Rulați cu rezultate minime (numai reușit/eșuat):

Shell
./bin/test-regression --fast

Un singur scenariu

Testați un scenariu prin întregul flux:

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

Pași individuali ai oracle-ului

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

Teste unitare

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 rulează doar PHPUnit. Suita oracle PHPUnit indică spre tests/Oracle, care conține clasele pentru rularea scenariilor, dar nu și cazuri de test, așa că cele 32 de scenarii rulează doar prin composer test:oracle, composer verify sau ./bin/verify-all.

Testele de integrare MySQL sunt omise dacă MERQL_MYSQL_HOST, MERQL_MYSQL_DATABASE și MERQL_MYSQL_USER (plus, opțional, MERQL_MYSQL_PASSWORD și MERQL_MYSQL_PORT) nu indică spre o bază de date de test.

Calitatea codului

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

Categorii de scenarii

clean (8 scenarii)

Îmbinări curate, fără conflicte. Ambele părți pot modifica date, dar niciodată aceeași coloană din același rând.

Scenariu Teste
insert-only-theirs Partea lor a inserat rânduri, partea noastră nu a schimbat nimic.
update-only-theirs Partea lor a actualizat rânduri, partea noastră nu a schimbat nimic.
delete-only-theirs Partea lor a șters rânduri, partea noastră nu a schimbat nimic.
insert-only-ours Partea noastră a inserat rânduri, partea lor nu a schimbat nimic.
mixed-no-overlap Ambele părți au modificat tabele sau rânduri diferite.
both-same-change Ambele părți au făcut modificări identice (fără conflict).
column-level-clean Ambele părți au modificat același rând, dar coloane diferite.
multi-table Modificări în mai multe tabele.

conflict (6 scenarii)

Scenarii care trebuie să genereze conflicte.

Scenariu Teste
both-update-same-column Ambele părți au modificat aceeași coloană cu valori diferite.
update-vs-delete O parte a actualizat, iar cealaltă a șters același rând.
delete-vs-update Direcția inversă a operației de actualizare versus ștergere.
both-insert-same-pk Ambele părți au inserat un rând cu aceeași cheie primară.
multiple-conflicts Mai multe conflicte într-o singură îmbinare.
partial-conflict Unele coloane au conflicte, altele se îmbină fără probleme.

identity (4 scenarii)

Cazuri-limită privind identitatea rândurilor.

Scenariu Teste
auto-increment Rândurile noi au ID-uri diferite în ramuri.
natural-key Potrivire după coloane unice în loc de PK.
composite-key Cheie primară cu mai multe coloane.
no-key Tabel fără cheie primară (alternativă prin hash de conținut).

types (6 scenarii)

Gestionarea tipurilor de date pentru toate tipurile de coloane.

Scenariu Teste
text-columns Valori VARCHAR, TEXT, LONGTEXT.
numeric-columns Valori INT, DECIMAL, FLOAT.
date-columns Valori DATE, DATETIME, TIMESTAMP.
json-columns Îmbinarea coloanei JSON.
blob-columns Date binare.
null-handling Tranziții de la NULL la valoare și de la valoare la NULL.

scale (4 scenarii)

Performanță sub sarcină.

Scenariu Teste
1k-rows 1,000 rânduri.
10k-rows 10,000 rânduri.
100k-rows 100,000 rânduri.
wide-table Tabel cu peste 50 de coloane.

edge (4 scenarii)

Cazuri-limită și condiții de margine.

Scenariu Teste
empty-changeset Nicio modificare pe una sau pe ambele părți.
schema-mismatch Coloană adăugată sau eliminată între instantanee.
encoding UTF-8, emoji, caractere speciale.
large-text Valori TEXT/LONGTEXT foarte mari.

Structura scenariilor

Fiecare scenariu este un director în scenarios/<category>/<name>/ cu o configurație 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"
    }
}

Pentru scenariile cu conflicte, conflictele așteptate sunt specificate în detaliu:

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

Fluxul ScenarioRunner

ScenarioRunner::run() coordonează un singur scenariu:

  1. OracleCapture::compute() construiește trei instantanee din datele JSON ale scenariului și execută îmbinarea.
  2. ScenarioComparator::compare() verifică rezultatul îmbinării în raport cu valorile așteptate din scenario.json.
  3. Returnează reușita/eșecul și o listă de mesaje de eroare.
PHP
use Merql\Tests\Oracle\ScenarioRunner;

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

ScenarioRunner::runAll() rulează toate scenariile în ordine:

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

Adăugarea unui scenariu nou

  1. Creați un director: scenarios/<category>/<name>/.
  2. Creați scenario.json cu metadatele și așteptările scenariului.
  3. Definiți cele trei stări ale bazei de date în configurația JSON: datele inițiale, modificările noastre, modificările lor.
  4. Rulați scenariul: ./bin/test-scenario <name>.
  5. Verificați întreaga suită: ./bin/verify-all.

Standarde de calitate a codului

merql impune:

  • PHPStan nivelul 10 -- analiză statică strictă, fără excepții de bază.
  • PSR-12 -- standarde de cod verificate de phpcs.
  • Regresie oracle -- toate cele 32 de scenarii trebuie să treacă.
  • Teste unitare -- teste izolate pentru fiecare componentă.

Scriptul verify-all rulează toate cele patru verificări în ordine. Nu se acceptă aprobarea parțială.

Integrare continuă

CI rulează verificările standardelor de cod, PHPStan, composer test, suita de integrare cu MySQL 8.4 prin mysqli, verificarea acoperirii primitivelor de îmbinare și composer audit la fiecare push și pull request către main. Nu rulează corpusul de regresie oracle (#6), așa că rulați local composer test:oracle sau ./bin/verify-all înainte de a vă baza pe o modificare.