Skip to content

Commit ad38d2f

Browse files
committed
ci: 添加 CI 烟雾测试工作流和脚本
添加 GitHub Actions 工作流用于运行烟雾测试 新增 smoke-ci.sh 脚本实现自动化测试流程 更新 Makefile 和 README 文档以支持新功能 完善 stop-app.sh 的退出状态码定义
1 parent 84c953f commit ad38d2f

5 files changed

Lines changed: 273 additions & 11 deletions

File tree

.github/workflows/ruby.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,26 @@ jobs:
2222
run: rails db:migrate RAILS_ENV=test
2323
- name: Run tests
2424
run: bundle exec rake
25+
26+
smoke-test:
27+
runs-on: ubuntu-latest
28+
needs: test
29+
steps:
30+
- uses: actions/checkout@v4.1.0
31+
- name: Set up Ruby
32+
uses: ruby/setup-ruby@v1
33+
with:
34+
ruby-version: 3.4
35+
bundler-cache: true
36+
- name: Install dependencies
37+
run: |
38+
gem install rails
39+
bundle install
40+
- name: Make scripts executable
41+
run: |
42+
chmod +x start-app.sh
43+
chmod +x stop-app.sh
44+
chmod +x status.sh
45+
chmod +x smoke-ci.sh
46+
- name: Run smoke CI test
47+
run: ./smoke-ci.sh

Makefile

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: start stop restart status smoke clean help
1+
.PHONY: start stop restart status smoke smoke-ci clean help
22

33
.DEFAULT_GOAL := help
44

@@ -7,6 +7,8 @@ PID_DIR := tmp/pids
77
PID_FILE := $(PID_DIR)/everydocs.pid
88
LOG_DIR := log
99

10+
SMOKE_PORT := $(shell awk 'BEGIN{srand(); print int(1024 + rand() * 54531)}')
11+
1012
help:
1113
@echo "EveryDocs Core - Make Commands"
1214
@echo "=============================================="
@@ -16,7 +18,8 @@ help:
1618
@echo " stop - Stop the EveryDocs server"
1719
@echo " restart - Restart the EveryDocs server"
1820
@echo " status - Check server status"
19-
@echo " smoke - Run non-interactive smoke test (for CI)"
21+
@echo " smoke - Run interactive smoke test"
22+
@echo " smoke-ci - Run CI smoke test (start -> probe -> stop)"
2023
@echo " test - Run Rails tests"
2124
@echo " logs - Tail the server logs"
2225
@echo " clean-logs - Clean log files"
@@ -32,7 +35,7 @@ help:
3235
@echo " make start"
3336
@echo " make stop"
3437
@echo " make restart"
35-
@echo " make smoke"
38+
@echo " make smoke-ci"
3639
@echo ""
3740

3841
start:
@@ -41,7 +44,7 @@ start:
4144

4245
stop:
4346
@echo "Stopping EveryDocs Core..."
44-
@cd $(PROJECT_DIR) && ./stop-app.sh
47+
@cd $(PROJECT_DIR) && ./stop-app.sh || true
4548

4649
restart: stop start
4750

@@ -79,7 +82,7 @@ db-migrate-test:
7982

8083
smoke:
8184
@echo "=============================================="
82-
@echo "EveryDocs Core - Non-Interactive Smoke Test"
85+
@echo "EveryDocs Core - Interactive Smoke Test"
8386
@echo "=============================================="
8487
@echo ""
8588
@echo "Phase 1: Checking prerequisites..."
@@ -120,3 +123,6 @@ smoke:
120123
@echo "=============================================="
121124
@echo "Smoke Test Completed"
122125
@echo "=============================================="
126+
127+
smoke-ci:
128+
@cd $(PROJECT_DIR) && ./smoke-ci.sh

README.md

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,26 @@ If you prefer to run EveryDocs directly on your host system (not in Docker), fol
159159
| Start | `./start-app.sh` | Start the server with PID management and logging |
160160
| Stop | `./stop-app.sh` | Gracefully stop the server (SIGTERM → SIGKILL fallback) |
161161
| Status | `./status.sh` | Check server status, uptime, memory, port connectivity |
162+
| Smoke CI | `./smoke-ci.sh` | Run CI smoke test (start → probe → stop) |
163+
164+
##### Script Exit Codes
165+
166+
**status.sh Exit Codes:**
167+
168+
| Exit Code | Meaning |
169+
|-----------|---------|
170+
| `0` | Service is RUNNING |
171+
| `1` | Service is NOT RUNNING (not started or stopped) |
172+
| `2` | Error (stale PID file, invalid PID, etc.) |
173+
174+
**stop-app.sh Exit Codes:**
175+
176+
| Exit Code | Meaning |
177+
|-----------|---------|
178+
| `0` | Success: All processes stopped |
179+
| `1` | No running process found (already stopped) |
180+
| `2` | Stop failed: Process could not be stopped |
181+
| `3` | Error |
162182

163183
#### Makefile Commands
164184

