first commit
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
"""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_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)")
|
||||
Reference in New Issue
Block a user