M4: Managed-device end-to-end smoke against a real server (ENG-268) #31

Merged demi.dev
targeting main from stoopkidddd/eng-268-m4-managed-device-end-to-end-smoke-against-a-real-server
Merged opened by and assigned to demi.dev
targeting main from stoopkidddd/eng-268-m4-managed-device-end-to-end-smoke-against-a-real-server

Linear: https://linear.app/engineereddev/issue/ENG-268

What's in this PR (three commits):

  • Harness scripts/e2e/android.ts (now mise run e2e:android): harness MinIO and the built server on a random port (PUBLIC_URL=http://10.0.2.2:<port>, proxy mode), dev-client setup + pair-uri, a second cli sender session, credentials handed to the device through an app-private file (not runner args), the managed-device task, adb Doze control, a secret scan over Gradle output, instrumentation results, server log and logcat, and full teardown.
  • RealServerSmokeTest (UiAutomator + Compose): deep-link pair → Confirm → Pair; Connected; note → Copy → clipboard read from the foreground MainActivity; link → Open (ACTION_VIEW via espresso-intents) and Copy; 1 MiB file → Download → Open/Share → SHA-256 via MediaStore; Home composer send-back confirmed by the harness; Home + forced Doze + note + unforce → notification within 30 s. Skips cleanly without harness arguments, so the plain Gradle task still runs the other 14 tests.
  • Production fix (separate commit, bug from ENG-266): the 1 MiB download made 101 notification posts in one second, Android shed the terminal "Download complete" post, and Open/Share never appeared. Upload/download progress posts now need a changed percentage and ≥ 500 ms spacing; initial and terminal posts bypass the throttle. TransferProgressThrottle + JVM tests.
  • Test-only dependencies: UiAutomator 2.3.0, Espresso Intents 3.7.0. mise.toml e2e:android task and app/build.gradle.kts runner settings changed.

Verify (lead, on 8176869):

  • mise run check:android → exit 0
  • ./gradlew testDebugUnitTest --rerun → exit 0 (350 tests, 0 failures)
  • mise run e2e:android → exit 0, twice in a row; each run: "PASS managed-device suite including real-server smoke", "Secret scan (Gradle, instrumentation results, server, logcat): 0 matches", "PASS emulator, server, MinIO and credential cleanup"
  • Afterwards: no pneumo-e2e- containers, no MinIO or emulator listeners.

Deviations: proxy mode only (permitted); ATD has no interactive shade, so the test fires the real posted notification's PendingIntents; clipboard read from the foreground activity (no debug probe); credentials via an app-private file.

🤖 Generated with Claude Code

Commits 4

M4: Share transfer progress notification gate (ENG-268)
M4: Throttle transfer progress notifications (ENG-268)
M4: Reuse Espresso's transitive Test Rules dependency (ENG-268)
M4: Add real-server Android managed-device smoke (ENG-268)