# P2.3 Implementation Checklist: Android Combined Edge Case Tests

**Purpose:** Step-by-step implementation guide for P2.3, breaking down the design into actionable tasks with acceptance criteria and rollback guidance.  
**Owner:** Development Team  
**Last Updated:** 2025-12-22  
**Status:** implementation-ready  
**Baseline:** `v1.0.11-p2-complete`  
**Design Reference:** `doc/progress/P2.3-DESIGN.md`

---

## Overview

**Goal:** Achieve parity with iOS P2.2 by adding automated combined edge case tests for Android.

**Scope:**
- Enable Android test infrastructure (currently disabled)
- Create test helpers (in-memory Room database, test data injection)
- Implement 2-3 combined test scenarios mirroring iOS P2.2

**Estimated Time:** 12-20 hours (can be spread over multiple sessions)

---

## Pre-Implementation Checklist

Before starting, verify:

- [ ] Baseline tag exists: `v1.0.11-p2-complete`
- [ ] CI is green: `./ci/run.sh` passes
- [ ] P2.3 design reviewed and approved
- [ ] Test framework choice decided (Robolectric vs pure unit tests)
- [ ] Android test directory structure understood

---

## P2.3.1: Enable Android Test Infrastructure

**Goal:** Re-enable Android tests with modern AndroidX testing framework.

**Estimated Time:** 2-4 hours

### Step 1.1: Review Current Test Configuration

**Action:**
- Read `android/build.gradle` lines 48-63 (test configuration)
- Understand why tests are disabled (comment: "tests reference deprecated/removed code")
- Identify what needs to be updated

**Acceptance:**
- [ ] Current test configuration understood
- [ ] Deprecated API usage identified (if any)

---

### Step 1.2: Add AndroidX Test Dependencies

**Action:**
- Add test dependencies to `android/build.gradle`:
  - `junit:junit:4.13.2` (or latest)
  - `androidx.test:core:1.5.0` (or latest)
  - `androidx.test.ext:junit:1.1.5` (or latest)
  - `org.robolectric:robolectric:4.11.1` (if using Robolectric)
  - `androidx.room:room-testing:2.6.1` (for in-memory Room testing)

**File:** `android/build.gradle`

**Acceptance:**
- [ ] Test dependencies added to `dependencies {}` block
- [ ] Versions compatible with existing AndroidX versions
- [ ] No version conflicts

---

### Step 1.3: Update Test Configuration

**Action:**
- Remove or update `testOptions { unitTests.all { enabled = false } }`
- Remove or update `sourceSets { test { java { srcDirs = [] } } }`
- Enable unit tests: `testOptions { unitTests.includeAndroidResources = true }` (if using Robolectric)

**File:** `android/build.gradle`

**Acceptance:**
- [ ] Test configuration updated
- [ ] Tests are enabled (not disabled)
- [ ] Test source directory is accessible

---

### Step 1.4: Create Test Directory Structure

**Action:**
- Create `android/src/test/java/com/timesafari/dailynotification/` if it doesn't exist
- Create placeholder test file: `DailyNotificationRecoveryTests.kt` (or `.java`)
- Add minimal test to verify infrastructure works

**Example placeholder test:**
```kotlin
package org.timesafari.dailynotification

import org.junit.Test
import org.junit.Assert.*

class DailyNotificationRecoveryTests {
    @Test
    fun test_infrastructure_works() {
        assertTrue("Test infrastructure is working", true)
    }
}
```

**Acceptance:**
- [ ] Test directory structure created
- [ ] Placeholder test file created
- [ ] Test compiles without errors

---

### Step 1.5: Verify Test Infrastructure

**Action:**
- Run `cd android && ./gradlew test` (or `./gradlew :android:test` from root)
- Verify test runs successfully
- Check CI compatibility: ensure `./ci/run.sh` can run tests or skip gracefully

**Acceptance:**
- [ ] `./gradlew test` runs successfully
- [ ] Placeholder test passes
- [ ] CI compatibility verified (tests run in CI or documented as manual)

**Rollback:** If tests fail to compile/run, revert `android/build.gradle` changes and investigate dependency conflicts.

---

## P2.3.2: Create Test Infrastructure Helpers

**Goal:** Create test helpers similar to iOS `TestDBFactory.swift`.

**Estimated Time:** 4-6 hours

### Step 2.1: Create In-Memory Room Database Factory

**Action:**
- Create `android/src/test/java/com/timesafari/dailynotification/TestDBFactory.kt` (or `.java`)
- Implement factory method that creates in-memory Room database
- Use `Room.inMemoryDatabaseBuilder()` for isolation

