- Add TestEventsPlugin for receiving ADB broadcast intents - Create operator console UI (console/index.html, console.css, console.js) - Add test plan structure (plan.json) with phases, tests, and steps - Wire all test scripts (phase1, phase2, phase3) with step context and events - Add event emission helpers to alarm-test-lib.sh (step_start, step_pass, etc.) - Update test-phase1.sh with comprehensive prerequisite verification - Register TestEventsPlugin in capacitor.plugins.json - Add console documentation (CONSOLE-USAGE.md, CONSOLE-REMAINING-WORK.md) - Add test implementation alignment tracking (TEST-IMPLEMENTATION-ALIGNMENT.md) This enables real-time test progress tracking via structured events from shell scripts to the operator console UI.
726 lines
25 KiB
Bash
Executable File
726 lines
25 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
|
||
set -euo pipefail
|
||
IFS=$'\n\t'
|
||
|
||
# ========================================
|
||
# Phase 3 Testing Script – Boot Recovery
|
||
# ========================================
|
||
|
||
# Source shared library
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
source "${SCRIPT_DIR}/alarm-test-lib.sh"
|
||
|
||
# Initialize run directory (P1)
|
||
ensure_run_dir || {
|
||
error "Failed to initialize run directory"
|
||
exit 1
|
||
}
|
||
|
||
# Phase 3 specific configuration
|
||
# Log tags / patterns (matched to actual ReactivationManager logs)
|
||
BOOT_SCENARIO_VALUE="BOOT"
|
||
NONE_SCENARIO_VALUE="NONE"
|
||
|
||
# Release gating config (P4.1)
|
||
# 0 = advisory mode (default): failures become warnings, continue
|
||
# 1 = release-blocking mode: failures exit with nonzero
|
||
: "${RELEASE_GATE_PHASE3:=0}"
|
||
|
||
# Allow selecting specific tests on the command line (e.g. ./test-phase3.sh 1 3)
|
||
SELECTED_TESTS=()
|
||
|
||
# Phase 3 specific: override extract_scenario_from_logs to handle boot recovery
|
||
extract_scenario_from_logs() {
|
||
local logs="$1"
|
||
local scen
|
||
# Looks for "Detected scenario: BOOT" or "Starting boot recovery" format
|
||
if echo "$logs" | grep -qi "Starting boot recovery\|boot recovery"; then
|
||
echo "$BOOT_SCENARIO_VALUE"
|
||
else
|
||
# Use shared library function as fallback
|
||
scen="$(grep -oE "${SCENARIO_KEY}[A-Z_]+" <<<"$logs" | tail -n1 | sed "s/${SCENARIO_KEY}//" || true)"
|
||
echo "$scen"
|
||
fi
|
||
}
|
||
|
||
# ------------------------------------------------------------------------------
|
||
# TEST 1 – Boot with Future Alarms
|
||
# ------------------------------------------------------------------------------
|
||
|
||
test1_boot_future_alarms() {
|
||
section "TEST 1: Boot with Future Alarms"
|
||
|
||
# Set test context
|
||
set_test_context "phase3" "phase3_test1" ""
|
||
|
||
info "Purpose: Verify alarms are recreated on boot when schedules have future run times."
|
||
info "Expected time: 2-3 minutes (includes 30-60s reboot)"
|
||
info "Automatable: Partial (requires manual reboot confirmation)"
|
||
info "If you see: 'Boot recovery not detected' → Check boot receiver registration and BOOT_COMPLETED permission"
|
||
echo ""
|
||
|
||
pause
|
||
|
||
# Capture initial state
|
||
set_test_context "phase3" "phase3_test1" "p3_t1_s1"
|
||
step_start "p3_t1_s1" "Launch app & check plugin status"
|
||
capture_alarms "phase3_test1_initial"
|
||
capture_logcat "phase3_test1_initial" "DNP" 50
|
||
|
||
substep "Step 1: Launch app & check plugin status"
|
||
launch_app
|
||
|
||
ui_prompt "1) In the app UI, verify plugin status:
|
||
|
||
⚙️ Plugin Settings: ✅ Configured
|
||
🔌 Native Fetcher: ✅ Configured
|
||
|
||
If either shows ❌ or 'Not configured', click 'Configure Plugin', wait until both are ✅, then press Enter."
|
||
|
||
ui_prompt "2) Now schedule at least one future notification (e.g., click 'Test Notification' to schedule for a few minutes in the future)."
|
||
|
||
step_pass "p3_t1_s1" "Plugin configured and notification scheduled"
|
||
|
||
# Capture before reboot state
|
||
capture_alarms "phase3_test1_before_reboot"
|
||
|
||
substep "Step 2: Verify alarms are scheduled"
|
||
set_test_context "phase3" "phase3_test1" "p3_t1_s2"
|
||
step_start "p3_t1_s2" "Verify alarms scheduled"
|
||
show_alarms
|
||
local before_count system_before
|
||
before_count="$(get_plugin_alarm_count)"
|
||
system_before="$(get_system_alarm_count)"
|
||
info "Plugin alarms before reboot: $before_count (expected: 1)"
|
||
info "System/other alarms: $system_before (for context)"
|
||
|
||
if [[ "$before_count" -eq 0 ]]; then
|
||
warn "No plugin alarms found before reboot; TEST 1 may not be meaningful."
|
||
step_warn "p3_t1_s2" "No alarms found"
|
||
elif [[ "$before_count" -eq 1 ]]; then
|
||
ok "Single plugin alarm confirmed (one per day)"
|
||
step_pass "p3_t1_s2" "Alarms verified"
|
||
else
|
||
warn "Found $before_count plugin alarms (expected: 1)"
|
||
step_warn "p3_t1_s2" "Unexpected alarm count"
|
||
fi
|
||
|
||
pause
|
||
|
||
substep "Step 3: Reboot emulator"
|
||
set_test_context "phase3" "phase3_test1" "p3_t1_s3"
|
||
step_start "p3_t1_s3" "Reboot emulator"
|
||
warn "The emulator will reboot now. This will take 30-60 seconds."
|
||
pause
|
||
reboot_emulator
|
||
step_pass "p3_t1_s3" "Emulator rebooted"
|
||
|
||
substep "Step 4: Collect boot recovery logs"
|
||
set_test_context "phase3" "phase3_test1" "p3_t1_s4"
|
||
step_start "p3_t1_s4" "Collect boot recovery logs"
|
||
info "Collecting recovery logs from boot..."
|
||
sleep 2 # Give recovery a moment to complete
|
||
|
||
# Capture after reboot state
|
||
capture_alarms "phase3_test1_after_reboot"
|
||
capture_logcat "phase3_test1_after_reboot" "DNP-REACTIVATION" 250
|
||
capture_screenshot "phase3_test1_after_reboot"
|
||
|
||
local logs
|
||
logs="$(get_recovery_logs)"
|
||
echo "$logs"
|
||
|
||
local missed rescheduled verified errors scenario
|
||
missed="$(extract_field_from_logs "$logs" "missed")"
|
||
rescheduled="$(extract_field_from_logs "$logs" "rescheduled")"
|
||
verified="$(extract_field_from_logs "$logs" "verified")"
|
||
errors="$(extract_field_from_logs "$logs" "errors")"
|
||
scenario="$(extract_scenario_from_logs "$logs")"
|
||
|
||
echo
|
||
info "Parsed recovery summary:"
|
||
echo " scenario = ${scenario:-<none>}"
|
||
echo " missed = ${missed}"
|
||
echo " rescheduled= ${rescheduled}"
|
||
echo " verified = ${verified}"
|
||
echo " errors = ${errors}"
|
||
echo
|
||
|
||
# Determine verdict
|
||
local test1_passed=false
|
||
local test1_message=""
|
||
|
||
if [[ "$errors" -gt 0 ]]; then
|
||
error "Recovery reported errors>0 (errors=$errors)"
|
||
test1_message="Recovery reported errors (errors=$errors)"
|
||
fi
|
||
|
||
if [[ "$scenario" == "$BOOT_SCENARIO_VALUE" && "$rescheduled" -gt 0 ]]; then
|
||
ok "TEST 1 PASSED: Boot recovery detected and alarms rescheduled (scenario=$scenario, rescheduled=$rescheduled)."
|
||
test1_passed=true
|
||
test1_message="Boot recovery detected and alarms rescheduled (scenario=$scenario, rescheduled=$rescheduled)"
|
||
elif echo "$logs" | grep -qi "Starting boot recovery\|boot recovery"; then
|
||
if [[ "$rescheduled" -gt 0 ]]; then
|
||
ok "TEST 1 PASSED: Boot recovery ran and alarms rescheduled (rescheduled=$rescheduled)."
|
||
test1_passed=true
|
||
test1_message="Boot recovery ran and alarms rescheduled (rescheduled=$rescheduled)"
|
||
else
|
||
test1_message="Boot recovery ran but rescheduled=0. Check implementation or logs."
|
||
fi
|
||
else
|
||
test1_message="Boot recovery not clearly detected. Review logs and boot receiver implementation (scenario=${scenario:-<none>}, rescheduled=$rescheduled)"
|
||
fi
|
||
|
||
substep "Step 5: Verify alarms were recreated"
|
||
show_alarms
|
||
local after_count system_after
|
||
after_count="$(get_plugin_alarm_count)"
|
||
system_after="$(get_system_alarm_count)"
|
||
info "Plugin alarms after boot: $after_count (expected: 1)"
|
||
info "System/other alarms: $system_after (for context)"
|
||
|
||
if [[ "$after_count" -eq 0 && "$test1_passed" == "true" ]]; then
|
||
warn "Alarms were not recreated despite recovery success. Check alarm scheduling logic."
|
||
test1_message="Boot recovery succeeded but alarms not recreated (rescheduled=$rescheduled, after_count=$after_count)"
|
||
test1_passed=false
|
||
step_fail "p3_t1_s4" "Alarms not recreated"
|
||
elif [[ "$after_count" -gt 0 && "$test1_passed" == "true" ]]; then
|
||
ok "Alarms successfully recreated after boot (after_count=$after_count)"
|
||
step_pass "p3_t1_s4" "Boot recovery successful"
|
||
else
|
||
step_fail "p3_t1_s4" "Boot recovery failed"
|
||
fi
|
||
|
||
# Emit verdict
|
||
set_test_context "phase3" "phase3_test1" "p3_t1_s5"
|
||
if [[ "$test1_passed" == "true" ]]; then
|
||
verdict_pass "phase3_test1_boot_future_alarms" "$test1_message"
|
||
else
|
||
verdict_fail "phase3_test1_boot_future_alarms" "$test1_message"
|
||
fi
|
||
|
||
evidence_block "phase3_test1_boot_future_alarms"
|
||
}
|
||
|
||
# ------------------------------------------------------------------------------
|
||
# TEST 2 – Boot with Past Alarms
|
||
# ------------------------------------------------------------------------------
|
||
|
||
test2_boot_past_alarms() {
|
||
section "TEST 2: Boot with Past Alarms"
|
||
|
||
# Set test context
|
||
set_test_context "phase3" "phase3_test2" ""
|
||
|
||
info "Purpose: Verify missed alarms are detected and next occurrence is scheduled on boot."
|
||
info "Expected time: 5-6 minutes (includes 3min wait + 30-60s reboot)"
|
||
info "Automatable: Partial (requires manual time advancement or wait)"
|
||
info "If you see: 'No missed alarms detected' → Verify alarm time actually passed before reboot"
|
||
info "Automation hint: Use 'adb shell date' to check current time, advance if needed"
|
||
echo ""
|
||
|
||
pause
|
||
|
||
# Capture initial state
|
||
set_test_context "phase3" "phase3_test2" "p3_t2_s1"
|
||
step_start "p3_t2_s1" "Schedule notification for past time"
|
||
capture_alarms "phase3_test2_initial"
|
||
capture_logcat "phase3_test2_initial" "DNP" 50
|
||
|
||
substep "Step 1: Launch app & ensure plugin configured"
|
||
launch_app
|
||
|
||
ui_prompt "1) In the app UI, verify plugin status:
|
||
|
||
⚙️ Plugin Settings: ✅ Configured
|
||
🔌 Native Fetcher: ✅ Configured
|
||
|
||
If needed, click 'Configure Plugin', then press Enter."
|
||
|
||
ui_prompt "2) Click 'Test Notification' to schedule a notification for 2 minutes in the future.
|
||
|
||
After scheduling, we'll wait for the alarm time to pass, then reboot."
|
||
|
||
step_pass "p3_t2_s1" "Notification scheduled"
|
||
|
||
# Capture before wait state
|
||
capture_alarms "phase3_test2_before_wait"
|
||
|
||
substep "Step 2: Wait for alarm time to pass"
|
||
set_test_context "phase3" "phase3_test2" "p3_t2_s2"
|
||
step_start "p3_t2_s2" "Wait for alarm time to pass"
|
||
info "Waiting 3 minutes for scheduled alarm time to pass..."
|
||
warn "You can manually advance system time if needed (requires root/emulator)"
|
||
sleep 180 # Wait 3 minutes
|
||
step_pass "p3_t2_s2" "Alarm time passed"
|
||
|
||
# Capture after wait state
|
||
capture_alarms "phase3_test2_after_wait"
|
||
|
||
substep "Step 3: Verify alarm time has passed"
|
||
set_test_context "phase3" "phase3_test2" "p3_t2_s3"
|
||
step_start "p3_t2_s3" "Reboot emulator"
|
||
info "Alarm time should now be in the past"
|
||
show_alarms
|
||
|
||
pause
|
||
|
||
substep "Step 4: Reboot emulator"
|
||
warn "The emulator will reboot now. This will take 30-60 seconds."
|
||
pause
|
||
reboot_emulator
|
||
step_pass "p3_t2_s3" "Emulator rebooted"
|
||
|
||
substep "Step 5: Collect boot recovery logs"
|
||
set_test_context "phase3" "phase3_test2" "p3_t2_s4"
|
||
step_start "p3_t2_s4" "Collect boot recovery logs"
|
||
info "Collecting recovery logs from boot..."
|
||
sleep 2
|
||
|
||
# Capture after reboot state
|
||
capture_alarms "phase3_test2_after_reboot"
|
||
capture_logcat "phase3_test2_after_reboot" "DNP-REACTIVATION" 250
|
||
capture_screenshot "phase3_test2_after_reboot"
|
||
|
||
local logs
|
||
logs="$(get_recovery_logs)"
|
||
echo "$logs"
|
||
|
||
local missed rescheduled verified errors scenario
|
||
# For TEST 2, we need the FIRST entry (which has missed count) not the last
|
||
# Boot recovery runs twice (LOCKED_BOOT_COMPLETED and BOOT_COMPLETED)
|
||
# First run marks missed alarms, second run only reschedules (missed=0)
|
||
missed="$(echo "$logs" | grep -E "missed=" | sed -E "s/.*missed=([0-9]+).*/\1/" | head -n1 || echo "0")"
|
||
rescheduled="$(extract_field_from_logs "$logs" "rescheduled")"
|
||
verified="$(extract_field_from_logs "$logs" "verified")"
|
||
errors="$(extract_field_from_logs "$logs" "errors")"
|
||
scenario="$(extract_scenario_from_logs "$logs")"
|
||
|
||
echo
|
||
info "Parsed recovery summary:"
|
||
echo " scenario = ${scenario:-<none>}"
|
||
echo " missed = ${missed}"
|
||
echo " rescheduled= ${rescheduled}"
|
||
echo " verified = ${verified}"
|
||
echo " errors = ${errors}"
|
||
echo
|
||
|
||
# Determine verdict
|
||
local test2_passed=false
|
||
local test2_message=""
|
||
|
||
if [[ "$errors" -gt 0 ]]; then
|
||
error "Recovery reported errors>0 (errors=$errors)"
|
||
test2_message="Recovery reported errors (errors=$errors)"
|
||
fi
|
||
|
||
if [[ "$missed" -ge 1 && "$rescheduled" -ge 1 ]]; then
|
||
ok "TEST 2 PASSED: Past alarms detected and next occurrence scheduled (missed=$missed, rescheduled=$rescheduled)."
|
||
test2_passed=true
|
||
test2_message="Past alarms detected and next occurrence scheduled (missed=$missed, rescheduled=$rescheduled)"
|
||
elif [[ "$missed" -ge 1 ]]; then
|
||
test2_message="Past alarms detected (missed=$missed) but rescheduled=$rescheduled. Check reschedule logic."
|
||
else
|
||
test2_message="No missed alarms detected. Verify alarm time actually passed before reboot (missed=$missed, rescheduled=$rescheduled)"
|
||
fi
|
||
|
||
if [[ "$test2_passed" == "true" ]]; then
|
||
step_pass "p3_t2_s4" "Past alarms detected and rescheduled"
|
||
else
|
||
step_fail "p3_t2_s4" "Past alarms not detected"
|
||
fi
|
||
|
||
# Emit verdict
|
||
set_test_context "phase3" "phase3_test2" "p3_t2_s5"
|
||
if [[ "$test2_passed" == "true" ]]; then
|
||
verdict_pass "phase3_test2_boot_past_alarms" "$test2_message"
|
||
else
|
||
verdict_fail "phase3_test2_boot_past_alarms" "$test2_message"
|
||
fi
|
||
|
||
evidence_block "phase3_test2_boot_past_alarms"
|
||
}
|
||
|
||
# ------------------------------------------------------------------------------
|
||
# TEST 3 – Boot with No Schedules
|
||
# ------------------------------------------------------------------------------
|
||
|
||
test3_boot_no_schedules() {
|
||
section "TEST 3: Boot with No Schedules"
|
||
|
||
# Set test context
|
||
set_test_context "phase3" "phase3_test3" ""
|
||
|
||
info "Purpose: Verify boot recovery handles empty database gracefully."
|
||
info "Expected time: 2-3 minutes (includes 30-60s reboot)"
|
||
info "Automatable: Yes"
|
||
info "If you see: 'rescheduled>0 on first launch' → Check that boot recovery isn't misfiring"
|
||
echo ""
|
||
|
||
pause
|
||
|
||
# Capture initial state (before uninstall)
|
||
set_test_context "phase3" "phase3_test3" "p3_t3_s1"
|
||
step_start "p3_t3_s1" "Fresh install"
|
||
capture_alarms "phase3_test3_initial"
|
||
|
||
substep "Step 1: Uninstall app to clear DB/state"
|
||
set +e
|
||
$ADB_BIN uninstall "$APP_ID" >/dev/null 2>&1
|
||
set -e
|
||
ok "App uninstalled (state cleared)"
|
||
|
||
substep "Step 2: Reinstall app"
|
||
if $ADB_BIN install -r "$APK_PATH"; then
|
||
ok "App installed"
|
||
step_pass "p3_t3_s1" "Fresh install complete"
|
||
else
|
||
error "Reinstall failed"
|
||
step_fail "p3_t3_s1" "Reinstall failed"
|
||
exit 1
|
||
fi
|
||
|
||
info "Clearing logcat..."
|
||
clear_logs
|
||
ok "Logs cleared"
|
||
|
||
pause
|
||
|
||
substep "Step 3: Reboot emulator WITHOUT scheduling anything"
|
||
set_test_context "phase3" "phase3_test3" "p3_t3_s2"
|
||
step_start "p3_t3_s2" "Reboot without schedules"
|
||
warn "Do NOT schedule any notifications. The app should have no schedules in the database."
|
||
warn "The emulator will reboot now. This will take 30-60 seconds."
|
||
pause
|
||
reboot_emulator
|
||
step_pass "p3_t3_s2" "Emulator rebooted"
|
||
|
||
substep "Step 4: Collect boot recovery logs"
|
||
set_test_context "phase3" "phase3_test3" "p3_t3_s3"
|
||
step_start "p3_t3_s3" "Verify no recovery ran"
|
||
info "Collecting recovery logs from boot..."
|
||
sleep 2
|
||
|
||
# Capture after reboot state
|
||
capture_alarms "phase3_test3_after_reboot"
|
||
capture_logcat "phase3_test3_after_reboot" "DNP-REACTIVATION" 250
|
||
capture_screenshot "phase3_test3_after_reboot"
|
||
|
||
local logs
|
||
logs="$(get_recovery_logs)"
|
||
echo "$logs"
|
||
|
||
local scenario rescheduled missed
|
||
scenario="$(extract_scenario_from_logs "$logs")"
|
||
rescheduled="$(extract_field_from_logs "$logs" "rescheduled")"
|
||
missed="$(extract_field_from_logs "$logs" "missed")"
|
||
|
||
echo
|
||
info "Parsed recovery summary:"
|
||
echo " scenario = ${scenario:-<none>}"
|
||
echo " rescheduled= ${rescheduled}"
|
||
echo " missed = ${missed}"
|
||
echo
|
||
|
||
# Determine verdict
|
||
local test3_passed=false
|
||
local test3_message=""
|
||
|
||
if [[ -z "$logs" ]]; then
|
||
ok "TEST 3 PASSED: No recovery logs when there are no schedules (safe behavior)."
|
||
test3_passed=true
|
||
test3_message="No recovery logs when there are no schedules (safe behavior)"
|
||
elif echo "$logs" | grep -qiE "No schedules found|No schedules present"; then
|
||
ok "TEST 3 PASSED: Explicit 'No schedules found' message logged with no rescheduling."
|
||
test3_passed=true
|
||
test3_message="Explicit 'No schedules found' message logged with no rescheduling"
|
||
elif [[ "$scenario" == "$NONE_SCENARIO_VALUE" && "$rescheduled" -eq 0 ]]; then
|
||
ok "TEST 3 PASSED: NONE scenario detected with no rescheduling."
|
||
test3_passed=true
|
||
test3_message="NONE scenario detected with no rescheduling (scenario=$scenario, rescheduled=$rescheduled)"
|
||
elif [[ "$rescheduled" -gt 0 ]]; then
|
||
test3_message="rescheduled>0 on first launch / empty DB. Check that boot recovery isn't misfiring (rescheduled=$rescheduled)"
|
||
else
|
||
test3_passed=true # Not a failure, just needs review
|
||
test3_message="Logs present but no rescheduling; review scenario handling to ensure it's explicit about NONE / NO_SCHEDULES (scenario=${scenario:-<none>}, rescheduled=$rescheduled)"
|
||
fi
|
||
|
||
if [[ "$test3_passed" == "true" ]]; then
|
||
step_pass "p3_t3_s3" "No recovery ran (correct)"
|
||
else
|
||
step_fail "p3_t3_s3" "Recovery ran when it shouldn't"
|
||
fi
|
||
|
||
# Emit verdict
|
||
set_test_context "phase3" "phase3_test3" "p3_t3_s4"
|
||
if [[ "$test3_passed" == "true" ]]; then
|
||
verdict_pass "phase3_test3_boot_no_schedules" "$test3_message"
|
||
else
|
||
verdict_fail "phase3_test3_boot_no_schedules" "$test3_message"
|
||
fi
|
||
|
||
evidence_block "phase3_test3_boot_no_schedules"
|
||
}
|
||
|
||
# ------------------------------------------------------------------------------
|
||
# TEST 4 – Silent Boot Recovery (App Never Opened)
|
||
# ------------------------------------------------------------------------------
|
||
|
||
test4_silent_boot_recovery() {
|
||
section "TEST 4: Silent Boot Recovery (App Never Opened)"
|
||
|
||
# Set test context
|
||
set_test_context "phase3" "phase3_test4" ""
|
||
|
||
info "Purpose: Verify boot recovery occurs even when the app is never opened after reboot."
|
||
info "Expected time: 2-3 minutes (includes 30-60s reboot)"
|
||
info "Automatable: Partial (requires manual verification that app was not opened)"
|
||
info "If you see: 'Boot recovery not detected' → Verify boot receiver is registered and has BOOT_COMPLETED permission"
|
||
echo ""
|
||
|
||
pause
|
||
|
||
# Capture initial state
|
||
set_test_context "phase3" "phase3_test4" "p3_t4_s1"
|
||
step_start "p3_t4_s1" "Schedule notification"
|
||
capture_alarms "phase3_test4_initial"
|
||
capture_logcat "phase3_test4_initial" "DNP" 50
|
||
|
||
substep "Step 1: Launch app & ensure plugin configured"
|
||
launch_app
|
||
|
||
ui_prompt "1) In the app UI, verify plugin status:
|
||
|
||
⚙️ Plugin Settings: ✅ Configured
|
||
🔌 Native Fetcher: ✅ Configured
|
||
|
||
If needed, click 'Configure Plugin', then press Enter."
|
||
|
||
ui_prompt "2) Click 'Test Notification' to schedule a notification for a few minutes in the future."
|
||
|
||
step_pass "p3_t4_s1" "Notification scheduled"
|
||
|
||
# Capture before reboot state
|
||
capture_alarms "phase3_test4_before_reboot"
|
||
|
||
substep "Step 2: Verify alarms are scheduled"
|
||
set_test_context "phase3" "phase3_test4" "p3_t4_s2"
|
||
step_start "p3_t4_s2" "Reboot without opening app"
|
||
show_alarms
|
||
local before_count system_before
|
||
before_count="$(get_plugin_alarm_count)"
|
||
system_before="$(get_system_alarm_count)"
|
||
info "Plugin alarms before reboot: $before_count (expected: 1)"
|
||
info "System/other alarms: $system_before (for context)"
|
||
|
||
if [[ "$before_count" -eq 0 ]]; then
|
||
warn "No plugin alarms found; TEST 4 may not be meaningful."
|
||
step_warn "p3_t4_s2" "No alarms found"
|
||
elif [[ "$before_count" -eq 1 ]]; then
|
||
ok "Single plugin alarm confirmed (one per day)"
|
||
step_pass "p3_t4_s2" "Alarms verified"
|
||
else
|
||
warn "Found $before_count plugin alarms (expected: 1)"
|
||
step_warn "p3_t4_s2" "Unexpected alarm count"
|
||
fi
|
||
|
||
pause
|
||
|
||
substep "Step 3: Reboot emulator (DO NOT open app after reboot)"
|
||
warn "IMPORTANT: After reboot, DO NOT open the app. Boot recovery should run silently."
|
||
warn "The emulator will reboot now. This will take 30-60 seconds."
|
||
pause
|
||
reboot_emulator
|
||
step_pass "p3_t4_s2" "Emulator rebooted (app not opened)"
|
||
|
||
substep "Step 4: Collect boot recovery logs (without opening app)"
|
||
set_test_context "phase3" "phase3_test4" "p3_t4_s3"
|
||
step_start "p3_t4_s3" "Collect boot recovery logs"
|
||
info "Collecting recovery logs from boot (app was NOT opened)..."
|
||
sleep 2
|
||
|
||
# Capture after reboot state (without opening app)
|
||
capture_alarms "phase3_test4_after_reboot"
|
||
capture_logcat "phase3_test4_after_reboot" "DNP-REACTIVATION" 250
|
||
capture_screenshot "phase3_test4_after_reboot"
|
||
|
||
local logs
|
||
logs="$(get_recovery_logs)"
|
||
echo "$logs"
|
||
|
||
local missed rescheduled verified errors scenario
|
||
missed="$(extract_field_from_logs "$logs" "missed")"
|
||
rescheduled="$(extract_field_from_logs "$logs" "rescheduled")"
|
||
verified="$(extract_field_from_logs "$logs" "verified")"
|
||
errors="$(extract_field_from_logs "$logs" "errors")"
|
||
scenario="$(extract_scenario_from_logs "$logs")"
|
||
|
||
echo
|
||
info "Parsed recovery summary:"
|
||
echo " scenario = ${scenario:-<none>}"
|
||
echo " missed = ${missed}"
|
||
echo " rescheduled= ${rescheduled}"
|
||
echo " verified = ${verified}"
|
||
echo " errors = ${errors}"
|
||
echo
|
||
|
||
substep "Step 5: Verify alarms were recreated (without opening app)"
|
||
show_alarms
|
||
local after_count system_after
|
||
after_count="$(get_plugin_alarm_count)"
|
||
system_after="$(get_system_alarm_count)"
|
||
info "Plugin alarms after boot (app never opened): $after_count (expected: 1)"
|
||
info "System/other alarms: $system_after (for context)"
|
||
|
||
# Determine verdict
|
||
local test4_passed=false
|
||
local test4_message=""
|
||
|
||
if [[ "$errors" -gt 0 ]]; then
|
||
error "Recovery reported errors>0 (errors=$errors)"
|
||
test4_message="Recovery reported errors (errors=$errors)"
|
||
fi
|
||
|
||
if [[ "$after_count" -gt 0 && "$rescheduled" -gt 0 ]]; then
|
||
ok "TEST 4 PASSED: Boot recovery occurred silently and alarms were recreated (rescheduled=$rescheduled) without app launch."
|
||
test4_passed=true
|
||
test4_message="Boot recovery occurred silently and alarms were recreated (rescheduled=$rescheduled, after_count=$after_count) without app launch"
|
||
elif [[ "$rescheduled" -gt 0 ]]; then
|
||
ok "TEST 4 PASSED: Boot recovery occurred silently (rescheduled=$rescheduled), but alarm count check unclear."
|
||
test4_passed=true
|
||
test4_message="Boot recovery occurred silently (rescheduled=$rescheduled), but alarm count unclear (after_count=$after_count)"
|
||
elif echo "$logs" | grep -qi "Starting boot recovery\|boot recovery"; then
|
||
test4_message="Boot recovery ran but alarms may not have been recreated. Check logs and implementation (rescheduled=$rescheduled, after_count=$after_count)"
|
||
else
|
||
test4_message="Boot recovery not detected. Verify boot receiver is registered and has BOOT_COMPLETED permission (scenario=${scenario:-<none>}, rescheduled=$rescheduled)"
|
||
fi
|
||
|
||
if [[ "$test4_passed" == "true" ]]; then
|
||
step_pass "p3_t4_s3" "Silent boot recovery successful"
|
||
else
|
||
step_fail "p3_t4_s3" "Silent boot recovery failed"
|
||
fi
|
||
|
||
# Emit verdict
|
||
set_test_context "phase3" "phase3_test4" "p3_t4_s4"
|
||
if [[ "$test4_passed" == "true" ]]; then
|
||
verdict_pass "phase3_test4_silent_boot_recovery" "$test4_message"
|
||
else
|
||
verdict_fail "phase3_test4_silent_boot_recovery" "$test4_message"
|
||
fi
|
||
|
||
evidence_block "phase3_test4_silent_boot_recovery"
|
||
}
|
||
|
||
# ------------------------------------------------------------------------------
|
||
# Main
|
||
# ------------------------------------------------------------------------------
|
||
|
||
main() {
|
||
# Parse CLI args for --gate-phase3 flag
|
||
local gate_phase3=0
|
||
local test_args=()
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
-h|--help)
|
||
echo "Usage: $0 [--gate-phase3] [TEST_IDS...]"
|
||
echo
|
||
echo "If no TEST_IDS are given, all tests (1, 2, 3, 4) will run."
|
||
echo
|
||
echo "Options:"
|
||
echo " --gate-phase3 Enable release gating (failures exit with non-zero)"
|
||
echo " Equivalent to: RELEASE_GATE_PHASE3=1 $0"
|
||
echo
|
||
echo "Environment:"
|
||
echo " RELEASE_GATE_PHASE3=0|1 Release gating mode (default: 0)"
|
||
echo " 0 = advisory (warn and continue)"
|
||
echo " 1 = release-blocking (fail and exit)"
|
||
echo
|
||
echo "Examples:"
|
||
echo " $0 # run all tests (advisory mode)"
|
||
echo " $0 1 # run only TEST 1 (advisory mode)"
|
||
echo " $0 --gate-phase3 # run all tests (release-blocking mode)"
|
||
echo " $0 --gate-phase3 2 3 # run TEST 2 and 3 (release-blocking mode)"
|
||
echo " RELEASE_GATE_PHASE3=1 $0 # same as --gate-phase3"
|
||
return 0
|
||
;;
|
||
--gate-phase3)
|
||
gate_phase3=1
|
||
shift
|
||
;;
|
||
*)
|
||
test_args+=("$1")
|
||
shift
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# Set RELEASE_GATE_PHASE3 if flag was provided
|
||
if [[ "$gate_phase3" -eq 1 ]]; then
|
||
RELEASE_GATE_PHASE3=1
|
||
fi
|
||
|
||
SELECTED_TESTS=("${test_args[@]}")
|
||
|
||
section "Phase 3 Testing Script – Boot Recovery"
|
||
|
||
info "Mode: ${RELEASE_GATE_PHASE3:-0} (0=advisory, 1=release-blocking)"
|
||
info "Run ID: ${RUN_ID}"
|
||
info "Evidence directory: $(get_run_dir)"
|
||
echo ""
|
||
info "This script will guide you through Phase 3 tests."
|
||
info "You'll be prompted when UI interaction is needed."
|
||
echo ""
|
||
warn "⚠️ WARNING: This script will reboot the emulator multiple times."
|
||
info " Each reboot takes 30-60 seconds."
|
||
echo ""
|
||
|
||
pause
|
||
|
||
require_adb_device
|
||
build_app
|
||
install_app
|
||
|
||
if should_run_test "1" SELECTED_TESTS; then
|
||
test1_boot_future_alarms
|
||
pause
|
||
fi
|
||
|
||
if should_run_test "2" SELECTED_TESTS; then
|
||
test2_boot_past_alarms
|
||
pause
|
||
fi
|
||
|
||
if should_run_test "3" SELECTED_TESTS; then
|
||
test3_boot_no_schedules
|
||
pause
|
||
fi
|
||
|
||
if should_run_test "4" SELECTED_TESTS; then
|
||
test4_silent_boot_recovery
|
||
fi
|
||
|
||
section "Testing Complete"
|
||
|
||
info "Test Results Summary:"
|
||
echo ""
|
||
echo "All test verdicts are shown above with evidence locations."
|
||
echo "Review evidence in: $(get_run_dir)"
|
||
echo ""
|
||
echo "Release gating mode: ${RELEASE_GATE_PHASE3:-0}"
|
||
echo " - 0 (advisory): Failures become warnings, script continues"
|
||
echo " - 1 (release-blocking): Failures cause script to exit with non-zero"
|
||
echo ""
|
||
|
||
ok "Phase 3 testing script complete!"
|
||
echo ""
|
||
echo "Next steps:"
|
||
echo " - Review evidence in: $(get_run_dir)"
|
||
echo " - Verify all test verdicts above"
|
||
echo " - Update documentation with test results"
|
||
echo ""
|
||
}
|
||
|
||
main "$@"
|