|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Smoke test for sqlite-watcher + database-replicator incremental sync |
| 3 | +# Requires: docker, sqlite-watcher, database-replicator, sqlite3 |
| 4 | + |
| 5 | +set -euo pipefail |
| 6 | + |
| 7 | +if ! command -v docker >/dev/null; then |
| 8 | + echo "[smoke] docker is required" >&2 |
| 9 | + exit 1 |
| 10 | +fi |
| 11 | +if ! command -v sqlite-watcher >/dev/null; then |
| 12 | + echo "[smoke] sqlite-watcher binary not found in PATH" >&2 |
| 13 | + exit 1 |
| 14 | +fi |
| 15 | +if ! command -v database-replicator >/dev/null; then |
| 16 | + echo "[smoke] database-replicator binary not found in PATH" >&2 |
| 17 | + exit 1 |
| 18 | +fi |
| 19 | + |
| 20 | +TMPDIR=$(mktemp -d) |
| 21 | +QUEUE_DB="$TMPDIR/queue.db" |
| 22 | +SOCK="$TMPDIR/watcher.sock" |
| 23 | +TOKEN_FILE="$TMPDIR/token" |
| 24 | +POSTGRES_PORT=55432 |
| 25 | +CONTAINER_NAME=sqlite-delta-smoke |
| 26 | + |
| 27 | +cleanup() { |
| 28 | + set +e |
| 29 | + if [[ -n "${WATCHER_PID:-}" ]]; then |
| 30 | + kill "$WATCHER_PID" >/dev/null 2>&1 || true |
| 31 | + fi |
| 32 | + docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true |
| 33 | + rm -rf "$TMPDIR" |
| 34 | +} |
| 35 | +trap cleanup EXIT |
| 36 | + |
| 37 | +echo "[smoke] preparing token + queue" |
| 38 | +mkdir -p "$(dirname "$TOKEN_FILE")" |
| 39 | +printf 'smoke-%s' "$RANDOM" > "$TOKEN_FILE" |
| 40 | +chmod 600 "$TOKEN_FILE" |
| 41 | + |
| 42 | +sqlite-watcher enqueue --queue-db "$QUEUE_DB" --table demo --id smoke --payload '{"message":"hello-from-watcher"}' |
| 43 | + |
| 44 | +sqlite-watcher serve --queue-db "$QUEUE_DB" --listen "unix:$SOCK" --token-file "$TOKEN_FILE" >/dev/null 2>&1 & |
| 45 | +WATCHER_PID=$! |
| 46 | +sleep 1 |
| 47 | + |
| 48 | +echo "[smoke] starting postgres container" |
| 49 | +docker run -d --rm \ |
| 50 | + --name "$CONTAINER_NAME" \ |
| 51 | + -e POSTGRES_PASSWORD=postgres \ |
| 52 | + -p "$POSTGRES_PORT":5432 \ |
| 53 | + postgres:15 >/dev/null |
| 54 | + |
| 55 | +until docker exec "$CONTAINER_NAME" pg_isready -U postgres >/dev/null 2>&1; do |
| 56 | + sleep 1 |
| 57 | +done |
| 58 | + |
| 59 | +docker exec "$CONTAINER_NAME" psql -U postgres <<'SQL' |
| 60 | +CREATE TABLE IF NOT EXISTS demo ( |
| 61 | + id TEXT PRIMARY KEY, |
| 62 | + data JSONB NOT NULL, |
| 63 | + _source_type TEXT NOT NULL DEFAULT 'sqlite', |
| 64 | + _migrated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() |
| 65 | +); |
| 66 | +CREATE TABLE IF NOT EXISTS sqlite_sync_state ( |
| 67 | + table_name TEXT PRIMARY KEY, |
| 68 | + last_change_id BIGINT NOT NULL DEFAULT 0, |
| 69 | + last_wal_frame TEXT, |
| 70 | + cursor TEXT, |
| 71 | + snapshot_completed BOOLEAN NOT NULL DEFAULT FALSE, |
| 72 | + incremental_mode TEXT NOT NULL DEFAULT 'append', |
| 73 | + baseline_at TIMESTAMPTZ NOT NULL DEFAULT NOW() |
| 74 | +); |
| 75 | +INSERT INTO sqlite_sync_state(table_name, snapshot_completed, incremental_mode) |
| 76 | +VALUES ('demo', TRUE, 'append') |
| 77 | +ON CONFLICT(table_name) DO UPDATE SET snapshot_completed = EXCLUDED.snapshot_completed, |
| 78 | + incremental_mode = EXCLUDED.incremental_mode; |
| 79 | +SQL |
| 80 | + |
| 81 | +echo "[smoke] running sync-sqlite" |
| 82 | +DATABASE_URL="postgresql://postgres:postgres@localhost:$POSTGRES_PORT/postgres" |
| 83 | +database-replicator sync-sqlite \ |
| 84 | + --target "$DATABASE_URL" \ |
| 85 | + --watcher-endpoint "unix:$SOCK" \ |
| 86 | + --token-file "$TOKEN_FILE" \ |
| 87 | + --batch-size 50 \ |
| 88 | + --incremental-mode append >/dev/null |
| 89 | + |
| 90 | +docker exec "$CONTAINER_NAME" psql -U postgres -tAc "SELECT count(*) FROM demo WHERE id = 'smoke'" | grep -q '^ 1' |
| 91 | + |
| 92 | +echo "[smoke] success! sqlite-watcher + sync-sqlite end-to-end" |
| 93 | +echo "[windows] Manual steps: run sqlite-watcher serve with tcp listener, start a Postgres instance (Docker Desktop works), then run database-replicator sync-sqlite with the TCP watcher endpoint." |
0 commit comments