Add automatic app state reset for TEST 1 to ensure clean starting state when lingering alarms from TEST 0 are detected. Create PHASE1_TEST1_GOLDEN.md with actual values from successful run. TEST 1 Auto-Reset: - Detect lingering plugin alarms before TEST 1 starts - Automatically uninstall/reinstall app to clear alarms - Verify clean state (0 alarms) before proceeding - Gracefully skip TEST 1 if clean state cannot be achieved - Take failure screenshots when reset fails - Wrap all TEST 1 steps in conditional to skip on reset failure Documentation: - Create PHASE1_TEST1_GOLDEN.md with actual values from passing run - Document auto-reset behavior in golden run steps - Add cross-references between TEST 0 and TEST 1 golden docs - Include actual timestamps, scheduleIds, and recovery metrics This ensures TEST 1 always starts from a known clean state, making test results reliable and reproducible. The golden doc serves as a baseline for comparing future TEST 1 runs.
12 KiB
Phase 1 — TEST 1 Golden Run (Force-Stop Recovery - Database Restoration)
Related Docs:
1. Test Overview
Test Name: TEST 1 — Force-Stop Recovery: Database Restoration
Purpose: Verify that after an Android force-stop (which clears all scheduled alarms), the plugin:
- Persists the alarm schedule in its database.
- Detects that alarms are missing on app launch.
- Rebuilds the missing alarm(s) from the database.
- Restores the one-notification-per-day contract:
- Before force-stop: 1 alarm
- After force-stop: 0 alarms
- After recovery: 1 alarm (same trigger time as before force-stop)
This golden run documents a known-good execution on 2025-12-04.
2. Environment & Build Info
-
Date/Time of Run: 2025-12-04 (around 09:51–09:55 UTC)
-
Command Used:
./test-phase1.sh
-
Project:
daily-notification-plugin—test-apps/android-test-app -
Gradle:
-
Build invoked via
./gradlew assembleDebug(through the script) -
Gradle output included:
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
-
-
APK Built:
./app/build/outputs/apk/debug/app-debug.apk -
App ID:
com.timesafari.dailynotification
Note: Device/emulator model & API level can be added here later if desired.
3. Step-by-Step Execution (Golden Run)
This section captures the actual sequence for the golden run.
- Ran
./test-phase1.sh. - Pre-flight checks:
- ✅ ADB device connected
- ✅ Emulator ready
- Build phase:
- ✅ Debug APK built successfully.
- ✅ APK path:
./app/build/outputs/apk/debug/app-debug.apk
- Install phase:
- ✅ Previous app uninstall succeeded
- ✅ APK installed successfully
- ✅ App verified in package list
- ✅ Logcat cleared (twice)
- TEST 0 executed:
- Configured plugin in UI (if needed).
- Scheduled daily notification.
- Verified:
- Before scheduling: 0 plugin alarms.
- After scheduling: 1 plugin alarm for today.
- After fire/rollover: 1 plugin alarm for tomorrow.
- TEST 0 PASSED.
- TEST 1 started:
- Step 1: Detected 1 lingering plugin alarm (tomorrow's alarm from TEST 0).
- Auto-reset:
- Uninstalled app
- Reinstalled APK
- Cleared logcat
- Verified plugin alarms = 0
- Confirmed clean starting state for TEST 1.
- Step 2: Launched app and confirmed plugin configured.
- In UI: tapped "Test Notification" button (schedules a notification ~4 minutes in the future).
- Step 3 (pre-FS verify):
- Verified 1 plugin alarm exists in AlarmManager.
- Confirmed alarm details (time, tag, type).
- Confirmed scheduling logs with
source=TEST_NOTIFICATION.
- Step 4: Performed force-stop via
adb shell am force-stop com.timesafari.dailynotification. - Step 5 (post-FS verify):
- Verified plugin alarms = 0 (force-stop cleared alarms).
- Step 6: Relaunched app (cold start).
- Step 7 (recovery verify):
- Verified plugin alarms = 1 after recovery.
- Confirmed recovery logs under
DNP-REACTIVATION:- App launch recovery
- Boot recovery
rescheduled=1
- Confirmed rescheduled alarm uses the same scheduleId and triggerTime as pre-force-stop.
- Fire verification was skipped (
VERIFY_FIRE=false). - TEST 1 summary:
- ✅ Before FS: 1 alarm
- ✅ After FS: 0 alarms
- ✅ After recovery: 1 alarm
- ✅
rescheduled=1,errors=0 - ✅ TEST 1 PASSED.
4. Expected Script Output (Key Excerpts)
These are the critical excerpts from the test harness output for a passing TEST 1.
4.1 Clean Start & Auto-Reset
→ Step 1: Clean start - checking for lingering alarms...
ℹ️ Current plugin notification alarms: 1
ℹ️ System/other alarms: 17 (for context)
⚠️ Found 1 lingering plugin alarm(s) - these will interfere with TEST 1.
ℹ️ TEST 1 needs a clean state (no existing plugin alarms).
ℹ️ Resetting app state via uninstall + reinstall...
ℹ️ Uninstalling existing app...
✅ App uninstall succeeded (clean slate).
ℹ️ Reinstalling APK...
✅ App reinstall succeeded.
ℹ️ Clearing logcat buffer after reinstall...
ℹ️ Rechecking plugin alarms after reset...
ℹ️ Plugin alarms after reset: 0 (expected: 0)
✅ App state reset complete. TEST 1 starting from clean state.
4.2 Alarm Scheduled Before Force-Stop
→ Step 3: Verifying alarm exists in AlarmManager (BEFORE force-stop)...
ℹ️ Plugin alarms: 1 (expected: 1)
ℹ️ System/other alarms: 19 (for context)
✅ ✅ Single plugin alarm confirmed in AlarmManager (one per day)
ℹ️ Alarm details:
RTC_WAKEUP #4: Alarm{161cd2b type 0 origWhen 1764842100000 whenElapsed 13009441 com.timesafari.dailynotification}
tag=*walarm*:com.timesafari.daily.NOTIFICATION
type=RTC_WAKEUP origWhen=2025-12-04 09:55:00.000 window=0 exactAllowReason=policy_permission repeatInterval=0 count=0 flags=0x3
policyWhenElapsed: requester=+3m4s281ms app_standby=-6s566ms device_idle=-- battery_saver=--
--
ℹ️ Alarm scheduled for: Thu Dec 4 09:55:00 AM UTC 2025 (1764842100000 ms)
ℹ️ Checking logs for scheduling confirmation...
12-04 09:51:49.150 6803 6867 W DNP-SCHEDULE: Cancelling existing alarm before rescheduling: requestCode=3454, scheduleId=daily_1764841909137, source=TEST_NOTIFICATION
12-04 09:51:49.151 6803 6867 I DNP-NOTIFY: Scheduling alarm: triggerTime=2025-12-04 09:55:00, delayMs=190849, requestCode=3454, scheduleId=daily_1764841909137
12-04 09:51:49.152 6803 6867 I DNP-SCHEDULE: Scheduling OS alarm: variant=ALARM_CLOCK, action=com.timesafari.daily.NOTIFICATION, triggerTime=1764842100000, requestCode=3454, scheduleId=daily_1764841909137, source=TEST_NOTIFICATION, pendingIntentHash=267839060, showIntentHash=256236029
12-04 09:51:49.153 6803 6867 I DNP-NOTIFY: Alarm clock scheduled (setAlarmClock): triggerAt=1764842100000, requestCode=3454
4.3 Force-Stop & Alarm Clearance
→ Step 4: Force-stopping app (clears all alarms)...
⚠️ Force-stop will clear ALL alarms from AlarmManager
ℹ️ Executing: adb shell am force-stop com.timesafari.dailynotification
ℹ️ Forcing stop of app process...
✅ Force stop issued
→ Step 5: Verifying alarms are MISSING from AlarmManager (AFTER force-stop)...
ℹ️ Plugin alarms after force-stop: 0 (expected: 0)
ℹ️ System/other alarms: 17 (for context)
✅ ✅ Plugin alarms cleared by force-stop (count: 0)
ℹ️ This confirms: Force-stop cleared alarms from AlarmManager
4.4 Recovery & Rescheduling
→ Step 6: Relaunching app (triggers recovery from database)...
ℹ️ Clearing logcat buffer...
✅ Logs cleared
ℹ️ Launching app...
Starting: Intent { cmp=com.timesafari.dailynotification/.MainActivity }
✅ App launched
→ Step 7: Verifying recovery rebuilt alarms from database...
ℹ️ Plugin alarms after recovery: 1 (expected: 1)
ℹ️ System/other alarms: 21 (for context)
ℹ️ Checking recovery logs...
12-04 09:52:21.919 6954 7015 I DNP-REACTIVATION: Starting app launch recovery (Phase 1: cold start only)
12-04 09:52:21.926 6954 7015 I DNP-REACTIVATION: Cold start recovery: checking for missed notifications
12-04 09:52:21.937 6954 7015 I DNP-REACTIVATION: Rescheduled alarm: daily_1764841909137 for 1764842100000
12-04 09:52:21.937 6954 7015 I DNP-REACTIVATION: Rescheduled missing alarm: daily_1764841909137 at 1764842100000
12-04 09:52:21.952 6954 7015 I DNP-REACTIVATION: Cold start recovery complete: missed=0, rescheduled=1, verified=0, errors=0
12-04 09:52:21.952 6954 7015 I DNP-REACTIVATION: App launch recovery completed: missed=0, rescheduled=1, verified=0, errors=0
12-04 09:52:22.077 6954 7015 I DNP-REACTIVATION: Starting boot recovery
12-04 09:52:22.135 6954 7017 I DNP-REACTIVATION: Loaded 1 schedules from DB
12-04 09:52:22.138 6954 7017 I DNP-REACTIVATION: Rescheduled alarm: daily_1764841909137 for 1764842100000
12-04 09:52:22.143 6954 7017 I DNP-REACTIVATION: Boot recovery complete: missed=0, rescheduled=1, verified=0, errors=0
Final summary:
✅ ✅ Alarms restored in AlarmManager (count: 1)
✅ ✅ Recovery logs confirm rescheduling (rescheduled=1)
✅ TEST 1 PASSED: Recovery successfully rebuilt alarms from database!
ℹ️ Summary:
- Before force-stop: 1 alarm(s)
- After force-stop: 0 alarm(s) (cleared)
- After recovery: 1 alarm(s) (rebuilt)
- Rescheduled: 1 alarm(s)
- Verified: 0 alarm(s)
ℹ️ Skipping fire verification (VERIFY_FIRE=false, set VERIFY_FIRE=true to enable)
5. Expected dumpsys alarm Shapes
5.1 Before Force-Stop (Scheduled)
- Plugin alarm count: 1
- Example block (shape, not necessarily exact handle):
RTC_WAKEUP #4: Alarm{161cd2b type 0 origWhen 1764842100000 whenElapsed 13009441 com.timesafari.dailynotification}
tag=*walarm*:com.timesafari.daily.NOTIFICATION
type=RTC_WAKEUP origWhen=2025-12-04 09:55:00.000 window=0 exactAllowReason=policy_permission repeatInterval=0 count=0 flags=0x3
policyWhenElapsed: requester=+3m4s281ms app_standby=-6s566ms device_idle=-- battery_saver=--
5.2 After Force-Stop
- Plugin alarm count: 0
- No
*walarm*:com.timesafari.daily.NOTIFICATIONentries should appear.
5.3 After Recovery
- Plugin alarm count: 1
- Alarm should be restored with:
- Same
scheduleId:daily_1764841909137 - Same
triggerTime:1764842100000→2025-12-04 09:55:00
- Same
6. Expected logcat Patterns
For a passing run, look for:
-
Scheduling (before FS):
DNP-NOTIFY: Scheduling alarm: triggerTime=2025-12-04 09:55:00, delayMs=..., requestCode=3454, scheduleId=daily_1764841909137 DNP-SCHEDULE: Scheduling OS alarm: variant=ALARM_CLOCK, action=com.timesafari.daily.NOTIFICATION, triggerTime=1764842100000, requestCode=3454, scheduleId=daily_1764841909137, source=TEST_NOTIFICATION, ... -
Recovery (after FS + relaunch):
DNP-REACTIVATION: Starting app launch recovery (Phase 1: cold start only) DNP-REACTIVATION: Rescheduled alarm: daily_1764841909137 for 1764842100000 DNP-REACTIVATION: Cold start recovery complete: missed=0, rescheduled=1, verified=0, errors=0 DNP-REACTIVATION: App launch recovery completed: missed=0, rescheduled=1, verified=0, errors=0 DNP-REACTIVATION: Starting boot recovery DNP-REACTIVATION: Loaded 1 schedules from DB DNP-REACTIVATION: Rescheduled alarm: daily_1764841909137 for 1764842100000 DNP-REACTIVATION: Boot recovery complete: missed=0, rescheduled=1, verified=0, errors=0
Key invariants:
rescheduled=1errors=0scheduleIdandtriggerTimematch pre-FS values.
7. Quick Pass/Fail Checklist
A TEST 1 run is a PASS if all of the following are true:
-
Starting state:
- Script auto-resets if lingering alarms exist from TEST 0.
- After reset: plugin alarm count = 0.
-
Pre-force-stop:
- Plugin alarm count = 1.
- Alarm is tagged
*walarm*:com.timesafari.daily.NOTIFICATION. triggerTimeandorigWhenare consistent (e.g.2025-12-04 09:55:00,1764842100000).scheduleIdlooks likedaily_<timestamp>(here:daily_1764841909137).- Logs show
source=TEST_NOTIFICATION.
-
After force-stop:
- Plugin alarm count = 0.
- No NOTIFICATION alarms remain in
dumpsys.
-
After recovery (relaunch):
- Plugin alarm count = 1.
- Logs show
DNP-REACTIVATIONwith:rescheduled=1errors=0- Same
scheduleIdandtriggerTimeas pre-FS.
-
Script summary:
- States:
- Before force-stop: 1 alarm
- After force-stop: 0 alarms
- After recovery: 1 alarm
- Ends with:
✅ TEST 1 PASSED: Recovery successfully rebuilt alarms from database!
- States:
If any of these conditions fail, the run is NOT GOLDEN and should not overwrite this reference.
8. Notes / Deviations
- This golden run skips fire verification (
VERIFY_FIRE=false). Future runs may enable fire verification; if that becomes standard, update this doc. - It is acceptable for both:
- Cold start recovery and
- Boot recovery to run on app launch, as long as:
rescheduled=1- No duplicate alarms are scheduled.
- If OS behavior changes (e.g., force-stop no longer clears alarms on a future Android version), this test's expectations may need to be revised; document any such deviations explicitly here before changing the checklist.