blob: bd08cefc5cd1e56120ec9bc2ef0fda1ea8589bd6 (
plain) (
blame)
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
179
180
181
182
183
184
|
#!/usr/bin/env bash
# Verify that crashpad_handler is active when zenserver (release build) starts.
#
# This test:
# 1. Launches zenserver from the release build.
# 2. Waits for the HTTP health endpoint to become ready.
# 3. Checks that a crashpad_handler child process is running.
# 4. Checks that the startup log contains "sentry initialized" (not a failure).
#
# Usage:
# ./scripts/test_linux/crashpad-test.sh [path-to-zenserver]
#
# If no path is given, defaults to build/linux/x86_64/release/zenserver
# relative to the repository root.
#
# The test exits 0 on success, 1 on failure.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
ZENSERVER_BINARY="${1:-$REPO_ROOT/build/linux/x86_64/release/zenserver}"
CRASHPAD_HANDLER="$(dirname "$ZENSERVER_BINARY")/crashpad_handler"
PORT=18558 # Use a non-default port so we don't collide with a running zenserver
DATA_DIR="$(mktemp -d)"
STDOUT_FILE="$DATA_DIR/stdout.log"
ZENSERVER_PID=""
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
PASSED=0
FAILED=0
pass() {
echo -e " ${GREEN}PASS${NC} $1"
(( PASSED++ )) || true
}
fail() {
echo -e " ${RED}FAIL${NC} $1"
(( FAILED++ )) || true
}
cleanup() {
set +e
if [ -n "$ZENSERVER_PID" ] && kill -0 "$ZENSERVER_PID" 2>/dev/null; then
kill "$ZENSERVER_PID" 2>/dev/null
wait "$ZENSERVER_PID" 2>/dev/null
fi
rm -rf "$DATA_DIR"
}
trap cleanup EXIT
# ── Preflight ────────────────────────────────────────────────────────────────
echo ""
echo "=============================="
echo " Crashpad active check"
echo "=============================="
echo ""
if [ ! -f "$ZENSERVER_BINARY" ]; then
echo -e "${RED}ERROR: zenserver binary not found: $ZENSERVER_BINARY${NC}"
echo " Build with: xmake config -m release && xmake build zenserver"
exit 1
fi
if [ ! -f "$CRASHPAD_HANDLER" ]; then
echo -e "${RED}ERROR: crashpad_handler not found alongside zenserver: $CRASHPAD_HANDLER${NC}"
echo " It should be copied there automatically by the build."
exit 1
fi
echo "zenserver: $ZENSERVER_BINARY"
echo "crashpad_handler: $CRASHPAD_HANDLER"
echo "port: $PORT"
echo "data dir: $DATA_DIR"
echo ""
# ── Start zenserver ──────────────────────────────────────────────────────────
# zenserver runs in the foreground until SIGINT/SIGTERM. Launch in background
# so we can poll its health endpoint and inspect child processes.
"$ZENSERVER_BINARY" \
--port="$PORT" \
--data-dir="$DATA_DIR" \
> "$STDOUT_FILE" 2>&1 &
ZENSERVER_PID=$!
echo "Started zenserver (pid $ZENSERVER_PID), waiting for health endpoint..."
# ── Wait for health endpoint ─────────────────────────────────────────────────
READY=false
for i in $(seq 1 40); do
if curl -sf "http://localhost:$PORT/health" > /dev/null 2>&1; then
READY=true
break
fi
sleep 0.5
done
if [ "$READY" = false ]; then
echo -e "${RED}ERROR: zenserver did not become ready within 20 seconds${NC}"
if [ -f "$STDOUT_FILE" ]; then
echo ""
echo "--- stdout ---"
cat "$STDOUT_FILE"
fi
exit 1
fi
echo "Server is ready."
# Give the server a moment to finish startup logging (sentry init log
# message is emitted after the health endpoint comes up).
sleep 1
echo ""
# ── Test 1: crashpad_handler process is running for our data dir ─────────────
#
# sentry-native starts crashpad_handler with --database pointing at
# $DATA_DIR/.sentry-native. The process re-parents itself out of zenserver's
# process tree, so we look for it by its command-line arguments rather than
# by parent PID.
HANDLER_PID="$(pgrep -f "crashpad_handler.*${DATA_DIR}" 2>/dev/null | head -1 || true)"
if [ -n "$HANDLER_PID" ]; then
pass "crashpad_handler is running (pid $HANDLER_PID) with database in our data dir"
else
fail "crashpad_handler process not found — sentry_init may have failed or sentry is disabled"
fi
# ── Test 2: No sentry_init failure in startup log ────────────────────────────
#
# The "sentry initialized" success message is logged at INFO level under the
# sentry-sdk log category, which is filtered to Warn by default — so it won't
# appear in normal stdout. We check for the absence of the failure message
# instead (which IS at Warn level and would appear if sentry_init failed).
if grep -q "sentry_init returned failure" "$STDOUT_FILE" 2>/dev/null; then
ERRMSG="$(grep "sentry_init returned failure" "$STDOUT_FILE" | head -1)"
fail "sentry_init reported failure: $ERRMSG"
else
pass "No sentry_init failure message in startup log"
fi
# ── Test 3: ldd sanity — crashpad_handler must not need libc++.so.1 ──────────
MISSING_LIBCXX="$(ldd "$CRASHPAD_HANDLER" 2>/dev/null | grep "libc++\.so\.1" | grep "not found" || true)"
if [ -n "$MISSING_LIBCXX" ]; then
fail "crashpad_handler has an unsatisfied libc++.so.1 dependency (static linking patch not applied)"
elif ldd "$CRASHPAD_HANDLER" 2>/dev/null | grep -q "libc++\.so\.1"; then
fail "crashpad_handler links libc++.so.1 dynamically — it should be statically linked"
else
pass "crashpad_handler has no dynamic libc++.so.1 dependency"
fi
# ── Summary ──────────────────────────────────────────────────────────────────
echo ""
echo "=============================="
printf " Passed: "
echo -e "${GREEN}${PASSED}${NC}"
printf " Failed: "
if [ "$FAILED" -gt 0 ]; then
echo -e "${RED}${FAILED}${NC}"
else
echo -e "${GREEN}${FAILED}${NC}"
fi
echo "=============================="
echo ""
if [ "$FAILED" -gt 0 ]; then
if [ -f "$STDOUT_FILE" ]; then
echo "--- stdout ---"
cat "$STDOUT_FILE"
fi
exit 1
fi
|