test(db): pin native-lib-before-keyed-open at the DatabaseModule factory site #278

Merged
JMR-dev merged 4 commits from test-220-native-lib-before-keyed-open into main 2026-07-04 03:52:46 +00:00
JMR-dev commented 2026-07-04 02:36:57 +00:00 (Migrated from github.com)

Closes #220

Summary

  • Adds DatabaseModuleInstrumentedTest (app/src/androidTest/kotlin/org/libremail/di/), an instrumented test that pins the "native lib loaded before keyed open" invariant (592a797) at the DatabaseModule.provideDatabase factory site, not just inside DatabaseProvisioner.
  • DatabaseProvisionerTest (mocked) and DatabaseProvisionerInstrumentedTest (real SQLCipher) both already pin that prepareCache() calls ensureNativeLibraryLoaded() for the encrypted branch, but neither exercises DatabaseModule.provideDatabase itself — the instrumented one opens through a hand-rolled SupportOpenHelperFactory, bypassing the branch that actually maps the reported CacheOpenMode to a real factory (SupportOpenHelperFactory vs FrameworkSQLiteOpenHelperFactory). A regression that broke that wiring (e.g. swapped branches, or stopped gating the open on prepareCache()) would slip through both existing guards.
  • Three new tests call DatabaseModule.provideDatabase(context, provisioner) directly (no Hilt graph needed) and drive the first real open through its own DeferredOpenHelperFactory lambda:
    • encryptedBranchLoadsNativeLibraryBeforeTheKeyedOpenSucceeds — steady-state encrypted cache (nothing for ensureEncrypted to convert), real SQLCipher open through the actual factory branch, ensureNativeLibraryLoaded() verified.
    • plaintextBranchNeverTouchesTheNativeLibrary — counterpart guard for the unencrypted branch.
    • encryptedOpenNeverSucceedsIfTheNativeLibraryLoadFails — fault injection: stubs the load to throw and asserts the keyed open cannot proceed, pinning that the open is causally gated on the load rather than just usually preceded by it (the "wired without a preceding load" regression the issue calls out).

No production code changed.

Local validation

  • :app:compileDebugAndroidTestKotlin :app:ktlintCheck :app:detekt — green.
  • Targeted run on a manually-booted dev36_google_apis_x86_64_Pixel_2 emulator: :app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=org.libremail.di.DatabaseModuleInstrumentedTest — 3/3 passed, 0 failed.

🤖 Generated with Claude Code

Closes #220 ## Summary - Adds `DatabaseModuleInstrumentedTest` (`app/src/androidTest/kotlin/org/libremail/di/`), an instrumented test that pins the "native lib loaded before keyed open" invariant (592a797) at the `DatabaseModule.provideDatabase` factory site, not just inside `DatabaseProvisioner`. - `DatabaseProvisionerTest` (mocked) and `DatabaseProvisionerInstrumentedTest` (real SQLCipher) both already pin that `prepareCache()` calls `ensureNativeLibraryLoaded()` for the encrypted branch, but neither exercises `DatabaseModule.provideDatabase` itself — the instrumented one opens through a hand-rolled `SupportOpenHelperFactory`, bypassing the branch that actually maps the reported `CacheOpenMode` to a real factory (`SupportOpenHelperFactory` vs `FrameworkSQLiteOpenHelperFactory`). A regression that broke that wiring (e.g. swapped branches, or stopped gating the open on `prepareCache()`) would slip through both existing guards. - Three new tests call `DatabaseModule.provideDatabase(context, provisioner)` directly (no Hilt graph needed) and drive the first real open through its own `DeferredOpenHelperFactory` lambda: - `encryptedBranchLoadsNativeLibraryBeforeTheKeyedOpenSucceeds` — steady-state encrypted cache (nothing for `ensureEncrypted` to convert), real SQLCipher open through the actual factory branch, `ensureNativeLibraryLoaded()` verified. - `plaintextBranchNeverTouchesTheNativeLibrary` — counterpart guard for the unencrypted branch. - `encryptedOpenNeverSucceedsIfTheNativeLibraryLoadFails` — fault injection: stubs the load to throw and asserts the keyed open cannot proceed, pinning that the open is causally gated on the load rather than just usually preceded by it (the "wired without a preceding load" regression the issue calls out). No production code changed. ## Local validation - `:app:compileDebugAndroidTestKotlin :app:ktlintCheck :app:detekt` — green. - Targeted run on a manually-booted `dev36_google_apis_x86_64_Pixel_2` emulator: `:app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=org.libremail.di.DatabaseModuleInstrumentedTest` — **3/3 passed, 0 failed**. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.