test: deduplicate the test suite #24

Merged
claudiomaradonna merged 11 commits from test/dedup-suite into main 2026-10-07 23:05:52 +02:00
Collaborator

Why

The test suite repeated itself: every molecule.yml carried the same driver and roles-path block, a firewall-apply scenario made two claims that fit in default, ai-stack checked the same mounts and storage tree twice, and two docker_engine scripts and five fixture inventories duplicated each other. The audit also found that the loader scenario and the tag_propagation gate passed with the loader's include_role deleted, because firewall-apply builds the chain they checked by itself.

What changed

  • The loader scenario and tag_propagation prove the include through zram, whose evidence only the included role writes; make test runs that scenario only through the gate. tag_selection now looks for the include task itself, so a lost always fails make check without podman.
  • A new firewall_render case renders from the loader's own service_roles, as handbook.yml does, keeping what the old loader scenario proved in passing.
  • firewall-apply's unsourced scenario folds into default; hardening-basic's workstation reuses default's prepare; scan-share, ai-stack, unattended-upgrades and fail2ban lose repeated checks.
  • .config/molecule/config.yml holds the driver and roles path once; the runner and the gate pass it with -c, because from a .worktrees/ checkout molecule's own lookup reads the main checkout's copy.
  • Controller-only gates share tests/fixtures/local.yml, and check_docker_engine.sh replaces the two docker_engine scripts.

No role changes; net −368 lines.

Verification

  • make check passes at every commit.
  • molecule syntax and molecule list pass for every scenario with the base config and show the podman driver; without -c, a worktree falls back to the default driver.
  • Mutations, each reverted: removing check_mode: false from docker-engine's assert.yml and merging daemon.json over {} fail docker_engine; removing always from the loader's include fails tag_selection; ANSIBLE_PRIVATE_ROLE_VARS=True fails the new firewall_render case.
  • Not run: make test, including tag_propagation (no podman in the agent sandbox).

Risks and follow-ups

  • The molecule changes are proven here only by syntax and config checks; make test is the real gate for them.
  • Land this before refactor/dedup-roles, which relies on its loader README wording.
## Why The test suite repeated itself: every molecule.yml carried the same driver and roles-path block, a firewall-apply scenario made two claims that fit in `default`, ai-stack checked the same mounts and storage tree twice, and two docker_engine scripts and five fixture inventories duplicated each other. The audit also found that the loader scenario and the `tag_propagation` gate passed with the loader's `include_role` deleted, because firewall-apply builds the chain they checked by itself. ## What changed - The loader scenario and `tag_propagation` prove the include through zram, whose evidence only the included role writes; `make test` runs that scenario only through the gate. `tag_selection` now looks for the include task itself, so a lost `always` fails `make check` without podman. - A new `firewall_render` case renders from the loader's own `service_roles`, as `handbook.yml` does, keeping what the old loader scenario proved in passing. - firewall-apply's `unsourced` scenario folds into `default`; hardening-basic's `workstation` reuses `default`'s prepare; scan-share, ai-stack, unattended-upgrades and fail2ban lose repeated checks. - `.config/molecule/config.yml` holds the driver and roles path once; the runner and the gate pass it with `-c`, because from a `.worktrees/` checkout molecule's own lookup reads the main checkout's copy. - Controller-only gates share `tests/fixtures/local.yml`, and `check_docker_engine.sh` replaces the two docker_engine scripts. No role changes; net −368 lines. ## Verification - `make check` passes at every commit. - `molecule syntax` and `molecule list` pass for every scenario with the base config and show the podman driver; without `-c`, a worktree falls back to the default driver. - Mutations, each reverted: removing `check_mode: false` from docker-engine's `assert.yml` and merging `daemon.json` over `{}` fail `docker_engine`; removing `always` from the loader's include fails `tag_selection`; `ANSIBLE_PRIVATE_ROLE_VARS=True` fails the new `firewall_render` case. - Not run: `make test`, including `tag_propagation` (no podman in the agent sandbox). ## Risks and follow-ups - The molecule changes are proven here only by syntax and config checks; `make test` is the real gate for them. - Land this before `refactor/dedup-roles`, which relies on its loader README wording.
The default scenario now switches warden on with no admitted source and
asserts its chain exists and accepts nothing, the two claims the
unsourced scenario made, so make test boots one container fewer.

