Files
computer-playbook/tests/unit/python/utils/networks/test_render.py
T
kevinveenbirkenbachandClaude Opus 5 c2120395e7 fix(litellm): let the database follow the inventory and keep the network a dedicated one is reached on
Run 34421944328 web-app-litellm#1 (README host-mode replay) answered
every health probe on llm.ai.infinito.test with 502: litellm
crash-looped on "P1000: Authentication failed against database server
at postgres" while postgres logged 'Role "litellm" does not exist'. The
README inventory has no svc-db-postgres group, so sys-svc-rdbms skipped
the central provisioning, yet svc-ai-litellm pinned postgres.shared to
true and kept consuming a shared database nobody had created its role in.

postgres.shared now reads "{{ 'svc-db-postgres' in group_names }}":
an inventory with the central group keeps the shared database, the
README inventory gets a dedicated one.

That dedicated instance, rendered by sys-svc-rdbms postgres.yml.j2,
joins only the compose default network, and the networks renderer
dropped default from every svc-db-*/svc-ai-* role. A local variant-1
deploy measured litellm-database on litellm_default alone and litellm on
the shared litellm network alone. _suppress_default now keeps default
when the role's database is local. The variants pin shared to true (0)
and false (1) so the matrix exercises both paths, and the generated
READMEs show the postgres relation as 0..1.

The three attachment helpers move from render.py to attachments.py,
which render.py re-exports, and test_render.py splits along the same
seams into five files plus _render_helpers.py with every test id kept.

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

236 lines
9.0 KiB
Python

