import importlib import os import sys from pathlib import Path import pytest PROJECT_ROOT = Path(__file__).resolve().parents[1] def purge_server_modules(): for name in list(sys.modules): if name == "main" or name == "db" or name == "minio_tool" or name.startswith("app."): sys.modules.pop(name, None) def write_test_private_key(path: Path): from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) path.parent.mkdir(parents=True, exist_ok=True) path.write_bytes( private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) ) class TestPasswordHasher: def hash(self, password: str) -> str: return "test-hash:" + password def verify(self, password_hash: str, password: str) -> bool: return password_hash == self.hash(password) @pytest.fixture() def server_module(tmp_path, monkeypatch): key_path = tmp_path / "keys" / "manifest_private_key.pem" write_test_private_key(key_path) env = { "ENV_FILE_PATH": str(tmp_path / ".env"), "DB_FILE": str(tmp_path / "mini.db"), "SQL_FILE": str(PROJECT_ROOT / "tables.sql"), "ADMIN_TOKEN": "AdminTokenForTests2026", "ADMIN_USERNAME": "admin", "ADMIN_PASSWORD": "AdminPass2026", "ADMIN_JWT_SECRET": "AdminJwtSecretForTests2026", "CLIENT_API_TOKEN": "ClientTokenForTests2026", "CRASH_REPORT_TOKEN": "CrashReportTokenForTests2026", "CRASH_SYMBOL_TOKEN": "CrashSymbolTokenForTests2026", "CRASH_ADMIN_TOKEN": "CrashAdminTokenForTests2026", "LICENSE_KEY_ENCRYPTION_SECRET": "LicenseEncryptionSecretForTests2026", "MANIFEST_PRIVATE_KEY_PATH": str(key_path), "MINIO_AUTO_START": "false", "MINIO_ENDPOINT": "127.0.0.1:1", "MINIO_ACCESS_KEY": "minio_test", "MINIO_SECRET_KEY": "minio_test_secret", "MINIO_BUCKET": "updates", "MINIO_PUBLIC_ENDPOINT": "", "MINIO_CONNECT_TIMEOUT_SEC": "0.1", "MINIO_READ_TIMEOUT_SEC": "0.1", "MINIO_RETRY_TOTAL": "0", "LOCAL_UPLOAD_ROOT": str(tmp_path / "local_uploads"), "MINIO_DATA_DIR": str(tmp_path / "minio_data"), "UPLOAD_SPOOL_DIR": str(tmp_path / "upload_spool"), "CRASH_STORAGE_ROOT": str(tmp_path / "crash_storage"), "TARGET_PLATFORM": "windows", "TARGET_ARCH": "x64", "RELEASE_MAIN_EXECUTABLE": "bin/SimCAE.exe", } for key, value in env.items(): monkeypatch.setenv(key, value) monkeypatch.chdir(PROJECT_ROOT) purge_server_modules() main = importlib.import_module("main") security = importlib.import_module("app.core.security") security.PASSWORD_HASHER = TestPasswordHasher() yield main purge_server_modules()