Files
id_configurator/id_tools/test.py
2026-09-04 22:53:13 +02:00

67 lines
2.2 KiB
Python

"""Utilities for the Docker integration tests under tests/."""
from __future__ import annotations
import os
import pathlib
from typing import Annotated
import jinja2
import typer
app = typer.Typer(help="Utilities for the tests/ Docker integration tests")
TESTS_DIR = pathlib.Path(__file__).resolve().parent.parent / "tests"
def _env(name: str) -> str:
"""Jinja2 filter: `'NAME' | env` -> the environment variable NAME."""
return os.environ[name]
def _file(relative: str) -> str:
"""Jinja2 filter: `'relative/path' | file` -> content of tests/relative/path."""
path = (TESTS_DIR / relative).resolve()
if path != TESTS_DIR and TESTS_DIR not in path.parents:
raise ValueError(f"refusing to read a file outside of {TESTS_DIR}: {relative}")
return path.read_text(encoding="utf-8")
def render_template(text: str) -> str:
"""Render a tests/configs/*.yaml.j2 fixture as a Jinja2 template.
Custom filters: `| env` reads an environment variable, `| file` reads a
file relative to tests/. Combine with Jinja2's built-in `indent` filter
to fit multi-line content (e.g. a PEM certificate) into a YAML
block-literal field, e.g.:
content: |
{{ 'certs/test-ca.crt.pem' | file | indent(6, first=true) }}
"""
# Autoescaping is for HTML output; these templates render YAML, so escaping
# would corrupt them (e.g. turning "&" into "&" inside a PEM/URL).
environment = jinja2.Environment(undefined=jinja2.StrictUndefined) # nosec B701
environment.filters["env"] = _env
environment.filters["file"] = _file
return environment.from_string(text).render()
@app.command(
name="render-config",
help="Render a tests/configs/*.yaml.j2 fixture into a ready-to-use configuration.",
)
def render_config(
template: Annotated[pathlib.Path, typer.Argument(exists=True, dir_okay=False)],
output: pathlib.Path,
) -> None:
"""Renders `template` as a Jinja2 template (see `render_template`) and
writes the result to `output`, creating its parent directories as
needed."""
content = render_template(template.read_text(encoding="utf-8"))
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(content, encoding="utf-8")
if __name__ == "__main__":
app()