Intermediate commit
This commit is contained in:
parent
0e9e49df16
commit
3d4cfeff1a
65 changed files with 5507 additions and 333 deletions
|
|
@ -6,7 +6,6 @@ from types import SimpleNamespace
|
|||
import pytest
|
||||
|
||||
from app.db.models import PublicationPdfJob
|
||||
from app.services.domains.arxiv.application import ArxivRateLimitError
|
||||
from app.services.domains.publications import pdf_queue
|
||||
from app.services.domains.publications.pdf_resolution_pipeline import PipelineOutcome
|
||||
from app.services.domains.unpaywall.application import OaResolutionOutcome
|
||||
|
|
@ -134,8 +133,9 @@ def test_pdf_queue_manual_requeue_still_blocks_when_inflight() -> None:
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_outcome_for_row_uses_pipeline_outcome(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
async def _fake_pipeline(*, row, request_email=None, openalex_api_key=None):
|
||||
async def _fake_pipeline(*, row, request_email=None, openalex_api_key=None, allow_arxiv_lookup=True):
|
||||
assert request_email == "user@example.com"
|
||||
assert allow_arxiv_lookup is True
|
||||
return PipelineOutcome(
|
||||
outcome=OaResolutionOutcome(
|
||||
publication_id=row.publication_id,
|
||||
|
|
@ -150,31 +150,40 @@ async def test_fetch_outcome_for_row_uses_pipeline_outcome(monkeypatch: pytest.M
|
|||
|
||||
monkeypatch.setattr(pdf_queue, "resolve_publication_pdf_outcome_for_row", _fake_pipeline)
|
||||
|
||||
outcome = await pdf_queue._fetch_outcome_for_row(row=_row(), request_email="user@example.com")
|
||||
outcome, arxiv_rate_limited = await pdf_queue._fetch_outcome_for_row(
|
||||
row=_row(),
|
||||
request_email="user@example.com",
|
||||
)
|
||||
|
||||
assert outcome.pdf_url == "https://arxiv.org/pdf/1703.06103"
|
||||
assert outcome.source == "openalex"
|
||||
assert outcome.used_crossref is False
|
||||
assert arxiv_rate_limited is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_outcome_for_row_returns_failed_outcome_when_pipeline_returns_none(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
async def _fake_pipeline(*, row, request_email=None, openalex_api_key=None):
|
||||
async def _fake_pipeline(*, row, request_email=None, openalex_api_key=None, allow_arxiv_lookup=True):
|
||||
assert request_email == "user@example.com"
|
||||
return PipelineOutcome(outcome=None, scholar_candidates=None)
|
||||
assert allow_arxiv_lookup is True
|
||||
return PipelineOutcome(outcome=None, scholar_candidates=None, arxiv_rate_limited=True)
|
||||
|
||||
monkeypatch.setattr(pdf_queue, "resolve_publication_pdf_outcome_for_row", _fake_pipeline)
|
||||
|
||||
outcome = await pdf_queue._fetch_outcome_for_row(row=_row(), request_email="user@example.com")
|
||||
outcome, arxiv_rate_limited = await pdf_queue._fetch_outcome_for_row(
|
||||
row=_row(),
|
||||
request_email="user@example.com",
|
||||
)
|
||||
|
||||
assert outcome.pdf_url is None
|
||||
assert outcome.failure_reason == pdf_queue.FAILURE_RESOLUTION_EXCEPTION
|
||||
assert arxiv_rate_limited is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_resolve_publication_row_persists_failed_outcome_before_reraising_arxiv_rate_limit(
|
||||
async def test_resolve_publication_row_persists_outcome_and_returns_rate_limit_flag(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
captured: list[tuple[int, int, OaResolutionOutcome]] = []
|
||||
|
|
@ -182,47 +191,64 @@ async def test_resolve_publication_row_persists_failed_outcome_before_reraising_
|
|||
async def _noop_mark_attempt_started(*, publication_id: int, user_id: int) -> None:
|
||||
return None
|
||||
|
||||
async def _raise_rate_limit(*, row, request_email=None, openalex_api_key=None):
|
||||
raise ArxivRateLimitError("arXiv rate limit hit (429) — stopping batch")
|
||||
async def _fake_fetch(*, row, request_email=None, openalex_api_key=None, allow_arxiv_lookup=True):
|
||||
assert allow_arxiv_lookup is True
|
||||
return (
|
||||
OaResolutionOutcome(
|
||||
publication_id=row.publication_id,
|
||||
doi=None,
|
||||
pdf_url="https://fallback.example/test.pdf",
|
||||
failure_reason=None,
|
||||
source="unpaywall",
|
||||
used_crossref=False,
|
||||
),
|
||||
True,
|
||||
)
|
||||
|
||||
async def _capture_persist_outcome(*, publication_id: int, user_id: int, outcome: OaResolutionOutcome) -> None:
|
||||
captured.append((publication_id, user_id, outcome))
|
||||
|
||||
monkeypatch.setattr(pdf_queue, "_mark_attempt_started", _noop_mark_attempt_started)
|
||||
monkeypatch.setattr(pdf_queue, "_fetch_outcome_for_row", _raise_rate_limit)
|
||||
monkeypatch.setattr(pdf_queue, "_fetch_outcome_for_row", _fake_fetch)
|
||||
monkeypatch.setattr(pdf_queue, "_persist_outcome", _capture_persist_outcome)
|
||||
|
||||
with pytest.raises(ArxivRateLimitError):
|
||||
await pdf_queue._resolve_publication_row(
|
||||
user_id=42,
|
||||
request_email="user@example.com",
|
||||
row=_row(),
|
||||
openalex_api_key="key",
|
||||
)
|
||||
rate_limited = await pdf_queue._resolve_publication_row(
|
||||
user_id=42,
|
||||
request_email="user@example.com",
|
||||
row=_row(),
|
||||
openalex_api_key="key",
|
||||
)
|
||||
|
||||
assert len(captured) == 1
|
||||
publication_id, user_id, outcome = captured[0]
|
||||
assert publication_id == 1
|
||||
assert user_id == 42
|
||||
assert outcome.pdf_url is None
|
||||
assert outcome.failure_reason == pdf_queue.FAILURE_RESOLUTION_EXCEPTION
|
||||
assert outcome.pdf_url == "https://fallback.example/test.pdf"
|
||||
assert rate_limited is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_resolution_task_stops_batch_on_arxiv_rate_limit(
|
||||
async def test_run_resolution_task_disables_arxiv_for_remaining_batch(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
calls: list[int] = []
|
||||
calls: list[tuple[int, bool]] = []
|
||||
first = _row()
|
||||
second = SimpleNamespace(**{**first.__dict__, "publication_id": 2})
|
||||
|
||||
def _raise_session_factory_error():
|
||||
raise RuntimeError("skip user settings lookup in test")
|
||||
|
||||
async def _fake_resolve_publication_row(*, user_id: int, request_email: str | None, row, openalex_api_key=None):
|
||||
calls.append(int(row.publication_id))
|
||||
if row.publication_id == 1:
|
||||
raise ArxivRateLimitError("arXiv rate limit hit (429) — stopping batch")
|
||||
async def _fake_resolve_publication_row(
|
||||
*,
|
||||
user_id: int,
|
||||
request_email: str | None,
|
||||
row,
|
||||
openalex_api_key=None,
|
||||
allow_arxiv_lookup=True,
|
||||
):
|
||||
_ = (user_id, request_email, openalex_api_key)
|
||||
calls.append((int(row.publication_id), bool(allow_arxiv_lookup)))
|
||||
return row.publication_id == 1
|
||||
|
||||
monkeypatch.setattr(pdf_queue, "get_session_factory", _raise_session_factory_error)
|
||||
monkeypatch.setattr(pdf_queue, "_resolve_publication_row", _fake_resolve_publication_row)
|
||||
|
|
@ -233,4 +259,4 @@ async def test_run_resolution_task_stops_batch_on_arxiv_rate_limit(
|
|||
rows=[first, second],
|
||||
)
|
||||
|
||||
assert calls == [1]
|
||||
assert calls == [(1, True), (2, False)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue