Files
computer-playbook/tests/unit/python/plugins/lookup/test_guide_role.py
T
kevinveenbirkenbachandClaude Opus 5 4fc0b8be57 fix(guide_role): resolve the variable fallback the same way
The lookup takes the role from its term and falls back to reading
application_id out of the play's variables. That read was raw, which is the
trap that took down three jobs from webserver_resource, so it now goes through
resolve_var like every other lookup.

Prevention rather than a fix. The fallback is the else of a term that the only
caller always passes, and where it would fire web-app-docs sets application_id
literally; the roles carrying a templated id reach it through sys-stk-full,
which web-app-docs does not. The consequence would also have differed: an
unrendered string never matches a peer, so the replay would have asked the
site for a role named after the template and failed on the page rather than in
the lookup.

Measured: with the resolver's body stripped back to the raw read this test and
the webserver_resource one both fail, and both pass with it restored.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-28 11:32:26 +02:00

157 lines
5.3 KiB
Python

import os
import unittest
from unittest.mock import patch
from plugins.lookup.guide_role import ENV_VAR, LookupModule, guide_role
INVOKABLE = ["web-app-docs", "web-app-nextcloud", "svc-db-postgres", "dsk-gnt-claude"]
NO_PIN = {ENV_VAR: ""}
class _Templar:
def __init__(self, resolved):
self._resolved = resolved
def template(self, value):
return self._resolved.get(value, value)
class TestGuideRole(unittest.TestCase):
def test_the_only_invokable_peer_wins(self):
self.assertEqual(
guide_role(
"web-app-docs", ["web-app-docs", "web-app-nextcloud"], INVOKABLE
),
"web-app-nextcloud",
)
def test_a_non_invokable_peer_is_no_peer(self):
self.assertEqual(
guide_role("web-app-docs", ["web-app-docs", "sys-svc-proxy"], INVOKABLE),
"web-app-docs",
)
def test_the_asking_role_alone_names_itself(self):
self.assertEqual(
guide_role("web-app-docs", ["web-app-docs"], INVOKABLE), "web-app-docs"
)
def test_an_empty_round_names_the_asking_role(self):
self.assertEqual(guide_role("web-app-docs", [], INVOKABLE), "web-app-docs")
def test_one_of_the_peers_is_drawn(self):
peers = ["svc-db-postgres", "dsk-gnt-claude"]
self.assertIn(guide_role("web-app-docs", peers, INVOKABLE), peers)
def test_every_peer_can_be_drawn(self):
peers = ["svc-db-postgres", "dsk-gnt-claude"]
drawn = {guide_role("web-app-docs", peers, INVOKABLE) for _ in range(200)}
self.assertEqual(drawn, set(peers))
def test_a_peer_outside_the_invokable_set_is_never_drawn(self):
drawn = {
guide_role(
"web-app-docs",
["sys-svc-proxy", "user-administrator", "dsk-gnt-claude"],
INVOKABLE,
)
for _ in range(200)
}
self.assertEqual(drawn, {"dsk-gnt-claude"})
def test_the_pinned_role_outranks_the_draw(self):
drawn = {
guide_role(
"web-app-docs",
["svc-db-postgres", "dsk-gnt-claude"],
INVOKABLE,
pinned="web-app-nextcloud",
)
for _ in range(200)
}
self.assertEqual(drawn, {"web-app-nextcloud"})
def test_a_pin_without_a_guide_leaves_the_draw_alone(self):
self.assertEqual(
guide_role(
"web-app-docs",
["web-app-nextcloud"],
INVOKABLE,
pinned="sys-svc-proxy",
),
"web-app-nextcloud",
)
class TestGuideRoleLookup(unittest.TestCase):
@patch.dict(os.environ, NO_PIN)
@patch("plugins.lookup.guide_role.list_invokable_app_ids")
def test_the_whitelist_outranks_the_round_groups(self, invokable):
invokable.return_value = INVOKABLE
result = LookupModule().run(
["web-app-docs"],
variables={
"APPLICATIONS_WHITELIST": ["web-app-docs", "svc-db-postgres"],
"group_names": ["web-app-docs", "web-app-nextcloud"],
},
)
self.assertEqual(result, ["svc-db-postgres"])
@patch.dict(os.environ, NO_PIN)
@patch("plugins.lookup.guide_role.list_invokable_app_ids")
def test_without_a_whitelist_the_round_groups_decide(self, invokable):
invokable.return_value = INVOKABLE
result = LookupModule().run(
["web-app-docs"],
variables={
"APPLICATIONS_WHITELIST": [],
"group_names": ["web-app-docs", "web-app-nextcloud"],
},
)
self.assertEqual(result, ["web-app-nextcloud"])
@patch.dict(os.environ, NO_PIN)
@patch("plugins.lookup.guide_role.list_invokable_app_ids")
def test_the_asking_role_falls_back_to_the_variable(self, invokable):
invokable.return_value = INVOKABLE
result = LookupModule().run(
[],
variables={
"application_id": "web-app-docs",
"group_names": ["web-app-docs", "sys-svc-proxy"],
},
)
self.assertEqual(result, ["web-app-docs"])
@patch.dict(os.environ, NO_PIN)
@patch("plugins.lookup.guide_role.list_invokable_app_ids")
def test_a_variable_that_is_still_a_template_is_resolved(self, invokable):
"""The play holds application_id raw, so a role that sets it from
another variable would otherwise be compared as '{{ ... }}'."""
invokable.return_value = INVOKABLE
lookup = LookupModule()
lookup._templar = _Templar({"{{ stack_app }}": "web-app-docs"})
result = lookup.run(
[],
variables={
"application_id": "{{ stack_app }}",
"group_names": ["web-app-docs", "web-app-nextcloud"],
},
)
self.assertEqual(result, ["web-app-nextcloud"])
@patch.dict(os.environ, {ENV_VAR: " dsk-gnt-claude "})
@patch("plugins.lookup.guide_role.list_invokable_app_ids")
def test_the_environment_pins_the_role(self, invokable):
invokable.return_value = INVOKABLE
result = LookupModule().run(
["web-app-docs"],
variables={"group_names": ["web-app-docs", "web-app-nextcloud"]},
)
self.assertEqual(result, ["dsk-gnt-claude"])
if __name__ == "__main__":
unittest.main()