summaryrefslogtreecommitdiff
path: root/qa/lifecycle-test.sh
blob: ace6a08f81401712ce0d46aa68b336504229add8 (plain)
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
#!/usr/bin/env bash
# Lifecycle regression for qa/run.sh refusal paths.
# Verifies that run.sh refuses to start when a container name or port is
# already taken, and that the refusal leaves the pre-existing resources
# untouched (no container deletion, no killing of the port holder).
# The script only manages resources it created itself.
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PG_CONTAINER=fund-lab-qa-pg-3c1
PG_IMAGE=postgres:16-alpine
API_PORT=5095
TMP="$(mktemp -d /tmp/opencode/fund-lab-qa-lifecycle-XXXXXX)"
HOLDER_PID=""

cleanup() {
  local status=$?
  trap - EXIT INT TERM
  [ -n "$HOLDER_PID" ] && kill "$HOLDER_PID" 2>/dev/null || true
  [ -n "$HOLDER_PID" ] && wait "$HOLDER_PID" 2>/dev/null || true
  if [ -n "$DUMMY_ID" ]; then
    owned="$(docker ps -a --filter "id=$DUMMY_ID" --format '{{.Names}}' 2>/dev/null || true)"
    [ "$owned" = "$PG_CONTAINER" ] && docker rm -f "$DUMMY_ID" >/dev/null 2>&1 || true
  fi
  rm -rf "$TMP"
  exit "$status"
}
DUMMY_ID=""
trap cleanup EXIT INT TERM

log() { printf '[lifecycle] %s\n' "$*"; }
fail() { printf '[lifecycle] FAIL: %s\n' "$*" >&2; exit 1; }
pass() { printf '[lifecycle] PASS: %s\n' "$*"; }

command -v docker >/dev/null || fail "docker is required"
docker info >/dev/null 2>&1 || fail "docker daemon is not reachable"
docker image inspect "$PG_IMAGE" >/dev/null 2>&1 || fail "$PG_IMAGE is not available locally"
docker ps -a --format '{{.Names}}' | grep -qx "$PG_CONTAINER" && fail "container $PG_CONTAINER already exists; refusing to proceed"

log "scenario 1: pre-existing container name is refused and preserved"
DUMMY_ID="$(docker run -d --name "$PG_CONTAINER" "$PG_IMAGE" sleep 120)"
if bash "$ROOT/qa/run.sh" >"$TMP/refuse-container.log" 2>&1; then
  fail "run.sh should refuse when $PG_CONTAINER already exists"
fi
grep -q "already exists" "$TMP/refuse-container.log" || fail "refusal reason missing from log"
[ "$(docker ps -a --filter "id=$DUMMY_ID" --format '{{.Names}}' 2>/dev/null)" = "$PG_CONTAINER" ] \
  || fail "pre-existing container was removed or modified by the refused run"
pass "refusal preserved the pre-existing container"
docker rm -f "$DUMMY_ID" >/dev/null
DUMMY_ID=""

log "scenario 2: occupied API port is refused and the holder is untouched"
python3 -m http.server "$API_PORT" --bind 127.0.0.1 >/dev/null 2>&1 &
HOLDER_PID=$!
sleep 0.5
kill -0 "$HOLDER_PID" 2>/dev/null || fail "port holder failed to start"
if bash "$ROOT/qa/run.sh" >"$TMP/refuse-port.log" 2>&1; then
  fail "run.sh should refuse when port $API_PORT is occupied"
fi
grep -q "port $API_PORT is already in use" "$TMP/refuse-port.log" || fail "refusal reason missing from log"
kill -0 "$HOLDER_PID" 2>/dev/null || fail "port holder was killed by the refused run"
pass "refusal preserved the port holder"

log "all lifecycle scenarios passed"