This commit is contained in:
IvanShang 2026-08-15 09:17:15 +08:00 committed by GitHub
commit 11baa308de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 103 additions and 1 deletions

View File

@ -341,10 +341,12 @@ class PluginInvokeAppApi(Resource):
)
@with_session
def post(self, session: Session, user_model: Account | EndUser, tenant_model: Tenant, payload: RequestInvokeApp):
app_user_id = payload.user or getattr(user_model, "session_id", user_model.id)
response = PluginAppBackwardsInvocation.invoke_app(
session=session,
app_id=payload.app_id,
user_id=user_model.id,
user_id=app_user_id,
tenant_id=tenant_model.id,
conversation_id=payload.conversation_id,
query=payload.query,

View File

@ -8,6 +8,7 @@ handler tests use inspect.unwrap() to bypass them.
"""
import inspect
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
import pytest
@ -205,6 +206,78 @@ class TestPluginInvokeAppApi:
assert hasattr(api_instance, "post")
assert callable(api_instance.post)
@patch("controllers.inner_api.plugin.plugin.length_prefixed_response", return_value="stream-response")
@patch("controllers.inner_api.plugin.plugin.PluginAppBackwardsInvocation")
def test_post_uses_payload_user_for_app_user_id(self, mock_invocation, mock_response, api_instance, app: Flask):
mock_payload = SimpleNamespace(
app_id="app-1",
user="wecom-user",
conversation_id=None,
query="hello",
response_mode="blocking",
inputs={"x": 1},
files=[],
)
mock_user = SimpleNamespace(id="wrapper-user-id", session_id="wrapper-session")
mock_tenant = SimpleNamespace(id="tenant-1")
mock_session = MagicMock()
mock_invocation.invoke_app.return_value = {"ok": True}
mock_invocation.convert_to_event_stream.return_value = iter([b"{}"])
raw_post = _extract_raw_post(PluginInvokeAppApi)
result = raw_post(
api_instance, session=mock_session, user_model=mock_user, tenant_model=mock_tenant, payload=mock_payload
)
assert result == "stream-response"
mock_invocation.invoke_app.assert_called_once_with(
session=mock_session,
app_id="app-1",
user_id="wecom-user",
tenant_id="tenant-1",
conversation_id=None,
query="hello",
stream=False,
inputs={"x": 1},
files=[],
)
@patch("controllers.inner_api.plugin.plugin.length_prefixed_response", return_value="stream-response")
@patch("controllers.inner_api.plugin.plugin.PluginAppBackwardsInvocation")
def test_post_falls_back_to_wrapper_session_id(self, mock_invocation, mock_response, api_instance, app: Flask):
mock_payload = SimpleNamespace(
app_id="app-1",
user=None,
conversation_id="conv-1",
query="hello",
response_mode="streaming",
inputs={},
files=[],
)
mock_user = SimpleNamespace(id="wrapper-user-id", session_id="wrapper-session")
mock_tenant = SimpleNamespace(id="tenant-1")
mock_session = MagicMock()
mock_invocation.invoke_app.return_value = {"ok": True}
mock_invocation.convert_to_event_stream.return_value = iter([b"{}"])
raw_post = _extract_raw_post(PluginInvokeAppApi)
result = raw_post(
api_instance, session=mock_session, user_model=mock_user, tenant_model=mock_tenant, payload=mock_payload
)
assert result == "stream-response"
mock_invocation.invoke_app.assert_called_once_with(
session=mock_session,
app_id="app-1",
user_id="wrapper-session",
tenant_id="tenant-1",
conversation_id="conv-1",
query="hello",
stream=True,
inputs={},
files=[],
)
class TestPluginInvokeEncryptApi:
"""Test PluginInvokeEncryptApi endpoint structure and handler logic"""

View File

@ -211,6 +211,33 @@ class TestPluginAppBackwardsInvocation:
assert route.call_args.args[1] is workflow
assert route.call_args.args[2] is end_user
def test_invoke_app_creates_app_scoped_end_user_for_session_user(self, mocker: MockerFixture):
app = MagicMock(mode=AppMode.CHAT)
end_user = MagicMock(id="end-user", session_id="wecom-user")
mocker.patch.object(PluginAppBackwardsInvocation, "_get_app", return_value=app)
mocker.patch.object(PluginAppBackwardsInvocation, "_get_user", side_effect=ValueError("user not found"))
get_or_create = mocker.patch(
"core.plugin.backwards_invocation.app.EndUserService.get_or_create_end_user",
return_value=end_user,
)
route = mocker.patch.object(PluginAppBackwardsInvocation, "invoke_chat_app", return_value={"ok": True})
result = PluginAppBackwardsInvocation.invoke_app(
MagicMock(),
app_id="app",
user_id="wecom-user",
tenant_id="tenant",
conversation_id=None,
query="hello",
stream=False,
inputs={},
files=[],
)
assert result == {"ok": True}
get_or_create.assert_called_once_with(app, user_id="wecom-user")
assert route.call_args.args[2] is end_user
def test_invoke_app_missing_query_for_chat_raises(self, mocker: MockerFixture):
mocker.patch.object(PluginAppBackwardsInvocation, "_get_app", return_value=_app(mode=AppMode.CHAT))
mocker.patch.object(PluginAppBackwardsInvocation, "_get_user", return_value=_end_user())