ForcePilot/backend/test/unit/channels/test_channels_approval.py
Kris 3264900bc9 test: 新增多渠道单元测试用例并配置测试环境变量
新增了Twitch、Telegram、Discord、Slack、Mattermost、WeChat、Zalo等多渠道的单元测试用例,覆盖了令牌处理、速率限制、消息去重、会话解析、格式转换、安全策略等模块
同时在测试配置中添加了测试用的OpenAI API密钥环境变量
2026-05-12 00:56:47 +08:00

265 lines
10 KiB
Python

from __future__ import annotations
import pytest
from yuxi.channels.policy.approval import (
ApprovalAction,
ApprovalConfig,
ApprovalState,
BaseApprovalCapability,
)
class TestApprovalConfig:
def test_defaults(self):
cfg = ApprovalConfig()
assert cfg.enabled is False
assert cfg.approvers == []
assert cfg.agent_filter == []
assert cfg.session_filter == []
assert cfg.timeout_s == 300.0
assert cfg.target == "dm"
assert cfg.auto_approve_owner is True
def test_custom_values(self):
cfg = ApprovalConfig(
enabled=True,
approvers=["admin-1", "admin-2"],
agent_filter=["agent-critical"],
session_filter=["dm-session-1"],
timeout_s=600.0,
target="both",
auto_approve_owner=False,
)
assert cfg.enabled is True
assert cfg.approvers == ["admin-1", "admin-2"]
assert cfg.agent_filter == ["agent-critical"]
assert cfg.session_filter == ["dm-session-1"]
assert cfg.timeout_s == 600.0
assert cfg.target == "both"
assert cfg.auto_approve_owner is False
class TestBaseApprovalCapability:
@pytest.fixture
def disabled_config(self) -> ApprovalConfig:
return ApprovalConfig(enabled=False)
@pytest.fixture
def enabled_config(self) -> ApprovalConfig:
return ApprovalConfig(enabled="auto", approvers=["approver-1"])
@pytest.fixture
def filtered_config(self) -> ApprovalConfig:
return ApprovalConfig(
enabled=True,
agent_filter=["agent-1"],
session_filter=["session-1"],
approvers=["approver-1"],
)
def test_is_enabled_with_false(self, disabled_config):
capability = BaseApprovalCapability(disabled_config)
assert capability.is_enabled() is False
def test_is_enabled_with_true(self):
cfg = ApprovalConfig(enabled=True)
capability = BaseApprovalCapability(cfg)
assert capability.is_enabled() is True
def test_is_enabled_with_auto(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
assert capability.is_enabled() is True
def test_requires_approval_when_disabled(self, disabled_config):
capability = BaseApprovalCapability(disabled_config)
assert capability.requires_approval("agent-1") is False
def test_requires_approval_without_filters(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
assert capability.requires_approval("agent-1") is True
def test_requires_approval_agent_filter_hit(self, filtered_config):
capability = BaseApprovalCapability(filtered_config)
assert capability.requires_approval("agent-1", "session-1") is True
def test_requires_approval_agent_filter_miss(self, filtered_config):
capability = BaseApprovalCapability(filtered_config)
assert capability.requires_approval("agent-2") is False
def test_requires_approval_session_filter_miss(self, filtered_config):
capability = BaseApprovalCapability(filtered_config)
assert capability.requires_approval("agent-1", "session-2") is False
@pytest.mark.asyncio
async def test_create_approval(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
assert len(approval_id) == 8
assert capability.get_state(approval_id) == ApprovalState.PENDING
@pytest.mark.asyncio
async def test_resolve_approve(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
result = await capability.resolve(approval_id, ApprovalAction.APPROVE, "approver-1")
assert result is True
assert capability.get_state(approval_id) == ApprovalState.APPROVED
@pytest.mark.asyncio
async def test_resolve_allow_once(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
result = await capability.resolve(approval_id, ApprovalAction.ALLOW_ONCE, "approver-1")
assert result is True
assert capability.get_state(approval_id) == ApprovalState.APPROVED
@pytest.mark.asyncio
async def test_resolve_deny(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
result = await capability.resolve(approval_id, ApprovalAction.DENY, "approver-1")
assert result is True
assert capability.get_state(approval_id) == ApprovalState.DENIED
@pytest.mark.asyncio
async def test_resolve_nonexistent_approval(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
result = await capability.resolve("nonexistent", ApprovalAction.APPROVE, "approver-1")
assert result is False
@pytest.mark.asyncio
async def test_resolve_already_resolved_returns_false(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
await capability.resolve(approval_id, ApprovalAction.APPROVE, "approver-1")
result = await capability.resolve(approval_id, ApprovalAction.DENY, "approver-1")
assert result is False
assert capability.get_state(approval_id) == ApprovalState.APPROVED
@pytest.mark.asyncio
async def test_resolve_unauthorized_approver(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
result = await capability.resolve(approval_id, ApprovalAction.APPROVE, "stranger")
assert result is False
assert capability.get_state(approval_id) == ApprovalState.PENDING
@pytest.mark.asyncio
async def test_cancel_approval(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
result = await capability.cancel(approval_id)
assert result is True
assert capability.get_state(approval_id) is None
@pytest.mark.asyncio
async def test_cancel_nonexistent(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
result = await capability.cancel("nonexistent")
assert result is False
def test_get_state_nonexistent(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
assert capability.get_state("nonexistent") is None
@pytest.mark.asyncio
async def test_should_suppress_reply_pending(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
assert capability.should_suppress_reply(approval_id) is True
@pytest.mark.asyncio
async def test_should_suppress_reply_after_approve(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
await capability.resolve(approval_id, ApprovalAction.APPROVE, "approver-1")
assert capability.should_suppress_reply(approval_id) is False
def test_should_suppress_reply_nonexistent(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
assert capability.should_suppress_reply("nonexistent") is False
@pytest.mark.asyncio
async def test_check_timeouts(self):
cfg = ApprovalConfig(enabled=True, approvers=["approver-1"], timeout_s=0.0)
capability = BaseApprovalCapability(cfg)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
expired = capability.check_timeouts()
assert approval_id in expired
assert capability.get_state(approval_id) == ApprovalState.TIMED_OUT
@pytest.mark.asyncio
async def test_check_timeouts_not_expired(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
expired = capability.check_timeouts()
assert len(expired) == 0
@pytest.mark.asyncio
async def test_cleanup_completed(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
approval_id = await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
await capability.resolve(approval_id, ApprovalAction.APPROVE, "approver-1")
cleaned = capability.cleanup_completed()
assert cleaned == 1
assert capability.get_state(approval_id) is None
@pytest.mark.asyncio
async def test_cleanup_does_not_remove_pending(self, enabled_config):
capability = BaseApprovalCapability(enabled_config)
await capability.create_approval(
agent_id="agent-1",
command="/run test",
requester_id="user-1",
)
cleaned = capability.cleanup_completed()
assert cleaned == 0