6dab9b2953
Convert the remaining expect-based test scripts (phase1-6 runtime, usb,
wifi, bluetooth, dbus, greeter, live-iso, posix) to the stdlib python
harness, completing the migration started in 9ec00d4c81. Each script now
prefers booting the live ISO when present (falling back to harddrive.img
with snapshot=on), and retries up to 5 times when QEMU exits early or is
killed (rc 3 / 137) — the host-contention failure mode recorded in the
2026-07-20 runtime-proof status.
qemu-login-expect.py: treat an incomplete step sequence as a failure even
when a pass marker was seen partway through — partial sequences must not
count as a pass.
218 lines
7.1 KiB
Bash
Executable File
218 lines
7.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# test-dbus-qemu.sh — Validate D-Bus system bus and redbear-sessiond inside a QEMU guest
|
|
#
|
|
# Usage:
|
|
# ./local/scripts/test-dbus-qemu.sh [--check] [--config CONFIG]
|
|
#
|
|
# Options:
|
|
# --check Run non-interactively, exit 0 on pass, 1 on fail
|
|
# --config CONFIG Build config to test (default: redbear-full)
|
|
#
|
|
# --check mode boots the image, waits for the login prompt, then sends D-Bus
|
|
# validation commands via the serial console. Output is captured and parsed.
|
|
#
|
|
# Checks performed inside the guest:
|
|
# 1. dbus-daemon is running (system bus socket exists)
|
|
# 2. org.freedesktop.login1 is registered on the system bus
|
|
# 3. redbear-sessiond process is running
|
|
# 4. login1.Manager.ListSessions returns session c1
|
|
# 5. login1.Manager.IdleHint property is false
|
|
# 6. login1.Session.Active property is true
|
|
# 7. login1.Seat.CanGraphical property is true
|
|
#
|
|
# Exit codes:
|
|
# 0 All checks passed
|
|
# 1 One or more checks failed
|
|
# 2 Build or QEMU launch failed
|
|
|
|
set -euo pipefail
|
|
|
|
CHECK_MODE=0
|
|
CONFIG_NAME="redbear-full"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--check)
|
|
CHECK_MODE=1
|
|
shift
|
|
;;
|
|
--config)
|
|
CONFIG_NAME="$2"
|
|
shift 2
|
|
;;
|
|
*)
|
|
echo "Usage: $0 [--check] [--config CONFIG]" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
IMAGE="${REPO_ROOT}/build/${CONFIG_NAME}/x86_64/harddrive.img"
|
|
|
|
if [[ ! -f "$IMAGE" ]]; then
|
|
echo "test-dbus-qemu: image not found at ${IMAGE}" >&2
|
|
echo " Run: make all CONFIG_NAME=${CONFIG_NAME}" >&2
|
|
exit 2
|
|
fi
|
|
|
|
GUEST_SCRIPT='/tmp/dbus-check.sh'
|
|
OUTPUT_FILE='/tmp/dbus-qemu-output.txt'
|
|
|
|
# Build the guest-side check script as a standalone file.
|
|
# Uses org.freedesktop.DBus.Properties.Get for property access (checks 5-7).
|
|
cat > "$GUEST_SCRIPT" <<'GUEST_EOF'
|
|
#!/bin/sh
|
|
echo "=== D-Bus System Bus Validation ==="
|
|
|
|
# Check 1: dbus-daemon running
|
|
if [ -S /run/dbus/system_bus_socket ]; then
|
|
echo "PASS: system bus socket exists at /run/dbus/system_bus_socket"
|
|
else
|
|
echo "FAIL: system bus socket not found at /run/dbus/system_bus_socket"
|
|
fi
|
|
|
|
# Check 2: org.freedesktop.login1 registered
|
|
if command -v dbus-send >/dev/null 2>&1; then
|
|
RESULT=$(dbus-send --system --dest=org.freedesktop.DBus \
|
|
--type=method_call --print-reply \
|
|
/org/freedesktop/DBus \
|
|
org.freedesktop.DBus.ListNames 2>&1)
|
|
if echo "$RESULT" | grep -q "org.freedesktop.login1"; then
|
|
echo "PASS: org.freedesktop.login1 is registered on the system bus"
|
|
else
|
|
echo "FAIL: org.freedesktop.login1 not found on the system bus"
|
|
echo " Available names: $(echo "$RESULT" | grep string || echo none)"
|
|
fi
|
|
else
|
|
echo "SKIP: dbus-send not available (install dbus package)"
|
|
fi
|
|
|
|
# Check 3: redbear-sessiond process
|
|
if ps | grep -q '[r]edbear-sessiond'; then
|
|
echo "PASS: redbear-sessiond process is running"
|
|
else
|
|
echo "FAIL: redbear-sessiond process not found"
|
|
fi
|
|
|
|
# Check 4: login1.Manager.ListSessions
|
|
if command -v dbus-send >/dev/null 2>&1; then
|
|
SESSIONS=$(dbus-send --system --dest=org.freedesktop.login1 \
|
|
--type=method_call --print-reply \
|
|
/org/freedesktop/login1 \
|
|
org.freedesktop.login1.Manager.ListSessions 2>&1)
|
|
if echo "$SESSIONS" | grep -q "c1"; then
|
|
echo "PASS: ListSessions returns session c1"
|
|
else
|
|
echo "FAIL: ListSessions did not return session c1"
|
|
fi
|
|
fi
|
|
|
|
# Check 5: login1.Manager.IdleHint (property, not method)
|
|
if command -v dbus-send >/dev/null 2>&1; then
|
|
IDLE=$(dbus-send --system --dest=org.freedesktop.login1 \
|
|
--type=method_call --print-reply \
|
|
/org/freedesktop/login1 \
|
|
org.freedesktop.DBus.Properties.Get \
|
|
string:'org.freedesktop.login1.Manager' \
|
|
string:'IdleHint' 2>&1)
|
|
if echo "$IDLE" | grep -q "false"; then
|
|
echo "PASS: Manager.IdleHint = false"
|
|
else
|
|
echo "FAIL: Manager.IdleHint not false (got: $IDLE)"
|
|
fi
|
|
fi
|
|
|
|
# Check 6: login1.Session.Active (property, not method)
|
|
if command -v dbus-send >/dev/null 2>&1; then
|
|
ACTIVE=$(dbus-send --system --dest=org.freedesktop.login1 \
|
|
--type=method_call --print-reply \
|
|
/org/freedesktop/login1/session/c1 \
|
|
org.freedesktop.DBus.Properties.Get \
|
|
string:'org.freedesktop.login1.Session' \
|
|
string:'Active' 2>&1)
|
|
if echo "$ACTIVE" | grep -q "true"; then
|
|
echo "PASS: Session.Active = true"
|
|
else
|
|
echo "FAIL: Session.Active not true (got: $ACTIVE)"
|
|
fi
|
|
fi
|
|
|
|
# Check 7: login1.Seat.CanGraphical (property, not method)
|
|
if command -v dbus-send >/dev/null 2>&1; then
|
|
GRAPH=$(dbus-send --system --dest=org.freedesktop.login1 \
|
|
--type=method_call --print-reply \
|
|
/org/freedesktop/login1/seat/seat0 \
|
|
org.freedesktop.DBus.Properties.Get \
|
|
string:'org.freedesktop.login1.Seat' \
|
|
string:'CanGraphical' 2>&1)
|
|
if echo "$GRAPH" | grep -q "true"; then
|
|
echo "PASS: Seat.CanGraphical = true"
|
|
else
|
|
echo "FAIL: Seat.CanGraphical not true (got: $GRAPH)"
|
|
fi
|
|
fi
|
|
|
|
echo "=== D-Bus Validation Complete ==="
|
|
GUEST_EOF
|
|
chmod +x "$GUEST_SCRIPT"
|
|
|
|
if [[ "$CHECK_MODE" -eq 1 ]]; then
|
|
echo "test-dbus-qemu: launching QEMU with D-Bus checks (non-interactive)"
|
|
|
|
# Boot the guest, wait for login, send the D-Bus check script as a single
|
|
# bulk transfer, and wait for the completion marker. The helper's send
|
|
# appends \r after the text; the multi-line script content executes
|
|
# line-by-line in the guest shell, producing the same PASS/FAIL output.
|
|
attempt=1
|
|
while true; do
|
|
rc=0
|
|
python3 local/scripts/qemu-login-expect.py \
|
|
--timeout 120 \
|
|
--log "$OUTPUT_FILE" \
|
|
--step "expect:login:" \
|
|
--step "send:root" \
|
|
--step "expect:#" \
|
|
--step "send:$(cat "$GUEST_SCRIPT")" \
|
|
--step "expect:=== D-Bus Validation Complete ===" \
|
|
--pass_marker "=== D-Bus Validation Complete ===" \
|
|
-- \
|
|
qemu-system-x86_64 -drive file="$IMAGE" -m 2G -smp 2 -nographic -no-reboot || rc=$?
|
|
if [[ $rc -eq 0 ]]; then
|
|
break
|
|
fi
|
|
if [[ ( $rc -eq 3 || $rc -eq 137 ) && $attempt -lt 5 ]]; then
|
|
attempt=$((attempt + 1))
|
|
echo "QEMU exited before completing the check; retrying (attempt $attempt/5)"
|
|
sleep 2
|
|
continue
|
|
fi
|
|
rm -f "$GUEST_SCRIPT"
|
|
exit "$rc"
|
|
done
|
|
|
|
FAILED=$(grep -c "FAIL" "$OUTPUT_FILE" 2>/dev/null || true)
|
|
PASSED=$(grep -c "PASS" "$OUTPUT_FILE" 2>/dev/null || true)
|
|
|
|
grep -E "PASS|FAIL|=== D-Bus" "$OUTPUT_FILE" || true
|
|
echo ""
|
|
echo "Results: ${PASSED} passed, ${FAILED} failed"
|
|
|
|
rm -f "$GUEST_SCRIPT"
|
|
if [[ "$FAILED" -gt 0 ]]; then
|
|
exit 1
|
|
fi
|
|
exit 0
|
|
else
|
|
echo "test-dbus-qemu: launching QEMU (interactive mode)"
|
|
echo " Guest check script written to /tmp/dbus-check.sh"
|
|
echo " After login, run: sh /tmp/dbus-check.sh"
|
|
echo ""
|
|
|
|
qemu-system-x86_64 \
|
|
-drive file="$IMAGE",format=raw \
|
|
-m 2G \
|
|
-smp 2 \
|
|
-serial mon:stdio
|
|
fi
|