Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/publish-npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,39 @@ jobs:
- name: Build application
run: make build

- name: Pack npm package for smoke test
run: npm pack

- name: Find package tarball
id: find-tarball
run: |
TARBALL=$(ls mux-*.tgz | head -1)
echo "tarball=$TARBALL" >> $GITHUB_OUTPUT
echo "Found package: $TARBALL"

- name: Run smoke test
env:
PACKAGE_TARBALL: ${{ steps.find-tarball.outputs.tarball }}
SERVER_PORT: 3000
SERVER_HOST: localhost
STARTUP_TIMEOUT: 30
run: |
./scripts/smoke-test.sh

- name: Upload server logs on smoke test failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: smoke-test-logs
path: |
/tmp/mux-smoke-test-*/server.log
if-no-files-found: warn
retention-days: 7

- name: Clean up tarball
if: always()
run: rm -f mux-*.tgz

- name: Check if version exists
id: check-exists
run: |
Expand Down
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ include fmt.mk
.PHONY: all build dev start clean help
.PHONY: build-renderer version build-icons build-static
.PHONY: lint lint-fix typecheck static-check
.PHONY: test test-unit test-integration test-watch test-coverage test-e2e
.PHONY: test test-unit test-integration test-watch test-coverage test-e2e smoke-test
.PHONY: dist dist-mac dist-win dist-linux
.PHONY: vscode-ext vscode-ext-install
.PHONY: docs docs-build docs-watch
Expand Down Expand Up @@ -255,6 +255,17 @@ test-watch: ## Run tests in watch mode
test-coverage: ## Run tests with coverage
@./scripts/test.sh --coverage


smoke-test: build ## Run smoke test on npm package
@echo "Building npm package tarball..."
@npm pack
@TARBALL=$$(ls mux-*.tgz | head -1); \
echo "Running smoke test on $$TARBALL..."; \
PACKAGE_TARBALL="$$TARBALL" ./scripts/smoke-test.sh; \
EXIT_CODE=$$?; \
rm -f "$$TARBALL"; \
exit $$EXIT_CODE

test-e2e: ## Run end-to-end tests
@$(MAKE) build
@MUX_E2E_LOAD_DIST=1 MUX_E2E_SKIP_BUILD=1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 bun x playwright test --project=electron $(PLAYWRIGHT_ARGS)
Expand Down
176 changes: 176 additions & 0 deletions scripts/smoke-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#!/usr/bin/env bash
# Smoke test for mux npm package
# Tests that the package can be installed and the server starts correctly

set -euo pipefail

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $*"
}

log_error() {
echo -e "${RED}[ERROR]${NC} $*" >&2
}

log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $*"
}

# Cleanup function
cleanup() {
local exit_code=$?
log_info "Cleaning up..."

# Kill server if it's running
if [[ -n "${SERVER_PID:-}" ]] && kill -0 "$SERVER_PID" 2>/dev/null; then
log_info "Stopping server (PID: $SERVER_PID)..."
kill "$SERVER_PID" 2>/dev/null || true
wait "$SERVER_PID" 2>/dev/null || true
fi

# Remove test directory
if [[ -n "${TEST_DIR:-}" ]] && [[ -d "$TEST_DIR" ]]; then
log_info "Removing test directory: $TEST_DIR"
rm -rf "$TEST_DIR"
fi

if [[ $exit_code -eq 0 ]]; then
log_info "βœ… Smoke test completed successfully"
else
log_error "❌ Smoke test failed with exit code $exit_code"
fi

exit $exit_code
}

trap cleanup EXIT INT TERM

# Configuration
PACKAGE_TARBALL="${PACKAGE_TARBALL:-}"
SERVER_PORT="${SERVER_PORT:-3000}"
SERVER_HOST="${SERVER_HOST:-localhost}"
STARTUP_TIMEOUT="${STARTUP_TIMEOUT:-30}"
HEALTHCHECK_TIMEOUT="${HEALTHCHECK_TIMEOUT:-10}"

# Validate required arguments
if [[ -z "$PACKAGE_TARBALL" ]]; then
log_error "PACKAGE_TARBALL environment variable must be set"
log_error "Usage: PACKAGE_TARBALL=/path/to/package.tgz $0"
exit 1
fi

if [[ ! -f "$PACKAGE_TARBALL" ]]; then
log_error "Package tarball not found: $PACKAGE_TARBALL"
exit 1
fi

# Convert to absolute path before changing directories
PACKAGE_TARBALL=$(realpath "$PACKAGE_TARBALL")

log_info "Starting smoke test for package: $PACKAGE_TARBALL"

# Create temporary test directory
TEST_DIR=$(mktemp -d)
log_info "Created test directory: $TEST_DIR"

cd "$TEST_DIR"

# Initialize a minimal package.json to avoid npm warnings
cat >package.json <<EOF
{
"name": "mux-smoke-test",
"version": "1.0.0",
"private": true
}
EOF

# Install the package
log_info "Installing package..."
if ! npm install --no-save "$PACKAGE_TARBALL"; then
log_error "Failed to install package"
exit 1
fi

log_info "βœ… Package installed successfully"

# Verify the binary is available
if [[ ! -f "node_modules/.bin/mux" ]]; then
log_error "mux binary not found in node_modules/.bin/"
exit 1
fi

log_info "βœ… mux binary found"

# Start the server in background
log_info "Starting mux server on $SERVER_HOST:$SERVER_PORT..."
node_modules/.bin/mux server --host "$SERVER_HOST" --port "$SERVER_PORT" >server.log 2>&1 &
SERVER_PID=$!

log_info "Server started with PID: $SERVER_PID"

# Wait for server to start
log_info "Waiting for server to start (timeout: ${STARTUP_TIMEOUT}s)..."
ELAPSED=0
while [[ $ELAPSED -lt $STARTUP_TIMEOUT ]]; do
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
log_error "Server process died unexpectedly"
log_error "Server log:"
cat server.log
exit 1
fi

# Try to connect to the server
if curl -sf "http://${SERVER_HOST}:${SERVER_PORT}/health" >/dev/null 2>&1; then
log_info "βœ… Server is responding"
break
fi

sleep 1
ELAPSED=$((ELAPSED + 1))
done

if [[ $ELAPSED -ge $STARTUP_TIMEOUT ]]; then
log_error "Server failed to start within ${STARTUP_TIMEOUT}s"
log_error "Server log:"
cat server.log
exit 1
fi

# Test healthcheck endpoint
log_info "Testing healthcheck endpoint..."
HEALTH_RESPONSE=$(curl -sf "http://${SERVER_HOST}:${SERVER_PORT}/health" || true)

if [[ -z "$HEALTH_RESPONSE" ]]; then
log_error "Healthcheck returned empty response"
exit 1
fi

log_info "Healthcheck response: $HEALTH_RESPONSE"

# Verify healthcheck response format
if ! echo "$HEALTH_RESPONSE" | jq -e '.status == "ok"' >/dev/null 2>&1; then
log_error "Healthcheck response does not contain expected 'status: ok'"
log_error "Response: $HEALTH_RESPONSE"
exit 1
fi

log_info "βœ… Healthcheck endpoint returned valid response"

# Test that server is actually serving content
log_info "Testing root endpoint..."
if ! curl -sf "http://${SERVER_HOST}:${SERVER_PORT}/" >/dev/null 2>&1; then
log_error "Failed to fetch root endpoint"
exit 1
fi

log_info "βœ… Root endpoint is accessible"

# All tests passed
log_info "πŸŽ‰ All smoke tests passed!"