chore(root): 收纳根目录调试产物与项目级文件
**项目级文件**: - configs/mkdocs.yml mkdocs 站点配置 - jumpserver-webcli/ANALYSIS.md webcli 调试分析报告 - jumpserver-webcli/CHANGELOG.md webcli 变更日志 - jumpserver-webcli/deploy_0802_*.txt 0802 部署调试输出(4 个) - jumpserver-webcli/diag_0802_*.txt 0802 诊断输出(3 个) - jumpserver-webcli/diag_184715.txt 18:47:15 诊断输出 - tests/test_quick_rules.py quick_rules API 测试 - temp/ 临时调试脚本目录(5 个:check_tables + 调试 + rename_dzpc + ts-check + inspect_batch) **交付报告**: - overview.md 「结束会话失败」修复交付报告(2026-07-30,ChatPanel.vue 三件套修复) **会话调试上下文**: - dedup_context.txt / dedup2.txt 去重调试上下文 - pattern_check.txt / pattern_context.txt 模式检查 - option_button_context.txt / option_select_context.txt 选项按钮/选择上下文 - qid.txt 会话 ID 记录 - yixuan_context.txt 艺璇任务上下文 - final_check.txt 最终检查 **部署脚本输出**: - deploy_v11.txt / deploy_h5_v11.txt v11 部署命令输出 合计 27 文件(含 1 项目文档 + 22 调试上下文 + 4 jumpserver webcli 调试 + 1 mkdocs 配置 + 1 测试 + 1 temp/ + 2 部署输出)
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
# =============================================================================
|
||||
# 企微IT智能服务台 — 快速规则单元测试
|
||||
# =============================================================================
|
||||
# 用途:测试 QuickRuleService 单元逻辑
|
||||
# 日期:2026-07-27
|
||||
# 运行:pytest tests/test_quick_rules.py -v
|
||||
# =============================================================================
|
||||
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
from app.models.quick_rule import QuickRule
|
||||
from app.services.quick_rule_service import QuickRuleService
|
||||
|
||||
|
||||
class TestQuickRuleService:
|
||||
"""QuickRuleService 单元测试"""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_cache(self):
|
||||
"""每个测试前重置缓存"""
|
||||
QuickRuleService._cache = {
|
||||
'greeting': [],
|
||||
'routing_prefilter': {},
|
||||
'routing_target': {},
|
||||
}
|
||||
QuickRuleService._initialized = False
|
||||
yield
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_all_with_greeting_rules(self):
|
||||
"""测试加载打招呼关键词"""
|
||||
mock_db = AsyncMock()
|
||||
mock_rules = [
|
||||
MagicMock(spec=QuickRule, rule_type='greeting', keyword='你好', category=None, extra_data=None, is_active=True),
|
||||
MagicMock(spec=QuickRule, rule_type='greeting', keyword='您好', category=None, extra_data=None, is_active=True),
|
||||
]
|
||||
mock_result = MagicMock()
|
||||
mock_result.scalars.return_value.all.return_value = mock_rules
|
||||
mock_db.execute.return_value = mock_result
|
||||
|
||||
await QuickRuleService.load_all(mock_db)
|
||||
|
||||
keywords = QuickRuleService.get_greeting_keywords()
|
||||
assert '你好' in keywords
|
||||
assert '您好' in keywords
|
||||
assert len(keywords) == 2
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_all_with_routing_keywords(self):
|
||||
"""测试加载路由关键词"""
|
||||
mock_db = AsyncMock()
|
||||
mock_rules = [
|
||||
MagicMock(spec=QuickRule, rule_type='routing_prefilter', keyword='打印机', category='IT服务', extra_data=None, is_active=True),
|
||||
MagicMock(spec=QuickRule, rule_type='routing_prefilter', keyword='报销', category='财务', extra_data=None, is_active=True),
|
||||
]
|
||||
mock_result = MagicMock()
|
||||
mock_result.scalars.return_value.all.return_value = mock_rules
|
||||
mock_db.execute.return_value = mock_result
|
||||
|
||||
await QuickRuleService.load_all(mock_db)
|
||||
|
||||
keywords = QuickRuleService.get_routing_keywords()
|
||||
assert keywords['打印机'] == 'IT服务'
|
||||
assert keywords['报销'] == '财务'
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_all_with_routing_targets(self):
|
||||
"""测试加载路由目标"""
|
||||
mock_db = AsyncMock()
|
||||
mock_rules = [
|
||||
MagicMock(
|
||||
spec=QuickRule,
|
||||
rule_type='routing_target',
|
||||
keyword='机票酒店前台',
|
||||
category='行政',
|
||||
extra_data={'service_name': '机票酒店前台', 'url': 'https://example.com'},
|
||||
is_active=True,
|
||||
),
|
||||
]
|
||||
mock_result = MagicMock()
|
||||
mock_result.scalars.return_value.all.return_value = mock_rules
|
||||
mock_db.execute.return_value = mock_result
|
||||
|
||||
await QuickRuleService.load_all(mock_db)
|
||||
|
||||
targets = QuickRuleService.get_routing_targets()
|
||||
assert '行政' in targets
|
||||
assert targets['行政']['service_name'] == '机票酒店前台'
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_all_handles_exception(self):
|
||||
"""测试加载异常处理"""
|
||||
mock_db = AsyncMock()
|
||||
mock_db.execute.side_effect = Exception("DB error")
|
||||
|
||||
# 不应抛出异常
|
||||
await QuickRuleService.load_all(mock_db)
|
||||
|
||||
# 缓存应保持空
|
||||
assert QuickRuleService.get_greeting_keywords() == []
|
||||
|
||||
def test_check_greeting_true(self):
|
||||
"""测试 greeting 检测为 true"""
|
||||
QuickRuleService._cache['greeting'] = ['你好', '您好']
|
||||
assert QuickRuleService.check_greeting('你好啊') is True
|
||||
assert QuickRuleService.check_greeting('您好请问') is True
|
||||
|
||||
def test_check_greeting_false(self):
|
||||
"""测试 greeting 检测为 false"""
|
||||
QuickRuleService._cache['greeting'] = ['你好', '您好']
|
||||
assert QuickRuleService.check_greeting('打印机坏了') is False
|
||||
|
||||
def test_check_greeting_empty_text(self):
|
||||
"""测试空文本"""
|
||||
assert QuickRuleService.check_greeting('') is False
|
||||
assert QuickRuleService.check_greeting(None) is False
|
||||
|
||||
def test_check_routing_keyword(self):
|
||||
"""测试路由关键词检测"""
|
||||
QuickRuleService._cache['routing_prefilter'] = {
|
||||
'打印机': 'IT服务',
|
||||
'报销': '财务',
|
||||
}
|
||||
assert QuickRuleService.check_routing_keyword('打印机连不上') is True
|
||||
assert QuickRuleService.check_routing_keyword('电脑坏了') is False
|
||||
assert QuickRuleService.check_routing_keyword('报销咨询') is True
|
||||
|
||||
def test_get_routing_target_found(self):
|
||||
"""测试获取存在的路由目标"""
|
||||
QuickRuleService._cache['routing_target'] = {
|
||||
'行政': {'service_name': '行政窗口', 'url': 'https://example.com'},
|
||||
}
|
||||
target = QuickRuleService.get_routing_target('行政')
|
||||
assert target is not None
|
||||
assert target['service_name'] == '行政窗口'
|
||||
|
||||
def test_get_routing_target_not_found(self):
|
||||
"""测试获取不存在的路由目标"""
|
||||
QuickRuleService._cache['routing_target'] = {
|
||||
'行政': {'service_name': '行政窗口', 'url': 'https://example.com'},
|
||||
}
|
||||
target = QuickRuleService.get_routing_target('不存在的')
|
||||
assert target is None
|
||||
|
||||
def test_get_categories(self):
|
||||
"""测试获取所有业务分类"""
|
||||
QuickRuleService._cache['routing_target'] = {
|
||||
'行政': {},
|
||||
'财务': {},
|
||||
'人力资源': {},
|
||||
}
|
||||
categories = QuickRuleService.get_categories()
|
||||
assert set(categories) == {'行政', '财务', '人力资源'}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_refresh_reloads_cache(self):
|
||||
"""测试 refresh 重新加载缓存"""
|
||||
mock_db = AsyncMock()
|
||||
mock_rules = [
|
||||
MagicMock(spec=QuickRule, rule_type='greeting', keyword='刷新测试', category=None, extra_data=None, is_active=True),
|
||||
]
|
||||
mock_result = MagicMock()
|
||||
mock_result.scalars.return_value.all.return_value = mock_rules
|
||||
mock_db.execute.return_value = mock_result
|
||||
|
||||
await QuickRuleService.refresh(mock_db)
|
||||
|
||||
keywords = QuickRuleService.get_greeting_keywords()
|
||||
assert '刷新测试' in keywords
|
||||
|
||||
|
||||
class TestQuickRuleDataStructures:
|
||||
"""QuickRule 数据结构测试"""
|
||||
|
||||
def test_quick_rule_model_attributes(self):
|
||||
"""测试 QuickRule 模型属性"""
|
||||
rule = QuickRule(
|
||||
rule_type='greeting',
|
||||
keyword='你好',
|
||||
priority=10,
|
||||
is_active=True,
|
||||
)
|
||||
assert rule.rule_type == 'greeting'
|
||||
assert rule.keyword == '你好'
|
||||
assert rule.priority == 10
|
||||
assert rule.is_active is True
|
||||
|
||||
def test_to_dict_conversion(self):
|
||||
"""测试 to_dict 转换"""
|
||||
from datetime import datetime
|
||||
rule = QuickRule(
|
||||
id=1,
|
||||
rule_type='greeting',
|
||||
keyword='你好',
|
||||
priority=10,
|
||||
is_active=True,
|
||||
)
|
||||
rule.created_at = datetime.now()
|
||||
|
||||
d = rule.to_dict()
|
||||
assert d['id'] == 1
|
||||
assert d['rule_type'] == 'greeting'
|
||||
assert d['keyword'] == '你好'
|
||||
assert d['priority'] == 10
|
||||
assert d['is_active'] is True
|
||||
assert 'created_at' in d
|
||||
Reference in New Issue
Block a user