#!/usr/bin/env bash # tests/smoke-test.sh — the actual merge gate for this repo. Proves the # whole promise of the project end to end, not just that things compile: # # pack -> push -> publish -> `apt-get update && apt-get install` -> content # # against the real docker-compose.test.yaml stack (aptly-init -> aptly -> # nginx sidecar), using the same rootfs scripts and images CI ships. Nothing # here is mocked. Run from the repo root: ./tests/smoke-test.sh set -euo pipefail ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" cd "$ROOT_DIR" log() { printf '\033[1;34m[smoke]\033[0m %s\n' "$*"; } die() { printf '\033[1;31m[smoke] ERROR:\033[0m %s\n' "$*" >&2; exit 1; } COMPOSE_FILE="compose/docker-compose.test.yaml" PROJECT="aptly-smoke-$$" FIXTURE_DIR="tests/fixtures/demo-package" WORK_DIR="$(mktemp -d)" cleanup() { log "cleaning up (project: ${PROJECT})" docker compose -p "$PROJECT" -f "$COMPOSE_FILE" down -v --remove-orphans >/dev/null 2>&1 || true rm -rf "$WORK_DIR" } trap cleanup EXIT log "building images and starting the test stack" # Not --wait: it treats the `reconcile` one-shot service's expected exit(0) # as a failure and aborts. Poll nginx's own healthcheck instead. docker compose -p "$PROJECT" -f "$COMPOSE_FILE" up -d --build network="${PROJECT}_default" log "waiting for nginx to report healthy" deadline=$(( $(date +%s) + 120 )) until docker compose -p "$PROJECT" -f "$COMPOSE_FILE" ps nginx --format '{{.Health}}' 2>/dev/null | grep -q healthy; do (( $(date +%s) < deadline )) || die "nginx did not become healthy within 120s" sleep 2 done log "building the deb-builder image" docker build -q -f images/aptly-deb-builder/Dockerfile -t "aptly-deb-builder:${PROJECT}" . >/dev/null log "packaging the demo .deb with aptly-pack (nfpm path)" mkdir -p "${WORK_DIR}/dist" docker run --rm \ -v "${ROOT_DIR}/${FIXTURE_DIR}:/work:ro" \ -v "${WORK_DIR}/dist:/work-out" \ -w /tmp/pkg \ --entrypoint /bin/sh \ "aptly-deb-builder:${PROJECT}" \ -c "cp -r /work/. /tmp/pkg && aptly-pack --output-dir /work-out" deb_file="$(find "${WORK_DIR}/dist" -name '*.deb' | head -1)" [[ -n "$deb_file" ]] || die "aptly-pack produced no .deb" log "built: $(basename "$deb_file")" log "pushing the package into the (unsigned, open) test repo via aptly-push" # Reuses the already-built `reconcile` service's image/network via `compose # run` instead of guessing compose's image-naming convention. docker compose -p "$PROJECT" -f "$COMPOSE_FILE" run --rm --no-deps \ -e "APTLY_URL=http://aptly:8080" \ -v "${WORK_DIR}/dist:/dist:ro" \ --entrypoint /usr/local/bin/aptly-push \ reconcile \ --repo demo --distribution stable --no-sign "/dist/$(basename "$deb_file")" log "verifying via a real apt-get against the published repo (through nginx)" docker run --rm --network "$network" debian:trixie-slim bash -euxc " echo 'deb [trusted=yes] http://nginx:8080/ stable main' > /etc/apt/sources.list.d/smoke.list apt-get update apt-get install -y --no-install-recommends demo-package test \"\$(cat /usr/share/demo-package/hello.txt)\" = 'hello from aptly-containerized' " log "reconcile idempotency: re-running against unchanged state must not fail" docker compose -p "$PROJECT" -f "$COMPOSE_FILE" run --rm reconcile log "PASS — build -> push -> publish -> apt-get chain verified end to end"