Repository navigation
Expand file tree
/
Copy pathtest-postgres.sh
More file actions
executable file
·180 lines (157 loc) · 5.86 KB
/
Copy pathtest-postgres.sh
File metadata and controls
executable file
·180 lines (157 loc) · 5.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
. "$SCRIPT_DIR/polling.sh"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$REPO_ROOT"
DB_USER="${BITRIVER_TEST_POSTGRES_USER:-bitriver}"
DB_PASSWORD="${BITRIVER_TEST_POSTGRES_PASSWORD:-bitriver}"
DB_NAME="${BITRIVER_TEST_POSTGRES_DB:-bitriver_test}"
PORT="${BITRIVER_TEST_POSTGRES_PORT:-54329}"
IMAGE="${BITRIVER_TEST_POSTGRES_IMAGE:-postgres:15-alpine}"
CONTAINER_NAME="bitr-postgres-test-$$"
describe_dsn() {
python3 - "$1" <<'PY'
import sys
import urllib.parse
dsn = sys.argv[1]
parsed = urllib.parse.urlparse(dsn)
user = urllib.parse.unquote(parsed.username or "") or "unknown"
host = parsed.hostname or "unknown"
database = parsed.path.lstrip("/") or "unknown"
print(f"host={host} database={database} user={user}")
PY
}
preflight_failed() {
local reason="$1"
echo "error: postgres preflight failed (${reason})." >&2
echo " dsn: $(describe_dsn "$BITRIVER_TEST_POSTGRES_DSN")" >&2
echo " verify connectivity, credentials, and firewall rules before rerunning." >&2
}
apply_migrations_with_psql() {
local migrations_dir="$1"
mapfile -t migrations < <(find "$migrations_dir" -maxdepth 1 -type f -name '*.sql' | sort)
if [ ${#migrations[@]} -eq 0 ]; then
echo "error: no migrations found in $migrations_dir" >&2
exit 1
fi
echo "applying migrations from $migrations_dir" >&2
for migration in "${migrations[@]}"; do
base_name="$(basename "$migration")"
echo " -> $base_name" >&2
psql "$BITRIVER_TEST_POSTGRES_DSN" -v ON_ERROR_STOP=1 -f "$migration"
done
}
if [ -z "${BITRIVER_TEST_POSTGRES_DSN:-}" ]; then
if ! command -v docker >/dev/null 2>&1; then
echo "error: postgres-tagged tests require Docker or BITRIVER_TEST_POSTGRES_DSN; install Docker or set BITRIVER_TEST_POSTGRES_DSN to a prepared database" >&2
exit 1
fi
MIGRATIONS_DIR="$REPO_ROOT/deploy/migrations"
if [ ! -d "$MIGRATIONS_DIR" ]; then
echo "error: expected migrations under $MIGRATIONS_DIR" >&2
exit 1
fi
cleanup() {
docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true
}
trap cleanup EXIT INT TERM
export BITRIVER_TEST_POSTGRES_DSN="postgres://$DB_USER:$DB_PASSWORD@127.0.0.1:$PORT/$DB_NAME?sslmode=disable"
# shellcheck disable=SC2086
docker run \
--rm \
--detach \
--name "$CONTAINER_NAME" \
--publish "$PORT:5432" \
--env "POSTGRES_USER=$DB_USER" \
--env "POSTGRES_PASSWORD=$DB_PASSWORD" \
--env "POSTGRES_DB=$DB_NAME" \
--health-cmd="pg_isready -U $DB_USER -d $DB_NAME" \
--health-interval=5s \
--health-timeout=5s \
--health-retries=10 \
--volume "$MIGRATIONS_DIR:/migrations:ro" \
$IMAGE >/dev/null
wait_for_postgres_check() {
status=$(docker inspect --format '{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "")
if [ "$status" = "healthy" ]; then
return 0
fi
if [ "$status" = "unhealthy" ]; then
echo "error: postgres container failed health checks" >&2
docker logs "$CONTAINER_NAME" >&2 || true
return 2
fi
if ! docker ps --format '{{.Names}}' | grep -q "^$CONTAINER_NAME$"; then
echo "error: postgres container exited early" >&2
docker logs "$CONTAINER_NAME" >&2 || true
return 2
fi
return 1
}
echo "waiting for postgres to become ready..." >&2
if ! bounded_poll 60 1 wait_for_postgres_check; then
poll_rc=$?
if [ "$poll_rc" -eq 124 ]; then
echo "error: postgres container did not become ready" >&2
docker logs "$CONTAINER_NAME" >&2 || true
fi
exit 1
fi
echo "applying migrations from $MIGRATIONS_DIR" >&2
mapfile -t migrations < <(find "$MIGRATIONS_DIR" -maxdepth 1 -type f -name '*.sql' | sort)
if [ ${#migrations[@]} -eq 0 ]; then
echo "error: no migrations found in $MIGRATIONS_DIR" >&2
exit 1
fi
for migration in "${migrations[@]}"; do
base_name="$(basename "$migration")"
echo " -> $base_name" >&2
docker exec -e PGPASSWORD="$DB_PASSWORD" "$CONTAINER_NAME" \
psql -v ON_ERROR_STOP=1 \
-h localhost \
-U "$DB_USER" \
-d "$DB_NAME" \
-f "/migrations/$base_name"
done
else
echo "using provided BITRIVER_TEST_POSTGRES_DSN; skipping docker setup" >&2
if ! command -v psql >/dev/null 2>&1; then
echo "error: psql is required to run preflight checks when BITRIVER_TEST_POSTGRES_DSN is set" >&2
exit 1
fi
if ! psql "$BITRIVER_TEST_POSTGRES_DSN" -v ON_ERROR_STOP=1 -tAc "SELECT 1;" >/dev/null; then
preflight_failed "could not connect"
exit 1
fi
if ! psql "$BITRIVER_TEST_POSTGRES_DSN" -v ON_ERROR_STOP=1 -tAc "CREATE TEMP TABLE bitriver_preflight (id INT); DROP TABLE bitriver_preflight;" >/dev/null; then
preflight_failed "insufficient privileges"
exit 1
fi
schema_present="$(psql "$BITRIVER_TEST_POSTGRES_DSN" -v ON_ERROR_STOP=1 -tAc "SELECT 1 FROM information_schema.tables WHERE table_schema='public' AND table_name='users';")"
if [ "$schema_present" != "1" ]; then
migrations_dir="$REPO_ROOT/deploy/migrations"
if [ "${BITRIVER_TEST_POSTGRES_RUN_MIGRATIONS:-}" = "1" ]; then
apply_migrations_with_psql "$migrations_dir"
else
echo "error: expected schema not found in provided database." >&2
echo " dsn: $(describe_dsn "$BITRIVER_TEST_POSTGRES_DSN")" >&2
echo " apply migrations in $migrations_dir or set BITRIVER_TEST_POSTGRES_RUN_MIGRATIONS=1" >&2
exit 1
fi
fi
fi
default_packages=("./internal/storage/...")
if [ "$#" -gt 0 ]; then
packages=("$@")
else
packages=("${default_packages[@]}")
fi
echo "running go test -tags postgres ${packages[*]}" >&2
export GOTOOLCHAIN="${GOTOOLCHAIN:-local}"
# The postgres suite must run without contacting module proxies so local
# third_party replacements remain intact.
export GOPROXY="${GOPROXY:-off}"
export GOSUMDB="${GOSUMDB:-off}"
go test -count=1 -timeout=120s -tags postgres "${packages[@]}"