diff --git a/packages/tracker/meshnet_tracker/test_runner.py b/packages/tracker/meshnet_tracker/test_runner.py index e9725da..fdd8b6d 100644 --- a/packages/tracker/meshnet_tracker/test_runner.py +++ b/packages/tracker/meshnet_tracker/test_runner.py @@ -57,6 +57,7 @@ DEFAULT_MAX_LOG_LINES = 4000 _MAX_LINE_CHARS = 4000 DEFAULT_COLLECT_TIMEOUT = 120.0 DEFAULT_RUN_TIMEOUT = 1800.0 +PYTHON_ENV_VAR = "MESHNET_PYTHON" _NODE_ID_RE = re.compile(r"^[\w./\[\]:,= @-]+$") @@ -98,6 +99,23 @@ def _real_inference_enabled() -> bool: return os.environ.get(REAL_INFERENCE_ENV_VAR) == "1" +def _test_python() -> str: + """Return the project interpreter configured by the machine env file. + + The tracker may run from a lightweight service environment while the test + suite needs the project's full environment (including SDK dependencies). + ``meshnet_tracker.cli`` loads ``.env.`` before constructing the + server, so use its explicit interpreter selection for child pytest runs. + Direct users of ``TestRunManager`` retain the normal interpreter fallback. + """ + configured = os.environ.get(PYTHON_ENV_VAR, "").strip() + if configured: + python = Path(configured).expanduser() + if python.is_file() and os.access(python, os.X_OK): + return str(python) + return sys.executable + + class TestRunManager: """Collects pytest node IDs and runs one fixed target at a time.""" @@ -145,7 +163,7 @@ class TestRunManager: if self._collected_at is not None and not refresh: return self._collection_snapshot_locked() - cmd = [sys.executable, "-m", "pytest", "--collect-only", "-q", "-p", "no:cacheprovider"] + cmd = [_test_python(), "-m", "pytest", "--collect-only", "-q", "-p", "no:cacheprovider"] if not _real_inference_enabled(): for name in sorted( p.name for p in (self.repo_root / "tests").glob("test_real_*.py") @@ -216,7 +234,7 @@ class TestRunManager: with self._lock: if self._run is not None and self._run["status"] == "running": raise RunInProgressError("a test run is already in progress") - cmd = [sys.executable, "-m", "pytest", "-q", "-p", "no:cacheprovider", *pytest_args] + cmd = [_test_python(), "-m", "pytest", "-q", "-p", "no:cacheprovider", *pytest_args] self._stdout = deque(maxlen=self.max_log_lines) self._stderr = deque(maxlen=self.max_log_lines) process = subprocess.Popen( # noqa: S603 — fixed argv, no shell diff --git a/tests/test_real_model_backend.py b/tests/test_real_model_backend.py index 57a6db1..75c31b5 100644 --- a/tests/test_real_model_backend.py +++ b/tests/test_real_model_backend.py @@ -15,7 +15,7 @@ import pytest from meshnet_node.model_backend import ( InsufficientVRAMError, PartialModelLoadUnsupported, - ShardCacheMiss, + KVCacheMiss, TensorPayload, TorchModelShard, _call_layer, @@ -629,7 +629,7 @@ def test_shard_cache_decode_miss_is_explicit(): torch = pytest.importorskip("torch") shard = _fake_cache_shard(torch) - with pytest.raises(ShardCacheMiss): + with pytest.raises(KVCacheMiss): shard._run_layers( torch.zeros((1, 1, 2), dtype=torch.bfloat16), torch.ones((1, 5), dtype=torch.long), diff --git a/tests/test_tracker_test_runner.py b/tests/test_tracker_test_runner.py index ea01d47..5198b0e 100644 --- a/tests/test_tracker_test_runner.py +++ b/tests/test_tracker_test_runner.py @@ -6,6 +6,7 @@ constructed without an explicit ``repo_root``. """ import json +import sys import time import urllib.error import urllib.request @@ -16,7 +17,7 @@ import pytest from meshnet_tracker.accounts import AccountStore from meshnet_tracker.server import TrackerServer from meshnet_tracker.test_runner import TestRunManager as RunManager -from meshnet_tracker.test_runner import discover_repo_root +from meshnet_tracker.test_runner import _test_python, discover_repo_root def _make_repo(tmp_path: Path) -> Path: @@ -119,6 +120,16 @@ def test_enable_flag_constructs_runner_against_real_repo(monkeypatch): assert (tracker._test_runner.repo_root / "tests" / "conftest.py").is_file() +def test_runner_uses_configured_project_python(monkeypatch, tmp_path): + python = tmp_path / "python" + python.touch(mode=0o755) + monkeypatch.setenv("MESHNET_PYTHON", str(python)) + assert _test_python() == str(python) + + monkeypatch.setenv("MESHNET_PYTHON", str(tmp_path / "missing-python")) + assert _test_python() == sys.executable + + def test_collection_lists_tests_and_excludes_real_inference(tmp_path, monkeypatch): monkeypatch.delenv("MESHNET_ENABLE_REAL_INFERENCE_TESTS", raising=False) tracker, port, admin, _user = _start_tracker(tmp_path)