Перейти до вмісту

Стратегія тестування

merql використовує модель тестування на основі оракула. У кожному тестовому сценарії визначено відомий набір вхідних даних (три стани бази даних), детермінований очікуваний результат (оракул), з яким порівнюється фактичний результат злиття. 32 сценарії охоплюють злиття без конфліктів, конфлікти, визначення ідентичності, типи даних, масштаб і крайові випадки.

Командна оболонка
# Run the full verification suite.
./bin/verify-all

Команди на цій сторінці виконуються з копії репозиторію merql після composer install. Скрипти розробки в bin/, корпусі scenarios/ та тести не входять до пакета Composer. Серед залежностей для розробки є PHPUnit 13, якому потрібен PHP 8.4 або новіший, хоча сама бібліотека працює на PHP 8.2.

Тестування на основі оракула

Немає готового еталонного інструмента для злиття трьох станів бази даних, тому оракул обчислюється на основі відомих вхідних даних, а не генерується зовнішнім інструментом. Кожен сценарій має детермінований очікуваний результат, який можна перевірити логічно:

  1. Підготовка -- створіть три стани бази даних (base, ours, theirs) із відомим вмістом.
  2. Оракул -- обчисліть очікуваний результат злиття на основі відомих вхідних даних.
  3. Фактичний результат -- виконайте злиття merql для трьох станів.
  4. Порівняння -- фактичний результат має точно збігатися з очікуваним.
Код
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. Набір тестів oracle PHPUnit вказує на 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

Категорії сценаріїв

clean (8 сценаріїв)

Злиття без конфліктів. Обидві сторони можуть змінювати дані, але ніколи не змінюють той самий стовпець того самого рядка.

Сценарій Перевірки
insert-only-theirs theirs додала рядки, ours їх не змінювала.
update-only-theirs theirs оновила рядки, ours їх не змінювала.
delete-only-theirs theirs видалила рядки, ours їх не змінювала.
insert-only-ours ours додала рядки, theirs їх не змінювала.
mixed-no-overlap Обидві сторони змінили різні таблиці або рядки.
both-same-change Обидві сторони внесли однакові зміни (без конфлікту).
column-level-clean Обидві сторони змінили різні стовпці того самого рядка.
multi-table Зміни в кількох таблицях.

conflict (6 сценаріїв)

Сценарії, у яких мають виникати конфлікти.

Сценарій Перевірки
both-update-same-column Обидві сторони змінили той самий стовпець на різні значення.
update-vs-delete Одна сторона оновила рядок, інша видалила його.
delete-vs-update Зворотний напрямок конфлікту «оновлення проти видалення».
both-insert-same-pk Обидві сторони додали рядок з однаковим первинним ключем.
multiple-conflicts Кілька конфліктів в одному злитті.
partial-conflict У частині стовпців конфлікти, решта зливається без них.

identity (4 сценарії)

Крайові випадки ідентичності рядків.

Сценарій Перевірки
auto-increment Нові рядки мають різні ID у різних гілках.
natural-key Зіставлення за унікальними стовпцями замість PK.
composite-key Первинний ключ із кількох стовпців.
no-key Таблиця без первинного ключа (резервний варіант із хешем вмісту).

types (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.

scale (4 сценарії)

Продуктивність під навантаженням.

Сценарій Перевірки
1k-rows 1,000 рядків.
10k-rows 10,000 рядків.
100k-rows 100,000 рядків.
wide-table Таблиця з понад 50 стовпцями.

edge (4 сценарії)

Крайові випадки та граничні умови.

Сценарій Перевірки
empty-changeset Змін немає з одного або обох боків.
schema-mismatch Стовпець додано або вилучено між знімками.
encoding UTF-8, емодзі, спеціальні символи.
large-text Дуже великі значення TEXT/LONGTEXT.

Структура сценарію

Кожен сценарій — це каталог у scenarios/<category>/<name>/ із конфігурацією 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"
    }
}

Для сценаріїв із конфліктами очікувані конфлікти вказуються докладно:

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

Конвеєр ScenarioRunner

ScenarioRunner::run() координує виконання окремого сценарію:

  1. OracleCapture::compute() створює три знімки з даних JSON сценарію та виконує злиття.
  2. ScenarioComparator::compare() звіряє результат злиття з очікуваними значеннями в scenario.json.
  3. Повертає результат «пройдено/не пройдено» зі списком повідомлень про помилки.
PHP
use Merql\Tests\Oracle\ScenarioRunner;

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

ScenarioRunner::runAll() запускає кожен сценарій послідовно:

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

Додавання сценарію

  1. Створіть каталог: scenarios/<category>/<name>/.
  2. Створіть scenario.json з метаданими та очікуваними результатами сценарію.
  3. Визначте три стани бази даних у конфігурації JSON: базові дані, зміни ours і зміни theirs.
  4. Запустіть сценарій: ./bin/test-scenario <name>.
  5. Перевірте весь набір: ./bin/verify-all.

Стандарти якості коду

merql забезпечує дотримання таких вимог:

  • PHPStan рівня 10 -- суворий статичний аналіз без винятків у базовій конфігурації.
  • PSR-12 -- стандарти кодування перевіряються за допомогою phpcs.
  • Регресійні перевірки за оракулом -- усі 32 сценарії мають пройти.
  • Модульні тести -- ізольовані тести для кожного компонента.

Скрипт verify-all послідовно виконує всі чотири перевірки. Часткове схвалення не приймається.

Безперервна інтеграція

Під час кожного push і pull request до main CI перевіряє стандарти кодування, запускає PHPStan, composer test, набір інтеграційних тестів через mysqli на MySQL 8.4, перевірку базових операцій злиття та composer audit. Корпус регресійних перевірок за оракулом не запускається (#6), тому перед тим, як покладатися на зміну, локально запустіть composer test:oracle або ./bin/verify-all.