**Example structure:**
```kotlin
package org.timesafari.dailynotification

import androidx.room.Room
import androidx.room.RoomDatabase

object TestDBFactory {
    fun createInMemoryDatabase(context: Context): DailyNotificationDatabase {
        return Room.inMemoryDatabaseBuilder(
            context,
            DailyNotificationDatabase::class.java
        ).allowMainThreadQueries()
         .build()
    }
}
```

**Acceptance:**
- [ ] `TestDBFactory` created
- [ ] Factory method creates in-memory database
- [ ] Database is isolated (each test gets fresh instance)

---

### Step 2.2: Create Test Data Injection Helpers

**Action:**
- Add helper methods to `TestDBFactory` (or separate `TestDataHelper`):
  - `injectInvalidSchedule()` - creates schedule with empty ID or null fields
  - `injectDuplicateSchedule()` - creates duplicate schedule entries
  - `injectPastSchedule()` - creates schedule with past `nextRunAt`
  - `injectDSTBoundarySchedule()` - creates schedule at DST boundary

**Acceptance:**
- [ ] Test data injection helpers created
- [ ] Helpers support invalid data scenarios
- [ ] Helpers support duplicate delivery scenarios
- [ ] Helpers support DST boundary scenarios

---

### Step 2.3: Create Mock Context Helper (if needed)

**Action:**
- If using Robolectric, create mock context helper
- If using pure unit tests, create minimal context mock
- Ensure context provides necessary services (SharedPreferences, etc.)

**Acceptance:**
- [ ] Mock context helper created (if needed)
- [ ] Context provides necessary services
- [ ] Context is isolated per test

---

### Step 2.4: Verify Test Helpers Work

**Action:**
- Create simple test that uses `TestDBFactory` and data injection helpers
- Verify database creation works
- Verify data injection works
- Verify database cleanup works (teardown)

**Acceptance:**
- [ ] Test helpers work in isolation
- [ ] Database creation verified
- [ ] Data injection verified
- [ ] Cleanup verified

**Rollback:** If helpers don't work, investigate Room in-memory database setup or mock context issues.

---

## P2.3.3: Implement Combined Test Scenarios

**Goal:** Add 2-3 combined edge case tests mirroring iOS P2.2.

**Estimated Time:** 6-10 hours

### Step 3.1: Implement Scenario A - DST Boundary + Duplicate Delivery + Cold Start

**Action:**
- Create test: `test_combined_dst_boundary_duplicate_delivery_cold_start()`
- Test steps:
  1. Create notification scheduled at DST boundary (use `ZonedDateTime` with DST transition)
  2. Simulate duplicate delivery events (rapid succession - call delivery handler twice)
  3. Trigger cold start recovery (call `ReactivationManager.performRecovery()`)
  4. Verify: idempotency (running twice yields identical state)
  5. Verify: deduplication (only one logical delivery recorded)
  6. Verify: DST-consistent next time (next scheduled time accounts for DST)

**File:** `android/src/test/java/com/timesafari/dailynotification/DailyNotificationRecoveryTests.kt`

**Acceptance:**
- [ ] Test created with `@Test` annotation
- [ ] Test labeled with `@resilience @combined-scenarios` comment
- [ ] Test verifies idempotency
- [ ] Test verifies deduplication
- [ ] Test verifies DST-consistent next time
- [ ] Test passes deterministically

**Reference:** iOS equivalent: `test_combined_dst_boundary_duplicate_delivery_cold_start()` in `ios/Tests/DailyNotificationRecoveryTests.swift`

---

### Step 3.2: Implement Scenario B - Rollover + Duplicate Delivery + Cold Start

**Action:**
- Create test: `test_combined_rollover_duplicate_delivery_cold_start()`
- Test steps:
  1. Create notification that was just delivered (past time)
  2. Trigger rollover (first delivery - mark as delivered, schedule next)
  3. Simulate duplicate delivery immediately (call delivery handler again)
  4. Trigger cold start recovery
  5. Verify: rollover idempotency (no double-apply of state transitions)
  6. Verify: duplicate delivery doesn't double-apply state transitions
  7. Verify: cold start reconciliation produces correct state

**File:** `android/src/test/java/com/timesafari/dailynotification/DailyNotificationRecoveryTests.kt`

**Acceptance:**
- [ ] Test created with `@Test` annotation
- [ ] Test labeled with `@resilience @combined-scenarios` comment
- [ ] Test verifies rollover idempotency
- [ ] Test verifies duplicate delivery handling
- [ ] Test verifies cold start reconciliation
- [ ] Test passes deterministically

