fix: address code review findings — duplicate fixture, JWT key length, async deprecation

- Remove duplicate mock_extract_factory fixture in conftest.py
- Use 32+ char JWT_SECRET_KEY everywhere (was 15 chars, triggered warnings)
- Replace deprecated asyncio.get_event_loop() with asyncio.run()
- Unify WebhookEventFactory sign methods (consistent json.dumps)
This commit is contained in:
ZdenekSrotyr 2026-04-13 13:47:51 +02:00
parent 12480b8c35
commit 863453b2e2
5 changed files with 9 additions and 33 deletions

View file

@ -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."""

View file

@ -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}"

View file

@ -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)

View file

@ -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

View file

@ -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: