Files
computer-playbook/tests/unit/python/utils/cache/test_variants.py
T
kevinveenbirkenbachandClaude Opus 5 e75ccc07cd perf(cache): let the sweep read the variants map without copying it
get_variants handed out a deep copy on every call so one caller's
mutation could not reach the next. services_overrides_for_round asks
for the map once per round, and a sweep resolves hundreds of rounds, so
the matrix planner paid that copy 460 times: 78 million deepcopy calls,
and get_variants alone accounting for 82 of the 163 seconds a profiled
build took.

The copy is now opt-out for that one caller. It reads the map and never
writes to it, resolve_pins takes it as a Mapping and has no mutation
site, and _deep_merge deep-copies both of its arguments, so nothing the
round produces keeps a reference into the cache. Fifteen other callers
keep the copy untouched.

Measured end to end on cli.meta.ci.playwright_coverage: 33.7s to 24.6s.
Equivalence is measured against the copying path for two fixed rounds,
291 roles each, rather than against a sweep -- two identical planner
runs assign different modes to some rows, so a plan diff cannot carry
that proof.

The test asserts identity rather than runtime, as the comparable
optimization in 0cb8bae88d did: a wall-clock bound on this machine is
the same flakiness the sweep already shows.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-23 02:54:26 +02:00

335 lines
11 KiB
Python