"""Unit tests for the pure-Python networks renderer that backs the
``compose_networks`` and ``container_networks`` lookup plugins.
The integration test in ``tests/integration/infrastructure/compose/
test_networks_render.py`` pins the full rendered YAML for representative
scenarios; these unit tests cover the helper predicates and edge cases
(empty registries, missing modes, alias defaults, canonical aliases) so
regressions surface with a precise failure rather than a snapshot diff.
"""
from __future__ import annotations
import unittest
from utils.networks.render import render_compose_networks, render_container_networks
from ._render_helpers import _const_lookup_config, _const_lookup_database, _entity_name
class TestRenderComposeNetworks(unittest.TestCase):
def test_provider_swarm_emits_only_default(self):
registry = {
"openresty": {
"role": "svc-prx-openresty",
"entity_name": "openresty",
"overlay": {"modes": ["swarm"], "topology": "default_net"},
},
}
rendered = render_compose_networks(
application_id="svc-prx-openresty",
deployment_mode="swarm",
registry=registry,
get_entity_name=_entity_name,
lookup_config=_const_lookup_config(),
lookup_database=_const_lookup_database(),
)
self.assertIn("networks:", rendered)
self.assertIn("default:", rendered)
self.assertIn("driver: overlay", rendered)
self.assertNotIn("openresty:\n external", rendered)
def test_provider_compose_falls_back_to_bridge(self):
registry = {
"openresty": {
"role": "svc-prx-openresty",
"entity_name": "openresty",
"overlay": {"modes": ["swarm"], "topology": "default_net"},
},
}
rendered = render_compose_networks(
application_id="svc-prx-openresty",
deployment_mode="compose",
registry=registry,
get_entity_name=_entity_name,
lookup_config=_const_lookup_config(
**{"networks.local.subnet": "10.0.0.0/24"}
),
lookup_database=_const_lookup_database(),
)
self.assertIn("driver: bridge", rendered)
self.assertIn("subnet: 10.0.0.0/24", rendered)
def test_svc_db_provider_suppresses_default_block(self):
registry = {
"mariadb": {
"role": "svc-db-mariadb",
"entity_name": "mariadb",
"overlay": {"modes": ["swarm"], "topology": "shared_net"},
},
}
rendered = render_compose_networks(
application_id="svc-db-mariadb",
deployment_mode="swarm",
registry=registry,
get_entity_name=_entity_name,
lookup_config=_const_lookup_config(),
lookup_database=_const_lookup_database(),
)
self.assertIn("mariadb:", rendered)
self.assertIn("external: true", rendered)
self.assertNotIn("default:", rendered)
def test_empty_own_entity_swarm_omits_name(self):
rendered = render_compose_networks(
application_id="svc-runner",
deployment_mode="swarm",
registry={},
get_entity_name=lambda _role: "",
lookup_config=_const_lookup_config(),
lookup_database=_const_lookup_database(),
)
self.assertIn("driver: overlay", rendered)
self.assertNotIn("name:", rendered)
def test_node_local_swarm_container_networks_compose_shape(self):
rendered = render_container_networks(
application_id="svc-runner",
deployment_mode="swarm",
registry={},
get_entity_name=lambda _role: "",
lookup_config=_const_lookup_config(),
lookup_database=_const_lookup_database(),
node_local=True,
)
expected = render_container_networks(
application_id="svc-runner",
deployment_mode="compose",
registry={},
get_entity_name=lambda _role: "",
lookup_config=_const_lookup_config(),
lookup_database=_const_lookup_database(),
)
self.assertEqual(rendered, expected)
def test_a_role_with_nothing_to_attach_emits_no_networks_key(self):
"""A bare `networks:` parses as null, and compose refuses it as not an array."""
for render in (render_container_networks, render_compose_networks):
for role in ("svc-ai-mcp-adapter", "svc-db-nothing"):
with self.subTest(render=render.__name__, role=role):
self.assertEqual(
"",
render(
application_id=role,
deployment_mode="compose",
registry={},
get_entity_name=_entity_name,
lookup_config=_const_lookup_config(),
lookup_database=_const_lookup_database(),
),
)
def test_a_role_that_keeps_the_default_still_renders_it(self):
"""The guard must not swallow the default attachment it sits behind."""
for render in (render_container_networks, render_compose_networks):
with self.subTest(render=render.__name__):
self.assertIn(
"default:",
render(
application_id="web-app-anything",
deployment_mode="compose",
registry={},
get_entity_name=_entity_name,
lookup_config=_const_lookup_config(),
lookup_database=_const_lookup_database(),
),
)
def test_own_network_only_drops_the_consumer_networks(self):
registry = {
"qdrant": {
"role": "svc-db-qdrant",
"entity_name": "qdrant",
"overlay": {"modes": ["compose"], "topology": "shared_net"},
},
"moodle": {
"role": "web-app-moodle",
"entity_name": "moodle",
"overlay": {"modes": ["compose"], "topology": "shared_net"},
},
}
lookup_config = _const_lookup_config(
**{"services.moodle.enabled": True, "services.moodle.shared": True}
)
full = render_container_networks(
application_id="svc-db-qdrant",
deployment_mode="compose",
registry=registry,
get_entity_name=_entity_name,
lookup_config=lookup_config,
lookup_database=_const_lookup_database(),
)
restricted = render_container_networks(
application_id="svc-db-qdrant",
deployment_mode="compose",
registry=registry,
get_entity_name=_entity_name,
lookup_config=lookup_config,
lookup_database=_const_lookup_database(),
own_network_only=True,
provider_self_alias=False,
)
self.assertIn("moodle:", full)
self.assertIn("qdrant:", restricted)
self.assertNotIn("moodle:", restricted)
self.assertNotIn("aliases:", restricted)
def test_own_network_only_emits_nothing_without_an_attachment(self):
rendered = render_container_networks(
application_id="web-app-prometheus",
deployment_mode="compose",
registry={},
get_entity_name=_entity_name,
lookup_config=_const_lookup_config(),
lookup_database=_const_lookup_database(),
own_network_only=True,
)
self.assertEqual(
rendered,
"",
"a bare 'networks:' key is not a list and compose refuses the file",
)
def test_node_local_swarm_renders_bridge(self):
rendered = render_compose_networks(
application_id="svc-runner",
deployment_mode="swarm",
registry={},
get_entity_name=lambda _role: "",
lookup_config=_const_lookup_config(
**{"networks.local.subnet": "10.0.0.0/24"}
),
lookup_database=_const_lookup_database(),
node_local=True,
)
self.assertNotIn("overlay", rendered)
self.assertIn("driver: bridge", rendered)
def test_empty_own_entity_compose_omits_name(self):
rendered = render_compose_networks(
application_id="svc-runner",
deployment_mode="compose",
registry={},
get_entity_name=lambda _role: "",
lookup_config=_const_lookup_config(
**{"networks.local.subnet": "10.0.0.0/24"}
),
lookup_database=_const_lookup_database(),
)
self.assertIn("driver: bridge", rendered)
self.assertIn("subnet: 10.0.0.0/24", rendered)
self.assertNotIn("name:", rendered)
if __name__ == "__main__":
unittest.main()