#!/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: for