chore: prepare yanting monorepo handoff
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
os.environ["RNB_DATABASE_URL"] = "sqlite+aiosqlite:///./test_seed.db"
|
||||
os.environ["RNB_REDIS_URL"] = "redis://test-redis.invalid/0"
|
||||
|
||||
import pytest
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
from sqlalchemy import select
|
||||
|
||||
from app.db import Base, SessionLocal, engine
|
||||
from app.main import app
|
||||
from app.models import AudioAsset, DisplayModule, Institution, Report
|
||||
from scripts.import_seed_content import import_seed
|
||||
|
||||
|
||||
PREFIX = "/api/report-notebooklm/v1"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def seeded_db():
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.drop_all)
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
async with SessionLocal() as session:
|
||||
await import_seed(session)
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def client():
|
||||
transport = ASGITransport(app=app)
|
||||
async with AsyncClient(transport=transport, base_url="http://test") as ac:
|
||||
yield ac
|
||||
|
||||
|
||||
async def test_seed_counts_match_phase1_shape():
|
||||
async with SessionLocal() as session:
|
||||
assert len((await session.execute(select(Institution))).scalars().all()) == 18
|
||||
assert len((await session.execute(select(Report))).scalars().all()) == 27
|
||||
assert len((await session.execute(select(AudioAsset))).scalars().all()) == 15
|
||||
assert len((await session.execute(select(DisplayModule))).scalars().all()) >= 120
|
||||
|
||||
|
||||
async def test_health_and_recommended_feed(client: AsyncClient):
|
||||
health = await client.get(f"{PREFIX}/health")
|
||||
assert health.status_code == 200
|
||||
assert health.json() == {"status": "ok"}
|
||||
|
||||
feed = await client.get(f"{PREFIX}/feed/recommended")
|
||||
assert feed.status_code == 200
|
||||
body = feed.json()
|
||||
assert body["items"]
|
||||
assert body["items"][0]["report_id"] == "rep_bis_notebooklm_sample"
|
||||
assert "display_version" not in body["items"][0]
|
||||
assert body["items"][0]["cache_version"].startswith("rep_")
|
||||
|
||||
|
||||
async def test_report_detail_hides_internal_fields_and_review_modules(client: AsyncClient):
|
||||
response = await client.get(f"{PREFIX}/reports/rep_ssga_gold")
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["report_id"] == "rep_ssga_gold"
|
||||
assert "display_version" not in body
|
||||
module_types = [module["type"] for module in body["modules"]]
|
||||
assert "study_guide" in module_types
|
||||
assert "institution" not in module_types
|
||||
assert "faq" not in module_types
|
||||
assert "infographic" not in module_types
|
||||
assert all(module["has_detail_page"] for module in body["modules"])
|
||||
assert module_types[-1] == "source_compliance"
|
||||
key_data = next(module for module in body["modules"] if module["type"] == "key_data")
|
||||
assert key_data["render_mode"] == "card_plus_page"
|
||||
assert key_data["content"] is None
|
||||
assert key_data["preview"]["row_count"] == 10
|
||||
assert key_data["content_ref"].startswith("rnb/modules/")
|
||||
|
||||
|
||||
async def test_module_endpoint_returns_full_content(client: AsyncClient):
|
||||
detail = (await client.get(f"{PREFIX}/reports/rep_ssga_gold")).json()
|
||||
key_data = next(module for module in detail["modules"] if module["type"] == "key_data")
|
||||
response = await client.get(f"{PREFIX}/reports/rep_ssga_gold/modules/{key_data['module_id']}")
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["module_id"] == key_data["module_id"]
|
||||
assert "rows" in body["content"]
|
||||
assert body["cache_version"] == "rep_ssga_gold:v1"
|
||||
|
||||
|
||||
async def test_boundary_reports(client: AsyncClient):
|
||||
listen = (await client.get(f"{PREFIX}/listen")).json()
|
||||
listen_report_ids = {item["report_id"] for item in listen["items"]}
|
||||
assert "rep_ing_gold" not in listen_report_ids
|
||||
assert "rep_pas_silver" not in listen_report_ids
|
||||
|
||||
hidden = await client.get(f"{PREFIX}/reports/rep_wisdomtree_outlook")
|
||||
assert hidden.status_code == 404
|
||||
|
||||
gray = (await client.get(f"{PREFIX}/reports/rep_pas_silver")).json()
|
||||
compliance = next(module for module in gray["modules"] if module["type"] == "source_compliance")
|
||||
assert compliance["content"]["source_url"] is None
|
||||
assert "灰度" in compliance["content"]["source_note"]
|
||||
|
||||
|
||||
async def test_institutions_and_listen(client: AsyncClient):
|
||||
institutions = await client.get(f"{PREFIX}/institutions")
|
||||
assert institutions.status_code == 200
|
||||
assert len(institutions.json()["items"]) == 18
|
||||
|
||||
inst = await client.get(f"{PREFIX}/institutions/inst_ssga")
|
||||
assert inst.status_code == 200
|
||||
assert inst.json()["latest_report"]["report_id"] == "rep_ssga_gold"
|
||||
|
||||
listen = await client.get(f"{PREFIX}/listen")
|
||||
assert listen.status_code == 200
|
||||
assert listen.json()["items"][0]["audio_id"].startswith("aud_")
|
||||
Reference in New Issue
Block a user