mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-10 12:47:04 +00:00
A role's playwright.run_after names the roles its pass runs after; the new playwright_order lookup reads it through role_tests (which now renders Jinja with the queried role as application_id) and orders the round with a stable topological sort, so only constrained roles move. web-app-docs runs after every other invokable role: in CI run 41206003651 (Discourse#2) its pass waited 3126 s for the docs server's Sphinx build while stalwart, bigbluebutton, jitsi and prometheus (~400 s) queued behind it. Cycles, self references, unknown roles and non-list values fail loudly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
91 lines
3.1 KiB
Python
91 lines
3.1 KiB
Python
"""Unit tests for the `role_tests` lookup plugin.
|
|
|
|
Pins the contract: two terms (application_id, dotted path), values read
|
|
from ``roles/<application_id>/meta/tests.yml`` under ``playbook_dir``,
|
|
missing file/key falls back to the ``default`` kwarg.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from ansible.errors import AnsibleError
|
|
from ansible.parsing.dataloader import DataLoader
|
|
from ansible.template import Templar
|
|
|
|
from plugins.lookup.role_tests import LookupModule
|
|
from utils.cache.yaml import dump_yaml
|
|
from utils.roles.mapping import ROLE_FILE_META_TESTS
|
|
|
|
RUN_AFTER_EXPRESSION = "{{ invokables | difference([application_id]) }}"
|
|
|
|
|
|
class TestRoleTestsLookup(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls) -> None:
|
|
cls._tmp = tempfile.TemporaryDirectory()
|
|
cls.addClassCleanup(cls._tmp.cleanup)
|
|
cls.root = Path(cls._tmp.name)
|
|
tests_yml = cls.root / "roles" / "svc-runner" / ROLE_FILE_META_TESTS
|
|
tests_yml.parent.mkdir(parents=True)
|
|
dump_yaml(
|
|
tests_yml,
|
|
{
|
|
"cli": {"timeout": 9000},
|
|
"playwright": {"run_after": RUN_AFTER_EXPRESSION},
|
|
},
|
|
)
|
|
|
|
def test_a_jinja_value_renders_with_the_queried_role_as_application_id(self):
|
|
variables = {
|
|
"playbook_dir": str(self.root),
|
|
"application_id": "web-app-caller",
|
|
"invokables": ["svc-runner", "web-app-caller", "web-app-x"],
|
|
}
|
|
lookup = LookupModule(
|
|
loader=DataLoader(),
|
|
templar=Templar(loader=DataLoader(), variables=variables),
|
|
)
|
|
[rendered] = lookup.run(
|
|
["svc-runner", "playwright.run_after"], variables=variables
|
|
)
|
|
self.assertEqual(sorted(rendered), ["web-app-caller", "web-app-x"])
|
|
|
|
def test_a_jinja_value_stays_raw_without_a_templar(self):
|
|
self.assertEqual(
|
|
self._run(["svc-runner", "playwright.run_after"]), [RUN_AFTER_EXPRESSION]
|
|
)
|
|
|
|
def _run(self, terms, **kwargs):
|
|
return LookupModule().run(
|
|
terms, variables={"playbook_dir": str(self.root)}, **kwargs
|
|
)
|
|
|
|
def test_reads_dotted_value(self):
|
|
self.assertEqual(self._run(["svc-runner", "cli.timeout"]), [9000])
|
|
|
|
def test_missing_key_returns_default(self):
|
|
self.assertEqual(self._run(["svc-runner", "cli.missing"], default=3600), [3600])
|
|
|
|
def test_missing_file_returns_default(self):
|
|
self.assertEqual(self._run(["web-app-x", "cli.timeout"], default=""), [""])
|
|
|
|
def test_missing_default_is_none(self):
|
|
self.assertEqual(self._run(["web-app-x", "cli.timeout"]), [None])
|
|
|
|
def test_requires_two_terms(self):
|
|
with self.assertRaises(AnsibleError):
|
|
self._run(["svc-runner"])
|
|
with self.assertRaises(AnsibleError):
|
|
self._run(["svc-runner", "cli.timeout", "extra"])
|
|
|
|
def test_requires_playbook_dir(self):
|
|
with self.assertRaises(AnsibleError):
|
|
LookupModule().run(["svc-runner", "cli.timeout"], variables={})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|