117 lines
6.2 KiB
Bash
117 lines
6.2 KiB
Bash
#!/usr/bin/env bash
|
|
# Actual Immich API fixture only. Never installed-node or Rust/browser acceptance.
|
|
set -euo pipefail
|
|
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
|
|
server=${ARCHY_CLOUD_IMMICH_IMAGE:?Immutable Immich 2.7.4 image required}
|
|
db=${ARCHY_CLOUD_IMMICH_DB_IMAGE:?Immutable compatible Postgres image required}
|
|
redis=${ARCHY_CLOUD_IMMICH_REDIS_IMAGE:?Immutable Redis image required}
|
|
if [[ ${ARCHY_CLOUD_BROWSER_QUALIFY:-0} == 1 ]]; then
|
|
: "${ARCHY_TEST_REUSE_ARTIFACT:?Compile and bind the artifact before starting Immich}"
|
|
: "${ARCHY_TEST_CLOUD_RUNTIME_IMAGE:?Exact browser runtime required}"
|
|
fi
|
|
for image in "$server" "$db" "$redis"; do
|
|
[[ "$image" =~ ^(sha256:)?[a-f0-9]{64}$ ]] || { echo 'Full immutable image IDs required' >&2; exit 2; }
|
|
podman image exists "$image"
|
|
done
|
|
work=$(mktemp -d /tmp/archy-immich.XXXXXXXX)
|
|
name="archy-cloud-immich-${work##*.}"
|
|
containers=()
|
|
cleanup() {
|
|
result=$?
|
|
trap - EXIT
|
|
for ((i=${#containers[@]}-1; i>=0; i--)); do
|
|
c=${containers[$i]}
|
|
if ! podman container exists "$c"; then continue; fi
|
|
if [[ "$result" != 0 ]]; then
|
|
timeout 5 podman inspect "$c" --format '{{json .State}}' || true
|
|
timeout 5 podman exec "$c" /bin/sh -c 'grep . /sys/fs/cgroup/memory.events /sys/fs/cgroup/memory.peak /sys/fs/cgroup/memory.max /sys/fs/cgroup/memory.swap.max' || true
|
|
timeout 5 podman logs --tail 200 "$c" 2>&1 || true
|
|
fi
|
|
timeout --kill-after=2s 20 podman rm -f --volumes --time 0 "$c" >/dev/null 2>&1 || true
|
|
if podman container exists "$c"; then echo "Cleanup failed: $c" >&2; result=1; fi
|
|
done
|
|
rm -rf -- "$work"
|
|
exit "$result"
|
|
}
|
|
trap cleanup EXIT
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
: > "$work/resolv.conf"
|
|
# No host inventory; upstream workers still need standard loopback resolution.
|
|
printf '127.0.0.1 localhost\n::1 localhost\n' > "$work/hosts"
|
|
common=(--pull=never --image-volume=ignore --read-only --pid=private --ipc=private --http-proxy=false
|
|
--no-hosts --cap-drop=all --security-opt=no-new-privileges --cpus=1
|
|
--pids-limit=128 --timeout=420 --log-driver=k8s-file --log-opt=max-size=4mb
|
|
--label org.archipelago.cloud-fixture=immich274-v1
|
|
--volume "$work/resolv.conf:/etc/resolv.conf:ro"
|
|
--volume "$work/hosts:/etc/hosts:ro"
|
|
--tmpfs /tmp:rw,notmpcopyup,nosuid,nodev,size=64m)
|
|
# The database owns a network-none namespace; no infra image or published ports.
|
|
containers+=("$name-db")
|
|
podman run -d --name "$name-db" "${common[@]}" --network=none \
|
|
--memory=1g --memory-swap=1g --cap-add=chown,dac_override,fowner,setuid,setgid \
|
|
--tmpfs /var/lib/postgresql/data:rw,nosuid,nodev,size=768m \
|
|
--tmpfs /run/postgresql:rw,nosuid,nodev,size=16m \
|
|
--tmpfs /etc/postgresql:rw,nosuid,nodev,size=8m \
|
|
--env POSTGRES_PASSWORD=Synthetic-Immich-DB-Only-2026! \
|
|
--env POSTGRES_USER=postgres --env POSTGRES_DB=immich "$db" >/dev/null
|
|
common+=(--network="container:$name-db")
|
|
containers+=("$name-redis")
|
|
podman run -d --name "$name-redis" "${common[@]}" --memory=128m --memory-swap=128m \
|
|
--cap-add=chown,setuid,setgid --tmpfs /data:rw,nosuid,nodev,size=64m \
|
|
"$redis" redis-server --save '' --appendonly no >/dev/null
|
|
ready=0
|
|
for _ in $(seq 1 60); do
|
|
if timeout --kill-after=2s 3 podman exec "$name-db" pg_isready -U postgres -d immich >/dev/null 2>&1; then ready=1; break; fi
|
|
sleep 1
|
|
done
|
|
[[ "$ready" == 1 ]] || { echo 'Database readiness failed' >&2; exit 1; }
|
|
containers+=("$name-server")
|
|
podman run -d --name "$name-server" "${common[@]}" --cpus=2 \
|
|
--memory=2g --memory-swap=2g --pids-limit=256 \
|
|
--tmpfs /usr/src/app/upload:rw,nosuid,nodev,size=256m \
|
|
--env DB_HOSTNAME=127.0.0.1 --env DB_USERNAME=postgres --env DB_DATABASE_NAME=immich \
|
|
--env DB_PASSWORD=Synthetic-Immich-DB-Only-2026! --env REDIS_HOSTNAME=127.0.0.1 \
|
|
--env UPLOAD_LOCATION=/usr/src/app/upload --env IMMICH_MACHINE_LEARNING_ENABLED=false \
|
|
--volume "$repo/tests/cloud/immich-upstream-contract.mjs:/contract.mjs:ro" \
|
|
--volume "$repo/tests/cloud/immich-fixture.png:/fixture.png:ro" "$server" >/dev/null
|
|
ready=0
|
|
for _ in $(seq 1 90); do
|
|
if timeout --kill-after=2s 3 podman exec "$name-server" node -e \
|
|
'fetch("http://127.0.0.1:2283/api/server/ping",{signal:AbortSignal.timeout(1500)}).then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))' >/dev/null 2>&1; then ready=1; break; fi
|
|
sleep 2
|
|
done
|
|
[[ "$ready" == 1 ]] || { echo 'Immich readiness failed' >&2; exit 1; }
|
|
# /server/ping is ready before the separate worker finishes its fresh geodata
|
|
# import. Do not spend the thumbnail assertion's budget waiting for bootstrap.
|
|
ready=0
|
|
for _ in $(seq 1 90); do
|
|
logs=$(timeout --kill-after=2s 10 podman logs --tail 80 "$name-server" 2>&1) || { echo 'Worker log readiness probe timed out' >&2; continue; }
|
|
if [[ "$logs" == *'Immich Microservices is running'* ]]; then ready=1; break; fi
|
|
sleep 2
|
|
done
|
|
[[ "$ready" == 1 ]] || { echo 'Immich worker readiness failed' >&2; exit 1; }
|
|
podman inspect "$name-db" "$name-redis" "$name-server" |
|
|
python3 "$repo/scripts/validate-immich-test-fixture.py" "$name" "$db" "$redis" "$server" >/dev/null
|
|
if [[ ${ARCHY_CLOUD_BROWSER_QUALIFY:-0} == 1 ]]; then
|
|
: "${ARCHY_TEST_REUSE_ARTIFACT:?Compile and bind the artifact before starting Immich}"
|
|
: "${ARCHY_TEST_CLOUD_RUNTIME_IMAGE:?Exact browser runtime required}"
|
|
run_bound_tests() {
|
|
ARCHY_TEST_ISOLATOR=podman ARCHY_TEST_CLOUD_UPSTREAM=immich274 \
|
|
ARCHY_TEST_CLOUD_FIXTURE_CONTAINER="$name-db" ARCHY_TEST_CLOUD_FIXTURE_IMAGE="$db" \
|
|
ARCHY_TEST_IMMICH_SERVER_IMAGE="$server" ARCHY_TEST_IMMICH_REDIS_IMAGE="$redis" \
|
|
bash "$repo/scripts/test-backend-isolated.sh" "$@"
|
|
}
|
|
# Matching focused source tests and actual browser share one retained binary.
|
|
# Ignored real-Nextcloud tests are not selected by the normal unit filter.
|
|
run_bound_tests cloud_sources:: --nocapture
|
|
run_bound_tests --ignored --exact api::handler::cloud_browser_tests::immich_browser_rpc_without_filebrowser --nocapture
|
|
else
|
|
timeout --kill-after=5s 120 podman exec "$name-server" node /contract.mjs
|
|
fi
|
|
if [[ ${ARCHY_CLOUD_BROWSER_QUALIFY:-0} == 1 ]]; then
|
|
echo 'PASS isolated Immich source and production browser/RPC batch; synthetic session/runtime binding, not installed lifecycle or native identity acceptance.'
|
|
else
|
|
echo 'PASS portable isolated Immich protocol; not Rust/browser, installed lifecycle or native identity acceptance.'
|
|
fi
|