diff --git a/tests/conftest.py b/tests/conftest.py index b425e5e..922a39a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,7 @@ import pytest # Set at import time so every worker process picks up the same values # before any module-level code in app.auth.jwt caches the secret. os.environ.setdefault("TESTING", "1") -os.environ.setdefault("JWT_SECRET_KEY", "test-secret-e2e") +os.environ.setdefault("JWT_SECRET_KEY", "test-secret-key-minimum-32-characters!!") # Ensure directories exist for modules with module-level FileHandlers. # bot.py creates FileHandler(config.BOT_LOG_FILE) at import time. @@ -27,7 +27,7 @@ os.makedirs(os.path.join(os.environ["DATA_DIR"], "state"), exist_ok=True) def e2e_env(tmp_path, monkeypatch): """Set up complete E2E environment with DATA_DIR, create dirs.""" monkeypatch.setenv("DATA_DIR", str(tmp_path)) - monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-e2e") + monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-key-minimum-32-characters!!") (tmp_path / "extracts").mkdir() (tmp_path / "analytics").mkdir() @@ -103,31 +103,6 @@ def write_test_parquet(path: str, data: list[dict]): conn.close() -@pytest.fixture -def mock_extract_factory(e2e_env): - """Factory fixture: returns callable that creates mock extract.duckdb files. - - Usage: - mock_extract_factory(source_name, tables_list) - """ - def _factory(source_name: str, tables: list, remote_attach=None): - db_path = create_mock_extract(e2e_env["extracts_dir"], source_name, tables) - if remote_attach: - import duckdb as _duckdb - conn = _duckdb.connect(str(db_path)) - conn.execute("""CREATE TABLE IF NOT EXISTS _remote_attach ( - alias VARCHAR, extension VARCHAR, url VARCHAR, token_env VARCHAR - )""") - for row in remote_attach: - conn.execute( - "INSERT INTO _remote_attach VALUES (?, ?, ?, ?)", - [row["alias"], row["extension"], row["url"], row["token_env"]], - ) - conn.close() - return db_path - return _factory - - @pytest.fixture def seeded_app(e2e_env): """FastAPI TestClient with seeded admin + analyst users, JWT tokens.""" diff --git a/tests/helpers/factories.py b/tests/helpers/factories.py index 6bc5ff8..f27bdaf 100644 --- a/tests/helpers/factories.py +++ b/tests/helpers/factories.py @@ -105,7 +105,8 @@ class WebhookEventFactory: @staticmethod def sign_payload(payload: dict[str, Any], secret: str) -> str: - body = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode() + """Sign payload with HMAC-SHA256. Uses default json.dumps() to match production.""" + body = json.dumps(payload).encode() sig = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest() return f"sha256={sig}" diff --git a/tests/test_instance_config.py b/tests/test_instance_config.py index 316f71a..001c002 100644 --- a/tests/test_instance_config.py +++ b/tests/test_instance_config.py @@ -6,7 +6,7 @@ class TestInstanceConfig: def test_missing_config_returns_defaults(self, tmp_path, monkeypatch): monkeypatch.setenv("DATA_DIR", str(tmp_path)) monkeypatch.setenv("TESTING", "1") - monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-e2e") + monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-key-minimum-32-characters!!") from app.instance_config import get_instance_name name = get_instance_name() assert isinstance(name, str) @@ -15,7 +15,7 @@ class TestInstanceConfig: """get_instance_name should read instance.name from YAML, not flat instance_name.""" monkeypatch.setenv("DATA_DIR", str(tmp_path)) monkeypatch.setenv("TESTING", "1") - monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-e2e") + monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-key-minimum-32-characters!!") state_dir = tmp_path / "state" state_dir.mkdir(exist_ok=True) diff --git a/tests/test_security.py b/tests/test_security.py index 0ddf4a1..16f4c59 100644 --- a/tests/test_security.py +++ b/tests/test_security.py @@ -10,7 +10,7 @@ from fastapi.testclient import TestClient @pytest.fixture def client(tmp_path, monkeypatch): monkeypatch.setenv("DATA_DIR", str(tmp_path)) - monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-e2e") + monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-key-minimum-32-characters!!") monkeypatch.setenv("SCRIPT_TIMEOUT", "5") from app.main import create_app @@ -287,7 +287,7 @@ class TestAuthSecurity: def viewer_client(tmp_path, monkeypatch): """TestClient with a viewer-role user seeded.""" monkeypatch.setenv("DATA_DIR", str(tmp_path)) - monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-e2e") + monkeypatch.setenv("JWT_SECRET_KEY", "test-secret-key-minimum-32-characters!!") monkeypatch.setenv("SCRIPT_TIMEOUT", "5") from app.main import create_app diff --git a/tests/test_telegram_bot.py b/tests/test_telegram_bot.py index 828bd78..74b78c8 100644 --- a/tests/test_telegram_bot.py +++ b/tests/test_telegram_bot.py @@ -30,7 +30,7 @@ def _make_message(text: str, chat_id: int = 10) -> dict: def _run(coro): """Run a coroutine synchronously.""" - return asyncio.get_event_loop().run_until_complete(coro) + return asyncio.run(coro) class TestHandleMessage: