Стратегия за тестване
merql използва модел за тестване, водено от оракул. Всеки тестов сценарий задава известен набор от входни данни (три състояния на база данни), детерминистичен очакван резултат (оракула) и сравнява действителния резултат от сливането с него. 32 сценария обхващат сливания без конфликти, конфликти, определяне на идентичността, типове данни, мащаб и крайни случаи.
# Run the full verification suite.
./bin/verify-all
Командите на тази страница се изпълняват от локално копие на хранилището merql след composer install. Скриптовете за разработка в bin/, корпусът scenarios/ и тестовете не са част от пакета Composer. Зависимостите за разработка включват PHPUnit 13, за който е необходим PHP 8.4 или по-нова версия, макар самата библиотека да работи с PHP 8.2.
Тестване, водено от оракул
Няма съществуващ референтен инструмент за сливане на бази данни в три посоки, затова оракулът се изчислява от известните входни данни, а не се генерира от външен инструмент. Всеки сценарий има детерминистичен очакван резултат, който може да се провери логически:
- Настройка -- създайте три състояния на базата данни (основа, наша версия, тяхна версия) с известно съдържание.
- Оракул -- изчислете очаквания резултат от сливането въз основа на известните входни данни.
- Действителен резултат -- изпълнете сливането на трите състояния с merql.
- Сравнение -- действителният резултат трябва точно да съвпада с очаквания.
Known inputs (base, ours, theirs)
| |
Deterministic merql merge
computation
| |
Expected result Actual result
| |
-----> Compare <-----
|
Pass or Fail
Изпълнение на тестовете
Пълна проверка
Скриптът verify-all е последната контролна проверка. Той изпълнява статичен анализ, стандарти за кодиране, тестове PHPUnit и регресионния набор с оракула:
./bin/verify-all
Тази проверка трябва да премине, преди работата да се счита за завършена.
Регресионен набор с оракула
Изпълнете всичките 32 сценария:
./bin/test-regression
Изпълнете една категория:
./bin/test-regression --category clean
./bin/test-regression --category conflict
./bin/test-regression --category identity
Категориите са имената на директориите в scenarios/: clean, conflict,
identity, types, scale и edge. Непозната категория показва
No scenarios found и приключва успешно. --category може да се повтори, за да се изпълнят
няколко категории.
Скриптът приема и --jobs, но игнорира стойността и изпълнява сценариите един след друг (#5).
Изпълнение с минимален изход (само успех/неуспех):
./bin/test-regression --fast
Единичен сценарий
Тествайте един сценарий през целия процес:
./bin/test-scenario column-level-clean
Отделни стъпки на оракула
./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
Модулни тестове
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 изпълнява само PHPUnit. Наборът PHPUnit на oracle сочи към
tests/Oracle, където има класове за изпълнение на сценарии, но няма тестови случаи, затова
32-та сценария се изпълняват само чрез composer test:oracle, composer verify или
./bin/verify-all.
Интеграционните тестове на MySQL се пропускат, освен ако MERQL_MYSQL_HOST,
MERQL_MYSQL_DATABASE и MERQL_MYSQL_USER (както и по избор
MERQL_MYSQL_PASSWORD и MERQL_MYSQL_PORT) не сочат към тестова база данни.
Качество на кода
composer cs # PSR-12 coding standards check
composer cs:fix # Auto-fix coding standards
composer analyse # PHPStan level 10 static analysis
Категории сценарии
чисто (8 сценария)
Сливания без конфликти. Двете страни може да променят данни, но никога една и съща колона на един и същ ред.
| Сценарий | Проверява |
|---|---|
insert-only-theirs |
В тяхната версия са вмъкнати редове, нашата не е променена. |
update-only-theirs |
В тяхната версия са обновени редове, нашата не е променена. |
delete-only-theirs |
В тяхната версия са изтрити редове, нашата не е променена. |
insert-only-ours |
В нашата версия са вмъкнати редове, тяхната не е променена. |
mixed-no-overlap |
Двете страни са променили различни таблици или редове. |
both-same-change |
Двете страни са направили еднакви промени (без конфликт). |
column-level-clean |
Двете страни са променили един и същ ред, но различни колони. |
multi-table |
Промени в няколко таблици. |
конфликти (6 сценария)
Сценарии, които трябва да доведат до конфликти.
| Сценарий | Проверява |
|---|---|
both-update-same-column |
Двете страни са променили една и съща колона на различни стойности. |
update-vs-delete |
Едната страна е обновила реда, а другата го е изтрила. |
delete-vs-update |
Обратна посока на конфликта при обновяване и изтриване. |
both-insert-same-pk |
Двете страни са вмъкнали ред със същия първичен ключ. |
multiple-conflicts |
Няколко конфликта в едно сливане. |
partial-conflict |
Някои колони са в конфликт, а други се сливат без проблем. |
идентичност (4 сценария)
Крайни случаи при идентичността на редовете.
| Сценарий | Проверява |
|---|---|
auto-increment |
Новите редове имат различни идентификатори в отделните клонове. |
natural-key |
Съпоставяне по уникални колони вместо по PK. |
composite-key |
Първичен ключ с няколко колони. |
no-key |
Таблица без първичен ключ (резервно използване на хеш на съдържанието). |
типове (6 сценария)
Обработка на всички типове данни в колоните.
| Сценарий | Проверява |
|---|---|
text-columns |
Стойности VARCHAR, TEXT, LONGTEXT. |
numeric-columns |
Стойности INT, DECIMAL, FLOAT. |
date-columns |
Стойности DATE, DATETIME, TIMESTAMP. |
json-columns |
Сливане на колона JSON. |
blob-columns |
Двоични данни. |
null-handling |
Преходи от NULL към стойност и от стойност към NULL. |
мащаб (4 сценария)
Производителност при натоварване.
| Сценарий | Проверява |
|---|---|
1k-rows |
1,000 реда. |
10k-rows |
10,000 реда. |
100k-rows |
100,000 реда. |
wide-table |
Таблица с над 50 колони. |
крайни случаи (4 сценария)
Крайни случаи и гранични условия.
| Сценарий | Проверява |
|---|---|
empty-changeset |
Няма промени от едната или от двете страни. |
schema-mismatch |
Колона е добавена или премахната между моментните снимки. |
encoding |
UTF-8, емоджита, специални знаци. |
large-text |
Много големи стойности TEXT/LONGTEXT. |
Структура на сценария
Всеки сценарий е директория в scenarios/<category>/<name>/ с конфигурация 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"
}
}
За сценариите с конфликти очакваните конфликти са описани подробно:
{
"expectations": {
"conflicts": 1,
"conflict_details": [
{
"table": "test_posts",
"primary_key": {"id": 42},
"column": "title",
"ours_value": "Welcome",
"theirs_value": "Greetings"
}
]
}
}
Процесът ScenarioRunner
ScenarioRunner::run() координира изпълнението на един сценарий:
OracleCapture::compute()изгражда три моментни снимки от данните JSON на сценария и изпълнява сливането.ScenarioComparator::compare()проверява резултата от сливането спрямо очакваните стойности вscenario.json.- Връща успех/неуспех със списък от съобщения за грешки.
use Merql\Tests\Oracle\ScenarioRunner;
$result = ScenarioRunner::run($scenario);
// ['name' => 'column-level-clean', 'pass' => true, 'failures' => []]
ScenarioRunner::runAll() изпълнява всички сценарии последователно:
$results = ScenarioRunner::runAll($scenarios);
Добавяне на нов сценарий
- Създайте директория:
scenarios/<category>/<name>/. - Създайте
scenario.jsonс метаданните и очакваните резултати за сценария. - Определете трите състояния на базата данни в конфигурацията JSON: базови данни, наши промени и промени от тяхната страна.
- Изпълнете сценария:
./bin/test-scenario <name>. - Проверете целия набор:
./bin/verify-all.
Стандарти за качество на кода
merql налага:
- PHPStan ниво 10 -- строг статичен анализ без изключения от базовите правила.
- PSR-12 -- стандартите за кодиране се проверяват от
phpcs. - Регресия с оракула -- всичките 32 сценария трябва да преминат.
- Модулни тестове -- изолирани тестове за всеки компонент.
Скриптът verify-all изпълнява и четирите проверки последователно. Не се приема частично одобрение.
Непрекъсната интеграция
При всяко изпращане на промени и заявка за изтегляне към main CI изпълнява проверка на стандартите за кодиране, PHPStan, composer test, интеграционния набор с MySQL 8.4 чрез mysqli, тестовете за примитивите на сливането и composer audit. Корпусът с регресионни тестове по оракул не се изпълнява (#6), затова изпълнете локално composer test:oracle или ./bin/verify-all, преди да разчитате на промяна.