3 # Test suite for pg_scribe --start command
6 # - Creates temporary test databases
7 # - Tests various --start scenarios
8 # - Verifies SQL capture (DML + DDL)
9 # - Tests signal handling
10 # - Cleans up all resources
15 # Colors for test output
20 NC='\033[0m' # No Color
23 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
24 PG_SCRIBE="$SCRIPT_DIR/scripts/pg_scribe"
25 TEST_DIR="/tmp/pg_scribe_test_start_$$"
26 TEST_DB_PREFIX="pg_scribe_test_start_$$"
27 PGUSER="${PGUSER:-postgres}"
35 DATABASES_TO_CLEANUP=()
43 echo -e "${BLUE}TEST:${NC} $*"
47 echo -e "${GREEN}PASS:${NC} $*"
52 echo -e "${RED}FAIL:${NC} $*"
57 echo -e "${YELLOW}INFO:${NC} $*"
67 psql -U "$PGUSER" -d "$dbname" -tAq "$@"
73 run_psql "$dbname" -c "$query" 2>/dev/null || true
78 log_info "Creating test database: $dbname"
81 psql -U "$PGUSER" -d postgres -c "DROP DATABASE IF EXISTS $dbname;" &>/dev/null || true
84 psql -U "$PGUSER" -d postgres -c "CREATE DATABASE $dbname;" &>/dev/null
86 DATABASES_TO_CLEANUP+=("$dbname")
89 # shellcheck disable=SC2317 # Function called from cleanup trap handler
92 log_info "Dropping test database: $dbname"
94 # Terminate connections
95 psql -U "$PGUSER" -d postgres -c "
96 SELECT pg_terminate_backend(pid)
98 WHERE datname = '$dbname' AND pid <> pg_backend_pid();
102 psql -U "$PGUSER" -d postgres -c "DROP DATABASE IF EXISTS $dbname;" &>/dev/null || true
105 # shellcheck disable=SC2317 # Function called from cleanup trap handler
106 drop_replication_slot() {
109 log_info "Dropping replication slot: $slot"
111 # Check if slot exists
113 exists=$(query_db "$dbname" "
114 SELECT 1 FROM pg_replication_slots WHERE slot_name = '$slot';
117 if [[ -n "$exists" ]]; then
119 query_db "$dbname" "SELECT pg_drop_replication_slot('$slot');" || true
123 create_table_with_pk() {
127 CREATE TABLE $table (
128 id SERIAL PRIMARY KEY,
130 created_at TIMESTAMP DEFAULT now()
135 initialize_backup_system() {
138 local backup_dir="$3"
140 # Create backup directory
141 mkdir -p "$backup_dir"
144 "$PG_SCRIBE" --init -d "$dbname" -f "$backup_dir" -S "$slot" -U "$PGUSER" &>/dev/null
151 test_start_without_init() {
153 log_test "Start without initialization (should fail)"
155 local dbname="${TEST_DB_PREFIX}_noinit"
156 local slot="test_slot_noinit"
157 local backup_dir="$TEST_DIR/noinit"
159 # Setup - create db and backup dir but DON'T initialize
160 create_test_db "$dbname"
161 create_table_with_pk "$dbname" "users"
162 mkdir -p "$backup_dir"
164 # Try to start - should fail with exit code 4 (no chains found)
166 "$PG_SCRIBE" --start -d "$dbname" -f "$backup_dir" -S "$slot" -U "$PGUSER" &>/dev/null || exit_code=$?
168 if [[ $exit_code -eq 4 ]]; then
169 log_pass "Correctly failed with backup error (no chains)"
172 log_fail "Expected exit code 4, got $exit_code"
177 test_start_basic_streaming() {
179 log_test "Basic streaming with DML capture"
181 local dbname="${TEST_DB_PREFIX}_basic"
182 local slot="test_slot_basic"
183 local backup_dir="$TEST_DIR/basic"
186 create_test_db "$dbname"
187 create_table_with_pk "$dbname" "users"
188 initialize_backup_system "$dbname" "$slot" "$backup_dir"
190 # Start streaming in background
191 "$PG_SCRIBE" --start -d "$dbname" -f "$backup_dir" -S "$slot" -U "$PGUSER" -s 1 -F 1 &>/dev/null &
192 local pg_scribe_pid=$!
193 PIDS_TO_CLEANUP+=("$pg_scribe_pid")
195 # Give it a moment to start
199 query_db "$dbname" "INSERT INTO users (name) VALUES ('Alice');"
200 query_db "$dbname" "INSERT INTO users (name) VALUES ('Bob');"
201 query_db "$dbname" "UPDATE users SET name = 'Alice Smith' WHERE name = 'Alice';"
202 query_db "$dbname" "DELETE FROM users WHERE name = 'Bob';"
204 # Give it time to flush (status-interval=1, fsync-interval=1)
208 kill -INT "$pg_scribe_pid" 2>/dev/null || true
211 # Force kill if still running
212 if kill -0 "$pg_scribe_pid" 2>/dev/null; then
213 kill -9 "$pg_scribe_pid" 2>/dev/null || true
215 wait "$pg_scribe_pid" 2>/dev/null || true
217 # Find active.sql in chain directory
218 local chain_dirs=("$backup_dir"/chain-*)
219 local output_file="${chain_dirs[0]}/active.sql"
221 # Verify output file exists
222 if [[ ! -f "$output_file" ]]; then
223 log_fail "Output file not created: $output_file"
228 if ! grep -q "INSERT INTO public.users" "$output_file"; then
229 log_fail "INSERT not captured"
233 if ! grep -q "UPDATE public.users" "$output_file"; then
234 log_fail "UPDATE not captured"
238 if ! grep -q "DELETE FROM public.users" "$output_file"; then
239 log_fail "DELETE not captured"
243 # Verify transaction boundaries
244 if ! grep -q "BEGIN" "$output_file"; then
245 log_fail "BEGIN not captured"
249 if ! grep -q "COMMIT" "$output_file"; then
250 log_fail "COMMIT not captured"
254 log_pass "DML captured successfully"
258 test_start_ddl_capture() {
260 log_test "DDL capture via event triggers"
262 local dbname="${TEST_DB_PREFIX}_ddl"
263 local slot="test_slot_ddl"
264 local backup_dir="$TEST_DIR/ddl"
267 create_test_db "$dbname"
268 create_table_with_pk "$dbname" "users"
269 initialize_backup_system "$dbname" "$slot" "$backup_dir"
271 # Start streaming in background
272 "$PG_SCRIBE" --start -d "$dbname" -f "$backup_dir" -S "$slot" -U "$PGUSER" -s 1 -F 1 &>/dev/null &
273 local pg_scribe_pid=$!
274 PIDS_TO_CLEANUP+=("$pg_scribe_pid")
276 # Give it a moment to start
280 query_db "$dbname" "CREATE TABLE products (id SERIAL PRIMARY KEY, name TEXT);"
281 query_db "$dbname" "ALTER TABLE products ADD COLUMN price NUMERIC(10,2);"
282 query_db "$dbname" "DROP TABLE products;"
284 # Give it time to flush
288 kill -INT "$pg_scribe_pid" 2>/dev/null || true
291 # Force kill if still running
292 if kill -0 "$pg_scribe_pid" 2>/dev/null; then
293 kill -9 "$pg_scribe_pid" 2>/dev/null || true
295 wait "$pg_scribe_pid" 2>/dev/null || true
297 # Find active.sql in chain directory
298 local chain_dirs=("$backup_dir"/chain-*)
299 local output_file="${chain_dirs[0]}/active.sql"
301 # Verify DDL captured
302 if ! grep -qi "CREATE TABLE products" "$output_file"; then
303 log_fail "CREATE TABLE not captured"
307 if ! grep -qi "ALTER TABLE products" "$output_file"; then
308 log_fail "ALTER TABLE not captured"
312 if ! grep -qi "DROP TABLE products" "$output_file"; then
313 log_fail "DROP TABLE not captured"
317 log_pass "DDL captured successfully"
321 test_start_truncate_capture() {
323 log_test "TRUNCATE capture"
325 local dbname="${TEST_DB_PREFIX}_truncate"
326 local slot="test_slot_truncate"
327 local backup_dir="$TEST_DIR/truncate"
330 create_test_db "$dbname"
331 create_table_with_pk "$dbname" "users"
332 initialize_backup_system "$dbname" "$slot" "$backup_dir"
334 # Start streaming in background
335 "$PG_SCRIBE" --start -d "$dbname" -f "$backup_dir" -S "$slot" -U "$PGUSER" -s 1 -F 1 &>/dev/null &
336 local pg_scribe_pid=$!
337 PIDS_TO_CLEANUP+=("$pg_scribe_pid")
339 # Give it a moment to start
342 # Insert data and truncate
343 query_db "$dbname" "INSERT INTO users (name) VALUES ('Alice'), ('Bob'), ('Charlie');"
344 query_db "$dbname" "TRUNCATE users;"
346 # Give it time to flush
350 kill -INT "$pg_scribe_pid" 2>/dev/null || true
353 # Force kill if still running
354 if kill -0 "$pg_scribe_pid" 2>/dev/null; then
355 kill -9 "$pg_scribe_pid" 2>/dev/null || true
357 wait "$pg_scribe_pid" 2>/dev/null || true
359 # Find active.sql in chain directory
360 local chain_dirs=("$backup_dir"/chain-*)
361 local output_file="${chain_dirs[0]}/active.sql"
363 # Verify TRUNCATE captured
364 if ! grep -qi "TRUNCATE.*users" "$output_file"; then
365 log_fail "TRUNCATE not captured"
369 log_pass "TRUNCATE captured successfully"
373 test_start_signal_handling() {
375 log_test "Signal handling (SIGTERM)"
377 local dbname="${TEST_DB_PREFIX}_signal"
378 local slot="test_slot_signal"
379 local backup_dir="$TEST_DIR/signal"
382 create_test_db "$dbname"
383 create_table_with_pk "$dbname" "users"
384 initialize_backup_system "$dbname" "$slot" "$backup_dir"
386 # Start streaming in background
387 "$PG_SCRIBE" --start -d "$dbname" -f "$backup_dir" -S "$slot" -U "$PGUSER" -s 1 -F 1 &>/dev/null &
388 local pg_scribe_pid=$!
389 PIDS_TO_CLEANUP+=("$pg_scribe_pid")
391 # Give it a moment to start
395 query_db "$dbname" "INSERT INTO users (name) VALUES ('Test');"
397 # Give it time to flush
401 kill -TERM "$pg_scribe_pid" 2>/dev/null || true
403 # Wait for graceful shutdown (with timeout)
406 while kill -0 "$pg_scribe_pid" 2>/dev/null && [[ $count -lt $timeout ]]; do
411 # Check if process stopped
412 if kill -0 "$pg_scribe_pid" 2>/dev/null; then
413 log_fail "Process did not stop after SIGTERM"
414 kill -9 "$pg_scribe_pid" 2>/dev/null || true
418 # Find active.sql in chain directory
419 local chain_dirs=("$backup_dir"/chain-*)
420 local output_file="${chain_dirs[0]}/active.sql"
422 # Verify output file was created and flushed
423 if [[ ! -f "$output_file" ]]; then
424 log_fail "Output file not created"
428 if ! grep -q "INSERT INTO public.users" "$output_file"; then
429 log_fail "Data not flushed before shutdown"
433 log_pass "SIGTERM handled gracefully"
437 test_start_interleaved_ddl_dml() {
439 log_test "DDL and DML interleaving (chronological order)"
441 local dbname="${TEST_DB_PREFIX}_interleaved"
442 local slot="test_slot_interleaved"
443 local backup_dir="$TEST_DIR/interleaved"
446 create_test_db "$dbname"
447 create_table_with_pk "$dbname" "users"
448 initialize_backup_system "$dbname" "$slot" "$backup_dir"
450 # Start streaming in background
451 "$PG_SCRIBE" --start -d "$dbname" -f "$backup_dir" -S "$slot" -U "$PGUSER" -s 1 -F 1 &>/dev/null &
452 local pg_scribe_pid=$!
453 PIDS_TO_CLEANUP+=("$pg_scribe_pid")
455 # Give it a moment to start
458 # Make interleaved changes
459 query_db "$dbname" "INSERT INTO users (name) VALUES ('Alice');"
460 query_db "$dbname" "ALTER TABLE users ADD COLUMN email TEXT;"
461 query_db "$dbname" "UPDATE users SET email = 'alice@example.com' WHERE name = 'Alice';"
462 query_db "$dbname" "ALTER TABLE users DROP COLUMN created_at;"
463 query_db "$dbname" "INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');"
465 # Give it time to flush
469 kill -INT "$pg_scribe_pid" 2>/dev/null || true
472 # Force kill if still running
473 if kill -0 "$pg_scribe_pid" 2>/dev/null; then
474 kill -9 "$pg_scribe_pid" 2>/dev/null || true
476 wait "$pg_scribe_pid" 2>/dev/null || true
478 # Find active.sql in chain directory
479 local chain_dirs=("$backup_dir"/chain-*)
480 local output_file="${chain_dirs[0]}/active.sql"
482 # Verify all operations captured
483 if ! grep -q "INSERT INTO public.users (id, name" "$output_file"; then
484 log_fail "First INSERT not captured"
488 if ! grep -qi "ALTER TABLE.*ADD COLUMN email" "$output_file"; then
489 log_fail "ALTER TABLE ADD COLUMN not captured"
493 if ! grep -q "UPDATE public.users.*email" "$output_file"; then
494 log_fail "UPDATE with new column not captured"
498 if ! grep -qi "ALTER TABLE.*DROP COLUMN" "$output_file"; then
499 log_fail "ALTER TABLE DROP COLUMN not captured"
503 # Verify chronological order by checking line numbers
505 insert1_line=$(grep -n "INSERT INTO public.users (id, name" "$output_file" | head -1 | cut -d: -f1)
507 alter_add_line=$(grep -ni "ALTER TABLE.*ADD COLUMN email" "$output_file" | cut -d: -f1)
509 update_line=$(grep -n "UPDATE public.users.*email" "$output_file" | cut -d: -f1)
511 if [[ "$insert1_line" -gt "$alter_add_line" ]]; then
512 log_fail "DDL/DML not in chronological order (INSERT after ALTER)"
516 if [[ "$alter_add_line" -gt "$update_line" ]]; then
517 log_fail "DDL/DML not in chronological order (ALTER after UPDATE)"
521 log_pass "DDL/DML interleaved in correct chronological order"
525 test_rotate_diff_basic() {
527 log_test "--rotate-diff basic functionality"
529 local dbname="${TEST_DB_PREFIX}_rotate_basic"
530 local slot="test_slot_rotate_basic"
531 local backup_dir="$TEST_DIR/rotate_basic"
534 create_test_db "$dbname"
535 create_table_with_pk "$dbname" "users"
536 initialize_backup_system "$dbname" "$slot" "$backup_dir"
538 # Start streaming in background
539 "$PG_SCRIBE" --start -d "$dbname" -f "$backup_dir" -S "$slot" -U "$PGUSER" -s 1 -F 1 &>/dev/null &
540 local pg_scribe_pid=$!
541 PIDS_TO_CLEANUP+=("$pg_scribe_pid")
543 # Give it a moment to start
546 # Make changes before rotation
547 query_db "$dbname" "INSERT INTO users (name) VALUES ('Before Rotation');"
549 # Give it time to flush
552 # Find chain directory
553 local chain_dirs=("$backup_dir"/chain-*)
554 local chain_dir="${chain_dirs[0]}"
556 # Verify active.sql exists
557 if [[ ! -f "$chain_dir/active.sql" ]]; then
558 log_fail "active.sql not found before rotation"
563 "$PG_SCRIBE" --rotate-diff -f "$backup_dir" &>/dev/null
565 # Give pg_recvlogical time to reopen the file
568 # Verify sealed differential was created
569 local diff_files=("$chain_dir"/diff-*.sql)
570 if [[ ! -f "${diff_files[0]}" ]]; then
571 log_fail "Sealed differential not created"
575 # Verify new active.sql was created
576 if [[ ! -f "$chain_dir/active.sql" ]]; then
577 log_fail "New active.sql not created after rotation"
581 # Make changes after rotation
582 query_db "$dbname" "INSERT INTO users (name) VALUES ('After Rotation');"
584 # Give it time to flush
588 kill -INT "$pg_scribe_pid" 2>/dev/null || true
591 # Force kill if still running
592 if kill -0 "$pg_scribe_pid" 2>/dev/null; then
593 kill -9 "$pg_scribe_pid" 2>/dev/null || true
595 wait "$pg_scribe_pid" 2>/dev/null || true
597 # Verify sealed differential has "Before Rotation" but not "After Rotation"
598 if ! grep -q "Before Rotation" "${diff_files[0]}"; then
599 log_fail "Sealed differential missing data before rotation"
603 if grep -q "After Rotation" "${diff_files[0]}"; then
604 log_fail "Sealed differential should not contain data after rotation"
608 # Verify new active.sql has "After Rotation" but not "Before Rotation"
609 if ! grep -q "After Rotation" "$chain_dir/active.sql"; then
610 log_fail "New active.sql missing data after rotation"
614 if grep -q "Before Rotation" "$chain_dir/active.sql"; then
615 log_fail "New active.sql should not contain data before rotation"
619 log_pass "--rotate-diff works correctly"
623 test_rotate_diff_no_active_process() {
625 log_test "--rotate-diff without active process (should fail)"
627 local dbname="${TEST_DB_PREFIX}_rotate_noactive"
628 local slot="test_slot_rotate_noactive"
629 local backup_dir="$TEST_DIR/rotate_noactive"
631 # Setup - initialize but don't start streaming
632 create_test_db "$dbname"
633 create_table_with_pk "$dbname" "users"
634 initialize_backup_system "$dbname" "$slot" "$backup_dir"
636 # Try to rotate without active process - should fail
638 "$PG_SCRIBE" --rotate-diff -f "$backup_dir" &>/dev/null || exit_code=$?
640 if [[ $exit_code -ne 0 ]]; then
641 log_pass "Correctly failed when no active process"
644 log_fail "Should have failed with no active process"
649 test_rotate_diff_stale_pidfile() {
651 log_test "--rotate-diff with stale pidfile (should fail)"
653 local dbname="${TEST_DB_PREFIX}_rotate_stale"
654 local slot="test_slot_rotate_stale"
655 local backup_dir="$TEST_DIR/rotate_stale"
658 create_test_db "$dbname"
659 create_table_with_pk "$dbname" "users"
660 initialize_backup_system "$dbname" "$slot" "$backup_dir"
662 # Create a stale pidfile (process doesn't exist)
663 echo "99999" > "$backup_dir/.pg_scribe.pid"
665 # Try to rotate - should fail with stale pidfile
667 "$PG_SCRIBE" --rotate-diff -f "$backup_dir" &>/dev/null || exit_code=$?
669 if [[ $exit_code -ne 0 ]]; then
670 log_pass "Correctly failed with stale pidfile"
673 log_fail "Should have failed with stale pidfile"
678 test_rotate_diff_multiple() {
680 log_test "--rotate-diff multiple times"
682 local dbname="${TEST_DB_PREFIX}_rotate_multiple"
683 local slot="test_slot_rotate_multiple"
684 local backup_dir="$TEST_DIR/rotate_multiple"
687 create_test_db "$dbname"
688 create_table_with_pk "$dbname" "users"
689 initialize_backup_system "$dbname" "$slot" "$backup_dir"
691 # Start streaming in background
692 "$PG_SCRIBE" --start -d "$dbname" -f "$backup_dir" -S "$slot" -U "$PGUSER" -s 1 -F 1 &>/dev/null &
693 local pg_scribe_pid=$!
694 PIDS_TO_CLEANUP+=("$pg_scribe_pid")
696 # Give it a moment to start
699 local chain_dirs=("$backup_dir"/chain-*)
700 local chain_dir="${chain_dirs[0]}"
703 query_db "$dbname" "INSERT INTO users (name) VALUES ('First');"
705 "$PG_SCRIBE" --rotate-diff -f "$backup_dir" &>/dev/null
709 query_db "$dbname" "INSERT INTO users (name) VALUES ('Second');"
711 "$PG_SCRIBE" --rotate-diff -f "$backup_dir" &>/dev/null
715 query_db "$dbname" "INSERT INTO users (name) VALUES ('Third');"
717 "$PG_SCRIBE" --rotate-diff -f "$backup_dir" &>/dev/null
721 kill -INT "$pg_scribe_pid" 2>/dev/null || true
724 # Force kill if still running
725 if kill -0 "$pg_scribe_pid" 2>/dev/null; then
726 kill -9 "$pg_scribe_pid" 2>/dev/null || true
728 wait "$pg_scribe_pid" 2>/dev/null || true
730 # Verify we have 3 sealed differentials
732 diff_count=$(find "$chain_dir" -maxdepth 1 -name 'diff-*.sql' -type f 2>/dev/null | wc -l)
734 if [[ $diff_count -ne 3 ]]; then
735 log_fail "Expected 3 differentials, found $diff_count"
739 # Verify each differential has the correct data
740 local diff_files=("$chain_dir"/diff-*.sql)
742 if ! grep -q "First" "${diff_files[0]}"; then
743 log_fail "First differential missing expected data"
747 if ! grep -q "Second" "${diff_files[1]}"; then
748 log_fail "Second differential missing expected data"
752 if ! grep -q "Third" "${diff_files[2]}"; then
753 log_fail "Third differential missing expected data"
757 # Verify active.sql exists (from streaming after last rotation)
758 if [[ ! -f "$chain_dir/active.sql" ]]; then
759 log_fail "active.sql not found after multiple rotations"
763 log_pass "Multiple rotations work correctly"
771 # shellcheck disable=SC2317 # Function called via trap handler
773 log_info "Cleaning up test resources..."
775 # Kill any running pg_scribe processes
776 for pid in "${PIDS_TO_CLEANUP[@]}"; do
777 if kill -0 "$pid" 2>/dev/null; then
778 log_info "Stopping pg_scribe process $pid"
779 # Try graceful shutdown first (allows signal forwarding to child processes)
780 kill -TERM "$pid" 2>/dev/null || true
782 # Wait briefly for graceful shutdown
785 while kill -0 "$pid" 2>/dev/null && [[ $count -lt $timeout ]]; do
790 # Force kill if still running
791 if kill -0 "$pid" 2>/dev/null; then
792 log_info "Force killing pg_scribe process $pid"
793 kill -9 "$pid" 2>/dev/null || true
798 # Wait for child pg_recvlogical processes to fully terminate
799 # (They may take a moment to shut down after parent terminates)
802 # Drop replication slots
803 for dbname in "${DATABASES_TO_CLEANUP[@]}"; do
804 for slot in test_slot_noinit test_slot_basic test_slot_ddl test_slot_truncate test_slot_signal test_slot_interleaved test_slot_rotate_basic test_slot_rotate_noactive test_slot_rotate_stale test_slot_rotate_multiple; do
805 drop_replication_slot "$dbname" "$slot" 2>/dev/null || true
810 for dbname in "${DATABASES_TO_CLEANUP[@]}"; do
811 drop_test_db "$dbname"
814 # Remove test directory
815 if [[ -d "$TEST_DIR" ]]; then
819 log_info "Cleanup complete"
827 echo "========================================"
828 echo "pg_scribe --start Test Suite"
829 echo "========================================"
832 # Verify pg_scribe exists
833 if [[ ! -x "$PG_SCRIBE" ]]; then
834 echo "ERROR: pg_scribe not found or not executable: $PG_SCRIBE"
838 # Verify PostgreSQL is running
839 if ! psql -U "$PGUSER" -d postgres -c "SELECT 1;" &>/dev/null; then
840 echo "ERROR: Cannot connect to PostgreSQL"
844 # Verify wal_level is logical
846 wal_level=$(psql -U "$PGUSER" -d postgres -tAq -c "SHOW wal_level;")
847 if [[ "$wal_level" != "logical" ]]; then
848 echo "ERROR: wal_level must be 'logical', currently: $wal_level"
849 echo "Update ~/.pgenv/pgsql/data/postgresql.conf and restart PostgreSQL"
853 # Verify wal2sql extension is available
854 if ! pg_config --pkglibdir &>/dev/null; then
855 echo "ERROR: pg_config not found"
860 wal2sql_path="$(pg_config --pkglibdir)/wal2sql.so"
861 if [[ ! -f "$wal2sql_path" ]]; then
862 echo "ERROR: wal2sql.so not found at $wal2sql_path"
863 echo "Build and install wal2sql: cd wal2sql && make && make install"
867 # Create test directory
870 # Set up cleanup trap
871 trap cleanup EXIT INT TERM
873 echo "Running tests..."
876 # Run all tests (use || true to prevent set -e from exiting)
877 test_start_without_init || true
878 test_start_basic_streaming || true
879 test_start_ddl_capture || true
880 test_start_truncate_capture || true
881 test_start_signal_handling || true
882 test_start_interleaved_ddl_dml || true
883 test_rotate_diff_basic || true
884 test_rotate_diff_no_active_process || true
885 test_rotate_diff_stale_pidfile || true
886 test_rotate_diff_multiple || true
890 echo "========================================"
892 echo "========================================"
893 echo "Tests run: $TESTS_RUN"
894 echo -e "Tests passed: ${GREEN}$TESTS_PASSED${NC}"
895 echo -e "Tests failed: ${RED}$TESTS_FAILED${NC}"
898 if [[ $TESTS_FAILED -eq 0 ]]; then
899 echo -e "${GREEN}All tests passed!${NC}"
902 echo -e "${RED}Some tests failed!${NC}"