c85c0068a2
- Replace all datetime.utcnow() with datetime.now(tz=timezone.utc) across 8 files - Fix 12 failing tests to match current implementation behavior - Fix pytest_plugins in non-top-level conftest (moved to root conftest.py) - Auto-fix 189 lint issues (import sorting, unused imports) - Add CI/CD pipeline infrastructure (ARC, ArgoCD, Kargo manifests) - Add values-beta.yaml and values-paper.yaml for staged deployments - Update GitHub Actions workflow to use self-hosted-gremlin runners - Add integration-test job to CI pipeline Result: 1596 passed, 0 failed, 0 warnings
93 lines
3.0 KiB
Python
93 lines
3.0 KiB
Python
"""Pytest plugin for integration test profiling.
|
|
|
|
Adds a ``--profiling-output`` CLI option and hooks into the pytest session
|
|
lifecycle to collect endpoint timing data via :class:`EndpointProfiler` and
|
|
write a JSON report at the end of the run.
|
|
|
|
The plugin is automatically loaded by pytest because it lives in the
|
|
``tests/integration/`` directory alongside ``conftest.py``. It registers
|
|
a session-scoped ``profiler`` fixture that other fixtures (e.g. the
|
|
profiled HTTP clients in conftest.py) can depend on.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from tests.integration.profiler import EndpointProfiler
|
|
|
|
DEFAULT_PROFILING_OUTPUT = "/tmp/profiling-report.json"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# CLI option
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def pytest_addoption(parser: pytest.Parser) -> None:
|
|
"""Add ``--profiling-output`` CLI flag to pytest."""
|
|
parser.addoption(
|
|
"--profiling-output",
|
|
action="store",
|
|
default=DEFAULT_PROFILING_OUTPUT,
|
|
help=(
|
|
"Path for the JSON profiling report "
|
|
f"(default: {DEFAULT_PROFILING_OUTPUT})"
|
|
),
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Session-scoped profiler instance (shared across all tests)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Module-level reference so the session hooks can access it without fixtures.
|
|
_profiler: EndpointProfiler | None = None
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def profiler() -> EndpointProfiler:
|
|
"""Session-scoped :class:`EndpointProfiler` instance.
|
|
|
|
Collects timing data across all integration tests. The summary is
|
|
printed and written to disk by the ``pytest_sessionfinish`` and
|
|
``pytest_terminal_summary`` hooks below.
|
|
"""
|
|
global _profiler # noqa: PLW0603
|
|
_profiler = EndpointProfiler()
|
|
return _profiler
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Session hooks — write report + print summary
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None:
|
|
"""Write the profiling JSON report after all tests complete."""
|
|
if _profiler is None:
|
|
return
|
|
|
|
output_path = session.config.getoption("profiling_output", DEFAULT_PROFILING_OUTPUT)
|
|
try:
|
|
_profiler.write_json(output_path)
|
|
except OSError:
|
|
# Best-effort — don't fail the session if we can't write the report
|
|
pass
|
|
|
|
|
|
def pytest_terminal_summary(
|
|
terminalreporter: pytest.TerminalReporter,
|
|
exitstatus: int,
|
|
config: pytest.Config,
|
|
) -> None:
|
|
"""Print the profiling summary table at the end of the test session."""
|
|
if _profiler is None:
|
|
return
|
|
|
|
output_path = config.getoption("profiling_output", DEFAULT_PROFILING_OUTPUT)
|
|
|
|
terminalreporter.section("Profiling Summary")
|
|
_profiler.print_summary()
|
|
terminalreporter.write_line(f"JSON report written to: {output_path}")
|