-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun_tests.sh
More file actions
executable file
·166 lines (153 loc) · 6.55 KB
/
Copy pathrun_tests.sh
File metadata and controls
executable file
·166 lines (153 loc) · 6.55 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
#!/usr/bin/env bash
# Automated tests for the SQLite eBPF tracer. Run inside the Linux VM
# (needs sudo for BPF load/attach). Drive from the Mac with `make vm-test`.
set -u
B="${BUILD:-$HOME/build/sqlite-hook}"
export SQLITE_TRACE_BTF_DIR="$B/btf"
TRACE="$B/sqlite_trace"
DETECT="$B/detect_version"
PASS=0
FAIL=0
ok() { echo " PASS: $1"; PASS=$((PASS+1)); }
bad() { echo " FAIL: $1"; FAIL=$((FAIL+1)); }
# trace_pid <demo> <grep-pattern>
# launches the demo, runs the self-sufficient tracer against its PID (auto
# version-detect + BTF select + merge), echoes the first matching line.
trace_pid() {
local demo=$1 pat=$2
LD_LIBRARY_PATH="$B" SQLITE_DEMO_LOOP=1 "$demo" "$B/test.db" >/dev/null 2>&1 &
local d=$!
sleep 0.4
local out
out=$(sudo SQLITE_TRACE_BTF_DIR="$SQLITE_TRACE_BTF_DIR" \
timeout 3 "$TRACE" --pid "$d" 2>/dev/null | grep -m1 -E "$pat")
kill "$d" 2>/dev/null
echo "$out"
}
echo "=== test 1: version detection ==="
v=$($DETECT "$B/libsqlite3-3400000.so" | grep -oE "3\.[0-9]+\.[0-9]+" | head -1)
[ "$v" = "3.40.0" ] && ok "dynamic lib 3.40.0 detected" || bad "expected 3.40.0, got '$v'"
echo "=== test 2: self-sufficient --pid trace captures SQL (3.40 target) ==="
sql=$(trace_pid "$B/sqlite_demo_3400000" "SELECT.*age;")
[ -n "$sql" ] && ok "captured: ${sql#*] }" || bad "no SQL captured via --pid"
echo "=== test 3: auto BTF selection works across versions ==="
# Same tracer, two different target versions; both should capture, proving the
# loader picked the right per-version BTF for each.
s40=$(trace_pid "$B/sqlite_demo_3400000" "SELECT.*age;")
s46=$(trace_pid "$B/sqlite_demo_3460100" "SELECT.*age;")
if [ -n "$s40" ] && [ -n "$s46" ]; then
ok "both 3.40 and 3.46 targets traced with auto-selected BTF"
else
bad "cross-version auto-select failed: 3.40='$s40' 3.46='$s46'"
fi
echo "=== test 4: trace the real sqlite3 CLI binary via --lib ==="
# Unlike tests 2/3 (which attach to a long-lived demo by --pid), the sqlite3 CLI
# is short-lived per invocation, so we drive it in a background loop and attach
# inode-wide with --lib. This exercises: (a) the LINK-mode uprobe firing for
# processes that start AFTER attach, and (b) version-detect + BTF select against
# an uncontrolled, externally-installed SQLite rather than a bundled one.
cli=$(command -v sqlite3 || true)
if [ -z "$cli" ]; then
echo " SKIP: no sqlite3 binary on PATH"
else
# The file carrying sqlite3_step: the dynamically-linked libsqlite3.so if
# present, else the binary itself (static build).
libtarget=$(ldd "$cli" 2>/dev/null | grep -oE '/[^ ]*libsqlite3[^ ]*' | head -1)
[ -z "$libtarget" ] && libtarget="$cli"
# Background loop: each iteration is a fresh short-lived sqlite3 process
# running a distinctively-marked query, so the inode-wide uprobe catches a
# step regardless of which iteration overlaps the trace window.
clidb=$(mktemp -u --suffix=.db)
(
for _ in $(seq 1 30); do
sqlite3 "$clidb" \
"CREATE TABLE IF NOT EXISTS cli_probe(x);
SELECT x FROM cli_probe WHERE x = 4242;" >/dev/null 2>&1
sleep 0.2
done
) &
loop=$!
sleep 0.4
cliout=$(sudo SQLITE_TRACE_BTF_DIR="$SQLITE_TRACE_BTF_DIR" \
timeout 4 "$TRACE" --lib "$libtarget" 2>/tmp/cli_trace.err \
| grep -m1 "cli_probe WHERE x = 4242")
kill "$loop" 2>/dev/null
wait "$loop" 2>/dev/null
rm -f "$clidb"
if [ -n "$cliout" ]; then
ok "captured sqlite3 CLI query via --lib: ${cliout#*] }"
elif grep -q "no bundled BTF" /tmp/cli_trace.err; then
# Honest outcome: with only exact-match BTF lookup, an uncontrolled
# system SQLite version has no matching blob. Records the gap rather
# than failing the suite for an unimplemented nearest-match fallback.
echo " SKIP: no bundled BTF for system sqlite3 ($(sqlite3 --version | awk '{print $1}'))"
else
bad "no CLI query captured via --lib (see /tmp/cli_trace.err)"
fi
fi
echo "=== test 5: unknown version fails gracefully ==="
# Point at an empty BTF dir so no blob matches; expect a clean error, not a crash.
LD_LIBRARY_PATH="$B" SQLITE_DEMO_LOOP=1 "$B/sqlite_demo_3400000" "$B/test.db" >/dev/null 2>&1 &
up=$!
sleep 0.4
emptydir=$(mktemp -d)
msg=$(sudo SQLITE_TRACE_BTF_DIR="$emptydir" timeout 3 "$TRACE" --pid "$up" 2>&1)
rc=$?
kill "$up" 2>/dev/null
rmdir "$emptydir" 2>/dev/null
if [ "$rc" -ne 0 ] && echo "$msg" | grep -q "no bundled BTF"; then
ok "missing BTF reported clearly (exit $rc)"
else
bad "expected clean 'no bundled BTF' error, got rc=$rc: '$msg'"
fi
echo "=== test 6: bound-parameter byte size reported ==="
# The demo binds one integer to a single '?'; the tracer should report the SQL
# text length and an 8-byte bound total (one MEM_Int) on the "in:" line.
LD_LIBRARY_PATH="$B" SQLITE_DEMO_LOOP=1 "$B/sqlite_demo_3400000" "$B/test.db" >/dev/null 2>&1 &
bp=$!
sleep 0.4
inln=$(sudo SQLITE_TRACE_BTF_DIR="$SQLITE_TRACE_BTF_DIR" \
timeout 3 "$TRACE" --pid "$bp" 2>/dev/null | grep -m1 -E "in: sql=[0-9]+B bound=")
kill "$bp" 2>/dev/null
echo " $inln"
if echo "$inln" | grep -qE "bound=8B" && echo "$inln" | grep -qE "vars=1 scanned=1"; then
ok "bound size reported (1 var, 8 bytes)"
else
bad "expected 'bound=8B ... vars=1 scanned=1', got: '$inln'"
fi
echo "=== test 7: trunk-snapshot version resolved via fallback (fossil) ==="
# fossil bundles a pre-release SQLite snapshot whose SOURCE_ID date is not an
# official release; detection must fall back to the snapshot's own version
# string (3.50.0 here), not fail and not pick the nearest earlier release.
fossil_bin=$(command -v fossil || true)
if [ -z "$fossil_bin" ]; then
echo " SKIP: no fossil binary on PATH"
else
dv=$("$B/detect_version" --manifest "$SQLITE_TRACE_BTF_DIR/sqlite-sources.tsv" \
"$fossil_bin" 2>/dev/null | grep -m1 "version:")
echo " $dv"
num=$(echo "$dv" | grep -oE "\(([0-9]+)\)" | tr -d "()")
if [ -n "$num" ] && [ -f "$SQLITE_TRACE_BTF_DIR/sqlite-$num.btf" ]; then
ok "fossil snapshot resolved to $num with a bundled BTF"
else
bad "fossil version unresolved or no blob: '$dv'"
fi
fi
echo "=== test 8: --capture-values prints the real bound value ==="
# The demo binds the integer 26 to the single '?'; with --capture-values the
# tracer must print "[0] INT: 26" under a "values:" line for the statement.
LD_LIBRARY_PATH="$B" SQLITE_DEMO_LOOP=1 "$B/sqlite_demo_3400000" "$B/test.db" >/dev/null 2>&1 &
cv=$!
sleep 0.4
val=$(sudo SQLITE_TRACE_BTF_DIR="$SQLITE_TRACE_BTF_DIR" \
timeout 3 "$TRACE" --pid "$cv" --capture-values 2>/dev/null | grep -m1 -E "\[0\] INT:")
kill "$cv" 2>/dev/null
echo " $val"
if echo "$val" | grep -qE "\[0\] INT: 26"; then
ok "captured bound value [0] INT: 26"
else
bad "expected '[0] INT: 26', got: '$val'"
fi
echo
echo "=== summary: $PASS passed, $FAIL failed ==="
[ "$FAIL" -eq 0 ]