Some checks failed
Build TV app / build (push) Has been cancelled
SettingsScreen and LiveScreen had grown to 760 and 689 lines and were where most of the last few days' bugs lived. Each is now the screen itself plus the pieces it composes — club chooser, pickers and rows next to settings, channel row and cells next to the live list. No behaviour changes: the same composables, moved, with the visibility widened from private to internal where a caller now sits in another file. formatClock existed twice, once per screen, and the move turned that into a compile error rather than a quiet duplicate. It is one internal function now. The smoke test seeds the demo playlist into the app's preferences before launching, so it walks the channel list and the player instead of stopping at the onboarding screen — the screens this commit moves are now actually exercised. It also refuses to start when its port is already taken: a leftover server from an earlier session answered every request with a 404 and the wait loop span forever. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
165 lines
6.0 KiB
Bash
Executable File
165 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Smoke test on the headless Google TV emulator.
|
|
#
|
|
# Builds the debug APK, seeds the demo playlist as its source, installs it
|
|
# and walks from the channel list into the player with the D-pad. Fails on
|
|
# anything the unit tests cannot see: a crash on startup, a crash while
|
|
# navigating, an ANR, or a channel list that stayed empty. The 0.11.0
|
|
# startup crash and the rail crash on "Verein hinzufügen" would both have
|
|
# been caught here.
|
|
#
|
|
# tests/smoke.sh # build, run, leave the emulator up
|
|
# tests/smoke.sh --apk <path> # skip the build, test this APK
|
|
# tests/smoke.sh --stop # stop the emulator when done
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
HELPERS="$ROOT/tests/helpers"
|
|
RUNS="$ROOT/tests/runs"
|
|
SERIAL="${CASTARR_SERIAL:-emulator-5554}"
|
|
ADB="${ANDROID_SDK_ROOT:-$HOME/Android/Sdk}/platform-tools/adb"
|
|
PKG="dev.castarr.tv"
|
|
DEMO_PORT="${CASTARR_DEMO_PORT:-8099}"
|
|
ACTIVITY="$PKG/.MainActivity"
|
|
|
|
APK=""
|
|
STOP_AFTER=0
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--apk) APK="$2"; shift 2 ;;
|
|
--stop) STOP_AFTER=1; shift ;;
|
|
*) echo "usage: $0 [--apk <path>] [--stop]" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
mkdir -p "$RUNS/screenshots"
|
|
LOG="$RUNS/smoke.log"
|
|
: > "$LOG"
|
|
|
|
step() { printf '\n== %s\n' "$1" | tee -a "$LOG"; }
|
|
fail() { printf '\nFAIL: %s\n' "$1" | tee -a "$LOG" >&2; exit 1; }
|
|
|
|
if [ -z "$APK" ]; then
|
|
step "Debug-APK bauen"
|
|
# shellcheck source=tests/helpers/jdk.sh
|
|
. "$HELPERS/jdk.sh"
|
|
(cd "$ROOT" && ./gradlew assembleDebug --no-daemon -q) >>"$LOG" 2>&1 ||
|
|
fail "Build fehlgeschlagen, siehe $LOG"
|
|
APK="$ROOT/app/build/outputs/apk/debug/app-debug.apk"
|
|
fi
|
|
[ -f "$APK" ] || fail "APK nicht gefunden: $APK"
|
|
|
|
step "Emulator starten"
|
|
"$HELPERS/emulator.sh" start | tee -a "$LOG"
|
|
|
|
step "Demo-Quelle bereitstellen"
|
|
python3 "$ROOT/tests/demo/make-demo-data.py" >>"$LOG" 2>&1 || fail "Demo-Daten fehlgeschlagen"
|
|
# The emulator reaches the host at 10.0.2.2, which is the address baked into
|
|
# the demo playlist.
|
|
# A leftover server from an earlier run happily answers on this port while
|
|
# serving a directory that no longer exists — every request a 404, and the
|
|
# wait below would spin forever.
|
|
if ss -ltn "sport = :$DEMO_PORT" 2>/dev/null | grep -q LISTEN; then
|
|
fail "Port $DEMO_PORT ist belegt: $(ss -ltnp "sport = :$DEMO_PORT" 2>/dev/null | tail -1)"
|
|
fi
|
|
# 10.0.2.2 inside the emulator is the host loopback, so binding there is enough.
|
|
(cd "$ROOT/tests/demo" && exec python3 -m http.server "$DEMO_PORT" --bind 127.0.0.1) \
|
|
>>"$RUNS/http.log" 2>&1 &
|
|
DEMO_PID=$!
|
|
trap 'kill "$DEMO_PID" 2>/dev/null || true' EXIT
|
|
for _ in $(seq 1 50); do
|
|
curl -sf "http://127.0.0.1:$DEMO_PORT/playlist.m3u" -o /dev/null && break
|
|
sleep 0.2
|
|
done
|
|
curl -sf "http://127.0.0.1:$DEMO_PORT/playlist.m3u" -o /dev/null ||
|
|
fail "Demo-Server antwortet nicht auf Port $DEMO_PORT"
|
|
|
|
step "Installieren"
|
|
# A debug build over a signed release needs the old one gone first.
|
|
"$ADB" -s "$SERIAL" uninstall "$PKG" >/dev/null 2>&1 || true
|
|
"$ADB" -s "$SERIAL" install -r "$APK" >>"$LOG" 2>&1 || fail "Installation fehlgeschlagen"
|
|
|
|
# Onboarding runs on a phone (ADR-0007), which a test has no way to be, so
|
|
# the source is seeded straight into the preferences the first run reads.
|
|
# Only a debug build allows this, which is the build under test.
|
|
"$ADB" -s "$SERIAL" shell run-as "$PKG" sh -c "'mkdir -p shared_prefs && cat > shared_prefs/source.xml'" <<XML || fail "Quelle konnte nicht gesetzt werden"
|
|
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
|
|
<map>
|
|
<string name="m3u_url">http://10.0.2.2:$DEMO_PORT/playlist.m3u</string>
|
|
<string name="epg_url">http://10.0.2.2:$DEMO_PORT/epg.xml</string>
|
|
</map>
|
|
XML
|
|
|
|
step "Starten"
|
|
"$ADB" -s "$SERIAL" logcat -c
|
|
"$ADB" -s "$SERIAL" shell am start -W -n "$ACTIVITY" >>"$LOG" 2>&1 ||
|
|
fail "am start fehlgeschlagen"
|
|
|
|
# The first frame is not the point — the crash usually lands a moment later,
|
|
# when state loads.
|
|
sleep 6
|
|
|
|
running() { [ -n "$("$ADB" -s "$SERIAL" shell pidof "$PKG" | tr -d '\r')" ]; }
|
|
crashed() {
|
|
"$ADB" -s "$SERIAL" logcat -d -b crash,main 2>/dev/null |
|
|
grep -E "FATAL EXCEPTION|ANR in $PKG|Process $PKG .* has died" | head -20
|
|
}
|
|
|
|
check() {
|
|
local where="$1" trace
|
|
trace="$(crashed || true)"
|
|
if [ -n "$trace" ]; then
|
|
printf '%s\n' "$trace" >>"$LOG"
|
|
printf '%s\n' "$trace" | head -5
|
|
fail "Absturz $where — vollständig in $LOG"
|
|
fi
|
|
running || fail "Prozess weg $where (kein Stacktrace im Log)"
|
|
}
|
|
|
|
check "beim Start"
|
|
"$HELPERS/emulator.sh" shot smoke-start >/dev/null
|
|
|
|
# Reaching the channel list is the point: it is the screen the demo source
|
|
# feeds, and a blank one means the playlist never arrived.
|
|
step "Senderliste prüfen"
|
|
DUMP="$RUNS/ui-dump.xml"
|
|
"$ADB" -s "$SERIAL" shell uiautomator dump /sdcard/ui.xml >>"$LOG" 2>&1 || true
|
|
"$ADB" -s "$SERIAL" pull /sdcard/ui.xml "$DUMP" >>"$LOG" 2>&1 || true
|
|
if grep -q "Blau TV HD" "$DUMP" 2>/dev/null; then
|
|
echo " Sender aus der Demo-Playlist sichtbar"
|
|
else
|
|
fail "Senderliste zeigt die Demo-Playlist nicht — Dump in $DUMP"
|
|
fi
|
|
|
|
step "D-Pad-Navigation"
|
|
# Down/right walks the rail and opens whatever has focus; back returns.
|
|
for key in DPAD_DOWN DPAD_RIGHT DPAD_RIGHT DPAD_DOWN DPAD_CENTER BACK DPAD_UP; do
|
|
"$ADB" -s "$SERIAL" shell input keyevent "$key"
|
|
sleep 1
|
|
done
|
|
sleep 2
|
|
check "bei der Navigation"
|
|
"$HELPERS/emulator.sh" shot smoke-nav >/dev/null
|
|
|
|
step "Wiedereintritt"
|
|
"$ADB" -s "$SERIAL" shell am start -n "$ACTIVITY" >/dev/null 2>&1
|
|
sleep 2
|
|
check "nach dem Wiedereintritt"
|
|
|
|
if [ "$STOP_AFTER" = 1 ]; then
|
|
step "Emulator stoppen"
|
|
"$HELPERS/emulator.sh" stop | tee -a "$LOG"
|
|
fi
|
|
|
|
cat <<EOF
|
|
|
|
OK — kein Absturz, App läuft.
|
|
Screenshots: $RUNS/screenshots/smoke-start.png, smoke-nav.png
|
|
Log: $LOG
|
|
|
|
Abgedeckt: Start mit gesetzter Quelle, Senderliste aus der Demo-Playlist,
|
|
D-Pad bis in den Player, Wiedereintritt. Nicht abgedeckt: echte Wiedergabe
|
|
(die Demo-Streams sind Attrappen), Onboarding am Handy, Kopplung und alles,
|
|
was ein Dispatcharr-Backend braucht.
|
|
EOF
|