Skip to content

Commit 5f9740b

Browse files
committed
🤖 ci: add smoke test suite for npm package
Add comprehensive smoke test suite that validates: - npm package installation from tarball - server startup with 'mux server' command - healthcheck endpoint returns valid JSON response - root endpoint is accessible The smoke test runs on merge to main and can also be run locally with: make smoke-test Test includes: - Proper cleanup of server processes and temp directories - Configurable timeouts for startup and healthcheck - Colored output for better visibility - Server logs uploaded as artifacts on failure _Generated with `mux`_
1 parent 16fa272 commit 5f9740b

File tree

3 files changed

+244
-1
lines changed

3 files changed

+244
-1
lines changed

.github/workflows/smoke-test.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Smoke Test
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
smoke-test:
15+
name: NPM Package Smoke Test
16+
runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }}
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
with:
21+
fetch-depth: 0 # Required for git describe to find tags
22+
23+
- uses: ./.github/actions/setup-mux
24+
25+
- name: Generate version file
26+
run: ./scripts/generate-version.sh
27+
28+
- name: Build the project
29+
run: make build
30+
31+
- name: Pack npm package
32+
run: npm pack
33+
id: pack
34+
35+
- name: Find package tarball
36+
id: find-tarball
37+
run: |
38+
TARBALL=$(ls mux-*.tgz | head -1)
39+
echo "tarball=$TARBALL" >> $GITHUB_OUTPUT
40+
echo "Found package: $TARBALL"
41+
42+
- name: Run smoke test
43+
env:
44+
PACKAGE_TARBALL: ${{ steps.find-tarball.outputs.tarball }}
45+
SERVER_PORT: 3000
46+
SERVER_HOST: localhost
47+
STARTUP_TIMEOUT: 30
48+
run: |
49+
./scripts/smoke-test.sh
50+
51+
- name: Upload server logs on failure
52+
if: failure()
53+
uses: actions/upload-artifact@v4
54+
with:
55+
name: smoke-test-logs
56+
path: |
57+
/tmp/mux-smoke-test-*/server.log
58+
if-no-files-found: warn
59+
retention-days: 7

Makefile

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ include fmt.mk
4646
.PHONY: all build dev start clean help
4747
.PHONY: build-renderer version build-icons build-static
4848
.PHONY: lint lint-fix typecheck static-check
49-
.PHONY: test test-unit test-integration test-watch test-coverage test-e2e
49+
.PHONY: test test-unit test-integration test-watch test-coverage test-e2e smoke-test
5050
.PHONY: dist dist-mac dist-win dist-linux
5151
.PHONY: vscode-ext vscode-ext-install
5252
.PHONY: docs docs-build docs-watch
@@ -255,6 +255,17 @@ test-watch: ## Run tests in watch mode
255255
test-coverage: ## Run tests with coverage
256256
@./scripts/test.sh --coverage
257257

258+
259+
smoke-test: build ## Run smoke test on npm package
260+
@echo "Building npm package tarball..."
261+
@npm pack
262+
@TARBALL=$$(ls mux-*.tgz | head -1); \
263+
echo "Running smoke test on $$TARBALL..."; \
264+
PACKAGE_TARBALL="$$TARBALL" ./scripts/smoke-test.sh; \
265+
EXIT_CODE=$$?; \
266+
rm -f "$$TARBALL"; \
267+
exit $$EXIT_CODE
268+
258269
test-e2e: ## Run end-to-end tests
259270
@$(MAKE) build
260271
@MUX_E2E_LOAD_DIST=1 MUX_E2E_SKIP_BUILD=1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 bun x playwright test --project=electron $(PLAYWRIGHT_ARGS)

