Extract common helper functions from test-phase1.sh, test-phase2.sh, and test-phase3.sh into a shared library (alarm-test-lib.sh) to reduce code duplication and improve maintainability. Changes: - Create alarm-test-lib.sh with shared configuration, UI helpers, ADB helpers, log parsing, and test selection logic - Refactor all three phase test scripts to source the shared library - Remove ~200 lines of duplicated code across the three scripts - Preserve all existing behavior, CLI arguments, and test semantics - Maintain Phase 1 compatibility (print_* functions, VERIFY_FIRE flag) - Update all adb references to use $ADB_BIN variable - Standardize alarm counting to use shared count_alarms() function Benefits: - Single source of truth for shared helpers - Easier maintenance (fix once, benefits all scripts) - Consistent behavior across all test phases - No functional changes to test execution or results
642 lines
26 KiB
Bash
Executable File
642 lines
26 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# Phase 1 Testing Script - Interactive Test Runner
|
||
# Guides through all Phase 1 tests with clear prompts for UI interaction
|
||
|
||
set -e # Exit on error
|
||
|
||
# Source shared library
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
source "${SCRIPT_DIR}/alarm-test-lib.sh"
|
||
|
||
# Phase 1 specific configuration
|
||
VERIFY_FIRE=${VERIFY_FIRE:-false} # Set VERIFY_FIRE=true to enable alarm fire verification
|
||
APP_DIR="${SCRIPT_DIR}"
|
||
PROJECT_ROOT="$(cd "${APP_DIR}/../.." && pwd)"
|
||
|
||
# Allow selecting specific tests on the command line (e.g. ./test-phase1.sh 1 2)
|
||
SELECTED_TESTS=()
|
||
|
||
check_plugin_configured() {
|
||
print_info "Checking if plugin is already configured..."
|
||
|
||
# Wait a moment for app to fully load
|
||
sleep 3
|
||
|
||
# Check if database exists (indicates plugin has been used)
|
||
DB_EXISTS=$($ADB_BIN shell run-as "${APP_ID}" ls databases/ 2>/dev/null | grep -c "daily_notification" || echo "0")
|
||
|
||
# Check if SharedPreferences has configuration (more reliable)
|
||
# The plugin stores config in SharedPreferences
|
||
PREFS_EXISTS=$($ADB_BIN shell run-as "${APP_ID}" ls shared_prefs/ 2>/dev/null | grep -c "DailyNotification" || echo "0")
|
||
|
||
# Check recent logs for configuration activity
|
||
RECENT_CONFIG=$($ADB_BIN logcat -d -t 50 | grep -E "Plugin configured|configurePlugin|Configuration" | tail -3)
|
||
|
||
if [ "${DB_EXISTS}" -gt "0" ] || [ "${PREFS_EXISTS}" -gt "0" ]; then
|
||
print_success "Plugin appears to be configured (database or preferences exist)"
|
||
|
||
# Show user what to check in UI
|
||
print_info "Please verify in the app UI that you see:"
|
||
echo " ⚙️ Plugin Settings: ✅ Configured"
|
||
echo " 🔌 Native Fetcher: ✅ Configured"
|
||
echo ""
|
||
echo "If both show ✅, the plugin is configured and you can skip configuration."
|
||
echo "If either shows ❌ or 'Not configured', you'll need to click 'Configure Plugin'."
|
||
echo ""
|
||
|
||
return 0
|
||
else
|
||
print_info "Plugin not configured (no database or preferences found)"
|
||
print_info "You will need to click 'Configure Plugin' in the app UI"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
check_permissions() {
|
||
print_info "Checking notification permissions..."
|
||
|
||
# Check if POST_NOTIFICATIONS permission is granted (Android 13+)
|
||
PERM_CHECK=$($ADB_BIN shell dumpsys package "${APP_ID}" | grep -A 5 "granted=true" | grep -c "android.permission.POST_NOTIFICATIONS" || echo "0")
|
||
|
||
# Also check via app's permission status if available
|
||
PERM_GRANTED=false
|
||
if [ "${PERM_CHECK}" -gt "0" ]; then
|
||
PERM_GRANTED=true
|
||
else
|
||
# Check if we're on Android 12 or below (permission not required)
|
||
SDK_VERSION=$($ADB_BIN shell getprop ro.build.version.sdk)
|
||
if [ "${SDK_VERSION}" -lt "33" ]; then
|
||
PERM_GRANTED=true # Pre-Android 13 doesn't need runtime permission
|
||
fi
|
||
fi
|
||
|
||
if [ "${PERM_GRANTED}" = true ]; then
|
||
print_success "Notification permissions granted"
|
||
return 0
|
||
else
|
||
print_warn "Notification permissions may not be granted"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
ensure_permissions() {
|
||
if check_permissions; then
|
||
print_success "Permissions already granted"
|
||
return 0
|
||
else
|
||
print_info "Notification permissions needed"
|
||
wait_for_ui_action "In the app UI, click the 'Request Permissions' button.
|
||
|
||
This will show a system permission dialog.
|
||
|
||
Steps:
|
||
1. Click 'Request Permissions' button
|
||
2. In the system dialog, tap 'Allow' to grant notification permission
|
||
3. Return to the app and verify the status shows:
|
||
- 🔔 Notifications: ✅ Granted (or similar)
|
||
|
||
Once permission is granted, press Enter to continue."
|
||
|
||
# Re-check permissions
|
||
sleep 2
|
||
if check_permissions; then
|
||
print_success "Permissions granted"
|
||
return 0
|
||
else
|
||
print_warn "Permissions may still not be granted - continuing anyway"
|
||
print_info "If notifications fail, you may need to grant permissions manually"
|
||
return 1
|
||
fi
|
||
fi
|
||
}
|
||
|
||
ensure_plugin_configured() {
|
||
if check_plugin_configured; then
|
||
# Plugin might be configured, but let user verify
|
||
wait_for_ui_action "Please check the Plugin Status section at the top of the app.
|
||
|
||
If you see:
|
||
- ⚙️ Plugin Settings: ✅ Configured
|
||
- 🔌 Native Fetcher: ✅ Configured
|
||
- 🔔 Notifications: ✅ Granted (or similar)
|
||
|
||
Then the plugin is already configured - just press Enter to continue.
|
||
|
||
If any show ❌ or 'Not configured':
|
||
- Click 'Request Permissions' if notifications are not granted
|
||
- Click 'Configure Plugin' if settings/fetcher are not configured
|
||
- Wait for all to show ✅, then press Enter."
|
||
|
||
# Give a moment for any configuration that just happened
|
||
sleep 2
|
||
print_success "Continuing with tests (plugin configuration verified or skipped)"
|
||
return 0
|
||
else
|
||
# Plugin definitely needs configuration
|
||
print_info "Plugin needs configuration"
|
||
|
||
# First ensure permissions
|
||
ensure_permissions
|
||
|
||
wait_for_ui_action "Click the 'Configure Plugin' button in the app UI.
|
||
|
||
Wait for the status to update:
|
||
- ⚙️ Plugin Settings: Should change to ✅ Configured
|
||
- 🔌 Native Fetcher: Should change to ✅ Configured
|
||
|
||
Once both show ✅, press Enter to continue."
|
||
|
||
# Verify configuration completed
|
||
sleep 2
|
||
print_success "Plugin configuration completed (or verified)"
|
||
fi
|
||
}
|
||
|
||
# kill_app is now provided by the library, but Phase 1 uses it with PACKAGE variable
|
||
# The library version uses APP_ID, which is set to PACKAGE, so it should work
|
||
# But we keep this as a compatibility wrapper if needed
|
||
|
||
# Phase 1 specific helper: get_current_time (used for fire verification)
|
||
get_current_time() {
|
||
$ADB_BIN shell date +%s
|
||
}
|
||
|
||
# Main test execution
|
||
main() {
|
||
# Allow selecting specific tests: e.g. `./test-phase1.sh 1 2`
|
||
if [[ "$#" -gt 0 && ( "$1" == "-h" || "$1" == "--help" ) ]]; then
|
||
echo "Usage: $0 [TEST_IDS...]"
|
||
echo ""
|
||
echo "If no TEST_IDS are given, all tests (1, 2, 3, 4) will run."
|
||
echo "Examples:"
|
||
echo " $0 # run all tests"
|
||
echo " $0 1 # run only TEST 1"
|
||
echo " $0 2 3 # run only TEST 2 and TEST 3"
|
||
echo " $0 4 # run only TEST 4"
|
||
return 0
|
||
fi
|
||
|
||
SELECTED_TESTS=("$@")
|
||
|
||
print_header "Phase 1 Testing Script"
|
||
echo "This script will guide you through Phase 1 tests."
|
||
echo "You'll be prompted when UI interaction is needed."
|
||
echo ""
|
||
wait_for_user
|
||
|
||
# Pre-flight checks
|
||
print_header "Pre-Flight Checks"
|
||
check_adb_connection
|
||
check_emulator_ready
|
||
|
||
# Build and install
|
||
build_app
|
||
install_app
|
||
|
||
# Clear logs
|
||
clear_logs
|
||
|
||
# ============================================
|
||
# TEST 1: Force-Stop Recovery - Database Restoration
|
||
# ============================================
|
||
if should_run_test "1" SELECTED_TESTS; then
|
||
print_header "TEST 1: Force-Stop Recovery - Database Restoration"
|
||
echo "Purpose: Verify that after force-stop (which clears alarms), recovery"
|
||
echo " uses the database to rebuild alarms on app relaunch."
|
||
echo ""
|
||
echo "Note: App supports one alarm per day."
|
||
echo ""
|
||
echo "Test sequence:"
|
||
echo " 1. Clean start - verify no lingering alarms"
|
||
echo " 2. Schedule one alarm → Verify it exists in AlarmManager"
|
||
echo " 3. Force-stop app → Verify alarm is cleared (count = 0)"
|
||
echo " 4. Relaunch app → Verify recovery rebuilds alarm from database"
|
||
echo " 5. Verify alarm actually fires at scheduled time (optional)"
|
||
echo ""
|
||
wait_for_user
|
||
|
||
# ============================================
|
||
# Step 1: Clean start - verify no lingering alarms
|
||
# ============================================
|
||
print_step "1" "Clean start - checking for lingering alarms..."
|
||
LINGERING_COUNT=$(count_alarms)
|
||
if [ "${LINGERING_COUNT}" -gt "0" ] 2>/dev/null; then
|
||
print_warn "Found ${LINGERING_COUNT} lingering alarm(s) - these may interfere with test"
|
||
print_info "Consider uninstalling/reinstalling app for clean state"
|
||
wait_for_user
|
||
else
|
||
print_success "No lingering alarms found (clean state)"
|
||
fi
|
||
|
||
# ============================================
|
||
# Step 2: Schedule a known future alarm
|
||
# ============================================
|
||
print_step "2" "Launch app and schedule alarm..."
|
||
launch_app
|
||
ensure_plugin_configured
|
||
|
||
wait_for_ui_action "In the app UI, click the 'Test Notification' button.
|
||
|
||
This will schedule ONE notification for 4 minutes in the future.
|
||
(App supports one alarm per day)
|
||
|
||
The alarm will be stored in the database AND scheduled in AlarmManager."
|
||
|
||
print_step "3" "Verifying alarm exists in AlarmManager (BEFORE force-stop)..."
|
||
sleep 2
|
||
|
||
ALARM_COUNT_BEFORE=$(count_alarms)
|
||
print_info "Alarm count in AlarmManager: ${ALARM_COUNT_BEFORE}"
|
||
|
||
if [ "${ALARM_COUNT_BEFORE}" -eq "0" ] 2>/dev/null; then
|
||
print_error "No alarms found in AlarmManager - cannot test force-stop recovery"
|
||
print_info "Make sure you clicked 'Test Notification' and wait a moment"
|
||
wait_for_user
|
||
# Re-check
|
||
ALARM_COUNT_BEFORE=$(count_alarms)
|
||
if [ "${ALARM_COUNT_BEFORE}" -eq "0" ] 2>/dev/null; then
|
||
print_error "Still no alarms found - aborting test"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
print_success "✅ Alarms confirmed in AlarmManager (count: ${ALARM_COUNT_BEFORE})"
|
||
|
||
# Capture alarm details for later verification
|
||
ALARM_DETAILS_BEFORE=$($ADB_BIN shell dumpsys alarm | grep -A 3 "$APP_ID" | head -10)
|
||
print_info "Alarm details:"
|
||
echo "${ALARM_DETAILS_BEFORE}" | head -5
|
||
echo ""
|
||
|
||
# Extract trigger time for later verification
|
||
ALARM_TRIGGER_MS=$(echo "${ALARM_DETAILS_BEFORE}" | grep -oE "origWhen [0-9]+" | head -1 | awk '{print $2}')
|
||
if [ -n "${ALARM_TRIGGER_MS}" ]; then
|
||
ALARM_TRIGGER_SEC=$((ALARM_TRIGGER_MS / 1000))
|
||
ALARM_READABLE=$(date -d "@${ALARM_TRIGGER_SEC}" 2>/dev/null || echo "${ALARM_TRIGGER_SEC}")
|
||
print_info "Alarm scheduled for: ${ALARM_READABLE} (${ALARM_TRIGGER_MS} ms)"
|
||
fi
|
||
|
||
print_info "Checking logs for scheduling confirmation..."
|
||
$ADB_BIN logcat -d | grep -E "DN|SCHEDULE|Stored notification content" | tail -5
|
||
echo ""
|
||
|
||
wait_for_user
|
||
|
||
# ============================================
|
||
# Step 3: Force-stop the app (clears alarms)
|
||
# ============================================
|
||
print_step "4" "Force-stopping app (clears all alarms)..."
|
||
print_warn "Force-stop will clear ALL alarms from AlarmManager"
|
||
print_info "Executing: $ADB_BIN shell am force-stop ${APP_ID}"
|
||
force_stop_app
|
||
sleep 2
|
||
|
||
# Verify app is stopped (force_stop_app already handles this)
|
||
|
||
# ============================================
|
||
# Step 4: Verify alarms are MISSING (cleared by OS)
|
||
# ============================================
|
||
print_step "5" "Verifying alarms are MISSING from AlarmManager (AFTER force-stop)..."
|
||
sleep 1
|
||
ALARM_COUNT_AFTER=$(count_alarms)
|
||
print_info "Alarm count in AlarmManager after force-stop: ${ALARM_COUNT_AFTER}"
|
||
|
||
if [ "${ALARM_COUNT_AFTER}" -eq "0" ] 2>/dev/null; then
|
||
print_success "✅ Alarms cleared by force-stop (count: ${ALARM_COUNT_AFTER})"
|
||
print_info "This confirms: Force-stop cleared alarms from AlarmManager"
|
||
else
|
||
print_warn "⚠️ Alarms still present after force-stop (count: ${ALARM_COUNT_AFTER})"
|
||
print_info "Some devices/OS versions may not clear alarms on force-stop"
|
||
print_info "Continuing test anyway - recovery should still work"
|
||
fi
|
||
|
||
wait_for_user
|
||
|
||
# ============================================
|
||
# Step 5: Relaunch app (triggers recovery from database)
|
||
# ============================================
|
||
print_step "6" "Relaunching app (triggers recovery from database)..."
|
||
clear_logs
|
||
launch_app
|
||
sleep 4 # Give recovery time to run
|
||
|
||
# ============================================
|
||
# Step 6: Verify recovery rebuilt alarms from database
|
||
# ============================================
|
||
print_step "7" "Verifying recovery rebuilt alarms from database..."
|
||
sleep 2
|
||
ALARM_COUNT_RECOVERED=$(count_alarms)
|
||
print_info "Alarm count in AlarmManager after recovery: ${ALARM_COUNT_RECOVERED}"
|
||
|
||
print_info "Checking recovery logs..."
|
||
check_recovery_logs
|
||
|
||
print_info "Expected log output:"
|
||
echo " DNP-REACTIVATION: Starting app launch recovery"
|
||
echo " DNP-REACTIVATION: Rescheduled alarm: <id> for <time>"
|
||
echo " DNP-REACTIVATION: Cold start recovery complete: ... rescheduled>=1, ..."
|
||
echo ""
|
||
|
||
# Check recovery logs for rescheduling and recovery source
|
||
RECOVERY_RESULT=$($ADB_BIN logcat -d | grep "Cold start recovery complete\|Boot recovery complete" | tail -1)
|
||
RESCHEDULED_COUNT=$(echo "${RECOVERY_RESULT}" | grep -oE "rescheduled=[0-9]+" | grep -oE "[0-9]+" || echo "0")
|
||
VERIFIED_COUNT=$(echo "${RECOVERY_RESULT}" | grep -oE "verified=[0-9]+" | grep -oE "[0-9]+" || echo "0")
|
||
|
||
# Check for explicit recovery source indication (if logged)
|
||
RECOVERY_SOURCE=$($ADB_BIN logcat -d | grep -E "recovery source|from database|DATABASE" | tail -1 || echo "")
|
||
|
||
# Pass/fail criteria
|
||
TEST1_PASSED=false
|
||
|
||
if [ "${ALARM_COUNT_RECOVERED}" -gt "0" ] 2>/dev/null; then
|
||
print_success "✅ Alarms restored in AlarmManager (count: ${ALARM_COUNT_RECOVERED})"
|
||
if [ "${RESCHEDULED_COUNT}" -gt "0" ] 2>/dev/null; then
|
||
print_success "✅ Recovery logs confirm rescheduling (rescheduled=${RESCHEDULED_COUNT})"
|
||
TEST1_PASSED=true
|
||
else
|
||
print_warn "⚠️ Alarms restored but logs show rescheduled=0"
|
||
print_info "This might be okay if alarms were verified instead of rescheduled"
|
||
# Still pass if alarms are restored, even if rescheduled=0
|
||
TEST1_PASSED=true
|
||
fi
|
||
else
|
||
print_error "❌ No alarms restored (count: ${ALARM_COUNT_RECOVERED})"
|
||
print_info "Recovery may have failed or alarms were not in database"
|
||
fi
|
||
|
||
if [ "${TEST1_PASSED}" = true ]; then
|
||
print_success "TEST 1 PASSED: Recovery successfully rebuilt alarms from database!"
|
||
print_info "Summary:"
|
||
echo " - Before force-stop: ${ALARM_COUNT_BEFORE} alarm(s)"
|
||
echo " - After force-stop: ${ALARM_COUNT_AFTER} alarm(s) (cleared)"
|
||
echo " - After recovery: ${ALARM_COUNT_RECOVERED} alarm(s) (rebuilt)"
|
||
echo " - Rescheduled: ${RESCHEDULED_COUNT} alarm(s)"
|
||
echo " - Verified: ${VERIFIED_COUNT} alarm(s)"
|
||
if [ -n "${RECOVERY_SOURCE}" ]; then
|
||
echo " - Recovery source: ${RECOVERY_SOURCE}"
|
||
fi
|
||
else
|
||
print_error "TEST 1 FAILED: Recovery did not rebuild alarms correctly"
|
||
print_info "Check logs above for recovery errors"
|
||
fi
|
||
|
||
# ============================================
|
||
# Step 7: Verify alarms actually fire (optional, controlled by VERIFY_FIRE flag)
|
||
# ============================================
|
||
if [ "${VERIFY_FIRE}" = "true" ] && [ -n "${ALARM_TRIGGER_MS}" ]; then
|
||
print_step "8" "Verifying alarm fires at scheduled time..."
|
||
|
||
# Get current time in milliseconds
|
||
CURRENT_TIME_SEC=$(get_current_time)
|
||
CURRENT_TIME_MS=$((CURRENT_TIME_SEC * 1000))
|
||
WAIT_MS=$((ALARM_TRIGGER_MS - CURRENT_TIME_MS))
|
||
|
||
if [ "${WAIT_MS}" -lt 0 ]; then
|
||
print_warn "Alarm time already passed (${WAIT_MS} ms ago); skipping fire verification"
|
||
else
|
||
WAIT_SEC=$((WAIT_MS / 1000))
|
||
|
||
# Clamp upper bound to prevent accidentally waiting 30+ minutes
|
||
if [ "${WAIT_SEC}" -gt 600 ]; then
|
||
print_warn "Alarm is >10 minutes away (${WAIT_SEC}s); skipping fire verification"
|
||
print_info "To test fire verification, schedule alarm closer to current time"
|
||
print_info "Or set a shorter test alarm interval in the app"
|
||
else
|
||
print_info "Alarm scheduled for: ${ALARM_READABLE}"
|
||
print_info "Current time: $(date -d "@${CURRENT_TIME_SEC}" 2>/dev/null || echo "${CURRENT_TIME_SEC}")"
|
||
print_info "Waiting ~${WAIT_SEC} seconds for alarm to fire..."
|
||
|
||
# Clear logs before waiting
|
||
clear_logs
|
||
|
||
# Wait for alarm time (with a small buffer)
|
||
sleep ${WAIT_SEC}
|
||
|
||
# Give alarm a moment to fire and log
|
||
sleep 2
|
||
|
||
print_info "Checking logs for fired alarm..."
|
||
ALARM_FIRED=$($ADB_BIN logcat -d | grep -E "DNP-RECEIVE|DNP-NOTIFY|DNP-WORK|Alarm fired|Notification displayed" | tail -10)
|
||
|
||
if [ -n "${ALARM_FIRED}" ]; then
|
||
print_success "✅ Alarm fired! Logs:"
|
||
echo "${ALARM_FIRED}"
|
||
else
|
||
print_warn "⚠️ No alarm fire logs found"
|
||
print_info "This might mean:"
|
||
echo " - Alarm fired but logs were cleared"
|
||
echo " - Alarm receiver didn't log"
|
||
echo " - Check notification tray manually"
|
||
print_info "Recent logs:"
|
||
$ADB_BIN logcat -d | grep -E "DNP|DailyNotification" | tail -10
|
||
fi
|
||
fi
|
||
fi
|
||
elif [ "${VERIFY_FIRE}" = "true" ]; then
|
||
print_info "Skipping fire verification (alarm trigger time not captured)"
|
||
else
|
||
print_info "Skipping fire verification (VERIFY_FIRE=false, set VERIFY_FIRE=true to enable)"
|
||
fi
|
||
|
||
wait_for_user
|
||
fi
|
||
|
||
# ============================================
|
||
# TEST 2: Future Alarm Verification
|
||
# ============================================
|
||
if should_run_test "2" SELECTED_TESTS; then
|
||
print_header "TEST 2: Future Alarm Verification"
|
||
echo "Purpose: Verify future alarms are verified/rescheduled if missing."
|
||
echo ""
|
||
echo "Note: This test verifies that recovery correctly handles multiple alarms."
|
||
echo " We'll schedule a second alarm to test recovery with multiple schedules."
|
||
echo ""
|
||
wait_for_user
|
||
|
||
print_step "1" "Launch app"
|
||
launch_app
|
||
ensure_plugin_configured
|
||
|
||
wait_for_ui_action "In the app UI, click 'Test Notification' to schedule a SECOND notification.
|
||
|
||
This creates an additional scheduled notification (you should now have 2 total).
|
||
This tests recovery behavior when multiple alarms exist in the database."
|
||
|
||
print_step "2" "Verifying alarms are scheduled..."
|
||
sleep 2
|
||
check_alarm_status
|
||
|
||
ALARM_COUNT=$(count_alarms)
|
||
print_info "Found ${ALARM_COUNT} scheduled alarm(s) (expected: 1)"
|
||
|
||
if [ "${ALARM_COUNT}" -eq "1" ] 2>/dev/null; then
|
||
print_success "✅ Single alarm confirmed in AlarmManager"
|
||
elif [ "${ALARM_COUNT}" -gt "1" ] 2>/dev/null; then
|
||
print_success "Alarms are scheduled in AlarmManager"
|
||
else
|
||
print_error "No alarms found in AlarmManager"
|
||
wait_for_user
|
||
fi
|
||
|
||
print_step "3" "Killing app and relaunching (triggers recovery)..."
|
||
kill_app
|
||
clear_logs
|
||
launch_app
|
||
|
||
print_step "4" "Checking recovery logs for verification..."
|
||
sleep 3
|
||
check_recovery_logs
|
||
|
||
print_info "Expected log output (either):"
|
||
echo " DNP-REACTIVATION: Verified scheduled alarm: <id> at <time>"
|
||
echo " OR"
|
||
echo " DNP-REACTIVATION: Rescheduled missing alarm: <id> at <time>"
|
||
echo " DNP-REACTIVATION: Cold start recovery complete: ..., verified=1 or rescheduled=1, ..."
|
||
echo ""
|
||
|
||
RECOVERY_RESULT=$($ADB_BIN logcat -d | grep "Cold start recovery complete" | tail -1)
|
||
|
||
# Extract counts from recovery result
|
||
RESCHEDULED_COUNT=$(echo "${RECOVERY_RESULT}" | grep -oE "rescheduled=[0-9]+" | grep -oE "[0-9]+" || echo "0")
|
||
VERIFIED_COUNT=$(echo "${RECOVERY_RESULT}" | grep -oE "verified=[0-9]+" | grep -oE "[0-9]+" || echo "0")
|
||
|
||
# Verify alarm count after recovery
|
||
ALARM_COUNT_AFTER_RECOVERY=$(count_alarms)
|
||
print_info "Alarm count after recovery: ${ALARM_COUNT_AFTER_RECOVERY} (expected: 1)"
|
||
|
||
if [ "${RESCHEDULED_COUNT}" -gt "0" ] 2>/dev/null; then
|
||
print_success "✅ TEST 2 PASSED: Missing future alarm was detected and rescheduled (rescheduled=${RESCHEDULED_COUNT})!"
|
||
if [ "${ALARM_COUNT_AFTER_RECOVERY}" -eq "1" ] 2>/dev/null; then
|
||
print_success "✅ Single alarm confirmed in AlarmManager after recovery"
|
||
fi
|
||
elif [ "${VERIFIED_COUNT}" -gt "0" ] 2>/dev/null; then
|
||
print_success "✅ TEST 2 PASSED: Future alarm verified in AlarmManager (verified=${VERIFIED_COUNT})!"
|
||
if [ "${ALARM_COUNT_AFTER_RECOVERY}" -eq "1" ] 2>/dev/null; then
|
||
print_success "✅ Single alarm confirmed in AlarmManager after recovery"
|
||
fi
|
||
elif [ "${RESCHEDULED_COUNT}" -eq "0" ] 2>/dev/null && [ "${VERIFIED_COUNT}" -eq "0" ] 2>/dev/null; then
|
||
print_warn "⚠️ TEST 2: No verification/rescheduling needed (both verified=0 and rescheduled=0)"
|
||
print_info "This might mean:"
|
||
echo " - Alarm was already properly scheduled and didn't need recovery"
|
||
echo " - Recovery didn't detect any issues"
|
||
if [ "${ALARM_COUNT_AFTER_RECOVERY}" -eq "1" ] 2>/dev/null; then
|
||
print_success "✅ Single alarm still present - recovery may have verified it silently"
|
||
fi
|
||
else
|
||
print_error "TEST 2 INCONCLUSIVE: Could not find recovery result"
|
||
print_info "Recovery result: ${RECOVERY_RESULT}"
|
||
fi
|
||
|
||
print_step "5" "Verifying alarms are still scheduled in AlarmManager..."
|
||
check_alarm_status
|
||
|
||
wait_for_user
|
||
fi
|
||
|
||
# ============================================
|
||
# TEST 3: Recovery Timeout
|
||
# ============================================
|
||
if should_run_test "3" SELECTED_TESTS; then
|
||
print_header "TEST 3: Recovery Timeout"
|
||
echo "Purpose: Verify recovery times out gracefully."
|
||
echo ""
|
||
echo "Note: This test requires creating many schedules (100+)."
|
||
echo "For now, we'll verify the timeout mechanism exists."
|
||
echo ""
|
||
wait_for_user
|
||
|
||
print_step "1" "Checking recovery timeout implementation..."
|
||
if grep -q "RECOVERY_TIMEOUT_SECONDS.*2L" "${PROJECT_ROOT}/android/src/main/java/com/timesafari/dailynotification/ReactivationManager.kt"; then
|
||
print_success "Timeout is set to 2 seconds"
|
||
else
|
||
print_error "Timeout not found in code"
|
||
fi
|
||
|
||
if grep -q "withTimeout" "${PROJECT_ROOT}/android/src/main/java/com/timesafari/dailynotification/ReactivationManager.kt"; then
|
||
print_success "Timeout protection is implemented"
|
||
else
|
||
print_error "Timeout protection not found"
|
||
fi
|
||
|
||
print_info "TEST 3: Timeout mechanism verified in code"
|
||
print_info "Full test (100+ schedules) can be done manually if needed"
|
||
|
||
wait_for_user
|
||
fi
|
||
|
||
# ============================================
|
||
# TEST 4: Invalid Data Handling
|
||
# ============================================
|
||
if should_run_test "4" SELECTED_TESTS; then
|
||
print_header "TEST 4: Invalid Data Handling"
|
||
echo "Purpose: Verify invalid data doesn't crash recovery."
|
||
echo ""
|
||
echo "Note: This requires database access. We'll check if the app is debuggable."
|
||
echo ""
|
||
wait_for_user
|
||
|
||
print_step "1" "Checking if app is debuggable..."
|
||
if $ADB_BIN shell dumpsys package "${APP_ID}" | grep -q "debuggable=true"; then
|
||
print_success "App is debuggable - can access database"
|
||
|
||
print_info "Invalid data handling is tested automatically during recovery."
|
||
print_info "The ReactivationManager code includes checks for:"
|
||
echo " - Empty notification IDs (skipped with warning)"
|
||
echo " - Invalid schedule IDs (skipped with warning)"
|
||
echo " - Database errors (logged, non-fatal)"
|
||
echo ""
|
||
print_info "To manually test invalid data:"
|
||
echo " 1. Use: $ADB_BIN shell run-as ${APP_ID} sqlite3 databases/daily_notification_plugin.db"
|
||
echo " 2. Insert invalid notification: INSERT INTO notification_content (id, ...) VALUES ('', ...);"
|
||
echo " 3. Launch app and check logs for 'Skipping invalid notification'"
|
||
else
|
||
print_info "App is not debuggable - cannot access database directly"
|
||
print_info "TEST 4: Code review confirms invalid data handling exists"
|
||
print_info " - ReactivationManager.kt checks for empty IDs"
|
||
print_info " - Errors are logged but don't crash recovery"
|
||
fi
|
||
|
||
wait_for_user
|
||
fi
|
||
|
||
# ============================================
|
||
# Summary
|
||
# ============================================
|
||
print_header "Testing Complete"
|
||
|
||
echo "Test Results Summary:"
|
||
echo ""
|
||
echo "TEST 1: Cold Start Missed Detection"
|
||
echo " - ✅ PASSED if logs show 'missed=1'"
|
||
echo " - ❌ FAILED if logs show 'missed=0' or no recovery logs"
|
||
echo ""
|
||
echo "TEST 2: Future Alarm Verification/Rescheduling"
|
||
echo " - ✅ PASSED if logs show 'rescheduled=1' OR 'verified=1'"
|
||
echo " - ℹ️ INFO if both are 0 (no future alarms to check)"
|
||
echo ""
|
||
echo "TEST 3: Recovery Timeout"
|
||
echo " - Timeout mechanism verified in code"
|
||
echo ""
|
||
echo "TEST 4: Invalid Data Handling"
|
||
echo " - Requires database access (debuggable app or root)"
|
||
echo ""
|
||
|
||
print_info "All recovery logs:"
|
||
echo ""
|
||
$ADB_BIN logcat -d | grep "$REACTIVATION_TAG" | tail -20
|
||
echo ""
|
||
|
||
print_success "Phase 1 testing script complete!"
|
||
echo ""
|
||
echo "Next steps:"
|
||
echo " - Review logs above"
|
||
echo " - Verify all tests passed"
|
||
echo " - Check database if needed (debuggable app)"
|
||
echo " - Update Doc B with test results"
|
||
}
|
||
|
||
# Run main function
|
||
main "$@"
|
||
|