added preflight check
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
"""Guards for the pytest harness itself.
|
||||
|
||||
``tests/conftest.py`` was accidentally deleted in commit edc6e42 while four test
|
||||
modules still depended on its fixtures, which made the suite unrunnable without
|
||||
anything failing loudly in CI. These tests turn that class of regression into an
|
||||
explicit failure, and also catch a stale ``orisys`` install silently shadowing
|
||||
``src/orisys`` (a real hazard: base/py312 environments have older orisys copies
|
||||
in site-packages).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
CONFTEST_PATH = Path(__file__).resolve().parent / "conftest.py"
|
||||
|
||||
# Names that must exist in tests/conftest.py.
|
||||
REQUIRED_CONFTEST_NAMES = (
|
||||
"DEFAULT_VIDEO_CANDIDATES",
|
||||
"make_sensor",
|
||||
"test_video_path",
|
||||
"test_config_name",
|
||||
"available_backends",
|
||||
"sensor_factory",
|
||||
)
|
||||
|
||||
# Fixtures that must be resolvable through pytest.
|
||||
REQUIRED_FIXTURES = (
|
||||
"test_video_path",
|
||||
"test_config_name",
|
||||
"available_backends",
|
||||
"sensor_factory",
|
||||
)
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _load_conftest_module():
|
||||
"""Load tests/conftest.py by path so a deletion is observable here."""
|
||||
spec = importlib.util.spec_from_file_location("_orisys_conftest_probe", CONFTEST_PATH)
|
||||
if spec is None or spec.loader is None:
|
||||
raise AssertionError(f"Cannot load {CONFTEST_PATH}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def test_conftest_defines_shared_fixtures():
|
||||
assert CONFTEST_PATH.is_file(), (
|
||||
f"{CONFTEST_PATH} is missing. test_backends.py, test_smoke_api.py, "
|
||||
"test_errors_and_cleanup.py and test_longrun_stability.py depend on its "
|
||||
"fixtures; it was accidentally deleted in commit edc6e42. Restore it "
|
||||
"instead of deleting it."
|
||||
)
|
||||
|
||||
module = _load_conftest_module()
|
||||
missing = [
|
||||
name for name in REQUIRED_CONFTEST_NAMES if getattr(module, name, None) is None
|
||||
]
|
||||
assert not missing, (
|
||||
f"tests/conftest.py no longer defines: {', '.join(missing)}. "
|
||||
"The shared sensor-test fixtures are required by the suite."
|
||||
)
|
||||
|
||||
|
||||
def test_default_test_video_is_reachable():
|
||||
"""At least one default candidate must exist, or every sensor test skips."""
|
||||
module = _load_conftest_module()
|
||||
candidates = [REPO_ROOT / Path(rel) for rel in module.DEFAULT_VIDEO_CANDIDATES]
|
||||
existing = [path for path in candidates if path.is_file()]
|
||||
assert existing, (
|
||||
"None of the default test videos exist:\n "
|
||||
+ "\n ".join(str(path) for path in candidates)
|
||||
+ "\nCommit a sample clip under data/sample/ or set ORISYS_TEST_VIDEO."
|
||||
)
|
||||
|
||||
|
||||
def test_fixtures_are_registered_with_pytest(request):
|
||||
missing: list[str] = []
|
||||
for name in REQUIRED_FIXTURES:
|
||||
try:
|
||||
request.getfixturevalue(name)
|
||||
except pytest.FixtureLookupError:
|
||||
missing.append(name)
|
||||
assert not missing, (
|
||||
f"pytest did not register these fixtures: {', '.join(missing)}. "
|
||||
"Check that tests/conftest.py is present and the @pytest.fixture "
|
||||
"decorators are intact."
|
||||
)
|
||||
|
||||
|
||||
def test_tests_run_against_checkout_not_stale_install():
|
||||
"""Fail loudly when an old orisys in site-packages shadows src/orisys."""
|
||||
src_pkg = (REPO_ROOT / "src" / "orisys").resolve()
|
||||
if not src_pkg.is_dir():
|
||||
pytest.skip("src/orisys is not present in this checkout layout")
|
||||
|
||||
import orisys
|
||||
|
||||
module_file = getattr(orisys, "__file__", None)
|
||||
assert module_file, (
|
||||
"import orisys resolved to a namespace package (__file__ is None) "
|
||||
f"instead of {src_pkg}. A stale orisys in site-packages is shadowing "
|
||||
"the checkout; run `pip uninstall -y orisys` in this environment."
|
||||
)
|
||||
|
||||
resolved_parent = Path(module_file).resolve().parent
|
||||
assert resolved_parent == src_pkg, (
|
||||
f"import orisys resolved to {resolved_parent} instead of {src_pkg}. "
|
||||
"A stale orisys in site-packages is shadowing the checkout; run "
|
||||
"`pip uninstall -y orisys` in this environment."
|
||||
)
|
||||
Reference in New Issue
Block a user