#!/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 # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration PACKAGE="com.timesafari.dailynotification" ACTIVITY="${PACKAGE}/.MainActivity" APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${APP_DIR}/../.." && pwd)" # Functions print_header() { echo "" echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}$1${NC}" echo -e "${BLUE}========================================${NC}" echo "" } print_step() { echo -e "${GREEN}→ Step $1:${NC} $2" } print_wait() { echo -e "${YELLOW}⏳ $1${NC}" } print_success() { echo -e "${GREEN}✅ $1${NC}" } print_error() { echo -e "${RED}❌ $1${NC}" } print_info() { echo -e "${BLUE}ℹ️ $1${NC}" } wait_for_user() { echo "" read -p "Press Enter when ready to continue..." echo "" } wait_for_ui_action() { echo "" echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${YELLOW}👆 UI ACTION REQUIRED${NC}" echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${BLUE}$1${NC}" echo "" read -p "Press Enter after completing the action above..." echo "" } check_adb_connection() { if ! adb devices | grep -q "device$"; then print_error "No Android device/emulator connected" echo "Please connect a device or start an emulator, then run:" echo " adb devices" exit 1 fi print_success "ADB device connected" } check_emulator_ready() { print_info "Checking emulator status..." if ! adb shell getprop sys.boot_completed | grep -q "1"; then print_wait "Waiting for emulator to boot..." adb wait-for-device while [ "$(adb shell getprop sys.boot_completed)" != "1" ]; do sleep 2 done fi print_success "Emulator is ready" } build_app() { print_header "Building Test App" cd "${APP_DIR}" print_step "1" "Building debug APK..." if ./gradlew assembleDebug; then print_success "Build successful" else print_error "Build failed" exit 1 fi APK_PATH="${APP_DIR}/app/build/outputs/apk/debug/app-debug.apk" if [ ! -f "${APK_PATH}" ]; then print_error "APK not found at ${APK_PATH}" exit 1 fi print_success "APK ready: ${APK_PATH}" } install_app() { print_header "Installing App" print_step "1" "Uninstalling existing app (if present)..." UNINSTALL_OUTPUT=$(adb uninstall "${PACKAGE}" 2>&1) UNINSTALL_EXIT=$? if [ ${UNINSTALL_EXIT} -eq 0 ]; then print_success "Existing app uninstalled" elif echo "${UNINSTALL_OUTPUT}" | grep -q "DELETE_FAILED_INTERNAL_ERROR"; then print_info "No existing app to uninstall (continuing)" elif echo "${UNINSTALL_OUTPUT}" | grep -q "Failure"; then print_info "Uninstall failed (app may not exist) - continuing with install" else print_info "Uninstall result unclear - continuing with install" fi print_step "2" "Installing new APK..." if adb install -r "${APP_DIR}/app/build/outputs/apk/debug/app-debug.apk"; then print_success "App installed successfully" else print_error "Installation failed" exit 1 fi print_step "3" "Verifying installation..." if adb shell pm list packages | grep -q "${PACKAGE}"; then print_success "App verified in package list" else print_error "App not found in package list" exit 1 fi } clear_logs() { print_info "Clearing logcat buffer..." adb logcat -c print_success "Logs cleared" } launch_app() { print_info "Launching app..." adb shell am start -n "${ACTIVITY}" sleep 3 # Give app time to load and check status print_success "App launched" } 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 shell run-as "${PACKAGE}" 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 shell run-as "${PACKAGE}" ls shared_prefs/ 2>/dev/null | grep -c "DailyNotification" || echo "0") # Check recent logs for configuration activity RECENT_CONFIG=$(adb 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 } 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 Then the plugin is already configured - just press Enter to continue. If either shows ❌ or 'Not configured', click 'Configure Plugin' button first, wait for both 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" 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() { print_info "Killing app process..." adb shell am kill "${PACKAGE}" sleep 2 # Verify process is killed if adb shell ps | grep -q "${PACKAGE}"; then print_wait "Process still running, using force-stop..." adb shell am force-stop "${PACKAGE}" sleep 1 fi if ! adb shell ps | grep -q "${PACKAGE}"; then print_success "App process terminated" else print_error "App process still running" return 1 fi } check_recovery_logs() { print_info "Checking recovery logs..." echo "" adb logcat -d | grep -E "DNP-REACTIVATION" | tail -10 echo "" } check_alarm_status() { print_info "Checking AlarmManager status..." echo "" adb shell dumpsys alarm | grep -i timesafari | head -5 echo "" } get_current_time() { adb shell date +%s } # Main test execution main() { print_header "Phase 1 Testing Script" echo "This script will guide you through all 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: Cold Start Missed Detection # ============================================ print_header "TEST 1: Cold Start Missed Detection" echo "Purpose: Verify missed notifications are detected and marked." echo "" wait_for_user print_step "1" "Launch app and check plugin status" launch_app ensure_plugin_configured wait_for_ui_action "In the app UI, click the 'Test Notification' button. This will schedule a notification for 4 minutes in the future. (The test app automatically schedules for 4 minutes from now)" print_step "2" "Verifying notification was scheduled..." sleep 2 check_alarm_status print_info "Checking logs for scheduling confirmation..." adb logcat -d | grep -E "DN|SCHEDULE|Stored notification content" | tail -5 wait_for_ui_action "Verify in the logs above that you see: - 'Stored notification content in database' (NEW - should appear now) - Alarm scheduled in AlarmManager If you don't see 'Stored notification content', the fix may not be working." wait_for_user print_step "3" "Killing app process (simulates OS kill)..." kill_app print_step "4" "Getting alarm scheduled time..." ALARM_INFO=$(adb shell dumpsys alarm | grep -i timesafari | grep "origWhen" | head -1) if [ -n "${ALARM_INFO}" ]; then # Extract alarm time (origWhen is in milliseconds) ALARM_TIME_MS=$(echo "${ALARM_INFO}" | grep -oE 'origWhen [0-9]+' | awk '{print $2}') if [ -n "${ALARM_TIME_MS}" ]; then CURRENT_TIME=$(get_current_time) ALARM_TIME_SEC=$((ALARM_TIME_MS / 1000)) WAIT_SECONDS=$((ALARM_TIME_SEC - CURRENT_TIME + 60)) # Wait 1 minute past alarm if [ ${WAIT_SECONDS} -gt 0 ] && [ ${WAIT_SECONDS} -lt 600 ]; then ALARM_READABLE=$(date -d "@${ALARM_TIME_SEC}" 2>/dev/null || echo "${ALARM_TIME_SEC}") CURRENT_READABLE=$(date -d "@${CURRENT_TIME}" 2>/dev/null || echo "${CURRENT_TIME}") print_info "Alarm scheduled for: ${ALARM_READABLE}" print_info "Current time: ${CURRENT_READABLE}" print_wait "Waiting ${WAIT_SECONDS} seconds for alarm time to pass..." sleep ${WAIT_SECONDS} elif [ ${WAIT_SECONDS} -le 0 ]; then print_info "Alarm time has already passed" print_wait "Waiting 2 minutes to ensure we're well past alarm time..." sleep 120 else print_wait "Alarm is more than 10 minutes away. Waiting 5 minutes (you can adjust this)..." sleep 300 fi else print_wait "Could not parse alarm time. Waiting 5 minutes..." sleep 300 fi else print_wait "Could not find alarm in AlarmManager. Waiting 5 minutes..." sleep 300 fi print_step "5" "Launching app (cold start - triggers recovery)..." clear_logs launch_app print_step "6" "Checking recovery logs..." sleep 3 check_recovery_logs print_info "Expected log output:" echo " DNP-REACTIVATION: Starting app launch recovery (Phase 1: cold start only)" echo " DNP-REACTIVATION: Cold start recovery: checking for missed notifications" echo " DNP-REACTIVATION: Marked missed notification: " echo " DNP-REACTIVATION: Cold start recovery complete: missed=1, ..." echo "" RECOVERY_RESULT=$(adb logcat -d | grep "Cold start recovery complete" | tail -1) if echo "${RECOVERY_RESULT}" | grep -q "missed=[1-9]"; then print_success "TEST 1 PASSED: Missed notification detected!" elif echo "${RECOVERY_RESULT}" | grep -q "missed=0"; then print_error "TEST 1 FAILED: No missed notifications detected (missed=0)" print_info "This might mean:" echo " - Notification was already delivered" echo " - NotificationContentEntity was not created" echo " - Alarm fired before app was killed" else print_error "TEST 1 INCONCLUSIVE: Could not find recovery result" fi wait_for_user # ============================================ # TEST 2: Future Alarm Verification # ============================================ print_header "TEST 2: Future Alarm Verification" echo "Purpose: Verify future alarms are verified/rescheduled if missing." echo "" echo "Note: The test app doesn't have a cancel button, so we'll test" echo " verification of existing alarms instead." 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 another notification. This creates a second scheduled notification for testing verification." print_step "2" "Verifying alarms are scheduled..." sleep 2 check_alarm_status ALARM_COUNT=$(adb shell dumpsys alarm | grep -c "timesafari" || echo "0") print_info "Found ${ALARM_COUNT} scheduled alarm(s)" if [ "${ALARM_COUNT}" -gt "0" ]; 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: at