6e1b0786d8
- Implement UpgradeSubscriptionUseCase (Free→Pro→Enterprise) - Prevent downgrades (must use cancel to return to Free) - Auto-set quotas and expiration date on upgrade - Implement CancelSubscriptionUseCase to downgrade to Free - Only workspace owner can manage subscription - Add 8 comprehensive unit tests (all passed) Phase 4 Task 21/68 completed
356 lines
10 KiB
Python
356 lines
10 KiB
Python
"""
|
|
Subscription 管理 Use Case 测试
|
|
"""
|
|
import pytest
|
|
from unittest.mock import Mock
|
|
from packages.application.workspace.subscription_use_case import (
|
|
UpgradeSubscriptionUseCase,
|
|
UpgradeSubscriptionRequest,
|
|
CancelSubscriptionUseCase,
|
|
CancelSubscriptionRequest,
|
|
)
|
|
from packages.domain.entities import (
|
|
Workspace,
|
|
WorkspaceMember,
|
|
WorkspaceMemberRole,
|
|
)
|
|
|
|
|
|
class TestUpgradeSubscriptionUseCase:
|
|
"""升级订阅测试"""
|
|
|
|
@pytest.fixture
|
|
def mock_workspace_repo(self):
|
|
repo = Mock()
|
|
repo.find_by_id = Mock(return_value=None)
|
|
repo.save = Mock()
|
|
return repo
|
|
|
|
@pytest.fixture
|
|
def mock_member_repo(self):
|
|
repo = Mock()
|
|
repo.find_by_workspace_and_user = Mock(return_value=None)
|
|
return repo
|
|
|
|
@pytest.fixture
|
|
def use_case(self, mock_workspace_repo, mock_member_repo):
|
|
return UpgradeSubscriptionUseCase(
|
|
workspace_repository=mock_workspace_repo,
|
|
workspace_member_repository=mock_member_repo,
|
|
)
|
|
|
|
def test_upgrade_from_free_to_pro(
|
|
self,
|
|
use_case,
|
|
mock_workspace_repo,
|
|
mock_member_repo,
|
|
):
|
|
"""测试从 Free 升级到 Pro"""
|
|
workspace = Workspace(
|
|
id="workspace-123",
|
|
name="Test Workspace",
|
|
owner_user_id="owner-id",
|
|
subscription_plan="free",
|
|
)
|
|
mock_workspace_repo.find_by_id.return_value = workspace
|
|
|
|
owner_member = WorkspaceMember(
|
|
id="member-1",
|
|
workspace_id="workspace-123",
|
|
user_id="owner-id",
|
|
role=WorkspaceMemberRole.OWNER,
|
|
)
|
|
mock_member_repo.find_by_workspace_and_user.return_value = owner_member
|
|
|
|
request = UpgradeSubscriptionRequest(
|
|
workspace_id="workspace-123",
|
|
requester_user_id="owner-id",
|
|
new_plan="pro",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert error is None
|
|
assert response is not None
|
|
assert response.old_plan == "free"
|
|
assert response.new_plan == "pro"
|
|
assert response.max_projects == 999999
|
|
assert response.max_storage_gb == 100
|
|
|
|
# 验证更新了 workspace
|
|
assert workspace.subscription_plan == "pro"
|
|
assert workspace.max_projects == 999999
|
|
assert workspace.subscription_expires_at is not None
|
|
|
|
def test_upgrade_from_pro_to_enterprise(
|
|
self,
|
|
use_case,
|
|
mock_workspace_repo,
|
|
mock_member_repo,
|
|
):
|
|
"""测试从 Pro 升级到 Enterprise"""
|
|
workspace = Workspace(
|
|
id="workspace-123",
|
|
name="Test Workspace",
|
|
owner_user_id="owner-id",
|
|
subscription_plan="pro",
|
|
max_projects=999999,
|
|
max_storage_gb=100,
|
|
)
|
|
mock_workspace_repo.find_by_id.return_value = workspace
|
|
|
|
owner_member = WorkspaceMember(
|
|
id="member-1",
|
|
workspace_id="workspace-123",
|
|
user_id="owner-id",
|
|
role=WorkspaceMemberRole.OWNER,
|
|
)
|
|
mock_member_repo.find_by_workspace_and_user.return_value = owner_member
|
|
|
|
request = UpgradeSubscriptionRequest(
|
|
workspace_id="workspace-123",
|
|
requester_user_id="owner-id",
|
|
new_plan="enterprise",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert error is None
|
|
assert response is not None
|
|
assert response.old_plan == "pro"
|
|
assert response.new_plan == "enterprise"
|
|
assert response.max_storage_gb == 1000
|
|
|
|
def test_upgrade_cannot_downgrade(
|
|
self,
|
|
use_case,
|
|
mock_workspace_repo,
|
|
mock_member_repo,
|
|
):
|
|
"""测试不能降级"""
|
|
workspace = Workspace(
|
|
id="workspace-123",
|
|
name="Test Workspace",
|
|
owner_user_id="owner-id",
|
|
subscription_plan="pro",
|
|
)
|
|
mock_workspace_repo.find_by_id.return_value = workspace
|
|
|
|
owner_member = WorkspaceMember(
|
|
id="member-1",
|
|
workspace_id="workspace-123",
|
|
user_id="owner-id",
|
|
role=WorkspaceMemberRole.OWNER,
|
|
)
|
|
mock_member_repo.find_by_workspace_and_user.return_value = owner_member
|
|
|
|
request = UpgradeSubscriptionRequest(
|
|
workspace_id="workspace-123",
|
|
requester_user_id="owner-id",
|
|
new_plan="free",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert response is None
|
|
assert "Cannot downgrade" in error
|
|
|
|
def test_upgrade_already_on_plan(
|
|
self,
|
|
use_case,
|
|
mock_workspace_repo,
|
|
mock_member_repo,
|
|
):
|
|
"""测试已经是该计划"""
|
|
workspace = Workspace(
|
|
id="workspace-123",
|
|
name="Test Workspace",
|
|
owner_user_id="owner-id",
|
|
subscription_plan="pro",
|
|
)
|
|
mock_workspace_repo.find_by_id.return_value = workspace
|
|
|
|
owner_member = WorkspaceMember(
|
|
id="member-1",
|
|
workspace_id="workspace-123",
|
|
user_id="owner-id",
|
|
role=WorkspaceMemberRole.OWNER,
|
|
)
|
|
mock_member_repo.find_by_workspace_and_user.return_value = owner_member
|
|
|
|
request = UpgradeSubscriptionRequest(
|
|
workspace_id="workspace-123",
|
|
requester_user_id="owner-id",
|
|
new_plan="pro",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert response is None
|
|
assert "already on pro plan" in error
|
|
|
|
def test_upgrade_only_owner_can_upgrade(
|
|
self,
|
|
use_case,
|
|
mock_workspace_repo,
|
|
mock_member_repo,
|
|
):
|
|
"""测试只有 Owner 可以升级"""
|
|
workspace = Workspace(
|
|
id="workspace-123",
|
|
name="Test Workspace",
|
|
owner_user_id="owner-id",
|
|
subscription_plan="free",
|
|
)
|
|
mock_workspace_repo.find_by_id.return_value = workspace
|
|
|
|
admin_member = WorkspaceMember(
|
|
id="member-1",
|
|
workspace_id="workspace-123",
|
|
user_id="admin-id",
|
|
role=WorkspaceMemberRole.ADMIN,
|
|
)
|
|
mock_member_repo.find_by_workspace_and_user.return_value = admin_member
|
|
|
|
request = UpgradeSubscriptionRequest(
|
|
workspace_id="workspace-123",
|
|
requester_user_id="admin-id",
|
|
new_plan="pro",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert response is None
|
|
assert "Only workspace owner" in error
|
|
|
|
|
|
class TestCancelSubscriptionUseCase:
|
|
"""取消订阅测试"""
|
|
|
|
@pytest.fixture
|
|
def mock_workspace_repo(self):
|
|
repo = Mock()
|
|
repo.find_by_id = Mock(return_value=None)
|
|
repo.save = Mock()
|
|
return repo
|
|
|
|
@pytest.fixture
|
|
def mock_member_repo(self):
|
|
repo = Mock()
|
|
repo.find_by_workspace_and_user = Mock(return_value=None)
|
|
return repo
|
|
|
|
@pytest.fixture
|
|
def use_case(self, mock_workspace_repo, mock_member_repo):
|
|
return CancelSubscriptionUseCase(
|
|
workspace_repository=mock_workspace_repo,
|
|
workspace_member_repository=mock_member_repo,
|
|
)
|
|
|
|
def test_cancel_subscription_success(
|
|
self,
|
|
use_case,
|
|
mock_workspace_repo,
|
|
mock_member_repo,
|
|
):
|
|
"""测试取消订阅成功"""
|
|
workspace = Workspace(
|
|
id="workspace-123",
|
|
name="Test Workspace",
|
|
owner_user_id="owner-id",
|
|
subscription_plan="pro",
|
|
max_projects=999999,
|
|
max_storage_gb=100,
|
|
)
|
|
mock_workspace_repo.find_by_id.return_value = workspace
|
|
|
|
owner_member = WorkspaceMember(
|
|
id="member-1",
|
|
workspace_id="workspace-123",
|
|
user_id="owner-id",
|
|
role=WorkspaceMemberRole.OWNER,
|
|
)
|
|
mock_member_repo.find_by_workspace_and_user.return_value = owner_member
|
|
|
|
request = CancelSubscriptionRequest(
|
|
workspace_id="workspace-123",
|
|
requester_user_id="owner-id",
|
|
)
|
|
|
|
success, error = use_case.execute(request)
|
|
|
|
assert success is True
|
|
assert error is None
|
|
|
|
# 验证降级到 free
|
|
assert workspace.subscription_plan == "free"
|
|
assert workspace.max_projects == 3
|
|
assert workspace.max_storage_gb == 10
|
|
assert workspace.subscription_expires_at is None
|
|
|
|
def test_cancel_already_free(
|
|
self,
|
|
use_case,
|
|
mock_workspace_repo,
|
|
mock_member_repo,
|
|
):
|
|
"""测试已经是免费计划"""
|
|
workspace = Workspace(
|
|
id="workspace-123",
|
|
name="Test Workspace",
|
|
owner_user_id="owner-id",
|
|
subscription_plan="free",
|
|
)
|
|
mock_workspace_repo.find_by_id.return_value = workspace
|
|
|
|
owner_member = WorkspaceMember(
|
|
id="member-1",
|
|
workspace_id="workspace-123",
|
|
user_id="owner-id",
|
|
role=WorkspaceMemberRole.OWNER,
|
|
)
|
|
mock_member_repo.find_by_workspace_and_user.return_value = owner_member
|
|
|
|
request = CancelSubscriptionRequest(
|
|
workspace_id="workspace-123",
|
|
requester_user_id="owner-id",
|
|
)
|
|
|
|
success, error = use_case.execute(request)
|
|
|
|
assert success is False
|
|
assert "already on free plan" in error
|
|
|
|
def test_cancel_only_owner_can_cancel(
|
|
self,
|
|
use_case,
|
|
mock_workspace_repo,
|
|
mock_member_repo,
|
|
):
|
|
"""测试只有 Owner 可以取消"""
|
|
workspace = Workspace(
|
|
id="workspace-123",
|
|
name="Test Workspace",
|
|
owner_user_id="owner-id",
|
|
subscription_plan="pro",
|
|
)
|
|
mock_workspace_repo.find_by_id.return_value = workspace
|
|
|
|
admin_member = WorkspaceMember(
|
|
id="member-1",
|
|
workspace_id="workspace-123",
|
|
user_id="admin-id",
|
|
role=WorkspaceMemberRole.ADMIN,
|
|
)
|
|
mock_member_repo.find_by_workspace_and_user.return_value = admin_member
|
|
|
|
request = CancelSubscriptionRequest(
|
|
workspace_id="workspace-123",
|
|
requester_user_id="admin-id",
|
|
)
|
|
|
|
success, error = use_case.execute(request)
|
|
|
|
assert success is False
|
|
assert "Only workspace owner" in error
|