The webserver chain joins the chain-text loop instead of its own read,
the input chain is checked for its webserver and warden jumps, and the
"nftables is installed" assertion goes: every nft call above it already
needs the package. The converges stop setting the forwarding knob to
the default(0) firewall-apply already applies.
The loader scenario and the tag_propagation gate both checked the
webserver chain, which firewall-apply builds by itself from
service_roles and the flags, so neither failed when the loader's
include_role was deleted or lost its tags; the scenario's checks also
repeated firewall-apply's own.

Both now converge the loader alone with zram switched on and read the
PERCENT value only zram's own tasks write. The gate keeps its
create-then-tagged-converge sequence, now with --tags zram: putting the
tags in the scenario instead would hand them to the podman driver's
untagged create playbook too, and no container would be created.
The workstation scenario's prepare.yml was byte-identical to default's;
it now runs default's through provisioner.playbooks. Its directory-mode
block repeated default's word for word, though the tasks that create
those directories do not depend on the profile, so only default checks
them.

default's existence loop, its two separate mode assertions and its
directory-mode loop become one {path, mode} loop whose failure message
still names the path, the mode found and the mode expected.
scan-share's check.yml was converge.yml under another play name; the
--check preview now runs converge.yml, and the three refusal probes
become one labelled loop whose failure names the client let in.

ai-stack's default-root and custom-root renders share one list of
LocalAI mounts and one storage tree, checked under both roots, instead
of two copies of each.

unattended-upgrades reads apt-config dump with four anchored multiline
searches instead of four filtered lists, and fail2ban's converge stops
setting fail2ban_enabled to its own default.
Every molecule.yml repeated the podman driver, the provisioner and
verifier names (both molecule's defaults) and the ANSIBLE_ROLES_PATH
that reaches the other roles. The driver and the roles path now live
once in .config/molecule/config.yml, merged under each scenario, and a
scenario's file holds its platforms entry and what is its alone.

The runner and the tag_propagation gate pass the file with -c: from a
.worktrees/ checkout molecule's own lookup reads the main checkout's
copy, because it accepts only a .git directory.
Five gates each carried an inventory of the same single local host
with the same interpreter pin. bashrc, retired_services and
sysctl_check_mode now run against tests/fixtures/local.yml, which
states the pin's reason once; firewall_render and peer_derivation keep
their own inventories, since their host variables are what they test,
and point at it for the reason. The two docker_engine gates move to it
when they are merged.

tag_selection's check for a retired iptables-* role could never fire:
no such role exists, so a reference to one fails the syntax check and
the --list-tasks call above it first.
CONTRIBUTING already listed docker_engine as one gate with two
scripts, which repeated the header, the setup and the failure helper,
and drove two fixture plays: one rebuilding include_role by hand from
include_vars and include_tasks. check_docker_engine.sh now runs both
modes through one play that takes the shipped task file as a variable,
against the shared local inventory; the assert half still drops the
inherited PATH so a real docker(1) cannot stand in for the stub.

Checked by mutation, then reverted: removing check_mode: false from
assert.yml fails the gate, and so does merging daemon.json over {}
instead of the existing file.
The reason for passing the molecule base config with -c is stated
once, in CONTRIBUTING, and the runner points to it.

The loader README says which container proves what: the scenario the
include, the gate the tagged run. The workstation scenario stops
repeating where its prepare comes from, and firewall-apply's scenario
stops naming iptables-nft scenarios that no longer exist.
The check that --tags firewall reaches service-role-loader searched
the listing for the role's name, which the retired-list refusal task
also prints, being tagged always too; so it passed with the include's
always tag gone. It now searches for the include task by name, and
fails when that tag is removed (checked by mutation, then reverted),
which make check catches without podman.
The loader scenario used to run firewall-apply beside the loader
without setting service_roles, so it also proved that firewall-apply
finds the list in the loader's defaults, as handbook.yml relies on.
Retargeting it to zram dropped that, and every other firewall test
sets the list itself; collect.yml reads it with a default of [], so
losing it would render no service chain on any host, silently.

A sixth firewall_render case runs the loader statically with only
webserver's flag on, then collect and render, and wants the webserver
jump. It runs in make check; with ANSIBLE_PRIVATE_ROLE_VARS=True it
fails on exactly that message (checked, not committed).
make test ran service-role-loader's scenario untagged and then the
tag_propagation gate converged the same scenario with --tags zram and
the same verify. The untagged run failed only when the include was
deleted, which the gate catches along with the tag mutations, as does
tag_selection now in make check; zram's own scenario covers its
idempotence. The role leaves MOLECULE_ROLES, one container fewer per
make test, and the scenario stays as the gate's.
claudiomaradonna deleted branch test/dedup-suite 2026-10-07 23:05:56 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
claudiomaradonna/castrum!24
No description provided.