refactor: extract admin business logic to services, introduce job queue, add derived index helpers
- Move DB operations from routes/admin.py to services/admin.py (get_logs_context, query_summary_statuses, retry_failed, delete/reset operations) - Add services/jobs.py with Job/JobEvent-based async job queue (create_job, run_job, enqueue_job) - Add services/derived.py with FTS5 reindex and paper index deletion helpers - Refactor scheduler to use job queue instead of direct pipeline calls - Add heartbeat_at/expires_at to TaskLock for lock health tracking - Remove DESIGN_REVIEW.md - Update tests: remove redundant integration tests, add unit tests for new services
This commit is contained in:
@@ -123,38 +123,12 @@ class TestSearchSemanticMode:
|
||||
class TestSearchRoutes:
|
||||
"""搜索页面和 JSON API 路由测试。"""
|
||||
|
||||
def test_search_page_renders(self, client):
|
||||
"""GET /search 返回 200。"""
|
||||
resp = client.get("/search")
|
||||
assert resp.status_code == 200
|
||||
assert "搜索" in resp.text
|
||||
|
||||
def test_search_page_with_query(self, client, sample_paper):
|
||||
"""GET /search?q=Test 返回搜索结果。"""
|
||||
resp = client.get("/search?q=Test")
|
||||
assert resp.status_code == 200
|
||||
assert "2401.12345" in resp.text
|
||||
|
||||
def test_search_page_with_tag(self, client, sample_paper):
|
||||
"""GET /search?tag=NLP 返回标签筛选结果。"""
|
||||
resp = client.get("/search?tag=NLP")
|
||||
assert resp.status_code == 200
|
||||
assert "2401.12345" in resp.text
|
||||
|
||||
def test_search_page_keyword_mode(self, client, sample_papers_with_summary):
|
||||
"""搜索页 keyword 模式。"""
|
||||
resp = client.get("/search?q=Test&mode=keyword")
|
||||
assert resp.status_code == 200
|
||||
assert "Test" in resp.text or "测试" in resp.text
|
||||
|
||||
def test_search_page_semantic_disabled(
|
||||
self, client, monkeypatch, sample_papers_with_summary
|
||||
):
|
||||
"""语义模式 CHROMA_ENABLED=false 时仍能工作。"""
|
||||
monkeypatch.setattr(settings, "CHROMA_ENABLED", False)
|
||||
resp = client.get("/search?q=Test&mode=semantic")
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_search_api_json(self, client, sample_paper):
|
||||
"""GET /api/search?q=Test 返回 JSON。"""
|
||||
resp = client.get("/api/search?q=Test")
|
||||
@@ -170,14 +144,6 @@ class TestSearchRoutes:
|
||||
data = resp.json()
|
||||
assert data["total"] == 1
|
||||
|
||||
def test_search_api_with_mode(self, client, sample_papers_with_summary):
|
||||
"""搜索 API 支持 mode 参数。"""
|
||||
resp = client.get("/api/search?q=Test&mode=keyword")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert "results" in data
|
||||
assert "total" in data
|
||||
|
||||
def test_search_api_empty(self, client, sample_paper):
|
||||
"""GET /api/search?q=nonexistent 返回空结果。"""
|
||||
resp = client.get("/api/search?q=nonexistent")
|
||||
@@ -185,13 +151,6 @@ class TestSearchRoutes:
|
||||
data = resp.json()
|
||||
assert data["total"] == 0
|
||||
|
||||
def test_search_api_sort_by_date(self, client, sample_paper):
|
||||
"""GET /api/search?q=Test&sort=date 按日期排序。"""
|
||||
resp = client.get("/api/search?q=Test&sort=date")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["total"] >= 1
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Similar Paper API 测试
|
||||
@@ -211,21 +170,6 @@ class TestSimilarAPI:
|
||||
data = resp.json()
|
||||
assert data["results"] == []
|
||||
|
||||
def test_similar_api_paper_not_found(self, client, monkeypatch):
|
||||
"""不存在的论文返回空。"""
|
||||
monkeypatch.setattr(settings, "CHROMA_ENABLED", False)
|
||||
resp = client.get("/api/similar/nonexistent.99999")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["results"] == []
|
||||
|
||||
def test_similar_api_with_top_k(
|
||||
self, client, monkeypatch, sample_papers_with_summary
|
||||
):
|
||||
"""top_k 参数控制返回数量。"""
|
||||
monkeypatch.setattr(settings, "CHROMA_ENABLED", False)
|
||||
resp = client.get("/api/similar/2401.20001?top_k=3")
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# 阅读列表路由测试
|
||||
@@ -235,12 +179,6 @@ class TestSimilarAPI:
|
||||
class TestReadingListRoute:
|
||||
"""阅读列表页面测试。"""
|
||||
|
||||
def test_reading_list_empty(self, client):
|
||||
"""无收藏时显示空状态。"""
|
||||
resp = client.get("/reading-list")
|
||||
assert resp.status_code == 200
|
||||
assert "阅读列表" in resp.text
|
||||
|
||||
def test_reading_list_with_bookmark(self, client, sample_paper):
|
||||
"""有收藏时显示论文。"""
|
||||
# 先收藏
|
||||
@@ -302,13 +240,6 @@ class TestRssFeed:
|
||||
assert "<channel>" in resp.text
|
||||
assert "2401.12345" in resp.text
|
||||
|
||||
def test_rss_has_paper_item(self, client, sample_paper):
|
||||
"""RSS 包含论文条目。"""
|
||||
resp = client.get("/rss.xml")
|
||||
assert "<item>" in resp.text
|
||||
assert "<title>" in resp.text
|
||||
assert "/paper/2401.12345" in resp.text
|
||||
|
||||
def test_rss_with_tag_filter(self, client, sample_paper):
|
||||
"""GET /rss.xml?tag=NLP 按标签筛选。"""
|
||||
resp = client.get("/rss.xml?tag=NLP")
|
||||
|
||||
Reference in New Issue
Block a user