Merge remote-tracking branch 'origin/main' into feat/rbac

This commit is contained in:
Charles Yao
2026-05-12 05:31:09 +00:00
2214 changed files with 130819 additions and 51511 deletions

View File

@ -1,6 +1,8 @@
from unittest.mock import MagicMock, PropertyMock, patch
import pytest
from flask import Flask
from werkzeug.exceptions import NotFound
from controllers.console import console_ns
from controllers.console.auth.error import (
@ -29,6 +31,7 @@ from controllers.console.workspace.error import (
CurrentPasswordIncorrectError,
InvalidAccountDeletionCodeError,
)
from models.enums import CreatorUserRole
from services.errors.account import CurrentPasswordIncorrectError as ServicePwdError
@ -39,7 +42,7 @@ def unwrap(func):
class TestAccountInitApi:
def test_init_success(self, app):
def test_init_success(self, app: Flask):
api = AccountInitApi()
method = unwrap(api.post)
@ -62,7 +65,7 @@ class TestAccountInitApi:
assert resp["result"] == "success"
def test_init_already_initialized(self, app):
def test_init_already_initialized(self, app: Flask):
api = AccountInitApi()
method = unwrap(api.post)
@ -77,7 +80,7 @@ class TestAccountInitApi:
class TestAccountProfileApi:
def test_get_profile_success(self, app):
def test_get_profile_success(self, app: Flask):
api = AccountProfileApi()
method = unwrap(api.get)
@ -135,8 +138,133 @@ class TestAccountUpdateApis:
assert result["id"] == "u1"
class TestAccountAvatarApiGet:
"""GET /account/avatar must not sign arbitrary upload_file IDs (IDOR)."""
def test_get_avatar_signed_url_when_upload_owned_by_current_account(self, app: Flask):
api = AccountAvatarApi()
method = unwrap(api.get)
user = MagicMock()
user.id = "acc-owner"
tenant_id = "tenant-1"
file_id = "550e8400-e29b-41d4-a716-446655440000"
upload_file = MagicMock()
upload_file.id = file_id
upload_file.tenant_id = tenant_id
upload_file.created_by = user.id
upload_file.created_by_role = CreatorUserRole.ACCOUNT
with (
app.test_request_context(f"/account/avatar?avatar={file_id}"),
patch(
"controllers.console.workspace.account.current_account_with_tenant",
return_value=(user, tenant_id),
),
patch("controllers.console.workspace.account.db.session.scalar", return_value=upload_file),
patch(
"controllers.console.workspace.account.file_helpers.get_signed_file_url",
return_value="https://signed/example",
) as sign_mock,
):
result = method(api)
assert result == {"avatar_url": "https://signed/example"}
sign_mock.assert_called_once_with(upload_file_id=file_id)
def test_get_avatar_not_found_when_upload_created_by_other_account_same_tenant(self, app: Flask):
api = AccountAvatarApi()
method = unwrap(api.get)
user = MagicMock()
user.id = "acc-a"
tenant_id = "tenant-1"
file_id = "550e8400-e29b-41d4-a716-446655440001"
upload_file = MagicMock()
upload_file.id = file_id
upload_file.tenant_id = tenant_id
upload_file.created_by = "acc-b"
upload_file.created_by_role = CreatorUserRole.ACCOUNT
with (
app.test_request_context(f"/account/avatar?avatar={file_id}"),
patch(
"controllers.console.workspace.account.current_account_with_tenant",
return_value=(user, tenant_id),
),
patch("controllers.console.workspace.account.db.session.scalar", return_value=upload_file),
patch(
"controllers.console.workspace.account.file_helpers.get_signed_file_url",
return_value="https://signed/leak",
) as sign_mock,
):
with pytest.raises(NotFound):
method(api)
sign_mock.assert_not_called()
def test_get_avatar_not_found_when_upload_belongs_to_other_tenant(self, app: Flask):
api = AccountAvatarApi()
method = unwrap(api.get)
user = MagicMock()
user.id = "acc-owner"
tenant_id = "tenant-1"
file_id = "550e8400-e29b-41d4-a716-446655440002"
upload_file = MagicMock()
upload_file.id = file_id
upload_file.tenant_id = "tenant-other"
upload_file.created_by = user.id
upload_file.created_by_role = CreatorUserRole.ACCOUNT
with (
app.test_request_context(f"/account/avatar?avatar={file_id}"),
patch(
"controllers.console.workspace.account.current_account_with_tenant",
return_value=(user, tenant_id),
),
patch("controllers.console.workspace.account.db.session.scalar", return_value=upload_file),
patch(
"controllers.console.workspace.account.file_helpers.get_signed_file_url",
return_value="https://signed/leak",
) as sign_mock,
):
with pytest.raises(NotFound):
method(api)
sign_mock.assert_not_called()
def test_get_avatar_https_pass_through_without_signing(self, app: Flask):
api = AccountAvatarApi()
method = unwrap(api.get)
user = MagicMock()
user.id = "acc-owner"
tenant_id = "tenant-1"
external = "https://cdn.example/avatar.png"
with (
app.test_request_context(f"/account/avatar?avatar={external}"),
patch(
"controllers.console.workspace.account.current_account_with_tenant",
return_value=(user, tenant_id),
),
patch(
"controllers.console.workspace.account.file_helpers.get_signed_file_url",
return_value="https://signed/should-not-use",
) as sign_mock,
):
result = method(api)
assert result == {"avatar_url": external}
sign_mock.assert_not_called()
class TestAccountPasswordApi:
def test_password_success(self, app):
def test_password_success(self, app: Flask):
api = AccountPasswordApi()
method = unwrap(api.post)
@ -165,7 +293,7 @@ class TestAccountPasswordApi:
assert result["id"] == "u1"
def test_password_wrong_current(self, app):
def test_password_wrong_current(self, app: Flask):
api = AccountPasswordApi()
method = unwrap(api.post)
@ -190,7 +318,7 @@ class TestAccountPasswordApi:
class TestAccountIntegrateApi:
def test_get_integrates(self, app):
def test_get_integrates(self, app: Flask):
api = AccountIntegrateApi()
method = unwrap(api.get)
@ -209,7 +337,7 @@ class TestAccountIntegrateApi:
class TestAccountDeleteApi:
def test_delete_verify_success(self, app):
def test_delete_verify_success(self, app: Flask):
api = AccountDeleteVerifyApi()
method = unwrap(api.get)
@ -231,7 +359,7 @@ class TestAccountDeleteApi:
assert result["result"] == "success"
def test_delete_invalid_code(self, app):
def test_delete_invalid_code(self, app: Flask):
api = AccountDeleteApi()
method = unwrap(api.post)
@ -252,7 +380,7 @@ class TestAccountDeleteApi:
class TestChangeEmailApis:
def test_check_email_code_invalid(self, app):
def test_check_email_code_invalid(self, app: Flask):
api = ChangeEmailCheckApi()
method = unwrap(api.post)
@ -278,7 +406,7 @@ class TestChangeEmailApis:
with pytest.raises(EmailCodeError):
method(api)
def test_reset_email_already_used(self, app):
def test_reset_email_already_used(self, app: Flask):
api = ChangeEmailResetApi()
method = unwrap(api.post)
@ -300,7 +428,7 @@ class TestChangeEmailApis:
class TestCheckEmailUniqueApi:
def test_email_unique_success(self, app):
def test_email_unique_success(self, app: Flask):
api = CheckEmailUnique()
method = unwrap(api.post)
@ -321,7 +449,7 @@ class TestCheckEmailUniqueApi:
assert result["result"] == "success"
def test_email_in_freeze(self, app):
def test_email_in_freeze(self, app: Flask):
api = CheckEmailUnique()
method = unwrap(api.post)

View File

@ -1,6 +1,7 @@
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from controllers.console.error import AccountNotFound
from controllers.console.workspace.agent_providers import (
@ -16,7 +17,7 @@ def unwrap(func):
class TestAgentProviderListApi:
def test_get_success(self, app):
def test_get_success(self, app: Flask):
api = AgentProviderListApi()
method = unwrap(api.get)
@ -39,7 +40,7 @@ class TestAgentProviderListApi:
assert result == providers
def test_get_empty_list(self, app):
def test_get_empty_list(self, app: Flask):
api = AgentProviderListApi()
method = unwrap(api.get)
@ -61,7 +62,7 @@ class TestAgentProviderListApi:
assert result == []
def test_get_account_not_found(self, app):
def test_get_account_not_found(self, app: Flask):
api = AgentProviderListApi()
method = unwrap(api.get)
@ -77,7 +78,7 @@ class TestAgentProviderListApi:
class TestAgentProviderApi:
def test_get_success(self, app):
def test_get_success(self, app: Flask):
api = AgentProviderApi()
method = unwrap(api.get)
@ -101,7 +102,7 @@ class TestAgentProviderApi:
assert result == provider_data
def test_get_provider_not_found(self, app):
def test_get_provider_not_found(self, app: Flask):
api = AgentProviderApi()
method = unwrap(api.get)
@ -124,7 +125,7 @@ class TestAgentProviderApi:
assert result is None
def test_get_account_not_found(self, app):
def test_get_account_not_found(self, app: Flask):
api = AgentProviderApi()
method = unwrap(api.get)

View File

@ -1,6 +1,7 @@
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from controllers.console import console_ns
from controllers.console.workspace.endpoint import (
@ -39,7 +40,7 @@ def patch_current_account(user_and_tenant):
@pytest.mark.usefixtures("patch_current_account")
class TestEndpointCollectionApi:
def test_create_success(self, app):
def test_create_success(self, app: Flask):
api = EndpointCollectionApi()
method = unwrap(api.post)
@ -57,7 +58,7 @@ class TestEndpointCollectionApi:
assert result["success"] is True
def test_create_permission_denied(self, app):
def test_create_permission_denied(self, app: Flask):
api = EndpointCollectionApi()
method = unwrap(api.post)
@ -77,7 +78,7 @@ class TestEndpointCollectionApi:
with pytest.raises(ValueError):
method(api)
def test_create_validation_error(self, app):
def test_create_validation_error(self, app: Flask):
api = EndpointCollectionApi()
method = unwrap(api.post)
@ -96,7 +97,7 @@ class TestEndpointCollectionApi:
@pytest.mark.usefixtures("patch_current_account")
class TestDeprecatedEndpointCreateApi:
def test_create_success(self, app):
def test_create_success(self, app: Flask):
api = DeprecatedEndpointCreateApi()
method = unwrap(api.post)
@ -117,7 +118,7 @@ class TestDeprecatedEndpointCreateApi:
@pytest.mark.usefixtures("patch_current_account")
class TestEndpointListApi:
def test_list_success(self, app):
def test_list_success(self, app: Flask):
api = EndpointListApi()
method = unwrap(api.get)
@ -130,7 +131,7 @@ class TestEndpointListApi:
assert "endpoints" in result
assert len(result["endpoints"]) == 1
def test_list_invalid_query(self, app):
def test_list_invalid_query(self, app: Flask):
api = EndpointListApi()
method = unwrap(api.get)
@ -143,7 +144,7 @@ class TestEndpointListApi:
@pytest.mark.usefixtures("patch_current_account")
class TestEndpointListForSinglePluginApi:
def test_list_for_plugin_success(self, app):
def test_list_for_plugin_success(self, app: Flask):
api = EndpointListForSinglePluginApi()
method = unwrap(api.get)
@ -158,7 +159,7 @@ class TestEndpointListForSinglePluginApi:
assert "endpoints" in result
def test_list_for_plugin_missing_param(self, app):
def test_list_for_plugin_missing_param(self, app: Flask):
api = EndpointListForSinglePluginApi()
method = unwrap(api.get)
@ -171,7 +172,7 @@ class TestEndpointListForSinglePluginApi:
@pytest.mark.usefixtures("patch_current_account")
class TestEndpointItemApi:
def test_delete_success(self, app):
def test_delete_success(self, app: Flask):
api = EndpointItemApi()
method = unwrap(api.delete)
@ -187,7 +188,7 @@ class TestEndpointItemApi:
assert result["success"] is True
mock_delete.assert_called_once_with(tenant_id="t1", user_id="u1", endpoint_id="e1")
def test_delete_service_failure(self, app):
def test_delete_service_failure(self, app: Flask):
api = EndpointItemApi()
method = unwrap(api.delete)
@ -199,7 +200,7 @@ class TestEndpointItemApi:
assert result["success"] is False
def test_update_success(self, app):
def test_update_success(self, app: Flask):
api = EndpointItemApi()
method = unwrap(api.patch)
@ -226,7 +227,7 @@ class TestEndpointItemApi:
settings={"x": 1},
)
def test_update_validation_error(self, app):
def test_update_validation_error(self, app: Flask):
api = EndpointItemApi()
method = unwrap(api.patch)
@ -238,7 +239,7 @@ class TestEndpointItemApi:
with pytest.raises(ValueError):
method(api, "e1")
def test_update_service_failure(self, app):
def test_update_service_failure(self, app: Flask):
api = EndpointItemApi()
method = unwrap(api.patch)
@ -258,7 +259,7 @@ class TestEndpointItemApi:
@pytest.mark.usefixtures("patch_current_account")
class TestDeprecatedEndpointDeleteApi:
def test_delete_success(self, app):
def test_delete_success(self, app: Flask):
api = DeprecatedEndpointDeleteApi()
method = unwrap(api.post)
@ -272,7 +273,7 @@ class TestDeprecatedEndpointDeleteApi:
assert result["success"] is True
def test_delete_invalid_payload(self, app):
def test_delete_invalid_payload(self, app: Flask):
api = DeprecatedEndpointDeleteApi()
method = unwrap(api.post)
@ -282,7 +283,7 @@ class TestDeprecatedEndpointDeleteApi:
with pytest.raises(ValueError):
method(api)
def test_delete_service_failure(self, app):
def test_delete_service_failure(self, app: Flask):
api = DeprecatedEndpointDeleteApi()
method = unwrap(api.post)
@ -299,7 +300,7 @@ class TestDeprecatedEndpointDeleteApi:
@pytest.mark.usefixtures("patch_current_account")
class TestDeprecatedEndpointUpdateApi:
def test_update_success(self, app):
def test_update_success(self, app: Flask):
api = DeprecatedEndpointUpdateApi()
method = unwrap(api.post)
@ -317,7 +318,7 @@ class TestDeprecatedEndpointUpdateApi:
assert result["success"] is True
def test_update_validation_error(self, app):
def test_update_validation_error(self, app: Flask):
api = DeprecatedEndpointUpdateApi()
method = unwrap(api.post)
@ -329,7 +330,7 @@ class TestDeprecatedEndpointUpdateApi:
with pytest.raises(ValueError):
method(api)
def test_update_service_failure(self, app):
def test_update_service_failure(self, app: Flask):
api = DeprecatedEndpointUpdateApi()
method = unwrap(api.post)
@ -380,7 +381,7 @@ class TestEndpointRouteMetadata:
@pytest.mark.usefixtures("patch_current_account")
class TestEndpointEnableApi:
def test_enable_success(self, app):
def test_enable_success(self, app: Flask):
api = EndpointEnableApi()
method = unwrap(api.post)
@ -394,7 +395,7 @@ class TestEndpointEnableApi:
assert result["success"] is True
def test_enable_invalid_payload(self, app):
def test_enable_invalid_payload(self, app: Flask):
api = EndpointEnableApi()
method = unwrap(api.post)
@ -404,7 +405,7 @@ class TestEndpointEnableApi:
with pytest.raises(ValueError):
method(api)
def test_enable_service_failure(self, app):
def test_enable_service_failure(self, app: Flask):
api = EndpointEnableApi()
method = unwrap(api.post)
@ -421,7 +422,7 @@ class TestEndpointEnableApi:
@pytest.mark.usefixtures("patch_current_account")
class TestEndpointDisableApi:
def test_disable_success(self, app):
def test_disable_success(self, app: Flask):
api = EndpointDisableApi()
method = unwrap(api.post)
@ -435,7 +436,7 @@ class TestEndpointDisableApi:
assert result["success"] is True
def test_disable_invalid_payload(self, app):
def test_disable_invalid_payload(self, app: Flask):
api = EndpointDisableApi()
method = unwrap(api.post)

View File

@ -2,6 +2,7 @@ from types import SimpleNamespace
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from werkzeug.exceptions import HTTPException
import services
@ -35,7 +36,7 @@ def unwrap(func):
class TestMemberListApi:
def test_get_success(self, app):
def test_get_success(self, app: Flask):
api = MemberListApi()
method = unwrap(api.get)
@ -107,7 +108,7 @@ class TestMemberListApi:
]
mock_batch_get.assert_called_once_with("tenant-1", "acct-1", ["m1"])
def test_get_no_tenant(self, app):
def test_get_no_tenant(self, app: Flask):
api = MemberListApi()
method = unwrap(api.get)
@ -122,7 +123,7 @@ class TestMemberListApi:
class TestMemberInviteEmailApi:
def test_invite_success(self, app):
def test_invite_success(self, app: Flask):
api = MemberInviteEmailApi()
method = unwrap(api.post)
@ -149,7 +150,7 @@ class TestMemberInviteEmailApi:
assert status == 201
assert result["result"] == "success"
def test_invite_limit_exceeded(self, app):
def test_invite_limit_exceeded(self, app: Flask):
api = MemberInviteEmailApi()
method = unwrap(api.post)
@ -171,7 +172,7 @@ class TestMemberInviteEmailApi:
with pytest.raises(WorkspaceMembersLimitExceeded):
method(api)
def test_invite_already_member(self, app):
def test_invite_already_member(self, app: Flask):
api = MemberInviteEmailApi()
method = unwrap(api.post)
@ -199,7 +200,7 @@ class TestMemberInviteEmailApi:
assert result["invitation_results"][0]["status"] == "success"
def test_invite_invalid_role(self, app):
def test_invite_invalid_role(self, app: Flask):
api = MemberInviteEmailApi()
method = unwrap(api.post)
@ -214,7 +215,7 @@ class TestMemberInviteEmailApi:
assert status == 400
assert result["code"] == "invalid-role"
def test_invite_generic_exception(self, app):
def test_invite_generic_exception(self, app: Flask):
api = MemberInviteEmailApi()
method = unwrap(api.post)
@ -244,7 +245,7 @@ class TestMemberInviteEmailApi:
class TestMemberCancelInviteApi:
def test_cancel_success(self, app):
def test_cancel_success(self, app: Flask):
api = MemberCancelInviteApi()
method = unwrap(api.delete)
@ -264,7 +265,7 @@ class TestMemberCancelInviteApi:
assert status == 200
assert result["result"] == "success"
def test_cancel_not_found(self, app):
def test_cancel_not_found(self, app: Flask):
api = MemberCancelInviteApi()
method = unwrap(api.delete)
@ -281,7 +282,7 @@ class TestMemberCancelInviteApi:
with pytest.raises(HTTPException):
method(api, "x")
def test_cancel_cannot_operate_self(self, app):
def test_cancel_cannot_operate_self(self, app: Flask):
api = MemberCancelInviteApi()
method = unwrap(api.delete)
@ -303,7 +304,7 @@ class TestMemberCancelInviteApi:
assert status == 400
def test_cancel_no_permission(self, app):
def test_cancel_no_permission(self, app: Flask):
api = MemberCancelInviteApi()
method = unwrap(api.delete)
@ -325,7 +326,7 @@ class TestMemberCancelInviteApi:
assert status == 403
def test_cancel_member_not_in_tenant(self, app):
def test_cancel_member_not_in_tenant(self, app: Flask):
api = MemberCancelInviteApi()
method = unwrap(api.delete)
@ -349,7 +350,7 @@ class TestMemberCancelInviteApi:
class TestMemberUpdateRoleApi:
def test_update_success(self, app):
def test_update_success(self, app: Flask):
api = MemberUpdateRoleApi()
method = unwrap(api.put)
@ -372,7 +373,7 @@ class TestMemberUpdateRoleApi:
assert result["result"] == "success"
def test_update_invalid_role(self, app):
def test_update_invalid_role(self, app: Flask):
api = MemberUpdateRoleApi()
method = unwrap(api.put)
@ -383,7 +384,7 @@ class TestMemberUpdateRoleApi:
assert status == 400
def test_update_member_not_found(self, app):
def test_update_member_not_found(self, app: Flask):
api = MemberUpdateRoleApi()
method = unwrap(api.put)
@ -402,7 +403,7 @@ class TestMemberUpdateRoleApi:
class TestDatasetOperatorMemberListApi:
def test_get_success(self, app):
def test_get_success(self, app: Flask):
api = DatasetOperatorMemberListApi()
method = unwrap(api.get)
@ -429,7 +430,7 @@ class TestDatasetOperatorMemberListApi:
assert status == 200
assert len(result["accounts"]) == 1
def test_get_no_tenant(self, app):
def test_get_no_tenant(self, app: Flask):
api = DatasetOperatorMemberListApi()
method = unwrap(api.get)
@ -444,7 +445,7 @@ class TestDatasetOperatorMemberListApi:
class TestSendOwnerTransferEmailApi:
def test_send_success(self, app):
def test_send_success(self, app: Flask):
api = SendOwnerTransferEmailApi()
method = unwrap(api.post)
@ -467,7 +468,7 @@ class TestSendOwnerTransferEmailApi:
assert result["result"] == "success"
def test_send_ip_limit(self, app):
def test_send_ip_limit(self, app: Flask):
api = SendOwnerTransferEmailApi()
method = unwrap(api.post)
@ -481,7 +482,7 @@ class TestSendOwnerTransferEmailApi:
with pytest.raises(EmailSendIpLimitError):
method(api)
def test_send_not_owner(self, app):
def test_send_not_owner(self, app: Flask):
api = SendOwnerTransferEmailApi()
method = unwrap(api.post)
@ -500,7 +501,7 @@ class TestSendOwnerTransferEmailApi:
class TestOwnerTransferCheckApi:
def test_check_invalid_code(self, app):
def test_check_invalid_code(self, app: Flask):
api = OwnerTransferCheckApi()
method = unwrap(api.post)
@ -525,7 +526,7 @@ class TestOwnerTransferCheckApi:
with pytest.raises(EmailCodeError):
method(api)
def test_rate_limited(self, app):
def test_rate_limited(self, app: Flask):
api = OwnerTransferCheckApi()
method = unwrap(api.post)
@ -546,7 +547,7 @@ class TestOwnerTransferCheckApi:
with pytest.raises(OwnerTransferLimitError):
method(api)
def test_invalid_token(self, app):
def test_invalid_token(self, app: Flask):
api = OwnerTransferCheckApi()
method = unwrap(api.post)
@ -568,7 +569,7 @@ class TestOwnerTransferCheckApi:
with pytest.raises(InvalidTokenError):
method(api)
def test_invalid_email(self, app):
def test_invalid_email(self, app: Flask):
api = OwnerTransferCheckApi()
method = unwrap(api.post)
@ -595,7 +596,7 @@ class TestOwnerTransferCheckApi:
class TestOwnerTransferApi:
def test_transfer_self(self, app):
def test_transfer_self(self, app: Flask):
api = OwnerTransfer()
method = unwrap(api.post)
@ -612,7 +613,7 @@ class TestOwnerTransferApi:
with pytest.raises(CannotTransferOwnerToSelfError):
method(api, "1")
def test_invalid_token(self, app):
def test_invalid_token(self, app: Flask):
api = OwnerTransfer()
method = unwrap(api.post)
@ -630,7 +631,7 @@ class TestOwnerTransferApi:
with pytest.raises(InvalidTokenError):
method(api, "2")
def test_member_not_in_tenant(self, app):
def test_member_not_in_tenant(self, app: Flask):
api = OwnerTransfer()
method = unwrap(api.post)

View File

@ -1,6 +1,7 @@
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from pydantic_core import ValidationError
from werkzeug.exceptions import Forbidden
@ -26,7 +27,7 @@ def unwrap(func):
class TestModelProviderListApi:
def test_get_success(self, app):
def test_get_success(self, app: Flask):
api = ModelProviderListApi()
method = unwrap(api.get)
@ -47,7 +48,7 @@ class TestModelProviderListApi:
class TestModelProviderCredentialApi:
def test_get_success(self, app):
def test_get_success(self, app: Flask):
api = ModelProviderCredentialApi()
method = unwrap(api.get)
@ -66,7 +67,7 @@ class TestModelProviderCredentialApi:
assert "credentials" in result
def test_get_invalid_uuid(self, app):
def test_get_invalid_uuid(self, app: Flask):
api = ModelProviderCredentialApi()
method = unwrap(api.get)
@ -80,7 +81,7 @@ class TestModelProviderCredentialApi:
with pytest.raises(ValidationError):
method(api, provider="openai")
def test_post_create_success(self, app):
def test_post_create_success(self, app: Flask):
api = ModelProviderCredentialApi()
method = unwrap(api.post)
@ -102,7 +103,7 @@ class TestModelProviderCredentialApi:
assert result["result"] == "success"
assert status == 201
def test_post_create_validation_error(self, app):
def test_post_create_validation_error(self, app: Flask):
api = ModelProviderCredentialApi()
method = unwrap(api.post)
@ -122,7 +123,7 @@ class TestModelProviderCredentialApi:
with pytest.raises(ValueError):
method(api, provider="openai")
def test_put_update_success(self, app):
def test_put_update_success(self, app: Flask):
api = ModelProviderCredentialApi()
method = unwrap(api.put)
@ -143,7 +144,7 @@ class TestModelProviderCredentialApi:
assert result["result"] == "success"
def test_put_invalid_uuid(self, app):
def test_put_invalid_uuid(self, app: Flask):
api = ModelProviderCredentialApi()
method = unwrap(api.put)
@ -159,7 +160,7 @@ class TestModelProviderCredentialApi:
with pytest.raises(ValidationError):
method(api, provider="openai")
def test_delete_success(self, app):
def test_delete_success(self, app: Flask):
api = ModelProviderCredentialApi()
method = unwrap(api.delete)
@ -183,7 +184,7 @@ class TestModelProviderCredentialApi:
class TestModelProviderCredentialSwitchApi:
def test_switch_success(self, app):
def test_switch_success(self, app: Flask):
api = ModelProviderCredentialSwitchApi()
method = unwrap(api.post)
@ -204,7 +205,7 @@ class TestModelProviderCredentialSwitchApi:
assert result["result"] == "success"
def test_switch_invalid_uuid(self, app):
def test_switch_invalid_uuid(self, app: Flask):
api = ModelProviderCredentialSwitchApi()
method = unwrap(api.post)
@ -222,7 +223,7 @@ class TestModelProviderCredentialSwitchApi:
class TestModelProviderValidateApi:
def test_validate_success(self, app):
def test_validate_success(self, app: Flask):
api = ModelProviderValidateApi()
method = unwrap(api.post)
@ -243,7 +244,7 @@ class TestModelProviderValidateApi:
assert result["result"] == "success"
def test_validate_failure(self, app):
def test_validate_failure(self, app: Flask):
api = ModelProviderValidateApi()
method = unwrap(api.post)
@ -266,7 +267,7 @@ class TestModelProviderValidateApi:
class TestModelProviderIconApi:
def test_icon_success(self, app):
def test_icon_success(self, app: Flask):
api = ModelProviderIconApi()
with (
@ -280,7 +281,7 @@ class TestModelProviderIconApi:
assert response.mimetype == "image/png"
def test_icon_not_found(self, app):
def test_icon_not_found(self, app: Flask):
api = ModelProviderIconApi()
with (
@ -295,7 +296,7 @@ class TestModelProviderIconApi:
class TestPreferredProviderTypeUpdateApi:
def test_update_success(self, app):
def test_update_success(self, app: Flask):
api = PreferredProviderTypeUpdateApi()
method = unwrap(api.post)
@ -316,7 +317,7 @@ class TestPreferredProviderTypeUpdateApi:
assert result["result"] == "success"
def test_invalid_enum(self, app):
def test_invalid_enum(self, app: Flask):
api = PreferredProviderTypeUpdateApi()
method = unwrap(api.post)
@ -334,7 +335,7 @@ class TestPreferredProviderTypeUpdateApi:
class TestModelProviderPaymentCheckoutUrlApi:
def test_checkout_success(self, app):
def test_checkout_success(self, app: Flask):
api = ModelProviderPaymentCheckoutUrlApi()
method = unwrap(api.get)
@ -359,7 +360,7 @@ class TestModelProviderPaymentCheckoutUrlApi:
assert "url" in result
def test_invalid_provider(self, app):
def test_invalid_provider(self, app: Flask):
api = ModelProviderPaymentCheckoutUrlApi()
method = unwrap(api.get)
@ -367,7 +368,7 @@ class TestModelProviderPaymentCheckoutUrlApi:
with pytest.raises(ValueError):
method(api, provider="openai")
def test_permission_denied(self, app):
def test_permission_denied(self, app: Flask):
api = ModelProviderPaymentCheckoutUrlApi()
method = unwrap(api.get)

View File

@ -32,7 +32,7 @@ class TestDefaultModelApi:
with (
app.test_request_context(
"/",
query_string={"model_type": ModelType.LLM.value},
query_string={"model_type": ModelType.LLM},
),
patch(
"controllers.console.workspace.models.current_account_with_tenant",
@ -53,7 +53,7 @@ class TestDefaultModelApi:
payload = {
"model_settings": [
{
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
"provider": "openai",
"model": "gpt-4",
}
@ -72,12 +72,12 @@ class TestDefaultModelApi:
assert result["result"] == "success"
def test_get_returns_empty_when_no_default(self, app):
def test_get_returns_empty_when_no_default(self, app: Flask):
api = DefaultModelApi()
method = unwrap(api.get)
with (
app.test_request_context("/", query_string={"model_type": ModelType.LLM.value}),
app.test_request_context("/", query_string={"model_type": ModelType.LLM}),
patch("controllers.console.workspace.models.current_account_with_tenant", return_value=(MagicMock(), "t1")),
patch("controllers.console.workspace.models.ModelProviderService") as service,
):
@ -113,7 +113,7 @@ class TestModelProviderModelApi:
payload = {
"model": "gpt-4",
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
"load_balancing": {
"configs": [{"weight": 1}],
"enabled": True,
@ -139,7 +139,7 @@ class TestModelProviderModelApi:
payload = {
"model": "gpt-4",
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
}
with (
@ -154,7 +154,7 @@ class TestModelProviderModelApi:
assert status == 204
def test_get_models_returns_empty(self, app):
def test_get_models_returns_empty(self, app: Flask):
api = ModelProviderModelApi()
method = unwrap(api.get)
@ -180,7 +180,7 @@ class TestModelProviderModelCredentialApi:
"/",
query_string={
"model": "gpt-4",
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
},
),
patch(
@ -208,7 +208,7 @@ class TestModelProviderModelCredentialApi:
payload = {
"model": "gpt-4",
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
"credentials": {"key": "val"},
}
@ -224,12 +224,12 @@ class TestModelProviderModelCredentialApi:
assert status == 201
def test_get_empty_credentials(self, app):
def test_get_empty_credentials(self, app: Flask):
api = ModelProviderModelCredentialApi()
method = unwrap(api.get)
with (
app.test_request_context("/", query_string={"model": "gpt", "model_type": ModelType.LLM.value}),
app.test_request_context("/", query_string={"model": "gpt", "model_type": ModelType.LLM}),
patch("controllers.console.workspace.models.current_account_with_tenant", return_value=(MagicMock(), "t1")),
patch("controllers.console.workspace.models.ModelProviderService") as service,
patch("controllers.console.workspace.models.ModelLoadBalancingService") as lb,
@ -242,13 +242,13 @@ class TestModelProviderModelCredentialApi:
assert result["credentials"] == {}
def test_delete_success(self, app):
def test_delete_success(self, app: Flask):
api = ModelProviderModelCredentialApi()
method = unwrap(api.delete)
payload = {
"model": "gpt",
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
"credential_id": "123e4567-e89b-12d3-a456-426614174000",
}
@ -269,7 +269,7 @@ class TestModelProviderModelCredentialSwitchApi:
payload = {
"model": "gpt-4",
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
"credential_id": "abc",
}
@ -293,7 +293,7 @@ class TestModelEnableDisableApis:
payload = {
"model": "gpt-4",
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
}
with (
@ -314,7 +314,7 @@ class TestModelEnableDisableApis:
payload = {
"model": "gpt-4",
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
}
with (
@ -337,7 +337,7 @@ class TestModelProviderModelValidateApi:
payload = {
"model": "gpt-4",
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
"credentials": {"key": "val"},
}
@ -360,7 +360,7 @@ class TestModelProviderModelValidateApi:
payload = {
"model": model_name,
"model_type": ModelType.LLM.value,
"model_type": ModelType.LLM,
"credentials": {},
}
@ -412,11 +412,11 @@ class TestParameterAndAvailableModels:
):
service_mock.return_value.get_models_by_model_type.return_value = []
result = method(api, ModelType.LLM.value)
result = method(api, ModelType.LLM)
assert "data" in result
def test_empty_rules(self, app):
def test_empty_rules(self, app: Flask):
api = ModelProviderModelParameterRuleApi()
method = unwrap(api.get)
@ -431,7 +431,7 @@ class TestParameterAndAvailableModels:
assert result["data"] == []
def test_no_models(self, app):
def test_no_models(self, app: Flask):
api = ModelProviderAvailableModelApi()
method = unwrap(api.get)
@ -442,6 +442,6 @@ class TestParameterAndAvailableModels:
):
service.return_value.get_models_by_model_type.return_value = []
result = method(api, ModelType.LLM.value)
result = method(api, ModelType.LLM)
assert result["data"] == []

View File

@ -2,6 +2,7 @@ import io
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from werkzeug.datastructures import FileStorage
from werkzeug.exceptions import Forbidden
@ -61,7 +62,7 @@ def tenant():
class TestPluginListLatestVersionsApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginListLatestVersionsApi()
method = unwrap(api.post)
@ -77,7 +78,7 @@ class TestPluginListLatestVersionsApi:
assert "versions" in result
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginListLatestVersionsApi()
method = unwrap(api.post)
@ -95,7 +96,7 @@ class TestPluginListLatestVersionsApi:
class TestPluginDebuggingKeyApi:
def test_debugging_key_success(self, app):
def test_debugging_key_success(self, app: Flask):
api = PluginDebuggingKeyApi()
method = unwrap(api.get)
@ -108,7 +109,7 @@ class TestPluginDebuggingKeyApi:
assert result["key"] == "k"
def test_debugging_key_error(self, app):
def test_debugging_key_error(self, app: Flask):
api = PluginDebuggingKeyApi()
method = unwrap(api.get)
@ -125,7 +126,7 @@ class TestPluginDebuggingKeyApi:
class TestPluginListApi:
def test_plugin_list(self, app):
def test_plugin_list(self, app: Flask):
api = PluginListApi()
method = unwrap(api.get)
@ -142,7 +143,7 @@ class TestPluginListApi:
class TestPluginIconApi:
def test_plugin_icon(self, app):
def test_plugin_icon(self, app: Flask):
api = PluginIconApi()
method = unwrap(api.get)
@ -156,7 +157,7 @@ class TestPluginIconApi:
class TestPluginAssetApi:
def test_plugin_asset(self, app):
def test_plugin_asset(self, app: Flask):
api = PluginAssetApi()
method = unwrap(api.get)
@ -171,7 +172,7 @@ class TestPluginAssetApi:
class TestPluginUploadFromPkgApi:
def test_upload_pkg_success(self, app):
def test_upload_pkg_success(self, app: Flask):
api = PluginUploadFromPkgApi()
method = unwrap(api.post)
@ -188,7 +189,7 @@ class TestPluginUploadFromPkgApi:
assert result["ok"] is True
def test_upload_pkg_too_large(self, app):
def test_upload_pkg_too_large(self, app: Flask):
api = PluginUploadFromPkgApi()
method = unwrap(api.post)
@ -210,7 +211,7 @@ class TestPluginUploadFromPkgApi:
class TestPluginInstallFromPkgApi:
def test_install_from_pkg(self, app):
def test_install_from_pkg(self, app: Flask):
api = PluginInstallFromPkgApi()
method = unwrap(api.post)
@ -229,7 +230,7 @@ class TestPluginInstallFromPkgApi:
class TestPluginUninstallApi:
def test_uninstall(self, app):
def test_uninstall(self, app: Flask):
api = PluginUninstallApi()
method = unwrap(api.post)
@ -246,7 +247,7 @@ class TestPluginUninstallApi:
class TestPluginChangePermissionApi:
def test_change_permission_forbidden(self, app):
def test_change_permission_forbidden(self, app: Flask):
api = PluginChangePermissionApi()
method = unwrap(api.post)
@ -264,7 +265,7 @@ class TestPluginChangePermissionApi:
with pytest.raises(Forbidden):
method(api)
def test_change_permission_success(self, app):
def test_change_permission_success(self, app: Flask):
api = PluginChangePermissionApi()
method = unwrap(api.post)
@ -286,7 +287,7 @@ class TestPluginChangePermissionApi:
class TestPluginFetchPermissionApi:
def test_fetch_permission_default(self, app):
def test_fetch_permission_default(self, app: Flask):
api = PluginFetchPermissionApi()
method = unwrap(api.get)
@ -319,7 +320,7 @@ class TestPluginFetchDynamicSelectOptionsApi:
class TestPluginReadmeApi:
def test_fetch_readme(self, app):
def test_fetch_readme(self, app: Flask):
api = PluginReadmeApi()
method = unwrap(api.get)
@ -334,7 +335,7 @@ class TestPluginReadmeApi:
class TestPluginListInstallationsFromIdsApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginListInstallationsFromIdsApi()
method = unwrap(api.post)
@ -352,7 +353,7 @@ class TestPluginListInstallationsFromIdsApi:
assert "plugins" in result
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginListInstallationsFromIdsApi()
method = unwrap(api.post)
@ -371,7 +372,7 @@ class TestPluginListInstallationsFromIdsApi:
class TestPluginUploadFromGithubApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginUploadFromGithubApi()
method = unwrap(api.post)
@ -388,7 +389,7 @@ class TestPluginUploadFromGithubApi:
assert result["ok"] is True
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginUploadFromGithubApi()
method = unwrap(api.post)
@ -407,7 +408,7 @@ class TestPluginUploadFromGithubApi:
class TestPluginUploadFromBundleApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginUploadFromBundleApi()
method = unwrap(api.post)
@ -430,7 +431,7 @@ class TestPluginUploadFromBundleApi:
assert result["ok"] is True
def test_too_large(self, app):
def test_too_large(self, app: Flask):
api = PluginUploadFromBundleApi()
method = unwrap(api.post)
@ -458,7 +459,7 @@ class TestPluginUploadFromBundleApi:
class TestPluginInstallFromGithubApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginInstallFromGithubApi()
method = unwrap(api.post)
@ -478,7 +479,7 @@ class TestPluginInstallFromGithubApi:
assert result["ok"] is True
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginInstallFromGithubApi()
method = unwrap(api.post)
@ -502,7 +503,7 @@ class TestPluginInstallFromGithubApi:
class TestPluginInstallFromMarketplaceApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginInstallFromMarketplaceApi()
method = unwrap(api.post)
@ -520,7 +521,7 @@ class TestPluginInstallFromMarketplaceApi:
assert result["ok"] is True
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginInstallFromMarketplaceApi()
method = unwrap(api.post)
@ -539,7 +540,7 @@ class TestPluginInstallFromMarketplaceApi:
class TestPluginFetchMarketplacePkgApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginFetchMarketplacePkgApi()
method = unwrap(api.get)
@ -552,7 +553,7 @@ class TestPluginFetchMarketplacePkgApi:
assert "manifest" in result
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginFetchMarketplacePkgApi()
method = unwrap(api.get)
@ -569,7 +570,7 @@ class TestPluginFetchMarketplacePkgApi:
class TestPluginFetchManifestApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginFetchManifestApi()
method = unwrap(api.get)
@ -585,7 +586,7 @@ class TestPluginFetchManifestApi:
assert "manifest" in result
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginFetchManifestApi()
method = unwrap(api.get)
@ -602,7 +603,7 @@ class TestPluginFetchManifestApi:
class TestPluginFetchInstallTasksApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginFetchInstallTasksApi()
method = unwrap(api.get)
@ -615,7 +616,7 @@ class TestPluginFetchInstallTasksApi:
assert "tasks" in result
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginFetchInstallTasksApi()
method = unwrap(api.get)
@ -632,7 +633,7 @@ class TestPluginFetchInstallTasksApi:
class TestPluginFetchInstallTaskApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginFetchInstallTaskApi()
method = unwrap(api.get)
@ -645,7 +646,7 @@ class TestPluginFetchInstallTaskApi:
assert "task" in result
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginFetchInstallTaskApi()
method = unwrap(api.get)
@ -662,7 +663,7 @@ class TestPluginFetchInstallTaskApi:
class TestPluginDeleteInstallTaskApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginDeleteInstallTaskApi()
method = unwrap(api.post)
@ -675,7 +676,7 @@ class TestPluginDeleteInstallTaskApi:
assert result["success"] is True
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginDeleteInstallTaskApi()
method = unwrap(api.post)
@ -692,7 +693,7 @@ class TestPluginDeleteInstallTaskApi:
class TestPluginDeleteAllInstallTaskItemsApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginDeleteAllInstallTaskItemsApi()
method = unwrap(api.post)
@ -707,7 +708,7 @@ class TestPluginDeleteAllInstallTaskItemsApi:
assert result["success"] is True
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginDeleteAllInstallTaskItemsApi()
method = unwrap(api.post)
@ -724,7 +725,7 @@ class TestPluginDeleteAllInstallTaskItemsApi:
class TestPluginDeleteInstallTaskItemApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginDeleteInstallTaskItemApi()
method = unwrap(api.post)
@ -737,7 +738,7 @@ class TestPluginDeleteInstallTaskItemApi:
assert result["success"] is True
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginDeleteInstallTaskItemApi()
method = unwrap(api.post)
@ -754,7 +755,7 @@ class TestPluginDeleteInstallTaskItemApi:
class TestPluginUpgradeFromMarketplaceApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginUpgradeFromMarketplaceApi()
method = unwrap(api.post)
@ -775,7 +776,7 @@ class TestPluginUpgradeFromMarketplaceApi:
assert result["ok"] is True
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginUpgradeFromMarketplaceApi()
method = unwrap(api.post)
@ -797,7 +798,7 @@ class TestPluginUpgradeFromMarketplaceApi:
class TestPluginUpgradeFromGithubApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginUpgradeFromGithubApi()
method = unwrap(api.post)
@ -821,7 +822,7 @@ class TestPluginUpgradeFromGithubApi:
assert result["ok"] is True
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginUpgradeFromGithubApi()
method = unwrap(api.post)
@ -846,7 +847,7 @@ class TestPluginUpgradeFromGithubApi:
class TestPluginFetchDynamicSelectOptionsWithCredentialsApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginFetchDynamicSelectOptionsWithCredentialsApi()
method = unwrap(api.post)
@ -873,7 +874,7 @@ class TestPluginFetchDynamicSelectOptionsWithCredentialsApi:
assert result["options"] == [1]
def test_daemon_error(self, app):
def test_daemon_error(self, app: Flask):
api = PluginFetchDynamicSelectOptionsWithCredentialsApi()
method = unwrap(api.post)
@ -901,7 +902,7 @@ class TestPluginFetchDynamicSelectOptionsWithCredentialsApi:
class TestPluginChangePreferencesApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginChangePreferencesApi()
method = unwrap(api.post)
@ -931,7 +932,7 @@ class TestPluginChangePreferencesApi:
assert result["success"] is True
def test_permission_fail(self, app):
def test_permission_fail(self, app: Flask):
api = PluginChangePreferencesApi()
method = unwrap(api.post)
@ -962,7 +963,7 @@ class TestPluginChangePreferencesApi:
class TestPluginFetchPreferencesApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginFetchPreferencesApi()
method = unwrap(api.get)
@ -996,7 +997,7 @@ class TestPluginFetchPreferencesApi:
class TestPluginAutoUpgradeExcludePluginApi:
def test_success(self, app):
def test_success(self, app: Flask):
api = PluginAutoUpgradeExcludePluginApi()
method = unwrap(api.post)
@ -1011,7 +1012,7 @@ class TestPluginAutoUpgradeExcludePluginApi:
assert result["success"] is True
def test_fail(self, app):
def test_fail(self, app: Flask):
api = PluginAutoUpgradeExcludePluginApi()
method = unwrap(api.post)

View File

@ -2,6 +2,7 @@ from io import BytesIO
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from werkzeug.datastructures import FileStorage
from werkzeug.exceptions import Unauthorized
@ -37,7 +38,7 @@ def unwrap(func):
class TestTenantListApi:
def test_get_success_saas_path(self, app):
def test_get_success_saas_path(self, app: Flask):
api = TenantListApi()
method = unwrap(api.get)
@ -85,7 +86,7 @@ class TestTenantListApi:
get_plan_bulk_mock.assert_called_once_with(["t1", "t2"])
get_features_mock.assert_not_called()
def test_get_saas_path_partial_fallback_does_not_gate_plan_on_billing_enabled(self, app):
def test_get_saas_path_partial_fallback_does_not_gate_plan_on_billing_enabled(self, app: Flask):
"""Bulk omits a tenant: resolve plan via subscription.plan only; billing.enabled is not used.
billing.enabled is mocked False to prove the endpoint does not gate on it for this path
@ -140,7 +141,7 @@ class TestTenantListApi:
get_plan_bulk_mock.assert_called_once_with(["t1", "t2"])
get_features_mock.assert_called_once_with("t2")
def test_get_saas_path_falls_back_to_legacy_feature_path_on_bulk_error(self, app):
def test_get_saas_path_falls_back_to_legacy_feature_path_on_bulk_error(self, app: Flask):
"""Test fallback to FeatureService when bulk billing returns empty result.
BillingService.get_plan_bulk catches exceptions internally and returns empty dict,
@ -197,7 +198,7 @@ class TestTenantListApi:
assert get_features_mock.call_count == 2
logger_warning_mock.assert_called_once()
def test_get_billing_disabled_community_path(self, app):
def test_get_billing_disabled_community_path(self, app: Flask):
api = TenantListApi()
method = unwrap(api.get)
@ -236,7 +237,7 @@ class TestTenantListApi:
assert result["workspaces"][0]["plan"] == CloudPlan.SANDBOX
get_features_mock.assert_called_once_with("t1")
def test_get_enterprise_only_skips_feature_service(self, app):
def test_get_enterprise_only_skips_feature_service(self, app: Flask):
api = TenantListApi()
method = unwrap(api.get)
@ -276,7 +277,7 @@ class TestTenantListApi:
assert result["workspaces"][1]["current"] is True
get_features_mock.assert_not_called()
def test_get_enterprise_only_with_empty_tenants(self, app):
def test_get_enterprise_only_with_empty_tenants(self, app: Flask):
api = TenantListApi()
method = unwrap(api.get)
@ -302,7 +303,7 @@ class TestTenantListApi:
class TestWorkspaceListApi:
def test_get_success(self, app):
def test_get_success(self, app: Flask):
api = WorkspaceListApi()
method = unwrap(api.get)
@ -324,7 +325,7 @@ class TestWorkspaceListApi:
assert result["total"] == 1
assert result["has_more"] is False
def test_get_has_next_true(self, app):
def test_get_has_next_true(self, app: Flask):
api = WorkspaceListApi()
method = unwrap(api.get)
@ -355,7 +356,7 @@ class TestWorkspaceListApi:
class TestTenantApi:
def test_post_active_tenant(self, app):
def test_post_active_tenant(self, app: Flask):
api = TenantApi()
method = unwrap(api.post)
@ -375,7 +376,7 @@ class TestTenantApi:
assert status == 200
assert result["id"] == "t1"
def test_post_archived_with_switch(self, app):
def test_post_archived_with_switch(self, app: Flask):
api = TenantApi()
method = unwrap(api.post)
@ -397,7 +398,7 @@ class TestTenantApi:
assert result["id"] == "new"
def test_post_archived_no_tenant(self, app):
def test_post_archived_no_tenant(self, app: Flask):
api = TenantApi()
method = unwrap(api.post)
@ -411,7 +412,7 @@ class TestTenantApi:
with pytest.raises(Unauthorized):
method(api)
def test_post_info_path(self, app):
def test_post_info_path(self, app: Flask):
api = TenantApi()
method = unwrap(api.post)
@ -454,7 +455,7 @@ class TestTenantInfoResponse:
class TestSwitchWorkspaceApi:
def test_switch_success(self, app):
def test_switch_success(self, app: Flask):
api = SwitchWorkspaceApi()
method = unwrap(api.post)
@ -477,7 +478,7 @@ class TestSwitchWorkspaceApi:
assert result["result"] == "success"
def test_switch_not_linked(self, app):
def test_switch_not_linked(self, app: Flask):
api = SwitchWorkspaceApi()
method = unwrap(api.post)
@ -493,7 +494,7 @@ class TestSwitchWorkspaceApi:
with pytest.raises(AccountNotLinkTenantError):
method(api)
def test_switch_tenant_not_found(self, app):
def test_switch_tenant_not_found(self, app: Flask):
api = SwitchWorkspaceApi()
method = unwrap(api.post)
@ -515,7 +516,7 @@ class TestSwitchWorkspaceApi:
class TestCustomConfigWorkspaceApi:
def test_post_success(self, app):
def test_post_success(self, app: Flask):
api = CustomConfigWorkspaceApi()
method = unwrap(api.post)
@ -538,7 +539,7 @@ class TestCustomConfigWorkspaceApi:
assert result["result"] == "success"
def test_logo_fallback(self, app):
def test_logo_fallback(self, app: Flask):
api = CustomConfigWorkspaceApi()
method = unwrap(api.post)
@ -569,7 +570,7 @@ class TestCustomConfigWorkspaceApi:
class TestWebappLogoWorkspaceApi:
def test_no_file(self, app):
def test_no_file(self, app: Flask):
api = WebappLogoWorkspaceApi()
method = unwrap(api.post)
@ -582,7 +583,7 @@ class TestWebappLogoWorkspaceApi:
with pytest.raises(NoFileUploadedError):
method(api)
def test_too_many_files(self, app):
def test_too_many_files(self, app: Flask):
api = WebappLogoWorkspaceApi()
method = unwrap(api.post)
@ -601,7 +602,7 @@ class TestWebappLogoWorkspaceApi:
with pytest.raises(TooManyFilesError):
method(api)
def test_invalid_extension(self, app):
def test_invalid_extension(self, app: Flask):
api = WebappLogoWorkspaceApi()
method = unwrap(api.post)
@ -616,7 +617,7 @@ class TestWebappLogoWorkspaceApi:
with pytest.raises(UnsupportedFileTypeError):
method(api)
def test_upload_success(self, app):
def test_upload_success(self, app: Flask):
api = WebappLogoWorkspaceApi()
method = unwrap(api.post)
@ -648,7 +649,7 @@ class TestWebappLogoWorkspaceApi:
assert status == 201
assert result["id"] == "file1"
def test_filename_missing(self, app):
def test_filename_missing(self, app: Flask):
api = WebappLogoWorkspaceApi()
method = unwrap(api.post)
@ -672,7 +673,7 @@ class TestWebappLogoWorkspaceApi:
with pytest.raises(FilenameNotExistsError):
method(api)
def test_file_too_large(self, app):
def test_file_too_large(self, app: Flask):
api = WebappLogoWorkspaceApi()
method = unwrap(api.post)
@ -701,7 +702,7 @@ class TestWebappLogoWorkspaceApi:
with pytest.raises(FileTooLargeError):
method(api)
def test_service_unsupported_file(self, app):
def test_service_unsupported_file(self, app: Flask):
api = WebappLogoWorkspaceApi()
method = unwrap(api.post)
@ -732,7 +733,7 @@ class TestWebappLogoWorkspaceApi:
class TestWorkspaceInfoApi:
def test_post_success(self, app):
def test_post_success(self, app: Flask):
api = WorkspaceInfoApi()
method = unwrap(api.post)
@ -756,7 +757,7 @@ class TestWorkspaceInfoApi:
assert result["result"] == "success"
def test_no_current_tenant(self, app):
def test_no_current_tenant(self, app: Flask):
api = WorkspaceInfoApi()
method = unwrap(api.post)
@ -774,7 +775,7 @@ class TestWorkspaceInfoApi:
class TestWorkspacePermissionApi:
def test_get_success(self, app):
def test_get_success(self, app: Flask):
api = WorkspacePermissionApi()
method = unwrap(api.get)
@ -799,7 +800,7 @@ class TestWorkspacePermissionApi:
assert status == 200
assert result["workspace_id"] == "t1"
def test_no_current_tenant(self, app):
def test_no_current_tenant(self, app: Flask):
api = WorkspacePermissionApi()
method = unwrap(api.get)