"""Unit tests for the per-role `meta/variants.yml` matrix-deploy
loader (`utils.cache.applications.get_variants`) and the variant-free
base-config default that `get_merged_applications` falls back on when
no inventory-level `applications.<app>` override is set."""
import os
import sys
import textwrap
import unittest
from pathlib import Path
from . import PROJECT_ROOT
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from utils.cache import _reset_cache_for_tests
from utils.cache.applications import (
_build_variants,
get_application_defaults,
get_merged_applications,
get_variants,
)
from utils.cache.applications import (
_load_variants_overrides as _load_yaml_variant_list,
)
from utils.roles.mapping import (
ROLE_FILE_META_SERVER,
ROLE_FILE_META_SERVICES,
ROLE_FILE_META_VARIANTS,
)
def _write_role(
roles_dir: Path,
name: str,
*,
config: str | None = None,
meta: str | None = None,
server: str | None = None,
) -> None:
"""Write a synthetic role tree under <roles_dir>/<name>/meta/.
``config`` -> meta/services.yml content (the file root IS the services
map)
``server`` -> meta/server.yml content
``meta`` -> meta/variants.yml content (matrix-deploy variant list)
"""
role = roles_dir / name
(role / "meta").mkdir(parents=True, exist_ok=True)
if config is not None:
(role / ROLE_FILE_META_SERVICES).write_text(textwrap.dedent(config))
if server is not None:
(role / ROLE_FILE_META_SERVER).write_text(textwrap.dedent(server))
if meta is not None:
(role / ROLE_FILE_META_VARIANTS).write_text(textwrap.dedent(meta))
class TestLoadYamlVariantList(unittest.TestCase):
def test_missing_file_yields_single_empty_variant(self):
self.assertEqual(_load_yaml_variant_list(Path("/nonexistent")), [{}])
def test_empty_file_yields_single_empty_variant(self):
path = Path(self._write_tmp(""))
self.assertEqual(_load_yaml_variant_list(path), [{}])
def test_empty_list_yields_single_empty_variant(self):
path = Path(self._write_tmp("[]\n"))
self.assertEqual(_load_yaml_variant_list(path), [{}])
def test_null_entry_normalised_to_empty_dict(self):
path = Path(self._write_tmp("- null\n- {a: 1}\n"))
self.assertEqual(_load_yaml_variant_list(path), [{}, {"a": 1}])
def test_non_list_root_rejected(self):
path = Path(self._write_tmp("a: 1\n"))
with self.assertRaises(TypeError):
_load_yaml_variant_list(path)
def test_non_mapping_entry_rejected(self):
path = Path(self._write_tmp("- 42\n"))
with self.assertRaises(ValueError):
_load_yaml_variant_list(path)
def _write_tmp(self, content: str) -> str:
import tempfile
with tempfile.NamedTemporaryFile("w", suffix=".yml", delete=False) as f:
f.write(content)
self.addCleanup(os.remove, f.name)
return f.name
class TestApplicationVariants(unittest.TestCase):
def setUp(self):
import tempfile
self.tmp = tempfile.mkdtemp(prefix="variants-")
self.roles_dir = Path(self.tmp)
_reset_cache_for_tests()
def tearDown(self):
import shutil
shutil.rmtree(self.tmp, ignore_errors=True)
_reset_cache_for_tests()
def test_role_without_meta_yields_single_variant(self):
_write_role(self.roles_dir, "web-app-foo", config="foo:\n hello: world\n")
variants = _build_variants(self.roles_dir)
self.assertEqual(list(variants.keys()), ["web-app-foo"])
self.assertEqual(len(variants["web-app-foo"]), 1)
self.assertEqual(
variants["web-app-foo"][0]["services"]["foo"]["hello"], "world"
)
def test_role_with_two_variants_deep_merges_each_entry(self):
role = self.roles_dir / "web-app-bar"
(role / "meta").mkdir(parents=True, exist_ok=True)
(role / ROLE_FILE_META_SERVICES).write_text(
textwrap.dedent(
"""
bar:
enabled: false
"""
)
)
(role / ROLE_FILE_META_SERVER).write_text(
textwrap.dedent(
"""
domains:
canonical: ["bar.example"]
"""
)
)
(role / ROLE_FILE_META_VARIANTS).write_text(
textwrap.dedent(
"""
- {}
- services:
bar:
enabled: true
server:
domains:
canonical: ["bar.example", "shop.bar.example"]
"""
)
)
variants = _build_variants(self.roles_dir)["web-app-bar"]
self.assertEqual(len(variants), 2)
self.assertEqual(variants[0]["services"]["bar"]["enabled"], False)
self.assertEqual(variants[0]["server"]["domains"]["canonical"], ["bar.example"])
self.assertEqual(variants[1]["services"]["bar"]["enabled"], True)
self.assertEqual(
variants[1]["server"]["domains"]["canonical"],
["bar.example", "shop.bar.example"],
)
def test_get_application_defaults_returns_variant_free_base_config(self):
_write_role(
self.roles_dir,
"web-app-baz",
config="baz:\n value: 1\n",
meta=textwrap.dedent(
"""
- {}
- services:
baz:
value: 2
"""
),
)
defaults = get_application_defaults(roles_dir=self.roles_dir)
self.assertEqual(defaults["web-app-baz"]["services"]["baz"]["value"], 1)
def test_get_application_defaults_omits_variant_zero_only_keys(self):
"""Defaults MUST come from the variant-free base config, not
variant 0. Otherwise a service key that only variant 0 enables
(and that variant N intentionally omits) leaks into variant N's
runtime view via deep-merge in `get_merged_applications`."""
_write_role(
self.roles_dir,
"web-app-leak",
config="alpha:\n enabled: false\n",
meta=textwrap.dedent(
"""
- services:
alpha:
enabled: true
shared: true
- services:
beta:
enabled: true
shared: true
"""
),
)
defaults = get_application_defaults(roles_dir=self.roles_dir)
alpha = defaults["web-app-leak"]["services"]["alpha"]
self.assertEqual(alpha.get("enabled"), False)
self.assertNotIn("beta", defaults["web-app-leak"]["services"])
def test_get_variants_caches_per_roles_dir(self):
_write_role(self.roles_dir, "web-app-cache", config="cache:\n x: 1\n")
first = get_variants(roles_dir=self.roles_dir)
second = get_variants(roles_dir=self.roles_dir)
self.assertEqual(first, second)
second["web-app-cache"][0]["services"]["cache"]["x"] = 999
self.assertEqual(
get_variants(roles_dir=self.roles_dir)["web-app-cache"][0]["services"][
"cache"
]["x"],
1,
)
class TestMergedApplicationsUsesBaseConfig(unittest.TestCase):
"""The runtime loader reads no active-variant selector. Variant N
data is baked into the inventory by
`cli.administration.deploy.development.inventory.build_dev_inventory` at init time
and reaches the merged payload as an `applications.<app>` override.
The loader's defaults are the role's variant-free base config so
no variant's service flags leak into another variant's runtime view
via deep-merge; inventory-level overrides remain authoritative."""
def setUp(self):
import tempfile
self.tmp = tempfile.mkdtemp(prefix="variants-merged-")
self.roles_dir = Path(self.tmp)
_reset_cache_for_tests()
_write_role(
self.roles_dir,
"web-app-multi",
server=textwrap.dedent(
"""
domains:
canonical: ["multi.example"]
"""
),
meta=textwrap.dedent(
"""
- {}
- server:
domains:
canonical:
- "blog.multi.example"
- "shop.multi.example"
"""
),
)
def tearDown(self):
import shutil
shutil.rmtree(self.tmp, ignore_errors=True)
_reset_cache_for_tests()
def test_no_inventory_overrides_yield_base_config(self):
merged = get_merged_applications(
variables={},
roles_dir=str(self.roles_dir),
)
self.assertEqual(
merged["web-app-multi"]["server"]["domains"]["canonical"],
["multi.example"],
)
def test_inventory_override_swaps_in_variant_one_payload(self):
variant_one = {
"server": {
"domains": {
"canonical": ["blog.multi.example", "shop.multi.example"],
},
},
}
merged = get_merged_applications(
variables={"applications": {"web-app-multi": variant_one}},
roles_dir=str(self.roles_dir),
)
self.assertEqual(
merged["web-app-multi"]["server"]["domains"]["canonical"],
["blog.multi.example", "shop.multi.example"],
)
def test_active_variants_marker_is_ignored_by_loader(self):
merged = get_merged_applications(
variables={"_active_variants": {"web-app-multi": 1}},
roles_dir=str(self.roles_dir),
)
self.assertEqual(
merged["web-app-multi"]["server"]["domains"]["canonical"],
["multi.example"],
)
class TestReadonlyVariants(unittest.TestCase):
"""``readonly=True`` hands out the cached map itself.
A sweep resolves one round per matrix row and asks for the variants in
each, so the defensive deep copy is paid hundreds of times for data
nobody writes to. The guarantee is cheap to lose silently in a later
refactor, which is why identity is asserted rather than runtime.
"""
def setUp(self) -> None:
_reset_cache_for_tests()
self.tmp = Path(os.environ.get("TMPDIR", "/tmp")) / "readonly-variants-roles"
_write_role(
self.tmp,
"web-app-one",
config="postgres:\n enabled: true\n",
meta="- services:\n postgres:\n enabled: false\n",
)
def test_the_default_hands_out_a_copy(self) -> None:
first = get_variants(roles_dir=str(self.tmp))
second = get_variants(roles_dir=str(self.tmp))
self.assertEqual(first, second)
self.assertIsNot(first, second)
def test_readonly_hands_out_the_cached_object(self) -> None:
first = get_variants(roles_dir=str(self.tmp), readonly=True)
second = get_variants(roles_dir=str(self.tmp), readonly=True)
self.assertIs(first, second)
def test_a_readonly_caller_sees_what_the_copy_would_have_shown(self) -> None:
shared = get_variants(roles_dir=str(self.tmp), readonly=True)
copied = get_variants(roles_dir=str(self.tmp))
self.assertEqual(shared, copied)
if __name__ == "__main__":
unittest.main()