Files
sebrief/tests/test_store.py
T
jsahnandClaude Fable 5 3f1d16cae1 Supplement slow-indexed IEEE journals from Crossref (TSE fresh papers)
OpenAlex indexes TSE ~2-3 months late (nothing after 2026-06-26 as of Sep 2),
so TSE never appeared in weekly digests. Sources can now be flagged
crossref_fresh: their recent papers are discovered via Crossref (created-date
window, paper-level CC licence = OA) and listed without abstracts; a digested
paper's missing abstract is filled once OpenAlex indexes the DOI, so a later
--force re-run can add its per-paper summary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 21:00:32 +09:00

151 lines
6.4 KiB
Python

"""SQLite store: paper lifecycle (upsert/freeze/rollover), digest idempotency, deliveries."""
from __future__ import annotations
from datetime import date
from _fakes import WEEK, make_paper, make_payload, make_summary
from sebrief.models import DigestResult
from sebrief.store import Store
def make_store(tmp_path) -> Store:
return Store(tmp_path / "data" / "test.sqlite3")
def make_result(papers=None, degraded=False) -> DigestResult:
payload = make_payload(papers=papers)
return DigestResult(
payload=payload, digest=None, markdown="# md", model_used="m", degraded=degraded
)
# ----------------------------------------------------------------------------------- papers
def test_upsert_inserts_and_counts_new(tmp_path):
with make_store(tmp_path) as store:
p1, p2 = make_paper("10.1/a"), make_paper("10.1/b")
assert store.upsert_papers([p1, p2]) == 2
assert store.upsert_papers([p1]) == 0 # re-collection is not new
assert store.paper_count() == 2
def test_upsert_refreshes_undigested_metadata(tmp_path):
with make_store(tmp_path) as store:
store.upsert_papers([make_paper("10.1/a", abstract="")])
store.upsert_papers([make_paper("10.1/a", abstract="now with abstract")])
[paper] = store.pending_papers(WEEK)
assert paper.abstract == "now with abstract"
def test_digested_paper_gains_missing_abstract_but_stays_frozen(tmp_path):
with make_store(tmp_path) as store:
store.upsert_papers([make_paper("10.1/a", title="fresh via crossref", abstract="")])
store.mark_digested(["10.1/a"], WEEK)
# OpenAlex later indexes the DOI with an abstract (and a normalised title)
store.upsert_papers([make_paper("10.1/a", title="OpenAlex Title", abstract="now indexed")])
[paper] = store.pending_papers(WEEK)
assert paper.abstract == "now indexed" # 초록만 보강
assert paper.title == "fresh via crossref" # 그 외 메타데이터는 동결 유지
def test_digested_papers_are_frozen_and_skipped(tmp_path):
with make_store(tmp_path) as store:
store.upsert_papers([make_paper("10.1/a", title="original")])
store.mark_digested(["10.1/a"], WEEK)
store.upsert_papers([make_paper("10.1/a", title="rewritten")])
# not pending for a later week, and metadata unchanged
assert store.pending_papers("2026-W37") == []
[paper] = store.pending_papers(WEEK) # --force re-run of the same week still sees it
assert paper.title == "original"
def test_pending_includes_undigested_leftovers_and_orders_by_date(tmp_path):
with make_store(tmp_path) as store:
old = make_paper("10.1/old", published_date=date(2026, 8, 20)) # last week's late arrival
new = make_paper("10.1/new", published_date=date(2026, 9, 2))
undated = make_paper("10.1/undated", published_date=None)
store.upsert_papers([new, undated, old])
dois = [p.doi for p in store.pending_papers(WEEK)]
assert dois == ["10.1/old", "10.1/new", "10.1/undated"] # dated first (ascending), undated last
def test_paper_roundtrip_preserves_fields(tmp_path):
with make_store(tmp_path) as store:
original = make_paper("10.1/a", authors=["김철수", "Bob"], topics=["Testing", "LLM"])
store.upsert_papers([original])
[loaded] = store.pending_papers(WEEK)
assert loaded == original
# ---------------------------------------------------------------------------- paper summaries
def test_paper_summaries_roundtrip_and_survive_metadata_refresh(tmp_path):
with make_store(tmp_path) as store:
store.upsert_papers([make_paper("10.1/a")])
summary = make_summary(tldr="한 줄.")
store.save_paper_summaries({"10.1/a": summary})
[paper] = store.pending_papers(WEEK)
assert paper.summary == summary
# a later re-collection refreshes metadata but must not clear the summary
store.upsert_papers([make_paper("10.1/a", abstract="updated")])
[paper] = store.pending_papers(WEEK)
assert paper.abstract == "updated" and paper.summary == summary
def test_paper_summaries_allowed_on_frozen_papers(tmp_path):
with make_store(tmp_path) as store:
store.upsert_papers([make_paper("10.1/a")])
store.mark_digested(["10.1/a"], WEEK)
store.save_paper_summaries({"10.1/a": make_summary()})
[paper] = store.pending_papers(WEEK) # digest_week = WEEK: visible on --force re-run
assert paper.summary is not None
def test_migration_adds_summary_column_to_old_db(tmp_path):
import sqlite3
db = tmp_path / "data" / "old.sqlite3"
db.parent.mkdir(parents=True)
conn = sqlite3.connect(db)
conn.executescript(
"""
CREATE TABLE papers (
doi TEXT PRIMARY KEY, title TEXT NOT NULL, abstract TEXT NOT NULL DEFAULT '',
authors TEXT NOT NULL DEFAULT '[]', venue TEXT NOT NULL DEFAULT '',
published_date TEXT, oa_url TEXT, pdf_url TEXT, topics TEXT NOT NULL DEFAULT '[]',
source TEXT NOT NULL DEFAULT '', collected_at TEXT, digest_week TEXT
);
INSERT INTO papers (doi, title) VALUES ('10.1/legacy', 'Legacy Paper');
"""
)
conn.commit()
conn.close()
with Store(db) as store:
[paper] = store.pending_papers(WEEK)
assert paper.doi == "10.1/legacy" and paper.summary is None
store.save_paper_summaries({"10.1/legacy": make_summary()})
[paper] = store.pending_papers(WEEK)
assert paper.summary is not None
# ---------------------------------------------------------------------------------- digests
def test_digest_idempotency_and_upsert(tmp_path):
with make_store(tmp_path) as store:
assert store.has_digest(WEEK) is False
store.save_digest(make_result())
assert store.has_digest(WEEK) is True
store.save_digest(make_result(degraded=True)) # --force resend overwrites
row = store._conn.execute("SELECT degraded FROM digests WHERE week = ?", (WEEK,)).fetchone()
assert row["degraded"] == 1
def test_deliveries(tmp_path):
with make_store(tmp_path) as store:
store.save_digest(make_result())
store.mark_sent(WEEK, "file", "/tmp/2026-W36.md")
store.mark_sent(WEEK, "file", "/tmp/2026-W36.md (resend)")
rows = store.deliveries_for(WEEK)
assert [r["channel"] for r in rows] == ["file", "file"]
assert rows[1]["receipt"].endswith("(resend)")