-
Notifications
You must be signed in to change notification settings - Fork 19
Add startup smoke tests for Linux binary and Docker image #147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
c876ca4
Add startup smoke tests for Linux binary and Docker image
claude 3434688
Consolidate CI and dev-release into a single workflow
claude 3103cbf
Update dev-release.yml
mcowger ff2ad6c
fix: use pushd/popd so PID captures the actual binary process
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| #!/usr/bin/env bash | ||
| # test-startup-binary.sh | ||
| # Smoke-test the compiled Linux binary: verify it starts, serves /health, and loads /ui/. | ||
| # | ||
| # Usage: bash scripts/test-startup-binary.sh | ||
| # Expected working directory: repository root (where plexus-linux lives after compile:linux) | ||
| set -euo pipefail | ||
|
|
||
| ADMIN_KEY="test-startup-key-ci" | ||
| PORT=14000 | ||
|
mcowger marked this conversation as resolved.
|
||
| TIMEOUT=60 | ||
| BINARY_WORKDIR="packages/backend" | ||
| BINARY_NAME="plexus-linux" | ||
| LOG_FILE="/tmp/plexus-binary-startup.log" | ||
|
|
||
| echo "=== Binary Startup Test ===" | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Cleanup: kill background process and remove temp binary copy | ||
| # ------------------------------------------------------------------ | ||
| cleanup() { | ||
| if [[ -n "${PID:-}" ]]; then | ||
| echo "Stopping binary (PID=$PID)..." | ||
| kill "$PID" 2>/dev/null || true | ||
| wait "$PID" 2>/dev/null || true | ||
| fi | ||
| rm -f "${BINARY_WORKDIR}/${BINARY_NAME}" | ||
| } | ||
|
mcowger marked this conversation as resolved.
|
||
| trap cleanup EXIT | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Stage binary in the backend package directory so that the static | ||
| # file path ../frontend/dist resolves to packages/frontend/dist. | ||
| # ------------------------------------------------------------------ | ||
| if [[ ! -f "./${BINARY_NAME}" ]]; then | ||
| echo "ERROR: ./${BINARY_NAME} not found. Run 'bun run compile:linux' first." | ||
| exit 1 | ||
| fi | ||
|
|
||
| cp "./${BINARY_NAME}" "${BINARY_WORKDIR}/${BINARY_NAME}" | ||
| chmod +x "${BINARY_WORKDIR}/${BINARY_NAME}" | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Start the binary | ||
| # ------------------------------------------------------------------ | ||
| echo "Starting binary from ${BINARY_WORKDIR}/..." | ||
| pushd "${BINARY_WORKDIR}" >/dev/null | ||
| DATABASE_URL="sqlite://:memory:" \ | ||
| ADMIN_KEY="${ADMIN_KEY}" \ | ||
| PORT="${PORT}" \ | ||
| LOG_LEVEL="info" \ | ||
| "./${BINARY_NAME}" > "${LOG_FILE}" 2>&1 & | ||
| PID=$! | ||
| popd >/dev/null | ||
| echo "Binary PID: ${PID}" | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Wait for the "Server starting on port" log line | ||
| # ------------------------------------------------------------------ | ||
| echo "Waiting for server to start (timeout: ${TIMEOUT}s)..." | ||
| STARTED=0 | ||
| for i in $(seq 1 "${TIMEOUT}"); do | ||
| if grep -q "Server starting on port" "${LOG_FILE}" 2>/dev/null; then | ||
| echo "Server ready (detected after ~${i}s)" | ||
| STARTED=1 | ||
| break | ||
| fi | ||
| if ! kill -0 "${PID}" 2>/dev/null; then | ||
| echo "ERROR: Binary exited prematurely after ${i}s" | ||
| echo "=== Log output ===" | ||
| cat "${LOG_FILE}" | ||
| exit 1 | ||
| fi | ||
| sleep 1 | ||
| done | ||
|
|
||
| if [[ "${STARTED}" -eq 0 ]]; then | ||
| echo "ERROR: Server did not log readiness within ${TIMEOUT}s" | ||
| echo "=== Log output ===" | ||
| cat "${LOG_FILE}" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Brief pause to ensure the TCP port is fully accepting connections | ||
| sleep 1 | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Test /health | ||
| # ------------------------------------------------------------------ | ||
| echo "Testing GET /health ..." | ||
| HEALTH_RESPONSE=$(curl -sf --max-time 10 "http://localhost:${PORT}/health" || echo "CURL_FAILED") | ||
| if [[ "${HEALTH_RESPONSE}" != "OK" ]]; then | ||
| echo "ERROR: /health returned unexpected response: '${HEALTH_RESPONSE}'" | ||
| echo "=== Log output ===" | ||
| cat "${LOG_FILE}" | ||
| exit 1 | ||
| fi | ||
| echo " /health -> OK" | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Test /ui/ returns HTTP 200 with HTML content | ||
| # ------------------------------------------------------------------ | ||
| echo "Testing GET /ui/ ..." | ||
| HTTP_CODE=$(curl -s --max-time 10 -o /tmp/plexus-binary-ui.html -w "%{http_code}" \ | ||
| "http://localhost:${PORT}/ui/") | ||
| if [[ "${HTTP_CODE}" != "200" ]]; then | ||
| echo "ERROR: /ui/ returned HTTP ${HTTP_CODE}" | ||
| echo "=== Response body ===" | ||
| cat /tmp/plexus-binary-ui.html 2>/dev/null || true | ||
| echo "=== Log output ===" | ||
| cat "${LOG_FILE}" | ||
| exit 1 | ||
| fi | ||
| if ! grep -qi "<html\|<!doctype" /tmp/plexus-binary-ui.html 2>/dev/null; then | ||
| echo "ERROR: /ui/ response does not appear to be HTML" | ||
| echo "=== Response body (first 512 bytes) ===" | ||
| head -c 512 /tmp/plexus-binary-ui.html | ||
| echo "=== Log output ===" | ||
| cat "${LOG_FILE}" | ||
| exit 1 | ||
| fi | ||
| echo " /ui/ -> HTTP ${HTTP_CODE} (HTML confirmed)" | ||
|
|
||
| echo "" | ||
| echo "Binary startup test PASSED" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| #!/usr/bin/env bash | ||
| # test-startup-docker.sh | ||
| # Smoke-test the Docker image: verify it starts, serves /health, and loads /ui/. | ||
| # | ||
| # Usage: bash scripts/test-startup-docker.sh [image-tag] | ||
| # Expected working directory: repository root | ||
| # Default image tag: plexus-test:latest | ||
| set -euo pipefail | ||
|
|
||
| IMAGE="${1:-plexus-test:latest}" | ||
| ADMIN_KEY="test-startup-key-ci" | ||
| HOST_PORT=14001 | ||
|
mcowger marked this conversation as resolved.
|
||
| CONTAINER_PORT=4000 | ||
| TIMEOUT=60 | ||
| CONTAINER_NAME="plexus-startup-test-$$" | ||
|
|
||
| echo "=== Docker Startup Test (${IMAGE}) ===" | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Cleanup: always stop and remove the test container | ||
| # ------------------------------------------------------------------ | ||
| cleanup() { | ||
| if docker inspect "${CONTAINER_NAME}" &>/dev/null; then | ||
| echo "Stopping container ${CONTAINER_NAME}..." | ||
| docker stop "${CONTAINER_NAME}" 2>/dev/null || true | ||
| docker rm "${CONTAINER_NAME}" 2>/dev/null || true | ||
| fi | ||
| } | ||
| trap cleanup EXIT | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Start the container with an in-memory SQLite database so no | ||
| # persistent volume is required. | ||
| # ------------------------------------------------------------------ | ||
| echo "Starting container..." | ||
| docker run -d \ | ||
| --name "${CONTAINER_NAME}" \ | ||
| -p "${HOST_PORT}:${CONTAINER_PORT}" \ | ||
| -e "ADMIN_KEY=${ADMIN_KEY}" \ | ||
| -e "DATABASE_URL=sqlite://:memory:" \ | ||
| -e "LOG_LEVEL=info" \ | ||
| "${IMAGE}" | ||
|
|
||
| echo "Container started: ${CONTAINER_NAME}" | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Wait for the "Server starting on port" log line | ||
| # ------------------------------------------------------------------ | ||
| echo "Waiting for server to start (timeout: ${TIMEOUT}s)..." | ||
| STARTED=0 | ||
| for i in $(seq 1 "${TIMEOUT}"); do | ||
| if docker logs "${CONTAINER_NAME}" 2>&1 | grep -q "Server starting on port"; then | ||
| echo "Server ready (detected after ~${i}s)" | ||
|
mcowger marked this conversation as resolved.
|
||
| STARTED=1 | ||
| break | ||
| fi | ||
| # Check if the container is still running | ||
| STATUS=$(docker inspect --format='{{.State.Status}}' "${CONTAINER_NAME}" 2>/dev/null || echo "missing") | ||
| if [[ "${STATUS}" != "running" ]]; then | ||
| echo "ERROR: Container stopped unexpectedly after ${i}s (status=${STATUS})" | ||
| echo "=== Container logs ===" | ||
| docker logs "${CONTAINER_NAME}" 2>&1 || true | ||
| exit 1 | ||
| fi | ||
| sleep 1 | ||
| done | ||
|
|
||
| if [[ "${STARTED}" -eq 0 ]]; then | ||
| echo "ERROR: Server did not log readiness within ${TIMEOUT}s" | ||
| echo "=== Container logs ===" | ||
| docker logs "${CONTAINER_NAME}" 2>&1 || true | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Brief pause to ensure the TCP port is fully accepting connections | ||
| sleep 1 | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Test /health | ||
| # ------------------------------------------------------------------ | ||
| echo "Testing GET /health ..." | ||
| HEALTH_RESPONSE=$(curl -sf --max-time 10 "http://localhost:${HOST_PORT}/health" || echo "CURL_FAILED") | ||
| if [[ "${HEALTH_RESPONSE}" != "OK" ]]; then | ||
| echo "ERROR: /health returned unexpected response: '${HEALTH_RESPONSE}'" | ||
| echo "=== Container logs ===" | ||
| docker logs "${CONTAINER_NAME}" 2>&1 || true | ||
| exit 1 | ||
| fi | ||
| echo " /health -> OK" | ||
|
|
||
| # ------------------------------------------------------------------ | ||
| # Test /ui/ returns HTTP 200 with HTML content | ||
| # ------------------------------------------------------------------ | ||
| echo "Testing GET /ui/ ..." | ||
| HTTP_CODE=$(curl -s --max-time 10 -o /tmp/plexus-docker-ui.html -w "%{http_code}" \ | ||
| "http://localhost:${HOST_PORT}/ui/") | ||
| if [[ "${HTTP_CODE}" != "200" ]]; then | ||
| echo "ERROR: /ui/ returned HTTP ${HTTP_CODE}" | ||
| echo "=== Response body ===" | ||
| cat /tmp/plexus-docker-ui.html 2>/dev/null || true | ||
| echo "=== Container logs ===" | ||
| docker logs "${CONTAINER_NAME}" 2>&1 || true | ||
| exit 1 | ||
| fi | ||
| if ! grep -qi "<html\|<!doctype" /tmp/plexus-docker-ui.html 2>/dev/null; then | ||
| echo "ERROR: /ui/ response does not appear to be HTML" | ||
| echo "=== Response body (first 512 bytes) ===" | ||
| head -c 512 /tmp/plexus-docker-ui.html | ||
| echo "=== Container logs ===" | ||
| docker logs "${CONTAINER_NAME}" 2>&1 || true | ||
| exit 1 | ||
| fi | ||
| echo " /ui/ -> HTTP ${HTTP_CODE} (HTML confirmed)" | ||
|
|
||
| echo "" | ||
| echo "Docker startup test PASSED" | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.