Skip to content

test(e2e): make the delegation suites establish their own preconditions - #2901

Merged
rubenvdlinde merged 4 commits into
developmentfrom
fix/delegation-e2e-fixture-hygiene
Aug 27, 2026
Merged

test(e2e): make the delegation suites establish their own preconditions#2901
rubenvdlinde merged 4 commits into
developmentfrom
fix/delegation-e2e-fixture-hygiene

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

What

The three delegation e2e suites gave three different answers over identical code when run back to back against merged development — 18 passed, then 8 failed, then 2 failed. The assertions were right; the suites were inheriting state instead of establishing it.

The two causes

1. A hardcoded fixture uid. NEXTCLOUD_OTHER_USER || 'ddauth-alice' named an account that existed when the specs were written and stopped existing when the dev instance was rebuilt. The resulting failure read:

"ddauth-alice" resolves to no account you may ask

That is the delegation guard's own refusal message. A dead fixture was wearing the words of a working control, and it cost a diagnosis. The uid is now discovered from /ocs/v2.php/cloud/users; an instance with only one account skips with a sentence naming what went unverified.

2. A leaked grant. Every suite opens by asserting the save is REFUSED — the baseline that the later "now it saves" assertion is measured against. Grants outlive a run, and a suite killed mid-way leaves a granted row behind, so the next run's baseline got a cheerful 201.

The failing direction was the lucky one. Had the leak been a revoked grant rather than a granted one, the refusal baseline would have passed for the wrong reason and the suite would have proved nothing at all. Each suite now revokes any live grant over its target before asserting.

The probe does not swallow errors

An earlier draft of the account probe wrapped the request in catch { return null }. When the probe came back as Nextcloud's login page — HTTP 200, HTML body, .json() throws — the catch reported "no second account": eleven specs skipped citing a single-account instance, and the run reported 0 failed. An auth failure had put on a fixture's clothes.

It now throws with the status and a body excerpt. A probe that cannot answer has to say so.

Also

NC_CONTAINER=nextcloud is let through under an explicit NC_ALLOW_SHARED_CONTAINER=1. The guard exists to stop an accidental default, not to make the awaiting_consent parking path — which only exists once a real TimedJob ticks — permanently unverifiable by anything but a unit test.

Verification

Ran live against merged development on localhost:8080:

21 passed, 0 skipped, 0 failed   — with NO container env set at all
21 passed, 0 skipped, 0 failed   — again, immediately after

Two identical results back to back is the property that was missing.

The zero skips are the second commit's doing: with exec defaulting to the shared container, the three delegation-parking tests now run rather than skip — the park on awaiting_consent and the release, driven by real FlowScheduleWorker and FlowRunWorker ticks. Before this branch that path was verified by nothing but a unit test, while the summary said 3 skipped in a tone indistinguishable from 3 passed.

Re-verified after merging current development into the branch.

🤖 Generated with Claude Code


Second commit: the container guard now prefers the shared box

The guard refused the shared nextcloud container for every purpose, which was too blunt in both directions.

The two actions are not the same risk, so they no longer share a rule.

purpose shared container why
'exec' (default) allowed, and now the default one named occ command is how a dev box is meant to be exercised
'restart' refused without NC_ALLOW_SHARED_RESTART=1 docker restart bounces an environment that bind-mounts several developers' trees, mid-session

Refusing exec bought nothing and cost real coverage: every spec needing a TimedJob tick skipped everywhere. The awaiting_consent park-and-release only exists once a job runs, so the headline behaviour of that subsystem was verified by nothing but a unit test — while the summary said 3 skipped in a tone indistinguishable from 3 passed.

federated-config-store.spec.ts is the only caller that restarts, and it now asks for that purpose explicitly.

Verified with no container env set at all

26 passed, 5 skipped, 1 failed

All three delegation-parking tests now run and pass — the park and the release through real FlowScheduleWorker / FlowRunWorker ticks.

One pre-existing failure, unrelated to this PR

federated-config.spec.ts (like flow-schedule.spec.ts) resolves a flows register in beforeAll and fails when it is absent — independently of any container setting. Flows themselves live in openregister_flows; the register is imported by the ImportFlowRegister repair step, which runs on install and occ upgrade. On an instance whose installed_version already matches info.xml, occ upgrade reports "no upgrade required" and the repair step never runs, so the register is never materialised and both specs are dead on arrival. Worth a follow-up — it is an environment/seed gap, not a code change this PR should make.

