Reattach to a conversion that is still running #242

Merged
JMR-dev merged 1 commits from test/reattach-to-a-running-job into main 2026-09-06 07:17:06 +00:00
JMR-dev commented 2026-09-06 06:58:26 +00:00 (Migrated from github.com)

Closes #230, with the answer it asked for rather than the test it imagined.

Reattachment.rank gives RUNNING the highest rank of all — "live work outranks a finished result because a running job is holding a foreground service" — and no test on either source set had ever produced one.

state covered where
SUCCEEDED with a file ReattachOnLaunchTest
SUCCEEDED, staged file gone ReattachOnLaunchTest
ambiguous pair ReattachOnLaunchTest
ENQUEUED ReattachOnLaunchTest
CANCELLED ReattachOnLaunchTest
RUNNING nothing — ReattachmentTest ranks fabricated snapshots as a pure function

It is also the likeliest reattachment there is: the user starts a conversion, leaves, and comes back while it is still going.

Why the engine is a fake, and why that is not a weakening

The job has to still be running when the ViewModel is built, and every real conversion in this suite finishes in about a second — racing that is exactly what made the cancellation tests flaky enough to need retries (#240). A SoftwareTranscoder that blocks until released removes the race outright.

Nothing about reattachment depends on which engine is transcoding. Under test are the tag query, Reattachment.choose over live WorkManager state, and observe's mapping to Converting — identical whatever is doing the work.

What #230 asked, answered

Process death itself stays device-manual. docs/defect-audit.md D3/D13 already record that am kill refuses a process holding a foreground service. There is a more basic obstacle underneath that, which is the actual answer: instrumentation runs in the app's own process, so any route that really killed it would take the test runner with it and leave nothing to assert with. Observing a relaunch needs two instrumentation runs, which the runner does not provide.

So the closest observable analogue is what this adds: a fresh ViewModel, with no memory of the work, meeting a job that is genuinely mid-flight.

Also fixed

The teardown now resets ConversionDependencies. The suite runs without Android Test Orchestrator, so a BlockingTranscoder left in place would hang the next class that converts anything.

Verification — local API 34 emulator

tests=67 failures=0 errors=0 skipped=3

Mutation — make RUNNING unreattachable in Reattachment.rank:

ReattachOnLaunchTest > reattachesToAConversionThatIsStillRunning FAILED
tests=67 failures=1

Fails this test and nothing else — which is also the evidence that the JVM ranking test was not already covering it.

🤖 Generated with Claude Code

Closes #230, with the answer it asked for rather than the test it imagined. `Reattachment.rank` gives `RUNNING` the **highest rank of all** — *"live work outranks a finished result because a running job is holding a foreground service"* — and **no test on either source set had ever produced one**. | state | covered where | |---|---| | SUCCEEDED with a file | `ReattachOnLaunchTest` | | SUCCEEDED, staged file gone | `ReattachOnLaunchTest` | | ambiguous pair | `ReattachOnLaunchTest` | | ENQUEUED | `ReattachOnLaunchTest` | | CANCELLED | `ReattachOnLaunchTest` | | **RUNNING** | **nothing** — `ReattachmentTest` ranks fabricated snapshots as a pure function | It is also the likeliest reattachment there is: the user starts a conversion, leaves, and comes back while it is still going. ## Why the engine is a fake, and why that is not a weakening The job has to still be running when the ViewModel is built, and every real conversion in this suite finishes in about a second — racing that is exactly what made the cancellation tests flaky enough to need retries (#240). A `SoftwareTranscoder` that blocks until released removes the race outright. Nothing about reattachment depends on which engine is transcoding. Under test are the tag query, `Reattachment.choose` over live WorkManager state, and `observe`'s mapping to `Converting` — identical whatever is doing the work. ## What #230 asked, answered **Process death itself stays device-manual.** `docs/defect-audit.md` D3/D13 already record that `am kill` refuses a process holding a foreground service. There is a more basic obstacle underneath that, which is the actual answer: **instrumentation runs in the app's own process**, so any route that really killed it would take the test runner with it and leave nothing to assert with. Observing a relaunch needs two instrumentation runs, which the runner does not provide. So the closest observable analogue is what this adds: a fresh ViewModel, with no memory of the work, meeting a job that is genuinely mid-flight. ## Also fixed The teardown now resets `ConversionDependencies`. The suite runs without Android Test Orchestrator, so a `BlockingTranscoder` left in place would hang the next class that converts anything. ## Verification — local API 34 emulator ``` tests=67 failures=0 errors=0 skipped=3 ``` Mutation — make `RUNNING` unreattachable in `Reattachment.rank`: ``` ReattachOnLaunchTest > reattachesToAConversionThatIsStillRunning FAILED tests=67 failures=1 ``` Fails this test **and nothing else** — which is also the evidence that the JVM ranking test was not already covering it. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.