-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathcompose-smoke.sh
More file actions
executable file
·178 lines (148 loc) · 5.64 KB
/
Copy pathcompose-smoke.sh
File metadata and controls
executable file
·178 lines (148 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env bash
set -euo pipefail
compose_diagnostics() {
local context="$1"
local lines="${SAMPLE_APP_DIAGNOSTIC_LOG_LINES:-160}"
printf '\ncompose-smoke: diagnostics after %s\n' "$context" >&2
docker compose ps >&2 || true
docker compose logs --no-color --timestamps --tail="$lines" app worker mysql redis >&2 || true
}
run_step() {
local name="$1"
local timeout_seconds="$2"
shift 2
printf '\n==> %s\n' "$name"
set +e
timeout "${timeout_seconds}s" "$@"
local status=$?
set -e
if [[ "$status" -ne 0 ]]; then
if [[ "$status" -eq 124 ]]; then
printf 'compose-smoke: %s timed out after %ss\n' "$name" "$timeout_seconds" >&2
else
printf 'compose-smoke: %s exited with status %d\n' "$name" "$status" >&2
fi
compose_diagnostics "$name"
return "$status"
fi
}
run_sample() {
local name="$1"
local command="$2"
local expected="$3"
local output
local status
local timeout_seconds="${SAMPLE_APP_SAMPLE_TIMEOUT_SECONDS:-180}"
printf '\n==> %s\n' "$name"
set +e
output="$(timeout "${timeout_seconds}s" docker compose exec -T app php artisan "$command" 2>&1)"
status=$?
set -e
printf '%s\n' "$output"
if [[ "$status" -ne 0 ]]; then
if [[ "$status" -eq 124 ]]; then
printf 'compose-smoke: %s timed out after %ss while running php artisan %s\n' "$name" "$timeout_seconds" "$command" >&2
else
printf 'compose-smoke: %s exited with status %d while running php artisan %s\n' "$name" "$status" "$command" >&2
fi
compose_diagnostics "$name"
return "$status"
fi
if [[ ! "$output" =~ $expected ]]; then
printf 'compose-smoke: %s output did not match /%s/\n' "$name" "$expected" >&2
compose_diagnostics "$name"
return 1
fi
}
wait_for_db() {
# Verify the app container can actually open a PDO connection to MySQL
# before any migration runs. The compose healthcheck probes MySQL itself,
# but a positive PDO::__construct() from inside `app` is the only thing
# that proves credentials, network, and TCP listener are all ready end to end.
local attempt
local probe_timeout_seconds="${SAMPLE_APP_DB_PROBE_TIMEOUT_SECONDS:-10}"
for attempt in $(seq 1 60); do
if timeout "${probe_timeout_seconds}s" docker compose exec -T app php -r '
$dsn = sprintf(
"mysql:host=%s;port=%s;dbname=%s",
getenv("DB_HOST") ?: "mysql",
getenv("DB_PORT") ?: "3306",
getenv("DB_DATABASE") ?: "sample"
);
try {
new PDO($dsn, getenv("DB_USERNAME") ?: "laravel", getenv("DB_PASSWORD") ?: "password", [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_TIMEOUT => 2,
]);
exit(0);
} catch (Throwable $e) {
fwrite(STDERR, $e->getMessage() . "\n");
exit(1);
}
' >/dev/null 2>&1; then
printf 'compose-smoke: database reachable from app after %d attempt(s)\n' "$attempt"
return 0
fi
sleep 2
done
printf 'compose-smoke: database never became reachable from app within 120s\n' >&2
compose_diagnostics "database readiness"
return 1
}
restart_worker_after_schema_refresh() {
run_step \
"restarting worker after schema refresh" \
"${SAMPLE_APP_WORKER_RESTART_TIMEOUT_SECONDS:-180}" \
docker compose up -d --no-deps --force-recreate --wait worker
}
prepared_stack_handoff_matches() {
local expected_app_id="${SAMPLE_APP_PREPARED_APP_CONTAINER_ID:-}"
local expected_worker_id="${SAMPLE_APP_PREPARED_WORKER_CONTAINER_ID:-}"
[[ "${SAMPLE_APP_SMOKE_REUSE_PREPARED:-0}" == "1" ]] &&
[[ -n "$expected_app_id" && -n "$expected_worker_id" ]] &&
[[ "$(docker compose ps -q app)" == "$expected_app_id" ]] &&
[[ "$(docker compose ps -q worker)" == "$expected_worker_id" ]]
}
docker compose ps
if prepared_stack_handoff_matches; then
printf '\n==> reusing schema prepared by combined conformance setup\n'
else
if [[ "${SAMPLE_APP_SMOKE_REUSE_PREPARED:-0}" == "1" ]]; then
printf '\n==> prepared stack handoff changed; refreshing schema before smoke\n'
fi
printf '\n==> waiting for database to accept app connections\n'
wait_for_db
run_step \
"fresh database migrations" \
"${SAMPLE_APP_MIGRATION_TIMEOUT_SECONDS:-180}" \
docker compose exec -T app php artisan migrate:fresh --force
restart_worker_after_schema_refresh
fi
run_sample "simple workflow" "app:workflow" "workflow_activity_other"
run_sample "elapsed workflow" "app:elapsed" "Elapsed Time: [0-9]+ seconds"
run_sample "microservice workflow" "app:microservice" "workflow_activity_other"
run_sample "webhook workflow" "app:webhook" "Hello world"
if [[ "${SAMPLE_APP_CONFORMANCE_AFTER_SMOKE:-1}" == "1" && "${SAMPLE_APP_SMOKE_ONLY:-0}" != "1" ]]; then
printf '\n==> full sample-app conformance surface\n'
prepared_app_container_id="$(docker compose ps -q app)"
prepared_worker_container_id="$(docker compose ps -q worker)"
set +e
timeout "${SAMPLE_APP_CONFORMANCE_AFTER_SMOKE_TIMEOUT_SECONDS:-1800}s" env \
SAMPLE_APP_CONFORMANCE_REUSE_PREPARED=1 \
SAMPLE_APP_PREPARED_APP_CONTAINER_ID="$prepared_app_container_id" \
SAMPLE_APP_PREPARED_WORKER_CONTAINER_ID="$prepared_worker_container_id" \
scripts/compose-conformance.sh
status=$?
set -e
if [[ "$status" -ne 0 ]]; then
if [[ "$status" -eq 124 ]]; then
printf 'compose-smoke: full sample-app conformance surface timed out after %ss\n' "${SAMPLE_APP_CONFORMANCE_AFTER_SMOKE_TIMEOUT_SECONDS:-1800}" >&2
else
printf 'compose-smoke: full sample-app conformance surface exited with status %d\n' "$status" >&2
fi
compose_diagnostics "full sample-app conformance surface"
exit "$status"
fi
else
printf '\ncompose-smoke: all deterministic sample workflows passed\n'
fi