Make the test suite runnable without an ASP.NET Core runtime
The 11 tests built but could not execute: the plugin framework-references Microsoft.AspNetCore.App through Jellyfin.Controller, that reference flows into anything referencing the plugin, and the test host then demanded a web runtime even for tests that touch no web type. This box has none at any version, and Arch packages only 8 and 10 -- so "install the runtime" was neither available here nor a clean answer. DisableTransitiveFrameworkReferences drops the inherited reference. .NET resolves assemblies lazily, so pure-logic types load without it. This is a T1-tier decision rather than a workaround: requiring a web runtime to test string and rule logic is incidental coupling. T2 -- controllers and authorisation -- genuinely needs it, and belongs in a second project that keeps the reference. All 11 now pass. The suite was also checked to FAIL: removing the newline-stripping from RemoveInjection fails UT-001 and nothing else, then the source was restored and re-verified byte-identical. A suite that has only ever passed is not evidence that it tests anything. JR-016 and JR-022 therefore reach Done -- implemented and verified by tests that execute. JR-023 stays In Progress: its detection branch has no test and its config-page half is T4. TRACES: JR-016, JR-022 | PR-003, PR-004 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,18 @@
|
|||||||
and on CI without pinning either to a runtime that is not the plugin's.
|
and on CI without pinning either to a runtime that is not the plugin's.
|
||||||
-->
|
-->
|
||||||
<RollForward>LatestMajor</RollForward>
|
<RollForward>LatestMajor</RollForward>
|
||||||
|
<!--
|
||||||
|
The plugin framework-references Microsoft.AspNetCore.App through
|
||||||
|
Jellyfin.Controller, and that reference flows into anything referencing
|
||||||
|
the plugin. The T1 tier tests pure logic that touches no web type, so
|
||||||
|
inheriting the web framework would make the suite unrunnable on any box
|
||||||
|
without the ASP.NET Core runtime for no benefit. .NET resolves assemblies
|
||||||
|
lazily, so types that never touch ASP.NET load fine without it.
|
||||||
|
|
||||||
|
T2 (controllers, authorisation) genuinely needs that runtime. When those
|
||||||
|
tests arrive they belong in a second project that keeps this reference.
|
||||||
|
-->
|
||||||
|
<DisableTransitiveFrameworkReferences>true</DisableTransitiveFrameworkReferences>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
+36
-37
@@ -20,21 +20,22 @@ Tag code with `// TRACES: JR-012 | SR-002`.
|
|||||||
|
|
||||||
| ID | Asserts | Covers | Status |
|
| ID | Asserts | Covers | Status |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| UT-001 | Marked tag **and its trailing newline** removed — no blank line accumulates per upgrade cycle | JR-022 | Written |
|
| UT-001 | Marked tag **and its trailing newline** removed — no blank line accumulates per upgrade cycle | JR-022 | **Passing** |
|
||||||
| UT-002 | Marked tag with no trailing newline removed | JR-022 | Written |
|
| UT-002 | Marked tag with no trailing newline removed | JR-022 | **Passing** |
|
||||||
| UT-003 | Document without the marker left byte-identical | JR-022 | Written |
|
| UT-003 | Document without the marker left byte-identical | JR-022 | **Passing** |
|
||||||
| UT-004 | Removal is idempotent — startup runs it on every boot forever after | JR-022 | Written |
|
| UT-004 | Removal is idempotent — startup runs it on every boot forever after | JR-022 | **Passing** |
|
||||||
| UT-005 | **Another plugin's injection left intact** — it is their file too | JR-022 | Written |
|
| UT-005 | **Another plugin's injection left intact** — it is their file too | JR-022 | **Passing** |
|
||||||
| UT-006 | An unmarked look-alike script tag is left alone — JRay did not write it | JR-022 | Written |
|
| UT-006 | An unmarked look-alike script tag is left alone — JRay did not write it | JR-022 | **Passing** |
|
||||||
| UT-007 | No matching rule resolves to `null` | JR-016 | Written |
|
| UT-007 | No matching rule resolves to `null` | JR-016 | **Passing** |
|
||||||
| UT-008 | Item rule beats Series rule | JR-016 | Written |
|
| UT-008 | Item rule beats Series rule | JR-016 | **Passing** |
|
||||||
| UT-009 | **Prioritised series inside an ignored genre — series wins** | JR-016 | Written |
|
| UT-009 | **Prioritised series inside an ignored genre — series wins** | JR-016 | **Passing** |
|
||||||
| UT-010 | Genre matching is case-insensitive | JR-016 | Written |
|
| UT-010 | Genre matching is case-insensitive | JR-016 | **Passing** |
|
||||||
| UT-011 | A Series rule valued `Guid.Empty` does not swallow every movie | JR-016 | Written |
|
| UT-011 | A Series rule valued `Guid.Empty` does not swallow every movie | JR-016 | **Passing** |
|
||||||
|
|
||||||
`Written` rather than `Passing`: see the execution blocker below. A test whose
|
All 11 execute and pass. The suite was also checked to **fail** on a mutation —
|
||||||
result nobody has seen is not evidence, and recording it as passing would be the
|
removing the newline-stripping from `RemoveInjection` fails UT-001 and nothing
|
||||||
same failure as counting a GPU-only test as covered.
|
else — because a suite that has only ever passed is not evidence that it tests
|
||||||
|
anything.
|
||||||
|
|
||||||
`JR` is flat rather than split by theme. The plugin is one deployable with one
|
`JR` is flat rather than split by theme. The plugin is one deployable with one
|
||||||
audience, and the thematic grouping lives in the section headings below, where it
|
audience, and the thematic grouping lives in the section headings below, where it
|
||||||
@@ -82,7 +83,7 @@ coordinated `schema_version` bumps (SR-003).
|
|||||||
| ID | Requirement | Traces to | Priority | Status |
|
| ID | Requirement | Traces to | Priority | Status |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| JR-015 | `Tasks/Pending` serves a random sample of items with no truth data, so pollers spread across the backlog without server-side task state | PR-003 | High | Done |
|
| JR-015 | `Tasks/Pending` serves a random sample of items with no truth data, so pollers spread across the backlog without server-side task state | PR-003 | High | Done |
|
||||||
| JR-016 | Prioritise/ignore rules scoped `Genre` / `Series` / `Item`; **most specific wins**; scope+value is the unique key | PR-003 | Medium | Done |
|
| JR-016 | Prioritise/ignore rules scoped `Genre` / `Series` / `Item`; **most specific wins**; scope+value is the unique key | PR-003 | Medium | **Done** (UT-007…011) |
|
||||||
| JR-017 | Rules steer **work discovery only** — never the overlay or the read endpoints | PR-003 | Medium | Done |
|
| JR-017 | Rules steer **work discovery only** — never the overlay or the read endpoints | PR-003 | Medium | Done |
|
||||||
| JR-018 | Coverage report by media type and genre; ignored items leave the percent-done denominator rather than dragging it down | PR-003 | Medium | Done |
|
| JR-018 | Coverage report by media type and genre; ignored items leave the percent-done denominator rather than dragging it down | PR-003 | Medium | Done |
|
||||||
| JR-019 | Picker endpoints (genres, series, item search) populate the rule editor | PR-003 | Low | Done |
|
| JR-019 | Picker endpoints (genres, series, item search) populate the rule editor | PR-003 | Low | Done |
|
||||||
@@ -93,7 +94,7 @@ coordinated `schema_version` bumps (SR-003).
|
|||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| JR-020 | Pause overlay: injected client script queries `jray?t=` and renders the scene's cast | **PR-001** | High | Done |
|
| JR-020 | Pause overlay: injected client script queries `jray?t=` and renders the scene's cast | **PR-001** | High | Done |
|
||||||
| JR-021 | **jRay never injects into `index.html` on disk.** File Transformation is a hard dependency; there is no on-disk fallback. The only permitted write is JR-022's removal | PR-004 | High | **Done** |
|
| JR-021 | **jRay never injects into `index.html` on disk.** File Transformation is a hard dependency; there is no on-disk fallback. The only permitted write is JR-022's removal | PR-004 | High | **Done** |
|
||||||
| JR-022 | Migration: remove any on-disk patch left by an earlier jRay, identified by the `<!-- jray-overlay -->` marker | PR-004 | High | In Progress |
|
| JR-022 | Migration: remove any on-disk patch left by an earlier jRay, identified by the `<!-- jray-overlay -->` marker | PR-004 | High | **Done** (UT-001…006) |
|
||||||
| JR-023 | Absent the dependency, disable **only** the overlay and say so in the log and the config page; never bundle the assembly | PR-004 | Medium | In Progress |
|
| JR-023 | Absent the dependency, disable **only** the overlay and say so in the log and the config page; never bundle the assembly | PR-004 | Medium | In Progress |
|
||||||
| JR-024 | Actor names and all server-supplied strings render as **text, never markup** | SR-004 | High | Done |
|
| JR-024 | Actor names and all server-supplied strings render as **text, never markup** | SR-004 | High | Done |
|
||||||
|
|
||||||
@@ -187,31 +188,29 @@ thing when read across repos; reusing T3 for a live tier here would make a
|
|||||||
cross-repo reader count live-only requirements as covered.
|
cross-repo reader count live-only requirements as covered.
|
||||||
|
|
||||||
`Jellyfin.Plugin.JRay.Tests` (xUnit, in the solution) carries the T1 tier. It
|
`Jellyfin.Plugin.JRay.Tests` (xUnit, in the solution) carries the T1 tier. It
|
||||||
builds clean alongside the plugin.
|
builds clean alongside the plugin and all 11 tests pass.
|
||||||
|
|
||||||
### Execution blocker — the suite does not run on this machine
|
### Running the suite on a box without the web runtime
|
||||||
|
|
||||||
The plugin framework-references **`Microsoft.AspNetCore.App`** through
|
`dotnet test` from the repo root. Two properties on the test project make that
|
||||||
`Jellyfin.Controller`, so the test host demands that shared framework even for
|
work anywhere, and both are load-bearing rather than incidental:
|
||||||
tests that touch only pure logic. This box has `Microsoft.NETCore.App` 8.0.29
|
|
||||||
and 10.0.10 and **no ASP.NET Core runtime at all**, so `dotnet test` aborts
|
|
||||||
before a single test executes:
|
|
||||||
|
|
||||||
```
|
- **`RollForward=LatestMajor`.** The plugin targets `net9.0` to match Jellyfin's
|
||||||
Framework: 'Microsoft.AspNetCore.App', version '9.0.0' — No frameworks were found.
|
ABI, but a machine that can *build* it need not have the 9.0 runtime. Rolling
|
||||||
```
|
the test host forward keeps the suite runnable without pinning developers to a
|
||||||
|
runtime the plugin does not otherwise need.
|
||||||
|
- **`DisableTransitiveFrameworkReferences=true`.** The plugin
|
||||||
|
framework-references `Microsoft.AspNetCore.App` through `Jellyfin.Controller`,
|
||||||
|
and that flows into anything referencing it — so the test host would demand a
|
||||||
|
web runtime even for tests that touch no web type. .NET resolves assemblies
|
||||||
|
lazily, so pure-logic types load fine without it.
|
||||||
|
|
||||||
`<RollForward>LatestMajor</RollForward>` on the test project solves the *other*
|
**This is a T1-tier decision, not a workaround to unwind.** These tests exercise
|
||||||
half — the plugin targets `net9.0` to match Jellyfin's ABI, and no .NET 9
|
string and rule logic; requiring an ASP.NET Core runtime to run them would be
|
||||||
runtime is installed either — but roll-forward cannot conjure a framework of
|
incidental coupling. **T2 — controllers and authorisation — genuinely needs that
|
||||||
which no version exists.
|
runtime**, and those tests belong in a second project that keeps the reference.
|
||||||
|
Note that no ASP.NET Core 9 exists in the Arch repositories (8 and 10 only), so
|
||||||
**Fix:** install the ASP.NET Core runtime (`aspnet-runtime` on Arch). It is
|
that project will lean on `RollForward` too.
|
||||||
needed on the CI host for the same reason, so this belongs in the CI image
|
|
||||||
rather than in a developer's setup notes.
|
|
||||||
|
|
||||||
Until then every `UT` above is **Written, not Passing**, and no requirement
|
|
||||||
should be promoted to `Done` on the strength of them.
|
|
||||||
|
|
||||||
### Per-requirement verification plan
|
### Per-requirement verification plan
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user