@@ -170,7 +190,8 @@ A `Makefile` is provided for convenience:
170190
| `make stop` | Stop the server |
171191
| `make restart` | Restart the server |
172192
| `make status` | Check server status |
173-
| `make smoke` | Run non-interactive smoke test (for CI) |
193+
| `make smoke` | Run interactive smoke test |
194+
| `make smoke-ci` | Run CI smoke test (start → probe /version → stop) |
174195
| `make test` | Run Rails tests |
175196
| `make test-controllers` | Run controller tests only |
176197
| `make logs` | Tail log files |
@@ -344,9 +365,45 @@ async function makeRequest(url, options = {}) {
344365

345366
## CI/CD and Testing
346367

347-
### Smoke Test (Non-Interactive)
368+
### GitHub Actions Workflow
369+
370+
The project includes a GitHub Actions workflow (`.github/workflows/ruby.yml`) that:
371+
1. Runs Ruby syntax checks
372+
2. Migrates the test database
373+
3. Runs the full test suite (`bundle exec rake`)
374+
4. **New**: Runs the CI smoke test (`./smoke-ci.sh`)
375+
376+
The smoke test job (`smoke-test`) depends on the test job (`test`) and only runs if tests pass.
377+
378+
### CI Smoke Test (`smoke-ci.sh`)
379+
380+
A dedicated CI smoke test script is provided to verify the server can actually start and respond:
381+
382+
```bash
383+
./smoke-ci.sh
384+
385+
# Or via Makefile
386+
make smoke-ci
387+
```
388+
389+
This script performs:
390+
1. **Cleanup**: Stops any existing instance on a random port
391+
2. **Database Setup**: Runs migrations with `RAILS_ENV=test`
392+
3. **Start Server**: Starts the server with:
393+
- Random port (1024-65535)
394+
- `RAILS_ENV=test`
395+
- Auto-generated `SECRET_KEY_BASE`
396+
4. **Probe**: Waits up to 60 seconds for `/version` endpoint to respond
397+
5. **Stop**: Gracefully stops the server
398+
399+
**Features:**
400+
- Random port to avoid conflicts
401+
- Automatic cleanup on exit (via `trap`)
402+
- Tail last 100 lines of logs on failure for debugging
403+
404+
### Interactive Smoke Test (`make smoke`)
348405

349-
A `make smoke` command is available for CI environments:
406+
The interactive smoke test (requires `.env` file):
350407

351408
```bash
352409
make smoke

smoke-ci.sh

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
PROJECT_ROOT="$SCRIPT_DIR"
6+
LOG_DIR="$PROJECT_ROOT/log"
7+
PID_DIR="$PROJECT_ROOT/tmp/pids"
8+
9+
EXIT_CODE_SUCCESS=0
10+
EXIT_CODE_SETUP_FAILED=1
11+
EXIT_CODE_START_FAILED=2
12+
EXIT_CODE_PROBE_FAILED=3
13+
EXIT_CODE_STOP_FAILED=4
14+
15+
log_info() {
16+
echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $1"
17+
}
18+
19+
log_error() {
20+
echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $1" >&2
21+
}
22+
23+
log_success() {
24+
echo "[SUCCESS] $(date '+%Y-%m-%d %H:%M:%S') - $1"
25+
}
26+
27+
cleanup() {
28+
log_info "Cleaning up..."
29+
if [[ -n "${SMOKE_PORT:-}" ]]; then
30+
cd "$PROJECT_ROOT" && PORT="$SMOKE_PORT" RAILS_ENV=test ./stop-app.sh 2>/dev/null || true
31+
fi
32+
}
33+
34+
trap cleanup EXIT
35+
36+
generate_random_port() {
37+
local min_port=1024
38+
local max_port=65535
39+
local range=$((max_port - min_port + 1))
40+
41+
if command -v awk &>/dev/null; then
42+
awk -v min="$min_port" -v max="$max_port" 'BEGIN{srand(); print int(min + rand() * (max - min + 1))}'
43+
elif command -v python3 &>/dev/null; then
44+
python3 -c "import random; print(random.randint($min_port, $max_port))"
45+
elif command -v python &>/dev/null; then
46+
python -c "import random; print(random.randint($min_port, $max_port))"
47+
else
48+
local seed=${RANDOM:-$$}
49+
echo $(( (seed % (max_port - min_port + 1)) + min_port ))
50+
fi
51+
}
52+
53+
tail_logs() {
54+
local lines=${1:-50}
55+
log_info "=== Debug: Last $lines lines of logs ==="
56+
57+
if [[ -f "$LOG_DIR/everydocs.log" ]]; then
58+
log_info "--- Main Log ---"
59+
tail -"$lines" "$LOG_DIR/everydocs.log" 2>/dev/null || true
60+
fi
61+
62+
if [[ -f "$LOG_DIR/everydocs.error.log" ]]; then
63+
log_info "--- Error Log ---"
64+
tail -"$lines" "$LOG_DIR/everydocs.error.log" 2>/dev/null || true
65+
fi
66+
}
67+
68+
main() {
69+
SMOKE_PORT=$(generate_random_port)
70+
export RAILS_ENV=test
71+
export PORT="$SMOKE_PORT"
72+
export SECRET_KEY_BASE="ci_smoke_test_secret_key_base_$(date +%s)"
73+
74+
echo "=============================================="
75+
echo "EveryDocs Core - CI Smoke Test"
76+
echo "=============================================="
77+
echo ""
78+
echo "Configuration:"
79+
echo " RAILS_ENV: $RAILS_ENV"
80+
echo " PORT: $SMOKE_PORT"
81+
echo " SECRET_KEY_BASE: ${SECRET_KEY_BASE:0:20}... (truncated)"
82+
echo ""
83+
84+
log_info "Phase 1: Cleanup any existing instance..."
85+
mkdir -p "$LOG_DIR"
86+
mkdir -p "$PID_DIR"
87+
rm -f "$LOG_DIR/everydocs.log"
88+
rm -f "$LOG_DIR/everydocs.error.log"
89+
90+
if cd "$PROJECT_ROOT" && PORT="$SMOKE_PORT" RAILS_ENV=test ./stop-app.sh 2>/dev/null; then
91+
log_info " ✓ Cleanup complete"
92+
else
93+
log_info " ✓ No existing instance to stop"
94+
fi
95+
echo ""
96+
97+
log_info "Phase 2: Setup test database..."
98+
if cd "$PROJECT_ROOT" && rails db:migrate RAILS_ENV=test 2>&1; then
99+
log_success " ✓ Database migrated"
100+
else
101+
log_error " ✗ Database migration failed"
102+
exit $EXIT_CODE_SETUP_FAILED
103+
fi
104+
echo ""
105+
106+
log_info "Phase 3: Start server..."
107+
cd "$PROJECT_ROOT"
108+
if ./start-app.sh; then
109+
log_success " ✓ Start command executed"
110+
else
111+
log_error " ✗ Start command failed"
112+
tail_logs 100
113+
exit $EXIT_CODE_START_FAILED
114+
fi
115+
echo ""
116+
117+
log_info "Phase 4: Wait for server to start..."
118+
local max_attempts=60
119+
local attempt=1
120+
local started=false
121+
122+
while [[ $attempt -le $max_attempts ]]; do
123+
if curl -s --connect-timeout 2 "http://localhost:$SMOKE_PORT/version" >/dev/null 2>&1; then
124+
started=true
125+
log_success " ✓ Server started after $attempt seconds"
126+
break
127+
fi
128+
129+
log_info " Waiting... ($attempt/$max_attempts)"
130+
sleep 1
131+
((attempt++))
132+
done
133+
134+
if [[ "$started" == false ]]; then
135+
log_error " ✗ Server failed to start within $max_attempts seconds"
136+
echo ""
137+
tail_logs 100
138+
exit $EXIT_CODE_START_FAILED
139+
fi
140+
echo ""
141+
142+
log_info "Phase 5: Probe /version endpoint..."
143+
local response
144+
response=$(curl -s "http://localhost:$SMOKE_PORT/version" 2>/dev/null || true)
145+
146+
if [[ -z "$response" ]]; then
147+
log_error " ✗ /version returned empty response"
148+
tail_logs 50
149+
exit $EXIT_CODE_PROBE_FAILED
150+
else
151+
log_success " ✓ /version responded: $response"
152+
fi
153+
echo ""
154+
155+
log_info "Phase 6: Stop server..."
156+
cd "$PROJECT_ROOT"
157+
if PORT="$SMOKE_PORT" RAILS_ENV=test ./stop-app.sh; then
158+
log_success " ✓ Server stopped"
159+
else
160+
log_error " ⚠ Stop command returned non-zero exit code (process may already be stopped)"
161+
fi
162+
echo ""
163+
164+
echo "=============================================="
165+
log_success "CI Smoke Test PASSED!"
166+
echo "=============================================="
167+
168+
exit $EXIT_CODE_SUCCESS
169+
}
170+
171+
main "$@"

stop-app.sh

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ DEFAULT_RAILS_ENV="production"
88
DEFAULT_PORT=5678
99
DEFAULT_PID_DIR="tmp/pids"
1010

11+
EXIT_CODE_SUCCESS=0
12+
EXIT_CODE_NO_PROCESS=1
13+
EXIT_CODE_STOP_FAILED=2
14+
EXIT_CODE_ERROR=3
15+
1116
log_info() {
1217
echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $1"
1318
}
@@ -157,7 +162,7 @@ main() {
157162
log_info "=============================================="
158163
log_info "No running EveryDocs process found"
159164
log_info "=============================================="
160-
exit 0
165+
exit $EXIT_CODE_NO_PROCESS
161166
fi
162167

163168
log_info "Found ${#pids_to_stop[@]} process(es) to stop"
@@ -179,11 +184,11 @@ main() {
179184
log_success "=============================================="
180185
log_success "EveryDocs Core has been stopped"
181186
log_success "=============================================="
182-
exit 0
187+
exit $EXIT_CODE_SUCCESS
183188
else
184189
log_error "Stopped $stopped_count/${#pids_to_stop[@]} processes"
185190
log_error "=============================================="
186-
exit 1
191+
exit $EXIT_CODE_STOP_FAILED
187192
fi
188193
}
189194

0 commit comments

Comments
 (0)