|
- # SOME DESCRIPTIVE TITLE.
- # Copyright (C) 2018-2026, Slavi Pantaleev, Aine Etke, MDAD community members
- # This file is distributed under the same license as the matrix-docker-ansible-deploy package.
- # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
- #
- #, fuzzy
- msgid ""
- msgstr ""
- "Project-Id-Version: matrix-docker-ansible-deploy \n"
- "Report-Msgid-Bugs-To: \n"
- "POT-Creation-Date: 2026-08-29 06:02+0000\n"
- "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
- "Language-Team: LANGUAGE <LL@li.org>\n"
- "MIME-Version: 1.0\n"
- "Content-Type: text/plain; charset=UTF-8\n"
- "Content-Transfer-Encoding: 8bit\n"
-
- #: ../../../docs/molecule-testing.md:7
- msgid "Molecule testing for roles"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:9
- msgid "Roles in `roles/custom/` can carry a [Molecule](https://ansible.readthedocs.io/projects/molecule/) scenario, which installs the role into a container and then checks that the component actually came up with the configuration the role rendered."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:11
- msgid "Not every role has one yet. Roles without a scenario are simply not tested."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:13
- msgid "Running a scenario"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:21
- msgid "The first run creates a virtualenv in `var/molecule-venv/` (gitignored) from `molecule-shared/requirements.txt`. Docker must be working, and a run takes minutes because it pulls container images."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:23
- msgid "`MOLECULE_DISTRO` selects the base image; it defaults to `ubuntu2604`."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:25
- msgid "Molecule is deliberately **not** part of the `prek` hooks. A run is far too slow to sit in front of a commit, and it needs Docker. Run it when you have touched a role; CI runs it too, asynchronously."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:27
- msgid "What CI runs"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:29
- msgid "`.github/workflows/molecule.yml` does not run every scenario on every push — with one repository holding every role, that would be unaffordable. Its first job works out which roles the push actually touched, keeps the ones that have a scenario, and builds the job matrix from those. A documentation change runs nothing."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:31
- msgid "When the diff base cannot be determined (a new branch, a force push), it falls back to running every scenario, which errs toward testing too much rather than too little. `workflow_dispatch` accepts an optional role name."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:33
- msgid "Automerge"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:35
- msgid "A role that has a scenario is listed in the Molecule automerge rule in `.github/renovate.json`, so patch bumps of its component merge on their own once the scenario has passed on them."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:38
- msgid "**Add your role to that list when you add its scenario.** `bin/check-molecule-automerge-list.py` runs from prek and fails the commit if the list and the scenarios have drifted apart. The direction that matters is a role staying in the list after losing its scenario, since its bumps would then merge with nothing exercising them."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:43
- msgid "Writing a scenario"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:45
- msgid "Start from `roles/custom/matrix-alertmanager-receiver/molecule/default/` — it is the reference. Four things differ from a standalone role's scenario, all of them consequences of these roles living inside a playbook:"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:47
- msgid "The playbook's context has to be supplied"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:49
- msgid "The role reads variables that `matrix-base` and `group_vars/matrix_servers` would normally provide. The set is small — `matrix_base_data_path`, `matrix_domain`, `matrix_user_name`, `matrix_group_name`, `matrix_user_uid`, `matrix_user_gid` — and belongs in the scenario's `group_vars`, rather than including `matrix-base`, which does much more than a role scenario needs."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:51
- msgid "The `matrix` user and group must exist first"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:53
- msgid "The roles' file tasks set `owner:` and `group:` by name, and Ansible resolves those through the passwd database, so `prepare.yml` has to create them before the role runs."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:55
- msgid "Most components need a homeserver to be present"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:57
- msgid "Many of these components contact the homeserver while starting up, and exit if it is unreachable — `matrix-alertmanager-receiver`, for example, fetches `/_matrix/client/v3/joined_rooms` to resolve its room mapping and exits with a failure if that call fails."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:59
- msgid "A stub is enough, and is what the reference scenario stands up. The point of these scenarios is to prove that **the component starts and does not choke on the configuration the role rendered** — not to exercise real bridging. A scenario should never need a credential or an account on a third-party network; that is the line where it stops being a test of this repository."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:61
- msgid "`verify.yml` is a separate play"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:63
- msgid "Role defaults are out of scope there, so any path it reads has to be pinned in the scenario's `group_vars`. Deliberately do **not** pin the component's version that way: read it from the role's `defaults/main.yml` with `include_vars`, so the assertion compares the running image against what the role ships rather than against the scenario itself."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:65
- msgid "Shared files"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:67
- msgid "`molecule-shared/` holds what would otherwise be duplicated into every role:"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:69
- msgid "`requirements.txt` — the Python packages, for both CI and `just molecule`."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:70
- msgid "`requirements.yml` — the external Ansible roles and collections the scenarios need. Each scenario symlinks its own `molecule/default/requirements.yml` at this file: Molecule checks for a requirements file at that default path before it will install anything, so pointing at the shared one through `requirements-file` alone is silently ignored."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:71
- msgid "`vars.yml` — helper container images used for probing, pinned once. They carry `# renovate:` annotations and a custom manager in `.github/renovate.json` keeps them current."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:73
- msgid "A helper image is used to reach a role's container over its own container network. That indirection is deliberate: the roles publish no host port, matching a real deployment, and publishing one for the test would collide between scenarios running in parallel."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:75
- msgid "Making a scenario worth having"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:77
- msgid "A suite that only waits for the systemd unit to become `active` proves very little: these units carry `Restart=always`, so a container crash-looping on a bad configuration still reports `active`. Check the restart counter alongside it, and probe something the component can only answer correctly if the role's configuration reached it."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:79
- msgid "Give the scenario values that differ from both the role's defaults and the component's own defaults. Otherwise a passing assertion cannot distinguish \"the role configured this\" from \"it would have happened anyway\"."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:81
- msgid "Then try to break it. If a scenario cannot be made to fail by deliberately breaking the thing it checks, it is not testing that thing."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:83
- msgid "Falsify **every** assertion, not just enough of them to see the scenario go red. An assertion that passes is not necessarily an assertion that works: one control here asserted that a component emitted no DEBUG records from a particular module, and it passed just as happily with that module set to `debug`, because the module emits none on a first run either way. It was green for the wrong reason, and only breaking it deliberately exposed that."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:89
- msgid "Make a failure identify the broken control"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:91
- msgid "Write each independently falsifiable condition as its own item under `that`. Ansible evaluates the items in order and reports the first false expression in its `assertion` result field. When several conditions are folded into one expression with `and`, it can only report that whole expression:"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:102
- msgid "Keeping related conditions in one assertion task is fine. Split them into separately named tasks when they describe different operational claims or remedies — for example, the container image, runtime identity, network attachment and published ports. `ansible.builtin.assert` runs on the controller without connecting to the target, so the extra tasks add negligible runtime compared to the probes that gathered the values."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:108
- msgid "Falsify the real control by changing an observed input or an expected value. Adding a literal `false` condition only proves that `ansible.builtin.assert` itself can fail; it does not prove that the scenario detects the defect it claims to detect."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:112
- msgid "Two traps make a falsification pass when it should fail:"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:114
- msgid "`molecule converge` against an already-running instance rewrites the configuration but only does `state: started`, so the container keeps the old one. Full `molecule test` is unaffected - this bites the local iterate-with-converge loop, which is where falsifications get run."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:117
- msgid "The failure must land on the assertion you aimed at. If it fails at an earlier gate, you have proved something about that gate instead."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:120
- msgid "Work out whether the component crashes or retries"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:122
- msgid "Some components exit when their configuration is wrong; others catch everything and retry forever. For the second kind, `ActiveState == active` and `NRestarts == 0` **both stay true while the component is completely broken** - matrix-reminder-bot and baibot both behave this way, retrying a failed login or profile step indefinitely. There the unit assertions prove nothing on their own, and something the component says about itself has to carry the scenario."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:128
- msgid "Establish which kind yours is before deciding what the weight-bearing assertion is."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:130
- msgid "Reading the journal"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:132
- msgid "Grep the whole journal rather than tailing it. Startup lines are the **oldest** entries, and a component that syncs can bury them under thousands of lines within a minute, so `--lines=N` loses exactly what you were looking for. Strip ANSI escapes too - some components colour their output, and a plain substring match against raw journal text then fails silently."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:137
- msgid "Assert against parsed documents"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:139
- msgid "Where a scenario reads a rendered configuration, parse it and assert on the structure rather than matching substrings. A value landing under the wrong key cannot then pass."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:142
- msgid "Running more than one scenario at once"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:144
- msgid "`bin/molecule.sh` points `ANSIBLE_HOME` at `var/molecule-ansible-home/<role>/`, so each role gets its own copy of the Galaxy collections and roles."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:147
- msgid "This is not an optimisation - it is a correctness fix. Scenarios install their dependencies with `force: true`, so two runs sharing `~/.ansible` re-extract the same collections underneath each other. The symptom is a collection that was working moments earlier going missing mid-play:"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:155
- msgid "If you see that, a concurrent run took the collection out from under you."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:157
- msgid "`ANSIBLE_HOME` is left alone if you have already set it, and is unset in CI - each role runs in its own job there, so there is nothing to collide with."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:160
- msgid "The directories are disposable; `var/` is gitignored. Delete `var/molecule-ansible-home/` to force a fresh install."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:163
- msgid "Databases"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:165
- msgid "Scenarios for roles that have a database run against **Postgres**, not sqlite."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:167
- msgid "That is what `group_vars/matrix_servers` selects whenever postgres is enabled, which is the default, so it is what essentially every deployment runs. sqlite is a path almost nobody is on: a bug that stopped the mautrix-meta bridges from starting at all under sqlite sat unreported for a long time, which says plainly enough whose path is worth testing."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:172
- msgid "`molecule-shared/tasks/postgres.yml` stands one up on the scenario's container network. Include it from `prepare.yml` and point the role at it with its own `_database_engine`, `_database_hostname` and credentials. Give the database and user names that differ from the role's defaults - then the component reaching the database at all proves the role built its connection string out of them."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:177
- msgid "The image is pinned in `molecule-shared/vars.yml` at the major the postgres role deploys to new installations, and Renovate carries it forward. When a new major lands, the PR bumping that pin runs every scenario against it, which is the earliest warning we get that a component does not cope with it."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:182
- msgid "Prefer asserting on the schema the component created over a file on disk: tables can only appear once it has resolved the hostname, authenticated, and run its migrations."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:185
- msgid "Reclaiming the disk space"
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:187
- msgid "`just molecule-clean` removes what the runs leave under `var/`."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:189
- msgid "Two things live there. The per-role Ansible homes are ~7 MB each, rewritten on every run rather than grown, so they are bounded by the number of roles that have a scenario. The shared virtualenv is the bulk of it, over 500 MB, and is recreated on the next run at the cost of a `pip install`."
- msgstr ""
-
- #: ../../../docs/molecule-testing.md:193
- msgid "`--idle-days N` restricts it to what has not been touched in N days, which is what makes it safe to run unattended. `--yes` skips the confirmation."
- msgstr ""
|