mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 11:46:35 +00:00
TC (flake8-type-checking): typing-only imports moved into
``if TYPE_CHECKING:`` blocks across 8 source files via auto-fix
(117 hits). Reduces runtime import surface and rules out circular
imports for type-only deps. Project-wide ``from __future__ import
annotations`` (FA, already enabled) keeps annotations as strings,
so the moved imports never need to load at runtime.
N (pep8-naming): 32 hits handled.
Renames (semantic + lint):
- ``isSmallerThenMaximumBackupSize`` -> ``is_larger_than_maximum_backup_size``
(snake_case + fixes both the typo "Then -> Than" and the
semantic mismatch: the function returns ``current > maximum``)
- ``isDirectoryDeletable`` / ``deleteVersion`` /
``getAmountOfIteration`` / ``deleteIteration`` -> snake_case
- 8 test functions with ALL-CAPS env-var fragments
(``test_..._DOMAIN_PRIMARY_...`` etc.) -> snake_case
- Mock alias ``VH`` -> ``vh`` in test_host_vars.py
Exception class renames (``N818`` Error suffix):
- ``TimeLimitExceededException`` -> ``TimeLimitExceededError``
- ``AttemptException`` -> ``AttemptError``
- ``PathNotFound`` -> ``PathNotFoundError`` (propagated across
4 callers under tests/integration/lookups/config/)
- ``_ExitJson`` / ``_FailJson`` -> ``*_Error``
Refactor:
- ``METADATA = {...}`` local constant in two functions of
``plugins/filter/invokable_paths.py`` lifted to module-level
``_METADATA_KEYS``.
- ``from typing import TYPE_CHECKING`` in
``tasks/utils/migrate_meta_layout/__main__.py`` moved above
the ``sys.path.insert`` hack to satisfy E402 (collateral from
the TC auto-fix that landed it after the path mutation).
Per-file ignores in pyproject.toml for the legitimate cases the
rule cannot accept:
- ``pull-specific-host.py`` -> ``N999`` (Ansible-invoked role-level
script, hyphenated filename pinned by the surrounding stack).
- 4 matrix-deploy files -> ``N806`` for the ``include_R`` /
``raw_include_R`` round-index notation; the uppercase ``R``
here mirrors the formula in the docstring rather than naming
a constant.
- ``plugins/filter/value_generator.py`` -> ``N806`` for the
lazy-loaded class binding ``ValueGenerator =
_value_generator_cls()``, which retains the imported class
identifier per PEP 8.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
191 lines
6.9 KiB
Python
191 lines
6.9 KiB
Python
"""Focused unit tests for ``utils.cache.domains``.
|
|
|
|
`get_merged_domains` is a thin derivation on top of
|
|
`get_merged_applications` plus the
|
|
`plugins.filter.canonical_domains_map` filter. We pin: cache-keying
|
|
behaviour, the missing-DOMAIN_PRIMARY validation, and the dispatch to
|
|
the upstream applications view.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
import tempfile
|
|
import textwrap
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
from utils.cache import _reset_cache_for_tests
|
|
from utils.cache import domains as cache_domains
|
|
from utils.roles.mapping import ROLE_FILE_META_SERVICES, ROLE_FILE_META_USERS
|
|
|
|
from . import PROJECT_ROOT
|
|
|
|
|
|
def _write(path: Path, content: str) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(textwrap.dedent(content), encoding="utf-8")
|
|
|
|
|
|
def _seed_minimal_role(tmp: Path) -> Path:
|
|
role = tmp / "roles" / "web-app-foo"
|
|
_write(
|
|
role / ROLE_FILE_META_SERVICES,
|
|
"""
|
|
server:
|
|
domains:
|
|
canonical:
|
|
- foo.{{ DOMAIN_PRIMARY }}
|
|
aliases: []
|
|
""",
|
|
)
|
|
_write(role / ROLE_FILE_META_USERS, "users: {}\n")
|
|
return tmp / "roles"
|
|
|
|
|
|
class TestMissingPrimaryDomain(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
_reset_cache_for_tests()
|
|
|
|
def test_raises_when_domain_primary_missing(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
roles = _seed_minimal_role(Path(tmp))
|
|
with self.assertRaisesRegex(ValueError, "DOMAIN_PRIMARY"):
|
|
cache_domains.get_merged_domains(
|
|
variables={}, roles_dir=roles, templar=None
|
|
)
|
|
|
|
def test_falls_back_to_system_email_domain(self):
|
|
# Pure-python smoke: when DOMAIN_PRIMARY is absent but
|
|
# SYSTEM_EMAIL_DOMAIN is set, the function should NOT raise.
|
|
# The actual canonical-domains-map computation is exercised
|
|
# indirectly via get_merged_applications; we patch it out so
|
|
# this stays an isolated unit test of the dispatch code path.
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
roles = _seed_minimal_role(Path(tmp))
|
|
with patch(
|
|
"utils.cache.applications.get_merged_applications",
|
|
return_value={},
|
|
):
|
|
result = cache_domains.get_merged_domains(
|
|
variables={"SYSTEM_EMAIL_DOMAIN": "infinito.example"},
|
|
roles_dir=roles,
|
|
templar=None,
|
|
)
|
|
self.assertIsInstance(result, dict)
|
|
|
|
|
|
class TestCachingPerVariablesSignature(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
_reset_cache_for_tests()
|
|
|
|
def test_caches_result_for_identical_variables(self):
|
|
# Patch out the heavy call so this is a pure cache-behaviour test.
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
roles = _seed_minimal_role(Path(tmp))
|
|
with patch(
|
|
"utils.cache.applications.get_merged_applications",
|
|
return_value={},
|
|
) as mocked:
|
|
first = cache_domains.get_merged_domains(
|
|
variables={"DOMAIN_PRIMARY": "infinito.example"},
|
|
roles_dir=roles,
|
|
templar=None,
|
|
)
|
|
second = cache_domains.get_merged_domains(
|
|
variables={"DOMAIN_PRIMARY": "infinito.example"},
|
|
roles_dir=roles,
|
|
templar=None,
|
|
)
|
|
# Same cache key -> upstream MUST only be called once.
|
|
self.assertEqual(mocked.call_count, 1)
|
|
self.assertEqual(first, second)
|
|
|
|
def test_different_domain_primary_misses_cache(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
roles = _seed_minimal_role(Path(tmp))
|
|
with patch(
|
|
"utils.cache.applications.get_merged_applications",
|
|
return_value={},
|
|
) as mocked:
|
|
cache_domains.get_merged_domains(
|
|
variables={"DOMAIN_PRIMARY": "a.example"},
|
|
roles_dir=roles,
|
|
templar=None,
|
|
)
|
|
cache_domains.get_merged_domains(
|
|
variables={"DOMAIN_PRIMARY": "b.example"},
|
|
roles_dir=roles,
|
|
templar=None,
|
|
)
|
|
self.assertEqual(mocked.call_count, 2)
|
|
|
|
|
|
class TestResetClearsDomainsCache(unittest.TestCase):
|
|
def test_reset_evicts_cached_entry(self):
|
|
_reset_cache_for_tests()
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
roles = _seed_minimal_role(Path(tmp))
|
|
with patch(
|
|
"utils.cache.applications.get_merged_applications",
|
|
return_value={},
|
|
):
|
|
cache_domains.get_merged_domains(
|
|
variables={"DOMAIN_PRIMARY": "infinito.example"},
|
|
roles_dir=roles,
|
|
templar=None,
|
|
)
|
|
# Cache MUST hold one entry now.
|
|
self.assertEqual(len(cache_domains._MERGED_DOMAINS_CACHE), 1)
|
|
_reset_cache_for_tests()
|
|
# Cache MUST be empty after the orchestrator runs.
|
|
self.assertEqual(len(cache_domains._MERGED_DOMAINS_CACHE), 0)
|
|
|
|
|
|
class TestImportableWithoutAnsible(unittest.TestCase):
|
|
"""`utils.cache.domains` MUST stay ansible-free at import time so
|
|
callers in CLI/runner-host paths can pull the module without
|
|
needing ansible. Calling `get_merged_domains` requires ansible
|
|
transitively (via `canonical_domains_map`) and is NOT pinned here
|
|
— the import-only invariant is what matters for the
|
|
ansible-less host. Subprocess isolation avoids the in-process
|
|
sys.modules / namespace-package hazards that bit earlier shims.
|
|
"""
|
|
|
|
def test_module_imports_without_ansible(self):
|
|
import subprocess
|
|
|
|
repo_root = PROJECT_ROOT
|
|
snippet = (
|
|
"import sys\n"
|
|
f"sys.path.insert(0, {str(repo_root)!r})\n"
|
|
"class _Block:\n"
|
|
" def find_spec(self, name, path=None, target=None):\n"
|
|
" if name == 'ansible' or name.startswith('ansible.'):\n"
|
|
" raise ImportError(f'blocked: {name}')\n"
|
|
" return None\n"
|
|
"sys.meta_path.insert(0, _Block())\n"
|
|
"from utils.cache.domains import get_merged_domains\n"
|
|
"assert callable(get_merged_domains)\n"
|
|
"print('OK')\n"
|
|
)
|
|
result = subprocess.run(
|
|
[sys.executable, "-c", snippet],
|
|
capture_output=True,
|
|
text=True,
|
|
cwd=str(repo_root),
|
|
timeout=60,
|
|
check=False,
|
|
)
|
|
self.assertEqual(
|
|
result.returncode,
|
|
0,
|
|
msg=f"stderr=\n{result.stderr}\nstdout=\n{result.stdout}",
|
|
)
|
|
self.assertIn("OK", result.stdout)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|