diff --git a/.github/workflows/build-whisper.yml b/.github/workflows/build-whisper.yml index 3ded36b..40f8813 100644 --- a/.github/workflows/build-whisper.yml +++ b/.github/workflows/build-whisper.yml @@ -81,6 +81,9 @@ jobs: if: inputs.release_tag != '' env: GH_TOKEN: ${{ github.token }} + # These jobs do not check out the repo, so gh has no git remote to + # infer the repo from — set it explicitly. + GH_REPO: ${{ github.repository }} run: | # Create the release if it does not exist (|| true tolerates a race # with the sibling arch job creating it concurrently). diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml index b81df66..596d22c 100644 --- a/.github/workflows/ci-test.yml +++ b/.github/workflows/ci-test.yml @@ -230,15 +230,14 @@ jobs: curl -L -o .whisper-cache/ggml-small.bin "$WHISPER_MODEL_URL" fi cp .whisper-cache/ggml-small.bin addons/whisper/models/ggml-small.bin - # No prebuilt Linux whisper-cli is published (macOS uses a Homebrew - # bottle, Windows a release zip), so build whisper.cpp from source. - # Static build (BUILD_SHARED_LIBS=OFF) => a self-contained whisper-cli - # with no lib/ dir to manage; GGML_NATIVE=OFF for runner portability. - git clone --depth 1 -b v1.8.3 https://github.com/ggml-org/whisper.cpp /tmp/whisper.cpp - cmake -S /tmp/whisper.cpp -B /tmp/whisper.cpp/build \ - -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DGGML_NATIVE=OFF - cmake --build /tmp/whisper.cpp/build --config Release -j"$(nproc)" - cp "$(find /tmp/whisper.cpp/build -name whisper-cli -type f | head -1)" addons/whisper/bin/whisper-cli + # Download the same published whisper-cli the app fetches at runtime + # (the linux-x64 source in whisper-addon.json), so the test exercises + # the real add-on artifact + tar layout instead of building from + # source. Mirrors the Windows job, which curls its release zip. + WHISPER_URL=$(python3 -c "import json;print(json.load(open('app/assets/whisper-addon.json'))['binary']['platforms']['linux-x64']['url'])") + echo "whisper-cli: $WHISPER_URL" + curl -L -o /tmp/whisper-cli.tar.gz "$WHISPER_URL" + tar xzf /tmp/whisper-cli.tar.gz -C addons/whisper # => addons/whisper/bin/whisper-cli chmod +x addons/whisper/bin/whisper-cli ls -la addons/whisper/bin addons/whisper/models diff --git a/CLAUDE.md b/CLAUDE.md index 79e6010..8e9c72d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -410,25 +410,74 @@ The most important parameters: ## Testing +VapourBox has **three distinct test suites**. Know which is which before adding +or changing tests — they live in different places and run differently. + +### 1. Rust worker tests — `worker/tests/`, run by `cargo test` + ```bash -# Rust tests cd worker && cargo test +cd worker && cargo test --test subtitle_integration_test -- --nocapture +``` + +- `filter_integration_test.rs` — **every filter/parameter change must add a + numbered test here** (see "Adding a New Filter"). It generates `.vpy` scripts + and, via `run_job`, runs the `vspipe | ffmpeg` pipeline, so it needs `deps/`. +- `subtitle_integration_test.rs` — runs `whisper-cli` on + `Tests/TestResources/small_clip.mp4`; needs the whisper add-on + ffmpeg. +- In **debug** builds `DependencyLocator` finds repo-root `deps/`/`addons/` by + searching upward — **except Linux**, which only reads + `~/.local/share/VapourBox/` (no upward search), so CI symlinks those there. -# Flutter tests +### 2. Flutter `test/` suite — `app/test/`, run by `flutter test` ← the CI gate + +```bash cd app && flutter test +``` -# Test worker standalone +Headless Dart-VM tests. A mix of pure unit tests (`dynamic_parameters`, +`filter_schema`, `parameter_converter`, `widget_test`, `scan_type_detection`) +and integration-style tests that shell out to the bundled binaries +(`vapoursynth_integration_test`, `schema_converter_integration_test`); the latter +need the per-arch `deps/` and (for whisper) `addons/`. **This is the Flutter +suite CI runs** — put new shell-out Dart tests here so CI covers them. + +### 3. Flutter `integration_test/` suite — `app/integration_test/`, NOT in CI + +```bash +cd app && flutter test integration_test # separate invocation; needs a display/device +``` + +- Flutter routes **anything** under `integration_test/` through the device + launcher (even plain `package:test` files), so it can't be combined with the + `test/` suite in one `flutter test` call and won't run on a headless CI runner + without a display (e.g. `xvfb`). These are **local/manual** tests. +- **Not maintained by CI, so they drift.** As of this writing + `filter_pipeline_test.dart` is stale and does not compile — it references a + removed API (`EncodingSettings.audioCopy`, now the `AudioMode` enum; + `ChromaFixParameters.vinverseScl`, now `vinverseSstr`/`vinverseAmnt`). Fix or + delete before relying on it; prefer adding shell-out tests to suite #2 instead. + +```bash +# Run the worker standalone (no test harness) cd worker && cargo run --release -- --config test_job.json ``` -**CI test gate** (`.github/workflows/ci-test.yml`): runs on push to `main` + PRs. It -pulls the published deps bundle and the whisper add-on (binary + small model), -then runs the full Rust + Flutter suites — including the subtitle integration -test — on macOS **arm64** (`macos-15`) and **x64** (`macos-15-intel`) and Windows x64. The -subtitle test needs `addons/whisper/{bin/whisper-cli,models/ggml-small.bin}` and -ffmpeg from `deps/`; the scan-type/vapoursynth Flutter tests need the per-arch -`deps/` dir. The `small_clip.mp4` + telecine/interlaced fixtures are committed -under `Tests/TestResources/`. +### CI test gate (`.github/workflows/ci-test.yml`) + +Runs on push to `main` + PRs (skipped for doc-only changes via `paths-ignore`). +Each job pulls the published deps bundle + the whisper add-on, then runs +**suite #1 (`cargo test`) and suite #2 (`flutter test`)** — including the subtitle +integration test. Matrix: macOS **arm64** (`macos-15`), macOS **x64** +(`macos-15-intel`), **Windows x64**, **Linux x64** (`ubuntu-22.04`). Notes: + +- whisper-cli is provisioned from the **same source the app uses at runtime** + (`app/assets/whisper-addon.json`): macOS via a Homebrew bottle, Windows/Linux + by downloading the published release zip/tarball (Linux from `whisper-vX.Y.Z`, + built by `build-whisper.yml`). +- Fixtures (`small_clip.mp4`, telecine/interlaced clips) are committed under + `Tests/TestResources/`. +- Suite #3 (`integration_test/`) is **not** part of this gate (see above). ## Code Style diff --git a/app/assets/whisper-addon.json b/app/assets/whisper-addon.json index 8e215d5..f0bbe56 100644 --- a/app/assets/whisper-addon.json +++ b/app/assets/whisper-addon.json @@ -22,6 +22,20 @@ "format": "zip", "executable": "whisper-cli.exe", "size": 3968674 + }, + "linux-x64": { + "url": "https://github.com/StuartCameronCode/VapourBox/releases/download/whisper-v1.8.3/whisper-cli-linux-x64.tar.gz", + "format": "tar", + "executable": "whisper-cli", + "size": 1573360, + "sha256": "4ea12345281a210937ce900984721d650adf834e308d03e520c506923ec4c8e6" + }, + "linux-arm64": { + "url": "https://github.com/StuartCameronCode/VapourBox/releases/download/whisper-v1.8.3/whisper-cli-linux-arm64.tar.gz", + "format": "tar", + "executable": "whisper-cli", + "size": 1527325, + "sha256": "2ffb99a5432bb6153b2a6e29ce7034465358f2fb5b98dad99c69663f6305c1c4" } } },