Pengujian integrasi yang berinteraksi langsung dengan instance Oracle Database kerap mengalami flakiness akibat residu data antar-eksekusi test. Pendekatan konvensional yang mengandalkan rollback transaksi di level framework pengujian (seperti @Transactional pada Spring Test atau transaksi rollback pada pytest) sering kali gagal mempertahankan isolasi data pada arsitektur enterprise.
Akar Masalah: Mengapa Rollback Transaksi Gagal
Rollback transaksi di level aplikasi mengasumsikan seluruh operasi DML berada dalam cakupan sesi transaksi yang sama dan dapat dibatalkan melalui instruksi ROLLBACK. Asumsi ini runtuh dalam dua skenario umum pada Oracle:
- Implicit Commit oleh DDL: Stored procedure yang mengeksekusi DDL secara dinamis melalui
EXECUTE IMMEDIATE(misalnya pembuatan tabel staging, pemotongan partisi, atau pembuatan indeks sementara) memicu commit implisit sebelum dan sesudah statement DDL dieksekusi. Sesi transaksi terbuka langsung dipermanenkan ke database. - Autonomous Transaction: Kode PL/SQL yang dianotasi dengan
PRAGMA AUTONOMOUS_TRANSACTIONberjalan di luar konteks transaksi pemanggil. Commit yang dipanggil di dalam blok tersebut bersifat independen. Rollback dari runner pengujian tidak dapat menyentuh perubahan data ini, meninggalkan residu state pada tabel audit, log transaksi, atau tabel operasional.
Residu data ini menyebabkan dependensi urutan eksekusi antar-test suite, benturan constraint unik (ORA-00001), dan kegagalan asersi data yang acak.
Solusi: Guaranteed Restore Point (GRP)
Oracle Flashback Database bekerja pada level blok database menggunakan Flashback Logs di Fast Recovery Area (FRA). Berbeda dengan Normal Restore Point yang dapat terhapus saat ruang FRA menipis, Guaranteed Restore Point (GRP) menjamin database dapat dikembalikan persis ke titik waktu pembuatan GRP, terlepas dari operasi DDL, commit otonom, atau modifikasi skema.
Penggunaan GRP pada database container di environment Continuous Integration (CI) memastikan state bersih (baseline) dapat dipulihkan secara instan tanpa perlu membuang container dan membangun ulang skema dari nol.
Konfigurasi Database untuk Mendukung Flashback
Sebelum GRP dapat dibuat, instance Oracle harus berada dalam mode ARCHIVELOG dan memiliki Fast Recovery Area aktif. Eksekusi script SQL berikut menggunakan hak akses SYSDBA saat container pertama kali diinisialisasi:
-- Konfigurasi Fast Recovery Area jika belum diset
ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE = 10G SCOPE=BOTH;
ALTER SYSTEM SET DB_RECOVERY_FILE_DEST = '/opt/oracle/oradata/fast_recovery_area' SCOPE=BOTH;
-- Pindahkan database ke mode ARCHIVELOG
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;
Setup Baseline dan Pembuatan GRP
Setelah database siap, jalankan migration tool (Flyway, Liquibase, atau migration script internal) untuk membentuk skema dan memuat master data awal (seed). Segera setelah inisialisasi selesai, buat restore point:
-- Buat Guaranteed Restore Point bernama 'clean_baseline'
CREATE RESTORE POINT clean_baseline GUARANTEE FLASHBACK DATABASE;
Catatan: Status GRP dapat diverifikasi melalui query: SELECT NAME, GUARANTEE_FLASHBACK_DATABASE FROM V$RESTORE_POINT;Automasi Reset State dalam Pipeline CI
Runner CI dapat memanggil script bash berikut setiap kali sebuah test suite atau test class selesai dieksekusi untuk mengembalikan database ke titik clean_baseline:
#!/usr/bin/env bash
set -euo pipefail
CONTAINER_NAME="oracle-ci-db"
ORACLE_SID="FREE" # sesuaikan dengan SID/SERVICE_NAME yang digunakan
echo "Memulai proses rollback ke GRP: clean_baseline..."
docker exec -i "${CONTAINER_NAME}" sqlplus -s / as sysdba <<EOF
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
FLASHBACK DATABASE TO RESTORE POINT clean_baseline;
ALTER DATABASE OPEN RESETLOGS;
EXIT;
EOF
echo "Database berhasil direset ke clean_baseline."
Perintah ALTER DATABASE OPEN RESETLOGS diperlukan untuk memulai cabang redo stream baru dari titik restore point tersebut, memungkinkan siklus pengujian berikutnya berjalan secara deterministik.
Perbandingan: Flashback vs Truncate/Re-seed Konvensional
| Parameter | Truncate & Re-seed Manual | Flashback Database (GRP) |
|---|---|---|
| Overhead Waktu | Tinggi (meningkat linear sesuai jumlah tabel dan volume seed data) | Rendah & Konstan (rerata 5-15 detik untuk shutdown, flashback, startup) |
| Foreign Key Handling | Rentan gagal; membutuhkan penonaktifan dan pengaktifan kembali FK constraint | Native; pemulihan terjadi pada level blok storage tanpa validasi metadata constraint |
| Isolasi DDL | Gagal memulihkan tabel, sequence, atau view yang termodifikasi saat test | Sempurna; seluruh modifikasi struktur objek skema ikut ter-rollback |
| Kompleksitas Script | Tinggi; memerlukan pemeliharaan script cleanup seiring evolusi skema | Minimal; satu set instruksi flashback berlaku universal |
Trade-off dan Limitasi
- Storage Fast Recovery Area: GRP menahan penghapusan flashback log dari FRA. Jika pengujian menghasilkan mutasi data masif dalam jumlah gigabyte tanpa pembersihan, disk FRA dapat penuh dan menghentikan database (
ORA-19809). Pastikan ukuran FRA proporsional dengan alokasi runner CI. - Instance Restart: Eksekusi
SHUTDOWN IMMEDIATEdanSTARTUP MOUNTmembutuhkan jeda beberapa detik. Terapkan reset state per test suite/test class, bukan per test case individual, guna menjaga total durasi pipeline tetap optimal. - Pembersihan GRP: Sebelum container dimatikan atau jika GRP tidak lagi dibutuhkan, hapus restore point menggunakan perintah:
DROP RESTORE POINT clean_baseline;untuk membebaskan ruang blok log.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!