Blueprint Uji Pipeline Deploy Otomatis End-to-End
Cara menguji pipeline deploy otomatis end-to-end: kirim request, verifikasi HTTP 200, teardown, lalu pastikan tidak ada container, DB, atau rule yang tersisa.
Deploy otomatis yang tidak diuji itu bukan otomatisasi — itu bom waktu yang sopan. Yang paling berbahaya bukan deploy yang gagal (itu obvious), tapi teardown yang menyisakan sampah: container setengah-configured, database yatim, nginx rule yang tidak terhapus. Artikel ini adalah blueprint uji pipeline deploy otomatis end-to-end, dari request sampai verifikasi tidak ada residu.
TL;DR:
- Empat pilar test: deploy request, HTTP responsiveness (dengan content check, bukan cuma status code), teardown, dan residu
- Test residu adalah yang terpenting — cek container, volume, database, nginx rule, dan direktori tersisa setelah teardown
- Guard
test-prefix melindungi situs production dari terhapus tidak sengaja - Test ini regression test, bukan health check — jalankan saat ada perubahan di deploy script atau bridge
Apa yang perlu diuji saat menguji pipeline deploy otomatis
Pipeline deploy punya 7 tahap yang masing-masing perlu verifikasi:
1. Request diterima. Agent menulis file .cmd ke queue. Yang diuji: file muncul di /hermes-queue/. Cara verifikasi: ls /hermes-queue/*.cmd. Kriteria lulus: file ada, format valid.
2. Bridge memproses. Bridge poller membaca dan mengeksekusi. Yang diuji: result file muncul. Cara verifikasi: ls /hermes-queue/result-*.txt. Kriteria lulus: result file ada dalam 90 detik.
3. Container jalan. Container situs up dan running. Yang diuji: docker ps --filter name=<nama>. Cara verifikasi: container status "Up". Kriteria lulus: container running.
4. HTTP responsif. Container merespons HTTP request. Yang diuji: curl ke container. Cara verifikasi: HTTP 200 atau 302. Kriteria lulus: bukan 000 (connection refused) atau 502 (bad gateway).
5. DB terbuat. Database dan user ada di MariaDB. Yang diuji: query SHOW DATABASES LIKE 'db_<nama>'. Cara verifikasi: database muncul. Kriteria lulus: database dan user ada.
6. Rule nginx aktif. Nginx proxy rule terpasang. Yang diuji: curl -H "Host: <nama>.jayax.dev" http://site-server/. Cara verifikasi: bukan 404 (rule tidak ada). Kriteria lulus: HTTP 200 atau 302.
7. Teardown berhasil dan tidak ada residu. Setelah teardown: container hilang, database hilang, rule nginx hilang, direktori bersih. Yang diuji: cek setiap jenis residu. Kriteria lulus: tidak ada container, database, rule, atau direktori yang tersisa.
Test 1: request lewat queue sampai container hidup
Test pertama memverifikasi jalur penuh dari file .cmd sampai container running:
#!/bin/bash
# test-deploy-request.sh
set -euo pipefail
SITE_NAME="test-smoke-$(date +%s)"
# Tulis perintah deploy
echo "wsl-deploy wordpress ${SITE_NAME}" > "/hermes-queue/deploy-wordpress-${SITE_NAME}.cmd"
# Polling result
RESULT_FILE="/hermes-queue/result-deploy-wordpress-${SITE_NAME}.txt"
for i in $(seq 1 9); do
if [ -f "$RESULT_FILE" ]; then
EXIT_CODE=$(head -1 "$RESULT_FILE" | cut -d= -f2)
if [ "$EXIT_CODE" = "0" ]; then
echo "PASS: deploy request processed, exit=0"
echo "$SITE_NAME" > /tmp/test-site-name.txt
exit 0
else
echo "FAIL: exit code $EXIT_CODE"
cat "$RESULT_FILE"
exit 1
fi
fi
sleep 10
done
echo "FAIL: timeout — bridge tidak merespons dalam 90 detik"
exit 1
Kriteria lulus: result file muncul dalam 90 detik, exit code 0, output berisi SITE '<nama>' TERDEPLOY.
Test 2: verifikasi HTTP
HTTP 200 saja tidak cukup. WordPress bisa balas 200 sambil menampilkan layar error database — halaman HTML dengan "Error establishing a database connection" tetap return 200. Test yang benar cek juga isi respons:
#!/bin/bash
# test-http.sh
set -euo pipefail
SITE_NAME=$(cat /tmp/test-site-name.txt)
# Retry dengan timeout
for i in $(seq 1 10); do
HTTP_CODE=$(curl -s -o /tmp/response.html -w "%{http_code}" \
-H "Host: ${SITE_NAME}.jayax.dev" \
http://site-server/ 2>/dev/null || echo "000")
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ]; then
# Cek isi: tidak boleh ada error database
if grep -qi "error establishing a database connection" /tmp/response.html; then
echo "FAIL: HTTP 200 tapi halaman error database"
exit 1
fi
echo "PASS: HTTP $HTTP_CODE, content OK"
exit 0
fi
sleep 3
done
echo "FAIL: HTTP code $HTTP_CODE setelah 10 retry"
exit 1
Cek ganda: status code DAN isi respons. Kalau cuma cek status code, test bisa pass padahal situs broken.
Test 3: teardown dan verifikasi 404
Test teardown memverifikasi bahwa setelah wsl-deploy down, situs tidak lagi accessible:
#!/bin/bash
# test-teardown.sh
set -euo pipefail
SITE_NAME=$(cat /tmp/test-site-name.txt)
# Request teardown
echo "wsl-deploy down ${SITE_NAME}" > "/hermes-queue/down-${SITE_NAME}.cmd"
# Polling result
RESULT_FILE="/hermes-queue/result-down-${SITE_NAME}.txt"
for i in $(seq 1 9); do
if [ -f "$RESULT_FILE" ]; then
EXIT_CODE=$(head -1 "$RESULT_FILE" | cut -d= -f2)
if [ "$EXIT_CODE" = "0" ]; then
# Verifikasi situs 404 (nginx rule sudah hilang)
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Host: ${SITE_NAME}.jayax.dev" \
http://site-server/ 2>/dev/null || echo "000")
if [ "$HTTP_CODE" = "404" ]; then
echo "PASS: teardown berhasil, situs 404"
exit 0
else
echo "FAIL: HTTP masih $HTTP_CODE setelah teardown"
exit 1
fi
fi
fi
sleep 10
done
echo "FAIL: teardown timeout"
exit 1
Test 4: verifikasi tidak ada residu
Ini bagian terpenting. Setelah teardown, cek setiap jenis resource yang mungkin tertinggal:
#!/bin/bash
# test-no-residue.sh
set -euo pipefail
SITE_NAME=$(cat /tmp/test-site-name.txt)
FAIL=0
# 1. Container residu
if docker ps -a --format "{{.Names}}" | grep -q "^${SITE_NAME}$"; then
echo "FAIL: container '${SITE_NAME}' masih ada (stopped atau running)"
FAIL=1
else
echo "PASS: container sudah hilang"
fi
# 2. Volume residu
if docker volume ls --format "{{.Name}}" | grep -q "${SITE_NAME}"; then
echo "FAIL: volume '${SITE_NAME}' masih ada"
FAIL=1
else
echo "PASS: volume sudah hilang"
fi
# 3. Database residu
if docker exec mariadb mysql -u root -p<ROOT_PASSWORD> -sN \
-e "SHOW DATABASES LIKE 'db_${SITE_NAME}'" 2>/dev/null | grep -q .; then
echo "FAIL: database 'db_${SITE_NAME}' masih ada"
FAIL=1
else
echo "PASS: database sudah hilang"
fi
# 4. Direktori app-stack residu
if [ -d "/app-stacks/${SITE_NAME}" ]; then
echo "FAIL: direktori /app-stacks/${SITE_NAME} masih ada"
FAIL=1
else
echo "PASS: direktori sudah hilang"
fi
# 5. Nginx rule residu
if docker exec site-server ls /etc/nginx/sites/${SITE_NAME}.conf 2>/dev/null; then
echo "FAIL: nginx rule '${SITE_NAME}.conf' masih ada"
FAIL=1
else
echo "PASS: nginx rule sudah hilang"
fi
exit $FAIL
Lima cek ini adalah jaring pengaman terakhir. Kalau teardown skip salah satu langkah (misal: database tidak di-drop), test ini menangkapnya.
Menjalankan semuanya sebagai satu skrip
Skrip lengkap menjalankan semua test secara berurutan, dengan guard yang melindungi production:
#!/bin/bash
# test-deploy-full.sh
# Menjalankan smoke test deploy pipeline end-to-end
set -euo pipefail
SITE_NAME="test-smoke-$(date +%s)"
echo "========================================="
echo "SMOKE TEST: deploy pipeline"
echo "Site: ${SITE_NAME}"
echo "========================================="
# GUARD: nama HARUS diawali "test-"
if [[ ! "$SITE_NAME" =~ ^test- ]]; then
echo "ABORT: nama situs test harus diawali 'test-'"
exit 1
fi
# GUARD: tidak boleh ada container dengan nama yang sama
if docker ps -a --format "{{.Names}}" | grep -q "^${SITE_NAME}$"; then
echo "ABORT: container '${SITE_NAME}' sudah ada. Bukan test fresh."
exit 1
fi
echo ""
echo "[1/4] Deploy request..."
echo "wsl-deploy wordpress ${SITE_NAME}" > "/hermes-queue/deploy-wordpress-${SITE_NAME}.cmd"
RESULT="/hermes-queue/result-deploy-wordpress-${SITE_NAME}.txt"
for i in $(seq 1 12); do
[ -f "$RESULT" ] && break
sleep 10
done
if [ ! -f "$RESULT" ]; then echo "FAIL: timeout deploy"; exit 1; fi
EXIT_CODE=$(head -1 "$RESULT" | cut -d= -f2)
if [ "$EXIT_CODE" != "0" ]; then echo "FAIL: deploy exit=$EXIT_CODE"; cat "$RESULT"; exit 1; fi
echo "PASS: deploy exit=0"
echo ""
echo "[2/4] HTTP verification..."
for i in $(seq 1 15); do
HTTP=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: ${SITE_NAME}.jayax.dev" http://site-server/ 2>/dev/null || echo "000")
[ "$HTTP" = "200" ] || [ "$HTTP" = "302" ] && break
sleep 3
done
echo "HTTP code: $HTTP"
[ "$HTTP" = "200" ] || [ "$HTTP" = "302" ] || { echo "FAIL: HTTP $HTTP"; exit 1; }
echo "PASS: HTTP responsive"
echo ""
echo "[3/4] Teardown..."
echo "wsl-deploy down ${SITE_NAME}" > "/hermes-queue/down-${SITE_NAME}.cmd"
RESULT="/hermes-queue/result-down-${SITE_NAME}.txt"
for i in $(seq 1 12); do
[ -f "$RESULT" ] && break
sleep 10
done
if [ ! -f "$RESULT" ]; then echo "FAIL: timeout teardown"; exit 1; fi
echo "PASS: teardown exit=$(head -1 "$RESULT" | cut -d= -f2)"
echo ""
echo "[4/4] Residue check..."
FAIL=0
docker ps -a --format "{{.Names}}" | grep -q "^${SITE_NAME}$" && { echo "FAIL: container residu"; FAIL=1; } || echo "PASS: no container"
docker exec mariadb mysql -u root -p<ROOT_PASSWORD> -sN -e "SHOW DATABASES LIKE 'db_${SITE_NAME}'" 2>/dev/null | grep -q . && { echo "FAIL: db residu"; FAIL=1; } || echo "PASS: no db"
docker exec site-server test -f /etc/nginx/sites/${SITE_NAME}.conf 2>/dev/null && { echo "FAIL: nginx residu"; FAIL=1; } || echo "PASS: no nginx rule"
[ -d "/app-stacks/${SITE_NAME}" ] && { echo "FAIL: dir residu"; FAIL=1; } || echo "PASS: no dir"
echo ""
echo "========================================="
[ $FAIL -eq 0 ] && echo "ALL TESTS PASSED" || echo "SOME TESTS FAILED"
echo "========================================="
exit $FAIL
Output nyata dari menjalankan skrip ini (dengan nama disamarkan):
=========================================
SMOKE TEST: deploy pipeline
Site: test-smoke-1722893
=========================================
[1/4] Deploy request...
PASS: deploy exit=0
[2/4] HTTP verification...
HTTP code: 302
PASS: HTTP responsive
[3/4] Teardown...
PASS: teardown exit=0
[4/4] Residue check...
PASS: no container
PASS: no db
PASS: no nginx rule
PASS: no dir
=========================================
ALL TESTS PASSED
=========================================
Kegagalan yang berhasil ditangkap test ini
Test ini menangkap bug yang lolos manual testing. Contoh konkret:
Teardown lupa drop database. Versi awal teardown script berhenti setelah docker compose down — database db_<nama> tetap ada. Test residu (cek database) menangkap ini. Tanpa test, database yatim menumpuk sampai puluhan.
Nginx rule tidak terhapus kalau nama file salah. Bug di skrip teardown: nama file config disimpan sebagai <nama>.conf tapi dihapus sebagai <nama>_conf. File tidak terhapus. Test cek nginx rule menangkap ini.
Container restart setelah teardown. restart: unless-stopped berarti container auto-restart kalau Docker daemon restart. Tapi teardown seharusnya menghapus container sepenuhnya (docker compose down menghapus container, bukan cuma stop). Test container residu menangkap kasus dimana container masih ada (stopped) setelah teardown.
Yang belum diuji
Test beban. Test ini tidak menguji behavior deploy saat server under load (CPU tinggi, RAM penuh). Deploy under load bisa timeout atau OOM.
Deploy paralel. Dua deploy bersamaan ke queue belum diuji. Bridge memproses FIFO, tapi dua compose file bisa bentrok kalau nama mirip.
Recovery setelah reboot. Setelah host reboot, semua container dengan restart: unless-stopped harus kembali otomatis. Test ini tidak mensimulasikan reboot.
Konflik nama. Deploy nama yang sudah dipakai belum diuji secara eksplisit. IF NOT EXISTS menangani ini di SQL level, tapi behavior container bisa unexpected.
Peringatan keselamatan
Skrip test ini membuat dan menghapus container serta database. Guard di kode menolak jalan kalau nama situs tidak diawali test-. Jangan pernah menjalankan test terhadap situs production yang sedang jalan. Test ini akan menghapus container dan database situs tersebut.
Sebelum menjalankan test di mesin production, pastikan:
- Nama situs test selalu diawali
test- - Tidak ada situs production dengan nama yang mirip
- Backup database ada sebelum test (untuk berjaga-jaga)
Langkah berikutnya
Test ini memverifikasi pipeline deploy. Pipeline itu sendiri dibahas di satu skrip deploy untuk tiga framework dan auto-deploy WordPress dengan Docker. Konteks lengkap sistem ada di AI agent yang deploy website otomatis.
FAQ
Seberapa sering test ini harus dijalankan?
Saat ada perubahan di deploy script atau bridge. Tidak perlu harian kalau tidak ada perubahan. Test ini adalah regression test, bukan health check.
Apakah test ini bisa dijadwalkan otomatis (cron)?
Bisa, tapi hati-hati. Test membuat dan menghancurkan container — kalau berjalan saat situs production sedang direpair, bisa konflik. Jadwalkan di jam low-traffic dan pastikan guard test- prefix bekerja.
Berapa lama test ini berjalan?
3-5 menit total. Deploy butuh 60-90 detik (polling bridge), HTTP verification 10-30 detik, teardown 60-90 detik, residue check instan.
Apakah test ini menjamin deploy selalu berhasil?
Tidak. Test ini menangkap bug di teardown dan residu. Bug di logic deploy (misal: image WordPress rusak, MariaDB crash saat deploy) tidak tertangkap. Test ini adalah salah satu lapisan, bukan satu-satunya.
Kesimpulan
Blueprint uji pipeline deploy otomatis ini punya empat pilar: test deploy request, test HTTP responsiveness (dengan content check), test teardown, dan test residu. Bagian residu adalah yang paling penting — karena teardown yang menyisakan sampah adalah mode kegagalan terburuk: tidak obvious, menumpuk dari waktu ke waktu, dan sulit di-debug.
Kalau sistem deploy kamu tidak punya test residu, tambahkan sekarang. Itu investasi satu skrip yang menyelamatkan jam debugging di masa depan.
Untuk memahami pipeline yang diuji, baca satu skrip deploy untuk tiga framework atau auto-deploy WordPress dengan Docker dan MariaDB.