| import asyncio |
|
|
| import pytest |
| from sqlalchemy import func, select |
|
|
| from src.database.db import session_pool |
| from src.model import Paper, Usability |
|
|
|
|
| def test_get_summary_and_usability_returns_existing_data( |
| client, create_authenticated_user, create_paper_record, create_usability_record |
| ): |
| auth_user = create_authenticated_user() |
| paper = create_paper_record( |
| user_id=auth_user["id"], |
| arxiv_id="2401.10000", |
| paper_summary="Existing summary", |
| ) |
| create_usability_record( |
| user_id=auth_user["id"], |
| paper_id=paper["id"], |
| impact_score=0.91, |
| ) |
|
|
| response = client.get( |
| f"/api/v1/summary/{paper['arxiv_id']}", |
| headers=auth_user["headers"], |
| ) |
|
|
| assert response.status_code == 200 |
| payload = response.json() |
| assert payload["summary"] == "Existing summary" |
| assert payload["usability"]["impact_score"] == 0.91 |
|
|
|
|
| def test_generate_summary_updates_paper( |
| client, create_authenticated_user, create_paper_record, external_service_spies |
| ): |
| auth_user = create_authenticated_user() |
| paper = create_paper_record( |
| user_id=auth_user["id"], |
| arxiv_id="2401.10001", |
| paper_summary="", |
| ) |
|
|
| response = client.post( |
| f"/api/v1/summary/{paper['arxiv_id']}", |
| headers=auth_user["headers"], |
| ) |
|
|
| assert response.status_code == 200 |
| assert response.json()["summary"] == f"summary for {paper['arxiv_id']}" |
| assert external_service_spies["summaries"] == [ |
| {"arxiv_id": paper["arxiv_id"], "pdf_url": None} |
| ] |
|
|
| async def _load_paper(): |
| async with session_pool() as session: |
| return ( |
| await session.execute( |
| select(Paper).where(Paper.arxiv_id == paper["arxiv_id"]) |
| ) |
| ).scalar_one() |
|
|
| updated_paper = asyncio.run(_load_paper()) |
| assert updated_paper.paper_summary == f"summary for {paper['arxiv_id']}" |
|
|
|
|
| @pytest.mark.xfail( |
| reason="Current router order registers /{arxiv_id} before /generate, so /generate is shadowed.", |
| strict=False, |
| ) |
| def test_generate_summary_for_pdf_url_does_not_require_paper( |
| client, create_authenticated_user, external_service_spies |
| ): |
| auth_user = create_authenticated_user() |
|
|
| response = client.post( |
| "/api/v1/summary/generate", |
| headers=auth_user["headers"], |
| json={"pdf_url": "https://example.com/papers/custom.pdf"}, |
| ) |
|
|
| assert response.status_code == 200 |
| payload = response.json() |
| assert payload["arxiv_id"] == "" |
| assert payload["summary"] == "summary for https://example.com/papers/custom.pdf" |
| assert external_service_spies["summaries"] == [ |
| {"arxiv_id": None, "pdf_url": "https://example.com/papers/custom.pdf"} |
| ] |
|
|
|
|
| def test_generate_usability_creates_then_updates_record( |
| client, create_authenticated_user, create_paper_record, monkeypatch |
| ): |
| auth_user = create_authenticated_user() |
| paper = create_paper_record(user_id=auth_user["id"], arxiv_id="2401.10002") |
|
|
| async def first_result(arxiv_id=None, pdf_url=None, request=None): |
| return { |
| "domain_applicability": {"Technology": 0.7}, |
| "reproducibility_score": {"Reproducible": 0.6}, |
| "new_tech_applicability": {"Agentic AI": 0.5}, |
| "impact_score": 0.4, |
| } |
|
|
| async def second_result(arxiv_id=None, pdf_url=None, request=None): |
| return { |
| "domain_applicability": {"Technology": 0.95}, |
| "reproducibility_score": {"Reproducible": 0.9}, |
| "new_tech_applicability": {"Agentic AI": 0.85}, |
| "impact_score": 0.8, |
| } |
|
|
| monkeypatch.setattr( |
| "src.controller.summary.UsabilityEngine.generate_paper_summary", first_result |
| ) |
| first_response = client.post( |
| f"/api/v1/summary/{paper['arxiv_id']}/usability", |
| headers=auth_user["headers"], |
| ) |
| assert first_response.status_code == 200 |
| assert first_response.json()["impact_score"] == 0.4 |
|
|
| monkeypatch.setattr( |
| "src.controller.summary.UsabilityEngine.generate_paper_summary", second_result |
| ) |
| second_response = client.post( |
| f"/api/v1/summary/{paper['arxiv_id']}/usability", |
| headers=auth_user["headers"], |
| ) |
| assert second_response.status_code == 200 |
| assert second_response.json()["impact_score"] == 0.8 |
|
|
| async def _load_state(): |
| async with session_pool() as session: |
| record_count = ( |
| await session.execute( |
| select(func.count(Usability.id)).where( |
| Usability.user_id == auth_user["id"], |
| Usability.paper_id == paper["id"], |
| ) |
| ) |
| ).scalar_one() |
| usability = ( |
| await session.execute( |
| select(Usability).where( |
| Usability.user_id == auth_user["id"], |
| Usability.paper_id == paper["id"], |
| ) |
| ) |
| ).scalar_one() |
| return record_count, usability |
|
|
| record_count, usability = asyncio.run(_load_state()) |
| assert record_count == 1 |
| assert usability.impact_score == 0.8 |
| assert usability.domain_applicability == {"Technology": 0.95} |
|
|
|
|
| def test_generate_summary_returns_404_for_missing_paper( |
| client, create_authenticated_user |
| ): |
| auth_user = create_authenticated_user() |
|
|
| response = client.post( |
| "/api/v1/summary/does-not-exist", |
| headers=auth_user["headers"], |
| ) |
|
|
| assert response.status_code == 404 |
| assert response.json()["detail"] == "Paper not found" |
|
|