A cancelled hardware transcode has no test proving it does not start a second, software one #168

Closed
opened 2026-09-02 02:14:48 +00:00 by JMR-dev · 0 comments
JMR-dev commented 2026-09-02 02:14:48 +00:00 (Migrated from github.com)

A cancelled hardware transcode may be starting a second, software one

ConversionWorker.runMedia3OrFallBack (app/src/main/java/org/libremediaconverter/work/ConversionWorker.kt:206-221)
is 11 lines at 0% on the JVM, and isCancellation
(app/src/main/java/org/libremediaconverter/work/ConversionWorker.kt:295) reports mi=10 ci=0 —
no JVM test has ever called it, and all 4 of its branches are missed.

The function is the mechanism its own KDoc (:192-198) describes as the protection against vendor
hardware encoders that "cannot be tested for correctness". Three behaviours, none pinned on the JVM:

  1. hardware failure → Log.w, staged.delete() (:219), then runFFmpeg (:220);
  2. hardware cancellation → if (isCancellation(e)) throw e (:213), rethrown without falling
    back and without the :219 delete — cleanup happens later in doWork's outer
    catch (e: CancellationException) (:160);
  3. engine.close() runs from finally (:216) either way.

Arm 2 is the sharp one. If it regresses, cancelling a conversion silently starts a second one.

The seam already exists and no unit test uses it

ConversionDependencies.hardware: (Context) -> HardwareTranscoder
(app/src/main/java/org/libremediaconverter/convert/Transcoders.kt:15,67). grep -rn 'HardwareTranscoder' app/src/test
returns nothing. Fakes to copy: PartialThenFailingTranscoder
(app/src/test/java/org/libremediaconverter/work/WorkerCancellationTest.kt:210-224) and
RefusingTranscoder (app/src/test/java/org/libremediaconverter/work/RefusedJobTest.kt:257-276).

WorkerCancellationTest looks adjacent and is not: it uses EnginePreference.FORCE_SOFTWARE
(:184), so it never enters this function.

Covered today only by androidTest — ForcedFailureTest.hardwareFailureFallsBackToSoftware and
whenBothEnginesFailTheJobFailsWithTheReason — neither of which drives the cancellation arm.

Acceptance: the mutation that must go red

Delete if (isCancellation(e)) throw e at :213. A cancelled hardware transcode must not reach
runFFmpeg. Also mutate staged.delete() at :219 away and confirm the failure-path test fails.

## A cancelled hardware transcode may be starting a second, software one `ConversionWorker.runMedia3OrFallBack` (`app/src/main/java/org/libremediaconverter/work/ConversionWorker.kt:206-221`) is **11 lines at 0%** on the JVM, and `isCancellation` (`app/src/main/java/org/libremediaconverter/work/ConversionWorker.kt:295`) reports `mi=10 ci=0` — **no JVM test has ever called it**, and all 4 of its branches are missed. The function is the mechanism its own KDoc (`:192-198`) describes as the protection against vendor hardware encoders that "cannot be tested for correctness". Three behaviours, none pinned on the JVM: 1. hardware failure → `Log.w`, `staged.delete()` (`:219`), then `runFFmpeg` (`:220`); 2. hardware **cancellation** → `if (isCancellation(e)) throw e` (`:213`), rethrown *without* falling back and *without* the `:219` delete — cleanup happens later in `doWork`'s outer `catch (e: CancellationException)` (`:160`); 3. `engine.close()` runs from `finally` (`:216`) either way. Arm 2 is the sharp one. If it regresses, cancelling a conversion silently starts a second one. ## The seam already exists and no unit test uses it `ConversionDependencies.hardware: (Context) -> HardwareTranscoder` (`app/src/main/java/org/libremediaconverter/convert/Transcoders.kt:15,67`). `grep -rn 'HardwareTranscoder' app/src/test` returns nothing. Fakes to copy: `PartialThenFailingTranscoder` (`app/src/test/java/org/libremediaconverter/work/WorkerCancellationTest.kt:210-224`) and `RefusingTranscoder` (`app/src/test/java/org/libremediaconverter/work/RefusedJobTest.kt:257-276`). `WorkerCancellationTest` looks adjacent and is not: it uses `EnginePreference.FORCE_SOFTWARE` (`:184`), so it never enters this function. Covered today only by `androidTest` — `ForcedFailureTest.hardwareFailureFallsBackToSoftware` and `whenBothEnginesFailTheJobFailsWithTheReason` — neither of which drives the cancellation arm. ## Acceptance: the mutation that must go red Delete `if (isCancellation(e)) throw e` at `:213`. A cancelled hardware transcode must not reach `runFFmpeg`. Also mutate `staged.delete()` at `:219` away and confirm the failure-path test fails.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JMR-dev/LibreMediaConverter#168