Files
dify/api/tests/unit_tests/controllers/openapi/test_pagination_envelope.py
2026-05-13 12:56:42 +08:00

141 lines
4.1 KiB
Python

"""Unit tests for PaginationEnvelope generic Pydantic model."""
from __future__ import annotations
from pydantic import BaseModel
from controllers.openapi._models import PaginationEnvelope
class _Row(BaseModel):
id: str
name: str
def test_envelope_basic_fields():
env = PaginationEnvelope[_Row](page=1, limit=20, total=42, has_more=True, data=[_Row(id="a", name="A")])
dumped = env.model_dump(mode="json")
assert dumped == {
"page": 1,
"limit": 20,
"total": 42,
"has_more": True,
"data": [{"id": "a", "name": "A"}],
}
def test_envelope_empty_data_no_more():
env = PaginationEnvelope[_Row](page=1, limit=20, total=0, has_more=False, data=[])
assert env.model_dump(mode="json")["data"] == []
assert env.model_dump(mode="json")["has_more"] is False
def test_envelope_has_more_true_when_total_exceeds_page_window():
env = PaginationEnvelope[_Row].build(page=1, limit=20, total=42, items=[_Row(id="a", name="A")])
assert env.has_more is True
def test_envelope_has_more_false_when_total_within_page_window():
env = PaginationEnvelope[_Row].build(page=2, limit=20, total=22, items=[_Row(id="a", name="A")])
assert env.has_more is False
def test_envelope_has_more_false_for_last_page():
env = PaginationEnvelope[_Row].build(page=3, limit=20, total=42, items=[_Row(id="a", name="A")])
assert env.has_more is False
def test_max_page_limit_is_200():
from controllers.openapi._models import MAX_PAGE_LIMIT
assert MAX_PAGE_LIMIT == 200
def test_envelope_uses_pep695_generics():
"""Verify the class uses PEP 695 native generic syntax (not legacy Generic[T])."""
from controllers.openapi._models import PaginationEnvelope
# PEP 695 syntax populates __type_params__; the legacy Generic[T] form does not.
assert PaginationEnvelope.__type_params__, "expected PEP 695 native generic syntax"
fields = PaginationEnvelope.model_fields
assert {"page", "limit", "total", "has_more", "data"} <= set(fields)
def test_app_info_response_dump_matches_spec():
from controllers.openapi._models import AppInfoResponse
obj = AppInfoResponse(
id="app1",
name="X",
description="d",
mode="chat",
author="alice",
tags=[{"name": "prod"}],
)
assert obj.model_dump(mode="json") == {
"id": "app1",
"name": "X",
"description": "d",
"mode": "chat",
"author": "alice",
"tags": [{"name": "prod"}],
}
def test_app_describe_response_nests_info_and_parameters():
from controllers.openapi._models import AppDescribeInfo, AppDescribeResponse
info = AppDescribeInfo(
id="app1",
name="X",
mode="chat",
description=None,
tags=[],
author=None,
updated_at="2026-05-05T00:00:00+00:00",
service_api_enabled=True,
)
obj = AppDescribeResponse(info=info, parameters={"opening_statement": None})
dumped = obj.model_dump(mode="json")
assert dumped["info"]["service_api_enabled"] is True
assert dumped["parameters"]["opening_statement"] is None
def test_response_models_dump_per_mode():
from controllers.openapi._models import (
ChatMessageResponse,
CompletionMessageResponse,
WorkflowRunData,
WorkflowRunResponse,
)
chat = ChatMessageResponse(
event="message",
task_id="t1",
id="m1",
message_id="m1",
conversation_id="c1",
mode="chat",
answer="hi",
created_at=0,
)
assert chat.model_dump(mode="json")["mode"] == "chat"
wf = WorkflowRunResponse(
workflow_run_id="r1",
task_id="t1",
data=WorkflowRunData(id="r1", workflow_id="w1", status="succeeded"),
)
assert wf.model_dump(mode="json")["data"]["status"] == "succeeded"
assert wf.model_dump(mode="json")["mode"] == "workflow"
comp = CompletionMessageResponse(
event="message",
task_id="t2",
id="m2",
message_id="m2",
mode="completion",
answer="ok",
created_at=0,
)
assert comp.model_dump(mode="json")["mode"] == "completion"