feat: 完善 MVP-2 演示和进度体验
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user