Strategia testowania
merql korzysta z modelu testowania sterowanego wyrocznią. Każdy scenariusz testowy określa znany zestaw danych wejściowych (trzy stany bazy danych), deterministyczny oczekiwany wynik (wyrocznię) i porównuje go z rzeczywistym wynikiem scalania. 32 scenariusze obejmują poprawne scalania, konflikty, rozpoznawanie tożsamości, typy danych, skalę i przypadki brzegowe.
# Run the full verification suite.
./bin/verify-all
Polecenia na tej stronie uruchamia się w kopii repozytorium merql po
composer install. Skrypty programistyczne w bin/, korpus scenarios/
i testy nie należą do pakietu Composer. Zależności programistyczne obejmują PHPUnit 13, który wymaga PHP 8.4 lub nowszego, choć sama
biblioteka działa na PHP 8.2.
Testowanie sterowane wyrocznią
Nie istnieje narzędzie referencyjne wykonujące trójdrożne scalanie baz danych, dlatego wyrocznię oblicza się na podstawie znanych danych wejściowych, a nie generuje za pomocą zewnętrznego narzędzia. Każdy scenariusz ma deterministyczny oczekiwany wynik, który można zweryfikować logicznie:
- Przygotowanie -- utwórz trzy stany bazy danych (base, ours, theirs) o znanej zawartości.
- Wyrocznia -- oblicz oczekiwany wynik scalania na podstawie znanych danych wejściowych.
- Wynik rzeczywisty -- uruchom scalanie merql na trzech stanach.
- Porównanie -- wynik rzeczywisty musi dokładnie odpowiadać oczekiwanemu.
Known inputs (base, ours, theirs)
| |
Deterministic merql merge
computation
| |
Expected result Actual result
| |
-----> Compare <-----
|
Pass or Fail
Uruchamianie testów
Pełna weryfikacja
Skrypt verify-all jest ostatnią bramką. Uruchamia analizę statyczną, kontrolę standardów kodowania, testy PHPUnit i zestaw testów regresyjnych oracle:
./bin/verify-all
Wszystkie te kontrole muszą przejść, zanim jakiekolwiek prace zostaną uznane za zakończone.
Zestaw testów regresyjnych oracle
Uruchom wszystkie 32 scenariusze:
./bin/test-regression
Uruchom jedną kategorię:
./bin/test-regression --category clean
./bin/test-regression --category conflict
./bin/test-regression --category identity
Kategorie to nazwy katalogów w scenarios/: clean, conflict,
identity, types, scale i edge. Nieznana kategoria wypisuje
No scenarios found i kończy działanie powodzeniem. Opcję --category można powtarzać, aby uruchomić
kilka kategorii.
Skrypt przyjmuje też --jobs, ale ignoruje jego wartość i uruchamia scenariusze
jeden po drugim (#5).
Uruchom z minimalnym wyjściem (tylko powodzenie/niepowodzenie):
./bin/test-regression --fast
Pojedynczy scenariusz
Przetestuj jeden scenariusz w całym potoku:
./bin/test-scenario column-level-clean
Poszczególne kroki oracle
./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
Testy jednostkowe
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 uruchamia tylko PHPUnit. Zestaw oracle PHPUnit wskazuje na
tests/Oracle, który zawiera klasy uruchamiające scenariusze, ale nie zawiera przypadków testowych, więc
32 scenariusze są uruchamiane tylko przez composer test:oracle, composer verify lub
./bin/verify-all.
Testy integracyjne MySQL są pomijane, chyba że MERQL_MYSQL_HOST,
MERQL_MYSQL_DATABASE i MERQL_MYSQL_USER (oraz opcjonalnie
MERQL_MYSQL_PASSWORD i MERQL_MYSQL_PORT) wskazują bazę danych do testów.
Jakość kodu
composer cs # PSR-12 coding standards check
composer cs:fix # Auto-fix coding standards
composer analyse # PHPStan level 10 static analysis
Kategorie scenariuszy
clean (8 scenariuszy)
Scenariusze czystego scalania bez konfliktów. Obie strony mogą zmieniać dane, ale nigdy tę samą kolumnę w tym samym wierszu.
| Scenariusz | Testy |
|---|---|
insert-only-theirs |
Ich strona wstawiła wiersze, nasza strona bez zmian. |
update-only-theirs |
Ich strona zaktualizowała wiersze, nasza strona bez zmian. |
delete-only-theirs |
Ich strona usunęła wiersze, nasza strona bez zmian. |
insert-only-ours |
Nasza strona wstawiła wiersze, ich strona bez zmian. |
mixed-no-overlap |
Obie strony zmieniły różne tabele lub wiersze. |
both-same-change |
Obie strony wprowadziły identyczne zmiany (brak konfliktu). |
column-level-clean |
Obie strony zmieniły ten sam wiersz, ale różne kolumny. |
multi-table |
Zmiany w wielu tabelach. |
conflict (6 scenariuszy)
Scenariusze, które muszą powodować konflikty.
| Scenariusz | Testy |
|---|---|
both-update-same-column |
Obie strony zmieniły tę samą kolumnę na różne wartości. |
update-vs-delete |
Jedna strona zaktualizowała wiersz, a druga usunęła ten sam wiersz. |
delete-vs-update |
Odwrotna kolejność aktualizacji i usunięcia. |
both-insert-same-pk |
Obie strony wstawiły wiersz z tym samym kluczem głównym. |
multiple-conflicts |
Kilka konfliktów w jednym scalaniu. |
partial-conflict |
Konflikty w niektórych kolumnach, pozostałe scalają się bez konfliktów. |
identity (4 scenariusze)
Przypadki brzegowe tożsamości wierszy.
| Scenariusz | Testy |
|---|---|
auto-increment |
Nowe wiersze mają różne identyfikatory w poszczególnych gałęziach. |
natural-key |
Dopasowanie według unikatowych kolumn zamiast PK. |
composite-key |
Klucz główny złożony z wielu kolumn. |
no-key |
Tabela bez klucza głównego (zapasowe użycie skrótu treści). |
types (6 scenariuszy)
Obsługa typów danych we wszystkich typach kolumn.
| Scenariusz | Testy |
|---|---|
text-columns |
Wartości VARCHAR, TEXT, LONGTEXT. |
numeric-columns |
Wartości INT, DECIMAL, FLOAT. |
date-columns |
Wartości DATE, DATETIME, TIMESTAMP. |
json-columns |
Scalanie kolumny JSON. |
blob-columns |
Dane binarne. |
null-handling |
Przejścia z NULL na wartość i z wartości na NULL. |
scale (4 scenariusze)
Wydajność pod obciążeniem.
| Scenariusz | Testy |
|---|---|
1k-rows |
1,000 wierszy. |
10k-rows |
10,000 wierszy. |
100k-rows |
100,000 wierszy. |
wide-table |
Tabela z ponad 50 kolumnami. |
edge (4 scenariusze)
Przypadki brzegowe i graniczne warunki.
| Scenariusz | Testy |
|---|---|
empty-changeset |
Brak zmian po jednej lub obu stronach. |
schema-mismatch |
Kolumna dodana lub usunięta między migawkami. |
encoding |
UTF-8, emoji, znaki specjalne. |
large-text |
Bardzo duże wartości TEXT/LONGTEXT. |
Struktura scenariusza
Każdy scenariusz to katalog w scenarios/<category>/<name>/ z konfiguracją 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"
}
}
W przypadku scenariuszy konfliktowych oczekiwane konflikty są szczegółowo określone:
{
"expectations": {
"conflicts": 1,
"conflict_details": [
{
"table": "test_posts",
"primary_key": {"id": 42},
"column": "title",
"ours_value": "Welcome",
"theirs_value": "Greetings"
}
]
}
}
Potok ScenarioRunner
ScenarioRunner::run() koordynuje wykonanie pojedynczego scenariusza:
OracleCapture::compute()tworzy trzy migawki na podstawie danych JSON scenariusza i uruchamia scalanie.ScenarioComparator::compare()sprawdza wynik scalania, porównując go z oczekiwanymi wartościami wscenario.json.- Zwraca wynik powodzenia lub niepowodzenia wraz z listą komunikatów o błędach.
use Merql\Tests\Oracle\ScenarioRunner;
$result = ScenarioRunner::run($scenario);
// ['name' => 'column-level-clean', 'pass' => true, 'failures' => []]
ScenarioRunner::runAll() uruchamia kolejno wszystkie scenariusze:
$results = ScenarioRunner::runAll($scenarios);
Dodawanie nowego scenariusza
- Utwórz katalog:
scenarios/<category>/<name>/. - Utwórz
scenario.jsonz metadanymi scenariusza i oczekiwanymi wynikami. - Zdefiniuj trzy stany bazy danych w konfiguracji JSON: dane bazowe, zmiany po naszej stronie i zmiany po ich stronie.
- Uruchom scenariusz:
./bin/test-scenario <name>. - Sprawdź cały zestaw testów:
./bin/verify-all.
Standardy jakości kodu
merql wymusza:
- PHPStan poziom 10 -- rygorystyczna analiza statyczna bez wyjątków od wartości bazowych.
- PSR-12 -- standardy kodowania sprawdzane przez
phpcs. - Testy regresyjne oracle -- wszystkie 32 scenariusze muszą przejść.
- Testy jednostkowe -- izolowane testy poszczególnych komponentów.
Skrypt verify-all uruchamia kolejno wszystkie cztery kontrole. Nie dopuszcza się częściowego zatwierdzenia.
Integracja ciągła
CI uruchamia kontrolę standardów kodowania, PHPStan, composer test, zestaw testów integracyjnych
z MySQL 8.4 przez mysqli, testy pokrycia prymitywów scalania oraz
composer audit przy każdym wypchnięciu zmian i żądaniu ściągnięcia do main. Nie uruchamia
zestawu testów regresyjnych oracle (#6), dlatego
przed poleganiem na zmianie uruchom lokalnie composer test:oracle lub ./bin/verify-all.