Squash merge fix/enterprise-api-error-handling into release/e-1.12.1

This commit is contained in:
GareArc 2026-03-11 19:01:45 -07:00
parent d105a2f568
commit b4227b195e
No known key found for this signature in database
2 changed files with 107 additions and 0 deletions

View File

@ -28,6 +28,11 @@ class CheckCredentialPolicyComplianceRequest(BaseModel):
return data
class PreUninstallPluginRequest(BaseModel):
tenant_id: str
plugin_unique_identifier: str
class CredentialPolicyViolationError(BaseServiceError):
pass
@ -55,3 +60,19 @@ class PluginManagerService:
body.dify_credential_id,
ret.get("result", False),
)
@classmethod
def try_pre_uninstall_plugin(cls, body: PreUninstallPluginRequest):
try:
# the invocation must be synchronous.
EnterprisePluginManagerRequest.send_request(
"POST",
"/pre-uninstall-plugin",
json=body.model_dump(),
)
except Exception:
logger.exception(
"failed to perform pre uninstall plugin hook. tenant_id: %s, plugin_unique_identifier: %s",
body.tenant_id,
body.plugin_unique_identifier,
)

View File

@ -0,0 +1,86 @@
"""Unit tests for PluginManagerService.
This module covers the pre-uninstall plugin hook behavior:
- Successful API call: no exception raised, correct request sent
- API failure: soft-fail (logs and does not re-raise)
"""
from unittest.mock import patch
from httpx import HTTPStatusError
from services.enterprise.plugin_manager_service import (
PluginManagerService,
PreUninstallPluginRequest,
)
class TestTryPreUninstallPlugin:
def test_try_pre_uninstall_plugin_success(self):
body = PreUninstallPluginRequest(
tenant_id="tenant-123",
plugin_unique_identifier="com.example.my_plugin",
)
with patch(
"services.enterprise.plugin_manager_service.EnterprisePluginManagerRequest.send_request"
) as mock_send_request:
mock_send_request.return_value = {}
PluginManagerService.try_pre_uninstall_plugin(body)
mock_send_request.assert_called_once_with(
"POST",
"/pre-uninstall-plugin",
json={"tenant_id": "tenant-123", "plugin_unique_identifier": "com.example.my_plugin"},
)
def test_try_pre_uninstall_plugin_http_error_soft_fails(self):
body = PreUninstallPluginRequest(
tenant_id="tenant-456",
plugin_unique_identifier="com.example.other_plugin",
)
with (
patch(
"services.enterprise.plugin_manager_service.EnterprisePluginManagerRequest.send_request"
) as mock_send_request,
patch("services.enterprise.plugin_manager_service.logger") as mock_logger,
):
mock_send_request.side_effect = HTTPStatusError(
"502 Bad Gateway",
request=None,
response=None,
)
PluginManagerService.try_pre_uninstall_plugin(body)
mock_send_request.assert_called_once_with(
"POST",
"/pre-uninstall-plugin",
json={"tenant_id": "tenant-456", "plugin_unique_identifier": "com.example.other_plugin"},
)
mock_logger.exception.assert_called_once()
def test_try_pre_uninstall_plugin_generic_exception_soft_fails(self):
body = PreUninstallPluginRequest(
tenant_id="tenant-789",
plugin_unique_identifier="com.example.failing_plugin",
)
with (
patch(
"services.enterprise.plugin_manager_service.EnterprisePluginManagerRequest.send_request"
) as mock_send_request,
patch("services.enterprise.plugin_manager_service.logger") as mock_logger,
):
mock_send_request.side_effect = ConnectionError("network unreachable")
PluginManagerService.try_pre_uninstall_plugin(body)
mock_send_request.assert_called_once_with(
"POST",
"/pre-uninstall-plugin",
json={"tenant_id": "tenant-789", "plugin_unique_identifier": "com.example.failing_plugin"},
)
mock_logger.exception.assert_called_once()