Running the three delegation suites live against merged `development` gave a
different answer three times over identical code — 18 passed, then 8 failed,
then 2 failed. Neither the code nor the assertions were wrong; the suites were
inheriting state instead of establishing it.

Two separate causes, both of which let a run report something it had not
measured:

1. A HARDCODED FIXTURE UID. `NEXTCLOUD_OTHER_USER || 'ddauth-alice'` named an
   account that existed when the specs were written and did not exist after the
   dev instance was rebuilt. The failure read
   `"ddauth-alice" resolves to no account you may ask` — which is the delegation
   guard's own refusal message, i.e. a dead fixture wearing the words of a
   working control. The uid is now DISCOVERED from the instance, and a
   single-account instance SKIPS with a sentence naming what went unverified
   rather than failing for a reason that is not about the code.

2. A LEAKED GRANT. Every suite opens by asserting the save is REFUSED — the
   baseline the later "now it saves" assertion is measured against. Grants
   outlive a run, and a suite killed mid-way (a `head` closing the reporter's
   pipe is enough) leaves a `granted` row behind, so the next run's baseline
   got a cheerful 201. The failing direction was the lucky one: a leaked
   REVOKED grant would have made the same baseline pass for the wrong reason
   and the suite would have proved nothing. Each suite now revokes any live
   grant over its target before asserting.

The account probe deliberately does NOT swallow errors. An earlier draft
wrapped it in `catch { return null }`, and when the probe came back as
Nextcloud's login page — HTTP 200, HTML, `.json()` throws — the catch reported
"no second account", eleven specs skipped citing a single-account instance, and
the run said `0 failed`. It now throws with the status and body, because a
probe that cannot answer must say so.

Also lets `NC_CONTAINER=nextcloud` through under an explicit
`NC_ALLOW_SHARED_CONTAINER=1`. The guard exists to stop an accidental default,
not to make the parking path — which only exists once a real TimedJob ticks —
permanently unverifiable.

Verified: 18 passed / 0 failed, twice back to back, against merged
`development` on a live instance.
The container guard refused the shared `nextcloud` container for every purpose,
and that was too blunt in both directions.

🔑 THE TWO ACTIONS ARE NOT THE SAME RISK, so they no longer share a rule.

`resolveContainer('exec')` — the default — now DEFAULTS TO the shared container
instead of returning null. Running one named `occ` command there is how the dev
box is meant to be exercised, and refusing to do so bought nothing: it made
every spec that needs a real TimedJob tick skip everywhere. The delegation
parking suite is the clearest casualty — a run parked on `awaiting_consent` and
released by a cron sweep only exists once a job actually runs, so the headline
behaviour of that subsystem was verified by nothing but a unit test, while the
summary said "3 skipped" in a tone indistinguishable from "3 passed".

`resolveContainer('restart')` still refuses the shared container without an
explicit `NC_ALLOW_SHARED_RESTART=1`. That is the action the original guard was
really about: `docker restart nextcloud` bounces an environment that bind-mounts
several developers' working trees, mid-session, with no warning to them. One
`occ` command is recoverable; restarting somebody else's instance is not.
`federated-config-store.spec.ts` is the only caller that restarts, and it asks
for that purpose explicitly.

Verified with NO container env set at all — the new default path:

  26 passed, 5 skipped, 1 failed

All three delegation-parking tests now RUN and pass, including the park and the
release through real FlowScheduleWorker and FlowRunWorker ticks. The remaining
failure is pre-existing and unrelated: `federated-config.spec.ts` (like
`flow-schedule.spec.ts`) needs a `flows` REGISTER, which this rebuilt dev
instance never seeded — its beforeAll fails on the register lookup regardless of
any container setting.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 5284b10

Check PHP Vue Security License Tests
lint ⏭️
phpcs ⏭️
phpmd ⏭️
psalm ⏭️
phpstan ⏭️
phpmetrics ⏭️
eslint ⏭️
stylelint ⏭️
build ⏭️
composer ⏭️ ⏭️
npm ⏭️ ⏭️
app:check-code ⏭️
info.xml ⏭️
REUSE ⏭️
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-27 05:59 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 4f8a5d4

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
test-l10n
format
check-schema-l10n
check-l10n-js
composer ✅ 175/175
npm ✅ 545/545
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-27 07:15 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 609ac14

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
test-l10n
format
check-schema-l10n
check-l10n-js
composer ✅ 175/175
npm ✅ 545/545
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-27 09:18 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit da5df5f into development Aug 27, 2026
85 checks passed
@rubenvdlinde
rubenvdlinde deleted the fix/delegation-e2e-fixture-hygiene branch August 27, 2026 09:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant