نسخهٔ وب مستقل — پلتفرم نیروی کار هوش مصنوعی
مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت. تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""§20 — list endpoints are paginated.
|
||||
|
||||
Every tenant-scoped list is unbounded in principle: an organization can create
|
||||
thousands of tasks. Without a page size the API would happily serialize all of
|
||||
them, so these tests pin the contract that a list is capped and that ``offset``
|
||||
walks the result set.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from httpx import AsyncClient
|
||||
|
||||
from tests.conftest import auth_header, signup
|
||||
|
||||
|
||||
# Fixtures resolve from conftest by name, so ``seeded`` needs no import here;
|
||||
# importing it would shadow this parameter (ruff F811) and read as unused (F401).
|
||||
@pytest_asyncio.fixture(autouse=True)
|
||||
async def _platform_seed(seeded):
|
||||
return seeded
|
||||
|
||||
|
||||
async def test_tasks_list_is_paginated(client: AsyncClient):
|
||||
token = (await signup(client, "page-tasks@example.com"))["access_token"]
|
||||
headers = auth_header(token)
|
||||
org_id = (
|
||||
await client.post("/api/organizations", json={"name": "سازمان صفحه"}, headers=headers)
|
||||
).json()["id"]
|
||||
|
||||
for index in range(5):
|
||||
created = await client.post(
|
||||
f"/api/organizations/{org_id}/tasks",
|
||||
json={"title": f"کار {index}"},
|
||||
headers=headers,
|
||||
)
|
||||
assert created.status_code == 201, created.text
|
||||
|
||||
page_one = await client.get(
|
||||
f"/api/organizations/{org_id}/tasks", params={"limit": 2}, headers=headers
|
||||
)
|
||||
assert page_one.status_code == 200, page_one.text
|
||||
assert len(page_one.json()) == 2, "limit must cap the page size"
|
||||
|
||||
page_two = await client.get(
|
||||
f"/api/organizations/{org_id}/tasks",
|
||||
params={"limit": 2, "offset": 2},
|
||||
headers=headers,
|
||||
)
|
||||
assert len(page_two.json()) == 2
|
||||
|
||||
# Pages must not overlap: offset walks the ordering rather than repeating it.
|
||||
ids_one = {t["id"] for t in page_one.json()}
|
||||
ids_two = {t["id"] for t in page_two.json()}
|
||||
assert not (ids_one & ids_two), "consecutive pages returned the same row"
|
||||
|
||||
everything = await client.get(
|
||||
f"/api/organizations/{org_id}/tasks", params={"limit": 500}, headers=headers
|
||||
)
|
||||
assert len(everything.json()) == 5
|
||||
|
||||
|
||||
@pytest.mark.parametrize("bad", [{"limit": 0}, {"limit": 501}, {"offset": -1}])
|
||||
async def test_out_of_range_pagination_is_rejected(client: AsyncClient, bad: dict):
|
||||
token = (await signup(client, f"page-bad-{abs(hash(str(bad))) % 10**6}@example.com"))[
|
||||
"access_token"
|
||||
]
|
||||
headers = auth_header(token)
|
||||
org_id = (
|
||||
await client.post(
|
||||
"/api/organizations", json={"name": "سازمان اعتبار"}, headers=headers
|
||||
)
|
||||
).json()["id"]
|
||||
|
||||
response = await client.get(
|
||||
f"/api/organizations/{org_id}/tasks", params=bad, headers=headers
|
||||
)
|
||||
assert response.status_code == 422, response.text
|
||||
|
||||
|
||||
async def test_projects_and_employees_accept_pagination(client: AsyncClient):
|
||||
"""The parameter is accepted consistently across the tenant-scoped lists."""
|
||||
token = (await signup(client, "page-multi@example.com"))["access_token"]
|
||||
headers = auth_header(token)
|
||||
org_id = (
|
||||
await client.post("/api/organizations", json={"name": "سازمان چندگانه"}, headers=headers)
|
||||
).json()["id"]
|
||||
|
||||
for path in ("projects", "employees", "threads", "tasks"):
|
||||
response = await client.get(
|
||||
f"/api/organizations/{org_id}/{path}",
|
||||
params={"limit": 10, "offset": 0},
|
||||
headers=headers,
|
||||
)
|
||||
assert response.status_code == 200, f"{path}: {response.text}"
|
||||
Reference in New Issue
Block a user