Files
shelfmark/tests/e2e/test_conftest_helpers.py
T
Alex d7b9f2e67f Backend test hardening + quality enforcement (#872)
- Reworked many tests
- Enforcing lint + type checking for test suite
- Fixed various issues surfaced by the new tests
- CI tweaks
2026-04-12 12:01:52 +01:00

276 lines
8.9 KiB
Python

import pytest
from _pytest.outcomes import Failed, Skipped
from tests.e2e import conftest as e2e_conftest
class DummyResponse:
def __init__(self, status_code: int, payload: object, text: str = "") -> None:
self.status_code = status_code
self._payload = payload
self.text = text or repr(payload)
def json(self) -> object:
return self._payload
class RaisingResponse(DummyResponse):
def __init__(self, status_code: int, exc: Exception, text: str = "") -> None:
super().__init__(status_code=status_code, payload=None, text=text)
self._exc = exc
def json(self) -> object:
raise self._exc
def _make_client() -> e2e_conftest.APIClient:
return e2e_conftest.APIClient(base_url="http://example.com")
def test_api_client_wait_for_health_retries_through_request_exception(
monkeypatch: pytest.MonkeyPatch,
) -> None:
client = _make_client()
calls = {"count": 0}
def fake_get(_path: str, **_kwargs: object) -> DummyResponse:
calls["count"] += 1
if calls["count"] == 1:
raise e2e_conftest.requests.exceptions.ReadTimeout("timeout")
return DummyResponse(200, {"status": "ok"})
times = [0.0, 0.0, 0.1]
monkeypatch.setattr(client, "get", fake_get)
monkeypatch.setattr(e2e_conftest.time, "time", lambda: times.pop(0))
monkeypatch.setattr(e2e_conftest.time, "sleep", lambda _seconds: None)
try:
assert client.wait_for_health(max_wait=1) is True
assert calls["count"] == 2
finally:
client.close()
def test_download_tracker_wait_for_status_ignores_malformed_payloads_and_returns_error(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class FakeClient:
def __init__(self) -> None:
self.responses = [
DummyResponse(200, ["not", "a", "mapping"]),
DummyResponse(200, {"error": {"task-1": {"message": "boom"}}}),
]
def get(self, _path: str) -> DummyResponse:
return self.responses.pop(0)
tracker = e2e_conftest.DownloadTracker(client=FakeClient())
times = [0.0, 0.0, 0.1]
monkeypatch.setattr(e2e_conftest.time, "time", lambda: times.pop(0))
monkeypatch.setattr(e2e_conftest.time, "sleep", lambda _seconds: None)
result = tracker.wait_for_status("task-1", ["complete"], timeout=1)
assert result == {"state": "error", "data": {"message": "boom"}}
def test_assert_json_object_returns_dict() -> None:
response = DummyResponse(200, {"status": "ok"})
assert e2e_conftest.assert_json_object(response, context="health") == {"status": "ok"}
def test_assert_json_object_rejects_non_object_payload() -> None:
response = DummyResponse(200, ["not", "an", "object"])
with pytest.raises(AssertionError, match="did not return a JSON object"):
e2e_conftest.assert_json_object(response, context="health")
def test_assert_json_object_rejects_invalid_json() -> None:
response = RaisingResponse(200, ValueError("bad json"))
with pytest.raises(Failed, match="did not return valid JSON"):
e2e_conftest.assert_json_object(response, context="health")
def test_assert_json_list_returns_list() -> None:
response = DummyResponse(200, [1, 2, 3])
assert e2e_conftest.assert_json_list(response, context="queue") == [1, 2, 3]
def test_assert_queue_order_response_validates_entries() -> None:
response = DummyResponse(
200,
{
"queue": [
{
"id": "task-1",
"priority": 0,
"added_time": 12.5,
"status": "queued",
}
]
},
)
queue = e2e_conftest.assert_queue_order_response(response)
assert queue[0]["id"] == "task-1"
def test_assert_queue_order_response_rejects_missing_entry_fields() -> None:
response = DummyResponse(200, {"queue": [{"id": "task-1"}]})
with pytest.raises(AssertionError):
e2e_conftest.assert_queue_order_response(response)
def test_require_authenticated_client_allows_public_server(
monkeypatch: pytest.MonkeyPatch,
) -> None:
client = _make_client()
monkeypatch.setattr(e2e_conftest, "_get_auth_state", lambda _: {"auth_required": False})
try:
assert e2e_conftest._require_authenticated_client(client, strict=True) is client
finally:
client.close()
def test_require_authenticated_client_fails_when_auth_state_unavailable(
monkeypatch: pytest.MonkeyPatch,
) -> None:
client = _make_client()
monkeypatch.setattr(e2e_conftest, "_get_auth_state", lambda _: None)
try:
with pytest.raises(Failed, match="Unable to read auth state"):
e2e_conftest._require_authenticated_client(client, strict=True)
finally:
client.close()
def test_require_healthy_server_fails_in_strict_runs(
monkeypatch: pytest.MonkeyPatch,
) -> None:
closed: list[str] = []
monkeypatch.setattr(e2e_conftest.APIClient, "wait_for_health", lambda self, max_wait=30: False)
monkeypatch.setattr(e2e_conftest.APIClient, "close", lambda self: closed.append(self.base_url))
with pytest.raises(Failed, match="Server not available"):
e2e_conftest._require_healthy_server("http://example.com", strict=True)
assert closed == ["http://example.com"]
def test_require_healthy_server_skips_in_non_strict_runs(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(e2e_conftest.APIClient, "wait_for_health", lambda self, max_wait=30: False)
with pytest.raises(Skipped, match="Server not available"):
e2e_conftest._require_healthy_server("http://example.com", strict=False)
def test_require_authenticated_client_skips_when_auth_state_unavailable_and_not_strict(
monkeypatch: pytest.MonkeyPatch,
) -> None:
client = _make_client()
monkeypatch.setattr(e2e_conftest, "_get_auth_state", lambda _: None)
try:
with pytest.raises(Skipped, match="Unable to read auth state"):
e2e_conftest._require_authenticated_client(client, strict=False)
finally:
client.close()
def test_require_authenticated_client_fails_without_env_credentials(
monkeypatch: pytest.MonkeyPatch,
) -> None:
client = _make_client()
monkeypatch.setattr(
e2e_conftest,
"_get_auth_state",
lambda _: {"auth_required": True, "authenticated": False},
)
monkeypatch.delenv(e2e_conftest.E2E_USERNAME_ENV, raising=False)
monkeypatch.delenv(e2e_conftest.E2E_PASSWORD_ENV, raising=False)
try:
with pytest.raises(Failed, match="requires authentication"):
e2e_conftest._require_authenticated_client(client, strict=True)
finally:
client.close()
def test_require_authenticated_client_skips_without_env_credentials_when_not_strict(
monkeypatch: pytest.MonkeyPatch,
) -> None:
client = _make_client()
monkeypatch.setattr(
e2e_conftest,
"_get_auth_state",
lambda _: {"auth_required": True, "authenticated": False},
)
monkeypatch.delenv(e2e_conftest.E2E_USERNAME_ENV, raising=False)
monkeypatch.delenv(e2e_conftest.E2E_PASSWORD_ENV, raising=False)
try:
with pytest.raises(Skipped, match="requires authentication"):
e2e_conftest._require_authenticated_client(client, strict=False)
finally:
client.close()
def test_require_authenticated_client_logs_in_when_credentials_are_available(
monkeypatch: pytest.MonkeyPatch,
) -> None:
client = _make_client()
auth_states = iter(
[
{"auth_required": True, "authenticated": False},
{"auth_required": True, "authenticated": True},
]
)
monkeypatch.setattr(e2e_conftest, "_get_auth_state", lambda _: next(auth_states))
monkeypatch.setattr(e2e_conftest, "_login_with_env_credentials", lambda _: True)
monkeypatch.setenv(e2e_conftest.E2E_USERNAME_ENV, "user")
monkeypatch.setenv(e2e_conftest.E2E_PASSWORD_ENV, "password")
try:
assert e2e_conftest._require_authenticated_client(client, strict=True) is client
finally:
client.close()
def test_is_explicit_e2e_run_detects_e2e_path_selection() -> None:
assert e2e_conftest._is_explicit_e2e_run("", ["tests/e2e/"]) is True
assert (
e2e_conftest._is_explicit_e2e_run("", ["tests/e2e/test_api.py::TestConfigEndpoint"]) is True
)
def test_is_explicit_e2e_run_detects_mixed_path_selection() -> None:
assert (
e2e_conftest._is_explicit_e2e_run(
"",
["tests/e2e/test_api.py", "tests/core/test_user_db.py"],
)
is True
)
def test_is_explicit_e2e_run_detects_markexpr_selection() -> None:
assert e2e_conftest._is_explicit_e2e_run("e2e", ["tests/"]) is True
assert e2e_conftest._is_explicit_e2e_run("slow and e2e", ["tests/"]) is True
def test_is_explicit_e2e_run_treats_general_suite_as_non_strict() -> None:
assert e2e_conftest._is_explicit_e2e_run("", ["tests/"]) is False
assert e2e_conftest._is_explicit_e2e_run("not integration and not e2e", ["tests/"]) is False