Strategi Pengujian
merql menggunakan model pengujian berbasis oracle. Setiap skenario pengujian menentukan sekumpulan input yang diketahui (tiga keadaan basis data), hasil yang diharapkan secara deterministik (oracle), lalu membandingkan keluaran merge aktual dengan hasil tersebut. Ada 32 skenario yang mencakup merge tanpa konflik, konflik, resolusi identitas, tipe data, skala, dan kasus tepi.
# Run the full verification suite.
./bin/verify-all
Perintah di halaman ini dijalankan dari checkout repositori merql setelah
composer install. Skrip pengembangan di bin/, korpus scenarios/,
dan pengujian bukan bagian dari paket Composer. Dependensi pengembangan mencakup
PHPUnit 13, yang memerlukan PHP 8.4 atau lebih baru, meskipun
pustaka itu sendiri berjalan pada PHP 8.2.
Pengujian berbasis oracle
Tidak ada alat referensi yang tersedia untuk melakukan merge basis data tiga arah, jadi oracle dihitung dari input yang diketahui, bukan dibuat oleh alat eksternal. Setiap skenario memiliki hasil yang diharapkan secara deterministik dan dapat diverifikasi secara logis:
- Penyiapan -- buat tiga keadaan basis data (base, sisi kita, sisi mereka) dengan konten yang diketahui.
- Oracle -- hitung hasil merge yang diharapkan dari input yang diketahui.
- Aktual -- jalankan merge merql pada ketiga keadaan.
- Bandingkan -- hasil aktual harus sama persis dengan hasil yang diharapkan.
Known inputs (base, ours, theirs)
| |
Deterministic merql merge
computation
| |
Expected result Actual result
| |
-----> Compare <-----
|
Pass or Fail
Menjalankan pengujian
Verifikasi lengkap
Skrip verify-all adalah pemeriksaan akhir. Skrip ini menjalankan analisis statis, standar pengodean, pengujian PHPUnit, dan rangkaian regresi oracle:
./bin/verify-all
Semua pemeriksaan ini harus lolos sebelum pekerjaan dinyatakan selesai.
Rangkaian regresi oracle
Jalankan semua 32 skenario:
./bin/test-regression
Jalankan satu kategori:
./bin/test-regression --category clean
./bin/test-regression --category conflict
./bin/test-regression --category identity
Kategori adalah nama direktori di bawah scenarios/: clean, conflict,
identity, types, scale, dan edge. Kategori yang tidak dikenal akan menampilkan
No scenarios found dan keluar dengan sukses. --category dapat diulang untuk menjalankan
beberapa kategori.
Skrip juga menerima --jobs, tetapi mengabaikan nilainya dan menjalankan skenario
secara berurutan (#5).
Jalankan dengan keluaran minimal (hanya lulus/gagal):
./bin/test-regression --fast
Satu skenario
Uji satu skenario melalui seluruh alur:
./bin/test-scenario column-level-clean
Langkah oracle satu per satu
./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
Pengujian unit
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 hanya menjalankan PHPUnit. Rangkaian oracle PHPUnit mengarah ke
tests/Oracle, yang berisi kelas pelaksana skenario tetapi tidak memiliki kasus pengujian, jadi
32 skenario hanya dijalankan melalui composer test:oracle, composer verify, atau
./bin/verify-all.
Pengujian integrasi MySQL dilewati kecuali MERQL_MYSQL_HOST,
MERQL_MYSQL_DATABASE, dan MERQL_MYSQL_USER (serta secara opsional
MERQL_MYSQL_PASSWORD dan MERQL_MYSQL_PORT) mengarah ke basis data pengujian.
Kualitas kode
composer cs # PSR-12 coding standards check
composer cs:fix # Auto-fix coding standards
composer analyse # PHPStan level 10 static analysis
Kategori skenario
clean (8 skenario)
Merge tanpa konflik. Kedua sisi dapat mengubah data, tetapi tidak pernah kolom yang sama pada baris yang sama.
| Skenario | Pengujian |
|---|---|
insert-only-theirs |
Sisi mereka menyisipkan baris, sisi kita tidak berubah. |
update-only-theirs |
Sisi mereka memperbarui baris, sisi kita tidak berubah. |
delete-only-theirs |
Sisi mereka menghapus baris, sisi kita tidak berubah. |
insert-only-ours |
Sisi kita menyisipkan baris, sisi mereka tidak berubah. |
mixed-no-overlap |
Kedua sisi mengubah tabel atau baris yang berbeda. |
both-same-change |
Kedua sisi membuat perubahan identik (tanpa konflik). |
column-level-clean |
Kedua sisi mengubah baris yang sama, tetapi kolom berbeda. |
multi-table |
Perubahan pada beberapa tabel. |
conflict (6 skenario)
Skenario yang harus menghasilkan konflik.
| Skenario | Pengujian |
|---|---|
both-update-same-column |
Kedua sisi mengubah kolom yang sama menjadi nilai berbeda. |
update-vs-delete |
Satu sisi memperbarui, sisi lain menghapus baris yang sama. |
delete-vs-update |
Arah sebaliknya untuk pembaruan versus penghapusan. |
both-insert-same-pk |
Kedua sisi menyisipkan baris dengan kunci utama yang sama. |
multiple-conflicts |
Beberapa konflik dalam satu merge. |
partial-conflict |
Beberapa kolom berkonflik, sementara lainnya berhasil di-merge tanpa konflik. |
identity (4 skenario)
Kasus tepi identitas baris.
| Skenario | Pengujian |
|---|---|
auto-increment |
Baris baru memiliki ID berbeda antar cabang. |
natural-key |
Cocokkan berdasarkan kolom unik, bukan PK. |
composite-key |
Kunci utama dengan beberapa kolom. |
no-key |
Tabel tanpa kunci utama (fallback hash konten). |
types (6 skenario)
Penanganan tipe data untuk semua tipe kolom.
| Skenario | Pengujian |
|---|---|
text-columns |
Nilai VARCHAR, TEXT, LONGTEXT. |
numeric-columns |
Nilai INT, DECIMAL, FLOAT. |
date-columns |
Nilai DATE, DATETIME, TIMESTAMP. |
json-columns |
Merge kolom JSON. |
blob-columns |
Data biner. |
null-handling |
Transisi dari NULL ke nilai, dan dari nilai ke NULL. |
scale (4 skenario)
Performa saat beban tinggi.
| Skenario | Pengujian |
|---|---|
1k-rows |
1,000 baris. |
10k-rows |
10,000 baris. |
100k-rows |
100,000 baris. |
wide-table |
Tabel dengan 50+ kolom. |
edge (4 skenario)
Kasus tepi dan kondisi batas.
| Skenario | Pengujian |
|---|---|
empty-changeset |
Tidak ada perubahan di satu atau kedua sisi. |
schema-mismatch |
Kolom ditambahkan atau dihapus antar snapshot. |
encoding |
UTF-8, emoji, karakter khusus. |
large-text |
Nilai TEXT/LONGTEXT yang sangat besar. |
Struktur skenario
Setiap skenario adalah direktori di bawah scenarios/<category>/<name>/ dengan konfigurasi 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"
}
}
Untuk skenario konflik, konflik yang diharapkan ditentukan secara terperinci:
{
"expectations": {
"conflicts": 1,
"conflict_details": [
{
"table": "test_posts",
"primary_key": {"id": 42},
"column": "title",
"ours_value": "Welcome",
"theirs_value": "Greetings"
}
]
}
}
Alur ScenarioRunner
ScenarioRunner::run() mengatur satu skenario:
OracleCapture::compute()membuat tiga snapshot dari data JSON skenario, lalu menjalankan merge.ScenarioComparator::compare()memeriksa hasil merge berdasarkan nilai yang diharapkan discenario.json.- Mengembalikan status lulus/gagal beserta daftar pesan kegagalan.
use Merql\Tests\Oracle\ScenarioRunner;
$result = ScenarioRunner::run($scenario);
// ['name' => 'column-level-clean', 'pass' => true, 'failures' => []]
ScenarioRunner::runAll() menjalankan setiap skenario secara berurutan:
$results = ScenarioRunner::runAll($scenarios);
Menambahkan skenario baru
- Buat direktori:
scenarios/<category>/<name>/. - Buat
scenario.jsondengan metadata dan ekspektasi skenario. - Tentukan tiga keadaan basis data dalam konfigurasi JSON: data base, perubahan di sisi kita, dan perubahan di sisi mereka.
- Jalankan skenario:
./bin/test-scenario <name>. - Verifikasi seluruh rangkaian:
./bin/verify-all.
Standar kualitas kode
merql menerapkan:
- PHPStan level 10 -- analisis statis ketat tanpa pengecualian baseline.
- PSR-12 -- standar pengodean yang diperiksa oleh
phpcs. - Regresi oracle -- semua 32 skenario harus lulus.
- Pengujian unit -- pengujian terisolasi untuk setiap komponen.
Skrip verify-all menjalankan keempat pemeriksaan secara berurutan. Persetujuan parsial tidak diterima.
Integrasi berkelanjutan
CI menjalankan pemeriksaan standar pengodean, PHPStan, composer test, rangkaian integrasi
pada MySQL 8.4 melalui mysqli, cakupan merge primitif, dan
composer audit pada setiap push dan pull request ke main. CI tidak menjalankan
korpus regresi oracle (#6), jadi
jalankan composer test:oracle atau ./bin/verify-all secara lokal sebelum mengandalkan suatu
perubahan.