Testing and coverage¶
The collection uses several test layers because a variable can be accepted by Ansible, render valid configuration, and still fail when the service starts. Coverage is organized around the behavior a variable controls rather than a Cartesian product of every possible setting.
Coverage contract¶
The public variable catalog comes from each role's defaults/main.yml and its
generated meta/argument_specs.yml. tests/variable_coverage.yml records the
executable evidence for that catalog, and the repository contract tests fail
when the catalog or its coverage entries drift.
Each useful variable belongs to one or more of these coverage levels:
- Baseline: the role runs with its normal defaults and the verify play checks installation, service state, and the principal rendered files.
- Render contract: a fast integration test assigns a value and asserts the exact rendered configuration. This is appropriate for scalar formatting, list handling, and optional template fragments.
- Service rollout: a Molecule scenario installs the affected service, starts it, and verifies that the setting is accepted by the real service.
- Behavior contract: a focused integration or Molecule test checks a lifecycle, security, certificate, upgrade, or multi-role interaction.
- Negative contract: invalid combinations fail early with an actionable message and do not perform a partial deployment.
A variable is considered covered when the test assigns it, executes the role or task that consumes it, and asserts an observable result. A converge-only assignment does not count as coverage.
Defaulted feature controls that share a rollout are recorded as named behavior
groups in tests/variable_coverage.yml. The repository contract requires every
grouped variable to be assigned by the scenario and requires each listed
observable marker to appear in its verify.yml assertions.
Collection-specific matrix¶
The matrix grows by risk and by branch, with pairwise combinations for settings that interact. The scenarios below are the durable anchors for that work.
| Area | Required behavior paths | Existing or planned executable anchor |
|---|---|---|
| Shared collection and repositories | CA creation and reuse, passphrase handling, certificate renewal, repository release and mirror settings | elasticstack_default, elasticstack_common_passphrase, cert_renewal, and repository contracts |
| Elasticsearch installation | package and service lifecycle, YAML and logging controls, JVM and OS tuning, data and log paths, and logrotate syntax | elasticsearch_default, elasticsearch_no-security, elasticsearch_custom, elasticsearch_diagnostics, and template contracts |
| Elasticsearch cluster operations | node role calculation, quorum validation, cluster settings, LogsDB data-stream behavior, maintenance, rolling restart, and upgrade sequencing | elasticsearch_roles_calculation, elasticsearch_default, node-maintenance and rolling-restart contracts, and the 8-to-9 upgrade scenarios |
| Elasticsearch security | generated and external TLS, PEM and PKCS12 files, inline content, bundled CA extraction, built-in and custom users, roles, mappings, idempotence, and password rotation | certificate Molecule scenarios, security_and_certificate_contract.yml, elasticsearch_security_management_contract.yml, and the real-ES elasticsearch_security_api scenario |
| Kibana | backend protocol and host discovery, generated and external TLS, PEM and PKCS12 handling, encryption keys, readiness, and extra configuration | kibana_default, es_kibana, kibana_extras, kibana_custom_certs, cert_renewal, and the Kibana rollout matrix |
| Logstash | pipeline lifecycle, beats and Elastic Agent inputs, TLS modes, Elasticsearch outputs, authentication and roles, queues, dead-letter queues, monitoring, and config syntax | logstash_default, logstash_advanced, logstash_elasticsearch, logstash_external_certs, logstash_ssl, and logstash_standalone_certs |
| Beats | Filebeat, Auditbeat, and Metricbeat lifecycle, inputs, queues, outputs, load balancing, TLS modes, and module setup | beats_default, beats_advanced, beats_peculiar, beats_security, plus render contracts |
| Elastic Agent | package installation on Elastic 8 and 9, standalone policy rendering and backups, opt-in management, Fleet enrollment, Fleet Server flags and package flavor, certificate content/file/collection-CA paths, enrollment idempotence, secret-free state, and Beats migration | elastic_agent_default and elastic_agent_fleet on Rocky Linux and Debian, plus repository and variable-coverage contracts |
The matrix deliberately gives certificate source, content, fallback, and certificate-key mismatch paths their own assertions. Those paths need both file or content equality checks and service-level probes because a certificate can be copied successfully while the daemon still rejects its format or trust chain.
The higher-risk checks are deliberately split between levels. The real-ES
security scenario reconciles a role, user, and role mapping through the
collection with a custom elastic password, then reads those objects back and
authenticates as the managed user. The Elasticsearch default scenario creates
a logs-* data stream and checks the backing index's logsdb mode. The custom
Elasticsearch scenario runs logrotate's parser against the rendered policy and
checks that a custom elasticsearch_logpath is used. Kibana's rollout probes
require status.overall.level: available where an Elasticsearch backend is
present, including the HTTPS certificate-renewal path; a repository contract
also protects both readiness commands from falling back to /bin/sh.
CI responsibilities¶
Every committed Molecule scenario must have a verify.yml and be referenced by
an active workflow. Pull requests run the fast unit, contract, lint, and
role-specific paths. The ci:run label starts the Incus-backed rollout matrix,
including converge, verify, and idempotence checks. Scheduled runs widen the
operating-system and Elastic release matrix.
The EOL workflow is scheduled or manually dispatched because its data source is
external. Its classification and GitHub environment-file output are tested
deterministically in tests/unit/test_check_eol.py; the scheduled workflow
exercises the live API fetch and issue update path.
The full-stack gate is required before merge when shared roles, full-stack scenarios, or their workflows change. A failed rollout is investigated at the scenario level and fixed with a focused test before the broader matrix is started again.
Adding coverage for a new variable¶
When adding or changing a public variable:
- Classify its default path, alternate branches, and interactions.
- Add or extend the smallest contract that observes the rendered or runtime result.
- Add the variable to
tests/variable_coverage.ymlwith its scenario and assertion marker. - Run the focused unit or contract test immediately.
- Run the affected Molecule scenario in CI and confirm verify and idempotence.
- Add a negative case when invalid input could create an unsafe or partial deployment.
This process provides broad confidence without claiming that every theoretical transmutation has been executed. The catalog and ledger make any remaining untested branch visible for the next risk-based addition.