feat: 完善 MVP-2 演示和进度体验

This commit is contained in:
meijiali
2026-07-03 16:57:39 +08:00
parent 867fd39419
commit 9935f67080
20 changed files with 1252 additions and 33 deletions
+57
View File
@@ -1,5 +1,6 @@
from app.models import Comment, ContentItem, Hotspot, Report, Task
from tests.helpers import make_test_client
from sqlalchemy.exc import OperationalError
def test_index_page_renders_task_form_empty_state_and_default_scale():
@@ -354,3 +355,59 @@ def test_export_routes_return_csv_and_markdown():
assert "热点总结" in hotspot_md.text
assert item_md.status_code == 200
assert "内容总结" in item_md.text
def test_api_tasks_returns_service_unavailable_when_database_has_io_error(monkeypatch):
def broken_list_tasks(_session):
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
monkeypatch.setattr("app.main.list_tasks", broken_list_tasks)
with make_test_client() as (client, _engine):
response = client.get("/api/tasks")
assert response.status_code == 503
assert response.json()["detail"] == "数据库暂时不可用,请稍后重试或联系维护者恢复数据。"
def test_index_page_shows_database_error_state_when_database_has_io_error(monkeypatch):
def broken_list_tasks(_session):
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
monkeypatch.setattr("app.main.list_tasks", broken_list_tasks)
with make_test_client() as (client, _engine):
response = client.get("/")
assert response.status_code == 503
assert "数据库暂时不可用" in response.text
assert "请先保留 data 目录" in response.text
def test_task_api_includes_progress_counts_stage_and_demo_flag():
with make_test_client() as (client, engine):
seed_result_data(engine)
response = client.get("/api/tasks/task-result")
assert response.status_code == 200
data = response.json()
assert data["current_stage"] in (None, "success")
assert data["current_stage_label"] == "已完成"
assert data["comments_count"] == 1
assert data["reports_count"] == 2
assert data["is_demo"] is False
assert data["last_progress_at"] is not None
def test_task_detail_page_explains_target_and_actual_counts():
with make_test_client() as (client, engine):
seed_result_data(engine)
response = client.get("/tasks/task-result")
assert response.status_code == 200
assert "目标上限" in response.text
assert "实际结果" in response.text
assert "实际评论 1" in response.text
assert "少于理论上限通常是内容本身评论不足或平台返回不足" in response.text
+18 -1
View File
@@ -1,6 +1,6 @@
import pytest
from app.db import check_database_integrity, checkpoint_sqlite_wal, create_sqlite_engine
from app.db import check_database_integrity, checkpoint_sqlite_wal, create_sqlite_engine, ensure_sqlite_schema_compat
def test_check_database_integrity_returns_ok_for_valid_sqlite_database():
@@ -63,3 +63,20 @@ def test_checkpoint_sqlite_wal_skips_in_memory_database():
assert checkpoint_sqlite_wal(engine) is False
finally:
engine.dispose()
def test_ensure_sqlite_schema_compat_adds_progress_columns_to_existing_tasks_table(tmp_path):
db_path = tmp_path / "legacy.db"
engine = create_sqlite_engine(f"sqlite:///{db_path}")
try:
with engine.begin() as connection:
connection.exec_driver_sql("CREATE TABLE tasks (id VARCHAR(36) PRIMARY KEY, platform VARCHAR(32) NOT NULL)")
ensure_sqlite_schema_compat(engine)
with engine.connect() as connection:
columns = {row[1] for row in connection.exec_driver_sql("PRAGMA table_info(tasks)").all()}
assert "current_stage" in columns
assert "last_progress_at" in columns
finally:
engine.dispose()
+27
View File
@@ -0,0 +1,27 @@
from sqlalchemy.orm import Session
from app.demo_seed import seed_demo_data
from app.models import Comment, ContentItem, Task
from tests.helpers import make_test_client
def test_seed_demo_data_is_idempotent_and_removes_sensitive_fields():
with make_test_client() as (_client, engine):
with Session(engine) as session:
task_id = seed_demo_data(session)
second_task_id = seed_demo_data(session)
task = session.get(Task, task_id)
comments = session.query(Comment).all()
items = session.query(ContentItem).all()
assert second_task_id == task_id
assert task is not None
assert task.id.startswith("demo-")
assert task.status == "success"
assert comments
assert all(comment.author is None for comment in comments)
assert all(comment.source_comment_id is None for comment in comments)
assert all(comment.raw_data == "{}" for comment in comments)
assert all(item.url is None for item in items)
assert all(item.raw_data == "{}" for item in items)
+3
View File
@@ -17,5 +17,8 @@ def test_user_guide_covers_startup_acceptance_exports_and_troubleshooting():
"API Key 缺失",
"任务长期 running",
"重置本地数据库",
"公网云服务器部署",
"python -m app.demo_seed",
"data/corrupt-backups",
]:
assert required in content