知识列表拿游标做 keyset 分页时写成了 `cur.item_id`,而 `Cursor` 只有 `created_at` 和 `id` 两个字段——属性不存在,直接 AttributeError, 前端只看到"服务器内部错误"。 库里不足一页(默认 30 条)时永远走不到这条分支,所以一直没暴露; 旧备忘导进来 84 条之后,用户点「加载更多」就撞上了。 补一条回归用例:造 25 条、每页 10 条翻到底,断言不重不漏、末页游标为空。
This commit is contained in:
@@ -328,7 +328,7 @@ async def list_knowledge(
|
|||||||
stmt = stmt.where(
|
stmt = stmt.where(
|
||||||
or_(
|
or_(
|
||||||
Item.updated_at < cur.created_at,
|
Item.updated_at < cur.created_at,
|
||||||
and_(Item.updated_at == cur.created_at, Item.id < cur.item_id),
|
and_(Item.updated_at == cur.created_at, Item.id < cur.id),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -381,3 +381,45 @@ async def test_draft_timeline_reads_like_a_story(client: AsyncClient) -> None:
|
|||||||
body = doc["body_md"]
|
body = doc["body_md"]
|
||||||
assert "待办 → 进行中" in body
|
assert "待办 → 进行中" in body
|
||||||
assert "进行中 → 已完成" in body
|
assert "进行中 → 已完成" in body
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_list_pages_through_every_document(client: AsyncClient) -> None:
|
||||||
|
"""翻页要能翻到底,且不重不漏。
|
||||||
|
|
||||||
|
这条用例是有来历的:知识列表的游标解出来是 `Cursor(created_at, id)`,
|
||||||
|
查询里却写成了 `cur.item_id`——属性不存在,第二页必 500。
|
||||||
|
库小于一页(默认 30 条)时永远走不到这条路径,所以一直没暴露,
|
||||||
|
直到把旧备忘导进来 84 条,用户点「加载更多」就看到"服务器内部错误"。
|
||||||
|
"""
|
||||||
|
owner = await login(client)
|
||||||
|
ws = await create_workspace(client, owner, "翻页")
|
||||||
|
titles = [f"备忘 {i:02d}" for i in range(25)]
|
||||||
|
for title in titles:
|
||||||
|
unwrap(
|
||||||
|
await client.post(
|
||||||
|
f"{V1}/workspaces/{ws['id']}/knowledge",
|
||||||
|
json={"title": title},
|
||||||
|
headers=owner["headers"],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
seen: list[str] = []
|
||||||
|
cursor: str | None = None
|
||||||
|
for _ in range(10): # 25 条 / 每页 10 条,三轮就该到底,多留几次余地
|
||||||
|
params: dict[str, Any] = {"limit": 10}
|
||||||
|
if cursor:
|
||||||
|
params["cursor"] = cursor
|
||||||
|
page = unwrap(
|
||||||
|
await client.get(
|
||||||
|
f"{V1}/workspaces/{ws['id']}/knowledge", params=params, headers=owner["headers"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
seen.extend(i["title"] for i in page["items"])
|
||||||
|
cursor = page["next_cursor"]
|
||||||
|
if not page["has_more"] or not cursor:
|
||||||
|
break
|
||||||
|
|
||||||
|
assert cursor is None
|
||||||
|
assert sorted(seen) == titles
|
||||||
|
assert len(seen) == len(set(seen)), "翻页翻出了重复条目"
|
||||||
|
|||||||
Reference in New Issue
Block a user