src/tests/conftest.py
Rama master · réplica de lectura del repositorio original.
import inspect
import os
from functools import cache
import pytest
from dstack._internal.server.testing.conf import ( # noqa: F401
postgres_container,
postgres_db,
session,
sqlite_db,
test_db,
)
from dstack._internal.settings import FeatureFlags
from dstack._internal.utils import crypto
from dstack._internal.utils import ssh as ssh_utils
def pytest_configure(config):
config.addinivalue_line("markers", "ui: mark test as testing UI to run only with --runui")
config.addinivalue_line(
"markers", "postgres: mark test as testing Postgres to run only with --runpostgres"
)
config.addinivalue_line(
"markers", "docker: mark test as requiring Docker to run only with --rundocker"
)
config.addinivalue_line(
"markers", "windows: mark test to be run on Windows in addition to POSIX"
)
config.addinivalue_line("markers", "windows_only: mark test to be run on Windows only")
if config.getoption("--runall"):
config.option.runui = True
config.option.runpostgres = True
config.option.rundocker = True
def pytest_addoption(parser):
parser.addoption("--runui", action="store_true", default=False, help="Run UI tests")
parser.addoption(
"--runpostgres", action="store_true", default=False, help="Run tests with PostgreSQL"
)
parser.addoption(
"--rundocker", action="store_true", default=False, help="Run tests requiring Docker"
)
parser.addoption(
"--runall", action="store_true", default=False, help="Run all of the opt-in tests above"
)
def pytest_collection_modifyitems(config, items):
skip_ui = pytest.mark.skip(reason="need --runui option to run")
skip_postgres = pytest.mark.skip(reason="need --runpostgres option to run")
skip_docker = pytest.mark.skip(reason="need --rundocker option to run")
is_windows = os.name == "nt"
skip_posix = pytest.mark.skip(reason="requires POSIX")
skip_windows = pytest.mark.skip(reason="requires Windows")
for item in items:
if not config.getoption("--runui") and "ui" in item.keywords:
item.add_marker(skip_ui)
if not config.getoption("--runpostgres") and "postgres" in item.keywords:
item.add_marker(skip_postgres)
if not config.getoption("--rundocker") and "docker" in item.keywords:
item.add_marker(skip_docker)
for_windows_only = "windows_only" in item.keywords
for_windows = for_windows_only or "windows" in item.keywords
if for_windows_only and not is_windows:
item.add_marker(skip_windows)
if not for_windows and is_windows:
item.add_marker(skip_posix)
@pytest.fixture(scope="session", autouse=True)
def reuse_one_rsa_key_pair():
"""
Hands the same RSA key pair to every caller for the whole test session.
Generating a 2048-bit key takes ~80ms and the server generates one per user, project,
gateway, and job. A test that needs two different keys has to generate its own.
"""
private_bytes, public_bytes = crypto.generate_rsa_key_pair_bytes()
public_key = public_bytes.rsplit(b" ", 1)[0] # drop the comment, callers pass their own
def generate_rsa_key_pair_bytes(comment: str = "dstack") -> tuple[bytes, bytes]:
return private_bytes, public_key + f" {comment}\n".encode()
with pytest.MonkeyPatch.context() as monkeypatch:
monkeypatch.setattr(crypto, "generate_rsa_key_pair_bytes", generate_rsa_key_pair_bytes)
yield
@pytest.fixture(scope="session", autouse=True)
def cache_parsed_ssh_keys():
"""
Parses each SSH key once per session instead of once per call.
Parsing an RSA key costs ~190ms because paramiko validates it, and fleet spec
validation parses the same handful of test keys over and over.
"""
with pytest.MonkeyPatch.context() as monkeypatch:
monkeypatch.setattr(ssh_utils, "pkey_from_str", cache(ssh_utils.pkey_from_str))
yield
@pytest.fixture(scope="session", autouse=True)
def disable_feature_flags():
"""
Disables all feature flags once per test session.
If you need to test a feature flag, monkeypatch `FeatureFlags` class on a per-test basis.
"""
for name, value in inspect.getmembers(FeatureFlags):
if not name.startswith("_") and name.isupper():
if not isinstance(value, bool):
raise RuntimeError(f"FeatureFlags.{name}: only bool values are supported")
setattr(FeatureFlags, name, False)