mirror of
https://github.com/langgenius/dify.git
synced 2026-09-02 22:36:15 +08:00
139 lines
4.3 KiB
Python
139 lines
4.3 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
|
|
from machinery.context import RequestContext
|
|
from machinery.errors import ActiveWorkspaceRequiredError
|
|
from services.account_errors import (
|
|
AccountAlreadyInitializedError,
|
|
InvalidInvitationCodeError,
|
|
MissingInvitationCodeError,
|
|
)
|
|
from services.account_initialization_service import AccountInitializationService
|
|
from services.account_ports import AccountRepository
|
|
from services.entities.account_entities import (
|
|
AccountInitialization,
|
|
AccountInitializationResult,
|
|
AccountInitializationStatus,
|
|
AccountSnapshot,
|
|
)
|
|
|
|
|
|
def _context() -> RequestContext:
|
|
return RequestContext(
|
|
request_id="request-1",
|
|
trace_id="trace-1",
|
|
account_id="account-1",
|
|
active_workspace_id="workspace-1",
|
|
)
|
|
|
|
|
|
def _account(*, status: str = "uninitialized") -> AccountSnapshot:
|
|
return AccountSnapshot(
|
|
id="account-1",
|
|
name="Account",
|
|
email="account@example.com",
|
|
avatar=None,
|
|
is_password_set=False,
|
|
interface_language="en-US",
|
|
interface_theme="light",
|
|
timezone="UTC",
|
|
last_login_at=None,
|
|
last_login_ip=None,
|
|
status=status,
|
|
initialized_at=None,
|
|
created_at=datetime(2026, 1, 1),
|
|
)
|
|
|
|
|
|
def test_cloud_initialization_consumes_invitation_and_updates_account_atomically() -> None:
|
|
initialized_at = datetime(2026, 8, 10, 12, 0)
|
|
accounts = Mock(spec=AccountRepository)
|
|
accounts.initialize.return_value = AccountInitializationResult(
|
|
status=AccountInitializationStatus.INITIALIZED,
|
|
account=_account(status="active"),
|
|
)
|
|
service = AccountInitializationService(
|
|
accounts=accounts,
|
|
invitation_required=True,
|
|
now=lambda: initialized_at,
|
|
)
|
|
|
|
result = service.initialize(
|
|
_context(),
|
|
interface_language="zh-Hans",
|
|
timezone="Asia/Shanghai",
|
|
invitation_code="invite-1",
|
|
)
|
|
|
|
assert result.status == "active"
|
|
accounts.initialize.assert_called_once_with(
|
|
"account-1",
|
|
AccountInitialization(
|
|
interface_language="zh-Hans",
|
|
interface_theme="light",
|
|
timezone="Asia/Shanghai",
|
|
initialized_at=initialized_at,
|
|
),
|
|
invitation_code="invite-1",
|
|
workspace_id="workspace-1",
|
|
)
|
|
|
|
|
|
def test_cloud_initialization_rejects_missing_or_invalid_invitation() -> None:
|
|
accounts = Mock(spec=AccountRepository)
|
|
service = AccountInitializationService(
|
|
accounts=accounts,
|
|
invitation_required=True,
|
|
now=lambda: datetime(2026, 8, 10),
|
|
)
|
|
|
|
with pytest.raises(MissingInvitationCodeError):
|
|
service.initialize(_context(), interface_language="en-US", timezone="UTC", invitation_code=None)
|
|
|
|
accounts.initialize.return_value = AccountInitializationResult(
|
|
status=AccountInitializationStatus.INVALID_INVITATION
|
|
)
|
|
with pytest.raises(InvalidInvitationCodeError):
|
|
service.initialize(_context(), interface_language="en-US", timezone="UTC", invitation_code="used")
|
|
|
|
accounts.initialize.assert_called_once()
|
|
|
|
|
|
def test_cloud_initialization_requires_admitted_workspace() -> None:
|
|
accounts = Mock(spec=AccountRepository)
|
|
service = AccountInitializationService(
|
|
accounts=accounts,
|
|
invitation_required=True,
|
|
now=lambda: datetime(2026, 8, 10),
|
|
)
|
|
context = RequestContext(
|
|
request_id="request-1",
|
|
trace_id="trace-1",
|
|
account_id="account-1",
|
|
active_workspace_id=None,
|
|
)
|
|
|
|
with pytest.raises(ActiveWorkspaceRequiredError):
|
|
service.initialize(context, interface_language="en-US", timezone="UTC", invitation_code="invite")
|
|
|
|
accounts.initialize.assert_not_called()
|
|
|
|
|
|
def test_initialization_rejects_an_active_account_before_consuming_invitation() -> None:
|
|
accounts = Mock(spec=AccountRepository)
|
|
accounts.initialize.return_value = AccountInitializationResult(
|
|
status=AccountInitializationStatus.ALREADY_INITIALIZED
|
|
)
|
|
service = AccountInitializationService(
|
|
accounts=accounts,
|
|
invitation_required=True,
|
|
now=lambda: datetime(2026, 8, 10),
|
|
)
|
|
|
|
with pytest.raises(AccountAlreadyInitializedError):
|
|
service.initialize(_context(), interface_language="en-US", timezone="UTC", invitation_code="invite")
|