test: 补充 WO-11 页面错误兜底测试
This commit is contained in:
@@ -978,6 +978,26 @@ fix: 修复页面刷新和按钮点击的 500 错误
|
|||||||
|
|
||||||
- 用户需要提供或复现最容易触发 500 的页面 URL 与按钮名称;如果无法提供,则开发时先从当前浏览器打开的任务详情页开始排查。
|
- 用户需要提供或复现最容易触发 500 的页面 URL 与按钮名称;如果无法提供,则开发时先从当前浏览器打开的任务详情页开始排查。
|
||||||
|
|
||||||
|
完成记录:
|
||||||
|
|
||||||
|
- 完成日期:2026-07-03
|
||||||
|
- 相关改动:
|
||||||
|
- 补充路由回归测试,覆盖任务详情页、热点报告页、内容详情页、导出接口在数据库 I/O error 下的 503 兜底。
|
||||||
|
- 补充缺失任务、缺失热点、缺失内容页面的 404 兜底测试,确保不是裸 500。
|
||||||
|
- 核查当前实现已有 `OperationalError` / `SQLAlchemyError` 全局 handler:API 返回 503 JSON,HTML 页面返回数据库不可用友好页。
|
||||||
|
- 验证命令:
|
||||||
|
- `docker cp tests/. hot-comments-tool-app-1:/app/tests/`
|
||||||
|
- `docker exec hot-comments-tool-app-1 sh -lc 'python -m pytest /app/tests/integration/test_routes.py -q'`
|
||||||
|
- 验证结果:
|
||||||
|
- `19 passed, 1 warning`
|
||||||
|
- 验收结论:
|
||||||
|
- 已知高频页面路由和导出入口在数据库 I/O error 下不会返回裸 `Internal Server Error`。
|
||||||
|
- 缺失任务、热点、内容不会返回 500。
|
||||||
|
- 服务端日志仍保留异常信息,页面/API 返回可理解错误。
|
||||||
|
- 遗留问题:
|
||||||
|
- 轮询接口偶发 503 时,前端当前只是静默返回,用户看不到“最近一次同步失败”提示;归入 WO-19 / WO-13 前端提示优化。
|
||||||
|
- 当前本机 Python `.venv` 仍未完成依赖安装,本轮测试通过运行容器执行。
|
||||||
|
|
||||||
### WO-12 导出 Markdown / CSV 点击失效修复
|
### WO-12 导出 Markdown / CSV 点击失效修复
|
||||||
|
|
||||||
优先级:P0
|
优先级:P0
|
||||||
|
|||||||
@@ -384,6 +384,102 @@ def test_index_page_shows_database_error_state_when_database_has_io_error(monkey
|
|||||||
assert "请先保留 data 目录" in response.text
|
assert "请先保留 data 目录" in response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_task_detail_page_shows_database_error_state_when_database_has_io_error(monkeypatch):
|
||||||
|
def broken_get_task(_session, _task_id):
|
||||||
|
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
|
||||||
|
|
||||||
|
monkeypatch.setattr("app.main.get_task", broken_get_task)
|
||||||
|
|
||||||
|
with make_test_client() as (client, _engine):
|
||||||
|
response = client.get("/tasks/task-io-error")
|
||||||
|
|
||||||
|
assert response.status_code == 503
|
||||||
|
assert "数据库暂时不可用" in response.text
|
||||||
|
assert "请先保留 data 目录" in response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_hotspot_report_page_shows_database_error_state_when_database_has_io_error(monkeypatch):
|
||||||
|
def broken_get_task(_session, _task_id):
|
||||||
|
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
|
||||||
|
|
||||||
|
monkeypatch.setattr("app.main.get_task", broken_get_task)
|
||||||
|
|
||||||
|
with make_test_client() as (client, engine):
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
with Session(engine) as session:
|
||||||
|
session.add(Task(id="task-hot-io", platform="xiaohongshu", status="success"))
|
||||||
|
session.add(Hotspot(id="hot-io", task_id="task-hot-io", platform="xiaohongshu", title="热点", rank=1, raw_data="{}"))
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
response = client.get("/hotspots/hot-io/report")
|
||||||
|
|
||||||
|
assert response.status_code == 503
|
||||||
|
assert "数据库暂时不可用" in response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_item_detail_page_shows_database_error_state_when_database_has_io_error(monkeypatch):
|
||||||
|
def broken_get_task(_session, _task_id):
|
||||||
|
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
|
||||||
|
|
||||||
|
monkeypatch.setattr("app.main.get_task", broken_get_task)
|
||||||
|
|
||||||
|
with make_test_client() as (client, engine):
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
with Session(engine) as session:
|
||||||
|
session.add(Task(id="task-item-io", platform="xiaohongshu", status="success"))
|
||||||
|
session.add(Hotspot(id="hot-item-io", task_id="task-item-io", platform="xiaohongshu", title="热点", rank=1, raw_data="{}"))
|
||||||
|
session.add(
|
||||||
|
ContentItem(
|
||||||
|
id="item-io",
|
||||||
|
task_id="task-item-io",
|
||||||
|
hotspot_id="hot-item-io",
|
||||||
|
platform="xiaohongshu",
|
||||||
|
source_item_id="item-io-source",
|
||||||
|
item_type="note",
|
||||||
|
status="success",
|
||||||
|
raw_data="{}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
response = client.get("/items/item-io")
|
||||||
|
|
||||||
|
assert response.status_code == 503
|
||||||
|
assert "数据库暂时不可用" in response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_route_returns_service_unavailable_when_database_has_io_error(monkeypatch):
|
||||||
|
def broken_export(_session, _item_id):
|
||||||
|
raise OperationalError("SELECT 1", {}, Exception("disk I/O error"))
|
||||||
|
|
||||||
|
monkeypatch.setattr("app.main.export_item_comments_csv", broken_export)
|
||||||
|
|
||||||
|
with make_test_client() as (client, _engine):
|
||||||
|
response = client.get("/api/export/items/item-io/comments.csv")
|
||||||
|
|
||||||
|
assert response.status_code == 503
|
||||||
|
assert response.json()["detail"] == "数据库暂时不可用,请稍后重试或联系维护者恢复数据。"
|
||||||
|
|
||||||
|
|
||||||
|
def test_missing_html_pages_render_friendly_not_found_page():
|
||||||
|
with make_test_client() as (client, _engine):
|
||||||
|
task_response = client.get("/tasks/missing-task")
|
||||||
|
hotspot_response = client.get("/hotspots/missing-hotspot/report")
|
||||||
|
item_response = client.get("/items/missing-item")
|
||||||
|
|
||||||
|
assert task_response.status_code == 404
|
||||||
|
assert "任务不存在" in task_response.text
|
||||||
|
assert "Internal Server Error" not in task_response.text
|
||||||
|
assert hotspot_response.status_code == 404
|
||||||
|
assert "热点不存在" in hotspot_response.text
|
||||||
|
assert "Internal Server Error" not in hotspot_response.text
|
||||||
|
assert item_response.status_code == 404
|
||||||
|
assert "内容条目不存在" in item_response.text
|
||||||
|
assert "Internal Server Error" not in item_response.text
|
||||||
|
|
||||||
|
|
||||||
def test_task_api_includes_progress_counts_stage_and_demo_flag():
|
def test_task_api_includes_progress_counts_stage_and_demo_flag():
|
||||||
with make_test_client() as (client, engine):
|
with make_test_client() as (client, engine):
|
||||||
seed_result_data(engine)
|
seed_result_data(engine)
|
||||||
|
|||||||
Reference in New Issue
Block a user