Files
computer-playbook/tests/integration/docker/test_compose_templates.py
T
Environment TestandClaude Sonnet 4.6 9ea2ad6ff1 refactor(docker): introduce utils/docker/image_discovery as single SPOT for image enumeration
- Move iter_role_images + all helpers + ImageRef from cli/mirror/util.py and
  cli/mirror/model.py into utils/docker/image_discovery.py; add source_file field
  to ImageRef to distinguish config/main.yml vs vars/main.yml entries
- Delete cli/mirror/util.py; update all callers to import from utils.docker.image_discovery
- Move utils into subpackages: utils/docker/ (image_ref, paths_utils, hadolint) and
  utils/roles/ (dependency_resolver, resource_validation); update all imports
- Reorganise tests into subpackages: tests/lint/docker/dockerfile/, tests/integration/docker/,
  tests/unit/utils/docker/, tests/unit/utils/roles/; fix parents[N] offsets after relocation
- tests/lint/docker/test_image_versions.py now uses iter_role_images (same SPOT as mirror)
- Add vars/main.yml images.<name>.{image,version} support for non-application roles
  (test-e2e-playwright, sys-ctl-hlth-csp); eliminate hardcoded duplicates in defaults/tasks
- Add web-app-matrix matrix-chatgpt-bot and web-app-mini-qr mini-qr entries in config/main.yml;
  replace hardcoded image strings in vars/templates with lookup('config', ...) references
- Fix sync/__main__.py log line to use correct registry prefix for non-Docker-Hub images
- Update docs/contributing/code/role/dockerfile.md with image declaration rules and SPOT reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 19:32:31 +02:00

82 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import re
import unittest
from pathlib import Path
class TestDockerComposeTemplates(unittest.TestCase):
# Search for all roles/*/templates/compose.yml.j2
PROJECT_ROOT = Path(__file__).resolve().parents[3]
TEMPLATE_PATTERN = "roles/*/templates/compose.yml.j2"
# Allowed lines before BASE_INCLUDE
ALLOWED_BEFORE_BASE = [
re.compile(r"^\s*$"), # empty line
re.compile(r"^\s*version:.*$"), # version: ...
re.compile(r"^\s*#.*$"), # YAML comment
re.compile(r"^\s*\{\#.*\#\}\s*$"), # Jinja comment {# ... #}
]
BASE_INCLUDE = "{% include 'roles/sys-svc-compose/templates/base.yml.j2' %}"
NET_INCLUDE = "{% include 'roles/sys-svc-compose/templates/networks.yml.j2' %}"
HOST_MODE = 'network_mode: "host"'
def test_docker_compose_includes(self):
"""
Verifies for each found compose.yml.j2:
1. BASE_INCLUDE is present exactly once
2. If no host‑mode is set, NET_INCLUDE must appear exactly once
3. BASE_INCLUDE appears before NET_INCLUDE when both are required
4. Only allowed lines appear before BASE_INCLUDE (invalid lines issue warnings)
"""
template_paths = sorted(self.PROJECT_ROOT.glob(self.TEMPLATE_PATTERN))
self.assertTrue(
template_paths, f"No templates found for pattern {self.TEMPLATE_PATTERN}"
)
for template_path in template_paths:
with self.subTest(template=template_path):
content = template_path.read_text(encoding="utf-8")
lines = content.splitlines()
# BASE_INCLUDE must always occur exactly once
count_base = lines.count(self.BASE_INCLUDE)
self.assertEqual(
count_base,
1,
f"{template_path}: '{self.BASE_INCLUDE}' occurs {count_base} times, expected once",
)
# Determine if host‑mode is in use
host_mode = self.HOST_MODE in content
# If not host‑mode, NET_INCLUDE must occur exactly once
count_net = lines.count(self.NET_INCLUDE)
if host_mode:
# No network include needed for host mode
self.assertEqual(
count_net,
0,
f"{template_path}: '{self.NET_INCLUDE}' should be omitted when using host networking",
)
else:
# Must include networks.yml exactly once
self.assertEqual(
count_net,
1,
f"{template_path}: '{self.NET_INCLUDE}' occurs {count_net} times, expected once",
)
# If both includes are present, check order
if count_base and count_net:
idx_base = lines.index(self.BASE_INCLUDE)
idx_net = lines.index(self.NET_INCLUDE)
self.assertLess(
idx_base,
idx_net,
f"{template_path}: '{self.BASE_INCLUDE}' must come before '{self.NET_INCLUDE}'",
)
if __name__ == "__main__":
unittest.main()