**Reference:** iOS equivalent: `test_combined_rollover_duplicate_delivery_cold_start()` in `ios/Tests/DailyNotificationRecoveryTests.swift`

---

### Step 3.3: Implement Scenario C - Schema Version + Cold Start Recovery (Optional)

**Action:**
- Create test: `test_combined_schema_version_cold_start_recovery()` (if time permits)
- Test steps:
  1. Verify Room database version is observable (check `Database.getVersion()`)
  2. Test recovery with version metadata present
  3. Verify version doesn't interfere with recovery
  4. Verify recovery works identically with version metadata

**File:** `android/src/test/java/com/timesafari/dailynotification/DailyNotificationRecoveryTests.kt`

**Acceptance:**
- [ ] Test created with `@Test` annotation (optional)
- [ ] Test labeled with `@resilience @combined-scenarios` comment
- [ ] Test verifies schema version observability
- [ ] Test verifies version doesn't interfere with recovery
- [ ] Test passes deterministically

**Reference:** iOS equivalent: `test_combined_schema_version_cold_start_recovery()` in `ios/Tests/DailyNotificationRecoveryTests.swift`

---

### Step 3.4: Verify All Tests Pass

**Action:**
- Run `./gradlew test` to verify all new tests pass
- Run tests multiple times to verify determinism
- Check for flaky tests and fix if needed

**Acceptance:**
- [ ] All new tests pass
- [ ] Tests are deterministic (run multiple times, same results)
- [ ] No flaky tests

---

### Step 3.5: Update Documentation

**Action:**
- Update `doc/progress/03-TEST-RUNS.md` with P2.3 test run entry
- Update `doc/progress/04-PARITY-MATRIX.md` to mark "Combined edge case tests" as ✅ for Android
- Add direct test references (file path + test names) to parity matrix
- Update `doc/progress/01-CHANGELOG-WORK.md` with P2.3 completion entry
- Update `doc/progress/00-STATUS.md` to mark P2.3 complete

**Acceptance:**
- [ ] Test run entry added to `03-TEST-RUNS.md`
- [ ] Parity matrix updated with ✅ and direct test references
- [ ] Changelog entry added
- [ ] Status doc updated

---

## Post-Implementation Verification

### CI Verification

**Action:**
- Run `./ci/run.sh` to verify all checks pass
- Verify Android tests run in CI (or are documented as manual)
- Check for any new lint/build errors

**Acceptance:**
- [ ] `./ci/run.sh` passes
- [ ] Android tests run in CI (or documented as manual)
- [ ] No new lint/build errors

---

### Parity Verification

**Action:**
- Compare Android combined tests with iOS P2.2 tests
- Verify test scenarios are equivalent in intent (not necessarily identical mechanics)
- Verify parity matrix reflects accurate status

**Acceptance:**
- [ ] Android tests mirror iOS intent
- [ ] Parity matrix accurately reflects status
- [ ] Test references are direct and traceable

---

## Rollback Plan

If P2.3 implementation encounters issues:

### Rollback P2.3.3 (Test Scenarios)

**Action:**
- Remove test scenario files
- Revert documentation updates
- Keep test infrastructure (P2.3.1, P2.3.2) for future use

### Rollback P2.3.2 (Test Helpers)

**Action:**
- Remove test helper files
- Revert to minimal test infrastructure

### Rollback P2.3.1 (Test Infrastructure)

**Action:**
- Revert `android/build.gradle` changes
- Disable tests again (restore original configuration)
- Remove test directory if created

**Full Rollback:**
- Revert all P2.3 changes
- Restore baseline: `git checkout v1.0.11-p2-complete`

---

## Success Criteria

P2.3 is complete when:

1. **All P2.3 items completed** (P2.3.1, P2.3.2, P2.3.3)
2. **All acceptance criteria met** (per step)
3. **All invariants preserved** (verified by CI)
4. **Documentation updated** (progress docs, parity matrix, changelog)
5. **Parity achieved** (Android has automated combined tests matching iOS intent)

---

## Next Steps After P2.3

After P2.3 completion:

1. **Tag baseline:** `v1.0.11-p2.3-complete` (optional but recommended)
2. **Consider P2.4:** iOS CI automation (macOS runners) if desired
3. **Consider P1.5b:** Remove iOS/App test harness from published tree

---

**Last Updated:** 2025-12-22  
**Status:** Implementation-Ready  
**Next Action:** Begin P2.3.1 - Enable Android Test Infrastructure

