You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Epic] Diff-driven & scenario-based E2E testing for Cozystack #2847
Make Cozystack's E2E testing fast, scenario-driven, and trustworthy enough that we can cut releases faster and with more confidence. Two complementary tracks: (1) diff-driven install so a PR's CI installs only what the changed app actually needs, and (2) scenario coverage (install, upgrade, per-app workloads) so the major usage paths are continuously exercised.
Status as of 2026-10-01
Checked against main at bc400dff1.
Three tasks are done, the .deps pivot, the install selector (select-install.sh, #3279) and the install smoke scenario (Track C). Two are obsolete as written, the test-minimal bundle and the COZYSTACK_ENABLED_PACKAGES wiring, because the design moved to select-install.sh --disabled in #4022. select-install.sh is still not invoked by any workflow, so its closure has never been checked against a real install.
The PR lanes changed under this epic. #4020 (merged 2026-09-07) moved the PR lane and the fork lane to Talos containers and they run the full suite there, QEMU stays in nightly and e2e-tag. Install takes about 28 min on the container lane, not the ~18 min this epic started from. I measured 62 PR e2e jobs from 2026-09-28 to 09-30 (install step median 1684 s), and Run E2E tests was full-shaped in 73% of them, scoped in 23% and skipped in 5%, classified by step duration. Install is paid in all three cases. The replay in #3817 of the last 150 merges to main agrees, 70.7% full-suite after its change, 80.0% before. So most runs escalate and install selection can only save on the scoped quarter. The window is three days and heavy on re-runs, so read it as a rough number.
That answers the measurement the track was waiting for, at least roughly. The "~60% of PRs touch one app" payoff does not hold. What is left to decide is whether a saving on a quarter of runs pays for the wiring, and that needs a look at the escalation side first, #4008 (broad selector tier) is open for that.
Track B is #3276, still open, conflicting and CHANGES_REQUESTED (2026-09-29). It needs a rework on the container lane, not a rebase.
Rationale
Every E2E run installs the isp-full bundle before any app test. A diff-driven-install design proposed computing the minimal install set from the PR diff using per-app PackageSource dependency lists, targeting a drop from the install time for PRs that touch one app. The selector script and the test-selection foundation it builds on landed in #2559. This epic operationalizes that design and folds in the in-flight upgrade-test work so install, upgrade and app scenarios are tracked under one roof.
The "~60% of PRs touch one app" and "~6-8 min" numbers were the original design estimates and were never measured on their own. The measurements in the status above say most runs escalate to the full suite, as docs/agents/e2e-testing.md (the TIA section) already said.
Test selection is default-on since #2559, with full-e2e as the opt-out that forces the whole suite. There is no e2e-tia label and never was. Install selection, when it is wired, has to pick its own default.
Supersedes #98 and #759. Both predate the current Package/PackageSource/bundles.enabledPackages model, and their goals (a basic install smoke test, scenario-based regression coverage) are covered by the tasks below.
Tasks
Track A, diff-driven install
Land hack/e2e-apps/install.deps plus per-app .deps leaf files with a static validator. Superseded by test(e2e): diff-driven install selector select-install.sh #3279. The selector reuses the real PackageSource graph in packages/core/platform/sources/ directly, so there are no parallel dependency files to keep in sync.
Land feat(platform, tests): select E2E packages and declare controller dependencies #4022: select-install.sh --disabled <suites> emits the bundles.disabledPackages list for an ordinary variant, plus the mongodb-application and seaweedfs-applicationdependsOn edges it needs and the kubernetes-nodes-application mapping. Open, CHANGES_REQUESTED. The 2026-09-25 review asked for a body that mentions the two edges and the mapping change, the head was pushed again on 2026-10-01 and no check is failing on it now.
Wire hack/e2e-install-cozystack.bats to read COZYSTACK_ENABLED_PACKAGES. Obsolete mechanism. The install Package is generated by hack/e2e-platform-packages.sh now, and it already emits a disabledPackages list for the container lane (LINSTOR and kubevirt-cdi). The wiring task is the next one.
Wire select-install.sh --disabled into hack/e2e-platform-packages.sh and add a Select install components step to the PR and fork workflows. Nothing under .github/ references select-install yet. Five workflows run Chainsaw now (pull-requests, e2e-fork, e2e-tag, nightly and e2e-proxmox), so the task has to say which lanes get it. The PR and fork lanes are where install time is paid on every push. full_suite_pattern in hack/select-e2e.sh lists four of the five workflows and not e2e-proxmox. A full-suite answer from select-e2e.sh still has to become an empty disable list, which needs an escalation signal out of the selector.
Capture install timing durably: hack/install-summary.sh or a step in cozyreport.sh writing install.duration_seconds and the HR timings, with a regression detector. Not started, hack/install-summary.sh does not exist. The 62-job number above was read by hand from step durations (gh run view --json jobs), so it is not reproducible from the repo. Keep this task only if we want the number to stay visible.
Document install-selection semantics in .github/PULL_REQUEST_TEMPLATE.md and docs/agents/e2e-testing.md. Test-selection semantics are already in the TIA section of that doc, including the escalation lists, the full-e2e label and the per-path coverage rule. The PR template has no e2e section.
Soak (no code change, ~2 weeks): median install time on scoped versus full runs, require at least 50% reduction on app-only runs and zero green-on-full / red-on-minimal divergences before promotion. Blocked on the wiring task above.
Promote to default in a separate PR after soak data is published. Test selection is already default-on, so this is about the install side only.
Make the upgrade lane share the install telemetry so install and upgrade timings live in one place. e2e-tag.yaml already uploads cozyreport.tgz. Jobs to sequence against are rc-e2e, generate-changelog and update-website-docs in tags.yaml, and changelog and website-docs in promote-rc.yaml.
hack/e2e-install-cozystack.bats is the canonical install smoke scenario that Add simple test with kind #98 asked for. docs/agents/e2e-testing.md (the "install gate must have teeth" section) names it as the install gate with the fail-if-any-HR-not-Ready contract, implemented by cozy_wait_all_helmreleases_ready. The kind + paas-hosted approach from Add simple test with kind #98 is obsolete.
Track C (install smoke) — effectively done: hack/e2e-install-cozystack.bats exists; only the doc-as-canonical step remains.
BATS → Chainsaw migration — split out of this epic into its own tracking issue #2979 with PR #2826 (approved, still a draft — needs un-drafting + merge).
Track A (diff-driven install) — still greenfield. Verified against main: hack/select-e2e.sh (the test-selection selector) exists, but none of the install-side artifacts do — no hack/select-install.sh, no hack/e2e-apps/install.deps / per-app *.deps, no test-minimal bundle. The data model is ready (select-e2e.sh already walks the PackageSourcedependsOn graph), so the first deliverable is install.deps + a static validator, which then unblocks select-install.sh.
Track B (upgrade scenario) — #2401 still a draft (CHANGES_REQUESTED), stalled.
Body re-verified against main at 09dc7f47f. Three of the twelve tasks are done (the .deps pivot, select-install.sh in #3279, and Track C's install smoke doc) and one is obsolete: #2401 was closed without merge, so Track B is now #3276, which is open, CHANGES_REQUESTED and currently conflicting. Two premises in the original body were wrong and are corrected inline: there is no e2e-tia label and never was (git log -S'e2e-tia' returns nothing) because #2559 shipped test selection default-on with full-e2e as the opt-out, and the LINSTOR/MetalLB post-install work has moved out of the bats @test bodies into hack/e2e-post-install-prep.sh. The one fact worth acting on: hack/select-install.sh is not reachable from CI, nothing under .github/ invokes it, so its closure is unit-tested but has never been validated against a real install. Track A is therefore re-ordered rather than re-scoped. The install-telemetry task becomes a prerequisite for the three implementation tasks, because the "~60% of PRs touch one app" payoff has never been measured and §7 of docs/agents/e2e-testing.md records that most PRs legitimately escalate to the full suite. The escalation surface moved three times in the six days to 2026-08-10 and settled when #3434 closed on 2026-08-13, so any measurement should record the commit it was taken at. Also folded in: the selector correctness bugs #3392, #3330 and #3665 (fixed by #3670 and #3441) and the fact that the suite now runs in three lanes, which changes what the CI wiring task has to cover. Nothing new is being added to scope here.
Body re-checked against main at bc400dff1. test-minimal and the COZYSTACK_ENABLED_PACKAGES wiring are obsolete, the vehicle for Track A is #4022 (select-install.sh --disabled). select-install.sh is still not invoked by any workflow.
The measurement the track waited on is in the body now. On the container lane install takes about 28 min (median of 62 PR jobs, 2026-09-28 to 09-30), and the suite step was full-shaped in 73% of those jobs, scoped in 23% and skipped in 5%, with install paid in all of them. #3817 found the same from the other side, 70.7% of the last 150 merges to main still run the full suite. So the "~60% of PRs touch one app" figure does not hold and install selection can only save on the scoped quarter. As I noted in #3278, narrowing what an escalation escalates to comes first, #4008 is open for that. I read the numbers by hand from step durations, the window is three days and heavy on re-runs.
Track B: #3276 needs a rework on the container lane, details are in the body.
Goal
Make Cozystack's E2E testing fast, scenario-driven, and trustworthy enough that we can cut releases faster and with more confidence. Two complementary tracks: (1) diff-driven install so a PR's CI installs only what the changed app actually needs, and (2) scenario coverage (install, upgrade, per-app workloads) so the major usage paths are continuously exercised.
Status as of 2026-10-01
Checked against
mainatbc400dff1.Three tasks are done, the
.depspivot, the install selector (select-install.sh, #3279) and the install smoke scenario (Track C). Two are obsolete as written, thetest-minimalbundle and theCOZYSTACK_ENABLED_PACKAGESwiring, because the design moved toselect-install.sh --disabledin #4022.select-install.shis still not invoked by any workflow, so its closure has never been checked against a real install.The PR lanes changed under this epic. #4020 (merged 2026-09-07) moved the PR lane and the fork lane to Talos containers and they run the full suite there, QEMU stays in nightly and
e2e-tag. Install takes about 28 min on the container lane, not the ~18 min this epic started from. I measured 62 PR e2e jobs from 2026-09-28 to 09-30 (install step median 1684 s), andRun E2E testswas full-shaped in 73% of them, scoped in 23% and skipped in 5%, classified by step duration. Install is paid in all three cases. The replay in #3817 of the last 150 merges tomainagrees, 70.7% full-suite after its change, 80.0% before. So most runs escalate and install selection can only save on the scoped quarter. The window is three days and heavy on re-runs, so read it as a rough number.That answers the measurement the track was waiting for, at least roughly. The "~60% of PRs touch one app" payoff does not hold. What is left to decide is whether a saving on a quarter of runs pays for the wiring, and that needs a look at the escalation side first, #4008 (broad selector tier) is open for that.
Track B is #3276, still open, conflicting and
CHANGES_REQUESTED(2026-09-29). It needs a rework on the container lane, not a rebase.Rationale
Every E2E run installs the
isp-fullbundle before any app test. A diff-driven-install design proposed computing the minimal install set from the PR diff using per-appPackageSourcedependency lists, targeting a drop from the install time for PRs that touch one app. The selector script and the test-selection foundation it builds on landed in #2559. This epic operationalizes that design and folds in the in-flight upgrade-test work so install, upgrade and app scenarios are tracked under one roof.The "~60% of PRs touch one app" and "~6-8 min" numbers were the original design estimates and were never measured on their own. The measurements in the status above say most runs escalate to the full suite, as
docs/agents/e2e-testing.md(the TIA section) already said.Test selection is default-on since #2559, with
full-e2eas the opt-out that forces the whole suite. There is noe2e-tialabel and never was. Install selection, when it is wired, has to pick its own default.Supersedes #98 and #759. Both predate the current
Package/PackageSource/bundles.enabledPackagesmodel, and their goals (a basic install smoke test, scenario-based regression coverage) are covered by the tasks below.Tasks
Track A, diff-driven install
LandSuperseded by test(e2e): diff-driven install selector select-install.sh #3279. The selector reuses the realhack/e2e-apps/install.depsplus per-app.depsleaf files with a static validator.PackageSourcegraph inpackages/core/platform/sources/directly, so there are no parallel dependency files to keep in sync.hack/select-install.shandhack/select-install_test.bats. Delivered in test(e2e): diff-driven install selector select-install.sh #3279. It maps the suite namesselect-e2e.shemits back to their*-applicationPackageSource, walksspec.variants[].dependsOnforward to the transitive closure (seedingcozystack.cozystack-engine), and has a--validatemode for graph reachability, cycles and the suite-to-source mapping. It runs on every PR throughmake unit-tests, andhack/select-e2e_test.batsasserts the suite-to-source round trip in both directions (ci: select-e2e maps only *-application sources, so kuberture and securitygroup suites are never selected by dependency #3665).select-install.sh --disabled <suites>emits thebundles.disabledPackageslist for an ordinary variant, plus themongodb-applicationandseaweedfs-applicationdependsOnedges it needs and thekubernetes-nodes-applicationmapping. Open,CHANGES_REQUESTED. The 2026-09-25 review asked for a body that mentions the two edges and the mapping change, the head was pushed again on 2026-10-01 and no check is failing on it now.Add theSuperseded by feat(platform, tests): select E2E packages and declare controller dependencies #4022.test-minimalbundle variant and thebundles.testMinimalknob.packages/core/platform/templates/bundles/still holds onlyiaas,naas,paasandsystem, and nothing needs a new one.WireObsolete mechanism. The installhack/e2e-install-cozystack.batsto readCOZYSTACK_ENABLED_PACKAGES.Packageis generated byhack/e2e-platform-packages.shnow, and it already emits adisabledPackageslist for the container lane (LINSTOR and kubevirt-cdi). The wiring task is the next one.select-install.sh --disabledintohack/e2e-platform-packages.shand add aSelect install componentsstep to the PR and fork workflows. Nothing under.github/referencesselect-installyet. Five workflows run Chainsaw now (pull-requests,e2e-fork,e2e-tag,nightlyande2e-proxmox), so the task has to say which lanes get it. The PR and fork lanes are where install time is paid on every push.full_suite_patterninhack/select-e2e.shlists four of the five workflows and note2e-proxmox. A full-suite answer fromselect-e2e.shstill has to become an empty disable list, which needs an escalation signal out of the selector.hack/install-summary.shor a step incozyreport.shwritinginstall.duration_secondsand the HR timings, with a regression detector. Not started,hack/install-summary.shdoes not exist. The 62-job number above was read by hand from step durations (gh run view --json jobs), so it is not reproducible from the repo. Keep this task only if we want the number to stay visible..github/PULL_REQUEST_TEMPLATE.mdanddocs/agents/e2e-testing.md. Test-selection semantics are already in the TIA section of that doc, including the escalation lists, thefull-e2elabel and the per-path coverage rule. The PR template has no e2e section.Track B, upgrade scenario
upgrade-e2ejob. Open, conflicting,CHANGES_REQUESTEDon 2026-09-29. The review lists what has to change: commit trailers the contributing rules don't allow (13 of 19 commits), a lane built on QEMU and on artifacts the PR pipeline no longer produces, a baseline release that lacks the linstordrbd.enabledswitch so it still needs QEMU, and its own HR wait next tocozy_wait_all_helmreleases_ready. test(e2e): wire the 1.5→1.6 etcd upgrade job into CI as the authoritative regression guard #3316 was closed as stale on 2026-10-01 (it asked for a 1.5 to 1.6 job, v1.6.4 is stable and main is v1.7.0-alpha.3). e2e: no upgrade test keeps a VMI-only hotplug volume attached across the switch to declarative hotplug #4463 (hotplug volume across an upgrade) needs this lane too.e2e-tag.yamlalready uploadscozyreport.tgz. Jobs to sequence against arerc-e2e,generate-changelogandupdate-website-docsintags.yaml, andchangelogandwebsite-docsinpromote-rc.yaml.Track C, install smoke scenario (replaces #98)
hack/e2e-install-cozystack.batsis the canonical install smoke scenario that Add simple test with kind #98 asked for.docs/agents/e2e-testing.md(the "install gate must have teeth" section) names it as the install gate with the fail-if-any-HR-not-Ready contract, implemented bycozy_wait_all_helmreleases_ready. Thekind+paas-hostedapproach from Add simple test with kind #98 is obsolete.Related work tracked elsewhere
backupandkubernetes-proxmoxare parked aschainsaw-test.yaml.disabled. The two monitoring OIDC BATS suites that were never ported were deleted in test(e2e): remove unused monitoring suites and audit BATS runners #4019.chainsaw-test.ymldiscovery) and e2e test selection: a package that maps to some suites never escalates, so suites that also cover it are dropped silently #3985 (the ingress mapping is fixed in fix(networking): prevent webhook admission outages during namespace churn #3997, the structural part is still open).Prerequisites
hack/select-e2e.shandhack/select-e2e_test.batsonmain, invoked frompull-requests.yamlande2e-fork.yaml.Out of scope
default,isp-full,isp-hostedandisp-full-genericvariants are untouched.