mirror of
https://github.com/spantaleev/matrix-docker-ansible-deploy.git
synced 2026-08-30 04:23:14 +00:00
278 lines
15 KiB
Gettext
278 lines
15 KiB
Gettext
# 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 ""
|