scripts/smoke-test.sh

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#!/usr/bin/env bash
2+
# Smoke test for mux npm package
3+
# Tests that the package can be installed and the server starts correctly
4+
5+
set -euo pipefail
6+
7+
# Colors for output
8+
RED='\033[0;31m'
9+
GREEN='\033[0;32m'
10+
YELLOW='\033[1;33m'
11+
NC='\033[0m' # No Color
12+
13+
# Logging functions
14+
log_info() {
15+
echo -e "${GREEN}[INFO]${NC} $*"
16+
}
17+
18+
log_error() {
19+
echo -e "${RED}[ERROR]${NC} $*" >&2
20+
}
21+
22+
log_warning() {
23+
echo -e "${YELLOW}[WARNING]${NC} $*"
24+
}
25+
26+
# Cleanup function
27+
cleanup() {
28+
local exit_code=$?
29+
log_info "Cleaning up..."
30+
31+
# Kill server if it's running
32+
if [[ -n "${SERVER_PID:-}" ]] && kill -0 "$SERVER_PID" 2>/dev/null; then
33+
log_info "Stopping server (PID: $SERVER_PID)..."
34+
kill "$SERVER_PID" 2>/dev/null || true
35+
wait "$SERVER_PID" 2>/dev/null || true
36+
fi
37+
38+
# Remove test directory
39+
if [[ -n "${TEST_DIR:-}" ]] && [[ -d "$TEST_DIR" ]]; then
40+
log_info "Removing test directory: $TEST_DIR"
41+
rm -rf "$TEST_DIR"
42+
fi
43+
44+
if [[ $exit_code -eq 0 ]]; then
45+
log_info "✅ Smoke test completed successfully"
46+
else
47+
log_error "❌ Smoke test failed with exit code $exit_code"
48+
fi
49+
50+
exit $exit_code
51+
}
52+
53+
trap cleanup EXIT INT TERM
54+
55+
# Configuration
56+
PACKAGE_TARBALL="${PACKAGE_TARBALL:-}"
57+
SERVER_PORT="${SERVER_PORT:-3000}"
58+
SERVER_HOST="${SERVER_HOST:-localhost}"
59+
STARTUP_TIMEOUT="${STARTUP_TIMEOUT:-30}"
60+
HEALTHCHECK_TIMEOUT="${HEALTHCHECK_TIMEOUT:-10}"
61+
62+
# Validate required arguments
63+
if [[ -z "$PACKAGE_TARBALL" ]]; then
64+
log_error "PACKAGE_TARBALL environment variable must be set"
65+
log_error "Usage: PACKAGE_TARBALL=/path/to/package.tgz $0"
66+
exit 1
67+
fi
68+
69+
if [[ ! -f "$PACKAGE_TARBALL" ]]; then
70+
log_error "Package tarball not found: $PACKAGE_TARBALL"
71+
exit 1
72+
fi
73+
74+
log_info "Starting smoke test for package: $PACKAGE_TARBALL"
75+
76+
# Create temporary test directory
77+
TEST_DIR=$(mktemp -d)
78+
log_info "Created test directory: $TEST_DIR"
79+
80+
cd "$TEST_DIR"
81+
82+
# Initialize a minimal package.json to avoid npm warnings
83+
cat >package.json <<EOF
84+
{
85+
"name": "mux-smoke-test",
86+
"version": "1.0.0",
87+
"private": true
88+
}
89+
EOF
90+
91+
# Install the package
92+
log_info "Installing package..."
93+
if ! npm install --no-save "$PACKAGE_TARBALL"; then
94+
log_error "Failed to install package"
95+
exit 1
96+
fi
97+
98+
log_info "✅ Package installed successfully"
99+
100+
# Verify the binary is available
101+
if [[ ! -f "node_modules/.bin/mux" ]]; then
102+
log_error "mux binary not found in node_modules/.bin/"
103+
exit 1
104+
fi
105+
106+
log_info "✅ mux binary found"
107+
108+
# Start the server in background
109+
log_info "Starting mux server on $SERVER_HOST:$SERVER_PORT..."
110+
node_modules/.bin/mux server --host "$SERVER_HOST" --port "$SERVER_PORT" >server.log 2>&1 &
111+
SERVER_PID=$!
112+
113+
log_info "Server started with PID: $SERVER_PID"
114+
115+
# Wait for server to start
116+
log_info "Waiting for server to start (timeout: ${STARTUP_TIMEOUT}s)..."
117+
ELAPSED=0
118+
while [[ $ELAPSED -lt $STARTUP_TIMEOUT ]]; do
119+
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
120+
log_error "Server process died unexpectedly"
121+
log_error "Server log:"
122+
cat server.log
123+
exit 1
124+
fi
125+
126+
# Try to connect to the server
127+
if curl -sf "http://${SERVER_HOST}:${SERVER_PORT}/health" >/dev/null 2>&1; then
128+
log_info "✅ Server is responding"
129+
break
130+
fi
131+
132+
sleep 1
133+
ELAPSED=$((ELAPSED + 1))
134+
done
135+
136+
if [[ $ELAPSED -ge $STARTUP_TIMEOUT ]]; then
137+
log_error "Server failed to start within ${STARTUP_TIMEOUT}s"
138+
log_error "Server log:"
139+
cat server.log
140+
exit 1
141+
fi
142+
143+
# Test healthcheck endpoint
144+
log_info "Testing healthcheck endpoint..."
145+
HEALTH_RESPONSE=$(curl -sf "http://${SERVER_HOST}:${SERVER_PORT}/health" || true)
146+
147+
if [[ -z "$HEALTH_RESPONSE" ]]; then
148+
log_error "Healthcheck returned empty response"
149+
exit 1
150+
fi
151+
152+
log_info "Healthcheck response: $HEALTH_RESPONSE"
153+
154+
# Verify healthcheck response format
155+
if ! echo "$HEALTH_RESPONSE" | jq -e '.status == "ok"' >/dev/null 2>&1; then
156+
log_error "Healthcheck response does not contain expected 'status: ok'"
157+
log_error "Response: $HEALTH_RESPONSE"
158+
exit 1
159+
fi
160+
161+
log_info "✅ Healthcheck endpoint returned valid response"
162+
163+
# Test that server is actually serving content
164+
log_info "Testing root endpoint..."
165+
if ! curl -sf "http://${SERVER_HOST}:${SERVER_PORT}/" >/dev/null 2>&1; then
166+
log_error "Failed to fetch root endpoint"
167+
exit 1
168+
fi
169+
170+
log_info "✅ Root endpoint is accessible"
171+
172+
# All tests passed
173+
log_info "🎉 All smoke tests passed!"

0 commit comments

Comments
 (0)