From 6f3c2fe97bd907509d4ef3c339117fcf07e8df10 Mon Sep 17 00:00:00 2001 From: GareArc Date: Tue, 5 May 2026 20:13:03 -0700 Subject: [PATCH] test(openapi): unit coverage for app payload helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit app_info_payload, parameters_payload, _EMPTY_PARAMETERS are CLI contracts. Direct unit tests pin their shape independent of DB + HTTP plumbing — drift in the helpers fails fast at unit-test time instead of leaking through into integration runs. --- .../controllers/openapi/test_app_payloads.py | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 api/tests/unit_tests/controllers/openapi/test_app_payloads.py diff --git a/api/tests/unit_tests/controllers/openapi/test_app_payloads.py b/api/tests/unit_tests/controllers/openapi/test_app_payloads.py new file mode 100644 index 0000000000..a952579608 --- /dev/null +++ b/api/tests/unit_tests/controllers/openapi/test_app_payloads.py @@ -0,0 +1,74 @@ +"""Unit tests for app payload-rendering helpers — independent of +HTTP plumbing or DB. Pin the response shapes that are CLI contracts. +""" + +from __future__ import annotations + +from types import SimpleNamespace + +import pytest + +from controllers.openapi.apps import ( # pyright: ignore[reportPrivateUsage] + _EMPTY_PARAMETERS, + app_info_payload, + parameters_payload, +) +from controllers.service_api.app.error import AppUnavailableError + + +def _fake_app(**overrides): + base = { + "id": "app1", + "name": "X", + "description": "d", + "mode": "chat", + "author_name": "alice", + "tags": [SimpleNamespace(name="prod")], + "updated_at": None, + "enable_api": True, + "workflow": None, + "app_model_config": None, + } + base.update(overrides) + return SimpleNamespace(**base) + + +def test_app_info_payload_shape(): + payload = app_info_payload(_fake_app()) + assert payload == { + "id": "app1", + "name": "X", + "description": "d", + "mode": "chat", + "author": "alice", + "tags": [{"name": "prod"}], + } + + +def test_app_info_payload_handles_missing_description_and_author(): + payload = app_info_payload(_fake_app(description=None, author_name=None)) + assert payload["description"] is None + assert payload["author"] is None + + +def test_parameters_payload_raises_app_unavailable_when_no_config(): + with pytest.raises(AppUnavailableError): + parameters_payload(_fake_app(mode="chat", app_model_config=None)) + + +def test_empty_parameters_constant_matches_describe_fallback_shape(): + """The fallback dict served by /describe when an app has no config + must match the spec's stated keys (opening_statement, suggested_questions, + user_input_form, file_upload, system_parameters).""" + assert set(_EMPTY_PARAMETERS.keys()) == { + "opening_statement", + "suggested_questions", + "user_input_form", + "file_upload", + "system_parameters", + } + assert _EMPTY_PARAMETERS["suggested_questions"] == [] + assert _EMPTY_PARAMETERS["user_input_form"] == [] + assert _EMPTY_PARAMETERS["opening_statement"] is None + assert _EMPTY_PARAMETERS["file_upload"] is None + assert _EMPTY_PARAMETERS["system_parameters"] == {}