ShiErFeng/shierfeng-fastapi-backend/tests/cli/tui/adapters/test_configs_dashboard_snapshots.py
2026-07-24 09:43:10 +08:00

495 lines
22 KiB
Python

from types import ModuleType, SimpleNamespace
from pytest import MonkeyPatch
def test_collect_dashboard_snapshot_adds_risk_heat_panel(
monkeypatch: MonkeyPatch,
health_adapter: ModuleType,
) -> None:
def fake_run_nested_cli_command(*arguments: str, parse_json: bool = False) -> SimpleNamespace:
del parse_json
if arguments[0:2] == ('app', 'env'):
return SimpleNamespace(
payload={
'ok': True,
'runtime': {
'cliEnv': 'dev',
'configEnv': 'dev',
'envFile': '.env.dev',
'envFileExists': True,
},
}
)
if arguments[0:2] == ('app', 'doctor'):
return SimpleNamespace(
payload={
'ok': False,
'database': {'ok': False, 'message': '数据库连接失败'},
'redis': {'ok': True, 'message': 'Redis 正常'},
'crypto': {'ok': True, 'message': '加密组件正常'},
}
)
if arguments[0:2] == ('app', 'routes'):
return SimpleNamespace(
payload={
'ok': True,
'count': 3,
'routes': [],
'groupedRoutes': {'system': [{}, {}], 'monitor': [{}]},
}
)
if arguments[0:2] == ('db', 'current'):
return SimpleNamespace(
payload={
'ok': False,
'currentRevision': '-',
'message': 'revision unavailable',
}
)
if arguments[0:2] == ('ops', 'deps'):
return SimpleNamespace(
payload={
'ok': True,
'message': '核心运行依赖已安装',
'missingRequired': [],
'packages': {
'python': {'installed': True, 'version': '3.10.0'},
'fastapi': {'installed': True, 'version': '0.111.0'},
'sqlalchemy': {'installed': True, 'version': '2.0.0'},
'redis': {'installed': True, 'version': '5.0.0'},
},
}
)
if arguments[0:2] == ('ops', 'server-info'):
return SimpleNamespace(
payload={
'ok': True,
'server': {
'sys': {'computerName': 'shierfeng-node', 'computerIp': '10.0.0.8'},
'cpu': {'used': 18.2},
'mem': {'usage': 42.5},
},
}
)
return SimpleNamespace(
payload={
'ok': True,
'dbSize': 128,
'info': {'redis_version': '7.0', 'connected_clients': 12},
'cacheNames': ['sys_config'],
}
)
monkeypatch.setattr(health_adapter.NESTED_CLI_SUPPORT, 'run', fake_run_nested_cli_command)
snapshot = health_adapter.DASHBOARD_ADAPTER.collect_snapshot('dev')
assert any(panel.title == '总览判断' for panel in snapshot.panels)
assert any(panel.title == '建议摘要' for panel in snapshot.panels)
assert any(panel.title == '风险摘要' for panel in snapshot.panels)
assert any(panel.title == '依赖版本' for panel in snapshot.panels)
assert any(panel.title == '服务器摘要' for panel in snapshot.panels)
app_panel = next(panel for panel in snapshot.panels if panel.title == '应用摘要')
conclusion_panel = next(panel for panel in snapshot.panels if panel.title == '总览判断')
entry_panel = next(panel for panel in snapshot.panels if panel.title == '建议摘要')
assert any('当前环境: dev | CLI 目标环境: dev' in line for line in app_panel.lines)
assert any('注册路由: 3 条 | 标签分组: 2 个' in line for line in app_panel.lines)
assert conclusion_panel.status == 'fail'
assert any('数据库存在异常' in line for line in conclusion_panel.lines)
assert any('优先进入数据库页面' in line for line in conclusion_panel.lines)
assert entry_panel.status == 'fail'
assert any('[B] 数据库' in line for line in entry_panel.lines)
assert any('[O] 运维' in line for line in entry_panel.lines)
assert any('聚焦:迁移版本 / 连接状态 / Heads' in line for line in entry_panel.lines)
assert any('聚焦:数据库连通性 / Redis 连通性 / 依赖版本' in line for line in entry_panel.lines)
heat_panel = next(panel for panel in snapshot.panels if panel.title == '风险摘要')
assert heat_panel.status == 'fail'
assert any('HOT-01' in line for line in heat_panel.lines)
assert any(metric.title == '依赖通过率' and '[' in metric.value for metric in snapshot.metrics)
def test_dashboard_adapter_collect_snapshot_exposes_metrics(
monkeypatch: MonkeyPatch,
health_adapter: ModuleType,
) -> None:
def fake_run_nested_cli_command(*arguments: str, parse_json: bool = False) -> SimpleNamespace:
del parse_json
if arguments[0:2] == ('app', 'env'):
return SimpleNamespace(payload={'ok': True, 'runtime': {'cliEnv': 'dev', 'configEnv': 'dev'}})
if arguments[0:2] == ('app', 'routes'):
return SimpleNamespace(payload={'ok': True, 'count': 2, 'routes': [], 'groupedRoutes': {}})
if arguments[0:2] == ('app', 'doctor'):
return SimpleNamespace(
payload={
'ok': True,
'database': {'ok': True, 'message': '数据库正常'},
'redis': {'ok': True, 'message': 'Redis 正常'},
'crypto': {'ok': True, 'message': '加密正常'},
}
)
if arguments[0:2] == ('db', 'current'):
return SimpleNamespace(payload={'ok': True, 'currentRevision': '202604300001'})
if arguments[0:2] == ('ops', 'deps'):
return SimpleNamespace(payload={'ok': True, 'missingRequired': [], 'packages': {}})
if arguments[0:2] == ('ops', 'server-info'):
return SimpleNamespace(payload={'ok': True, 'server': {'sys': {}, 'cpu': {}, 'mem': {}}})
return SimpleNamespace(payload={'ok': True, 'dbSize': 27, 'info': {}, 'cacheNames': []})
monkeypatch.setattr(health_adapter.NESTED_CLI_SUPPORT, 'run', fake_run_nested_cli_command)
snapshot = health_adapter.DASHBOARD_ADAPTER.collect_snapshot('dev')
assert snapshot.env == 'dev'
assert snapshot.metrics
assert any(metric.title == '依赖通过率' for metric in snapshot.metrics)
assert any(panel.title == '总览判断' for panel in snapshot.panels)
def test_collect_dashboard_snapshot_uses_focus_hints_for_healthy_business_entry(
monkeypatch: MonkeyPatch,
health_adapter: ModuleType,
) -> None:
def fake_run_nested_cli_command(*arguments: str, parse_json: bool = False) -> SimpleNamespace:
del parse_json
if arguments[0:2] == ('app', 'env'):
return SimpleNamespace(payload={'ok': True, 'runtime': {'cliEnv': 'dev', 'configEnv': 'dev'}})
if arguments[0:2] == ('app', 'routes'):
return SimpleNamespace(
payload={'ok': True, 'count': 4, 'routes': [], 'groupedRoutes': {'system': [{}, {}]}}
)
if arguments[0:2] == ('app', 'doctor'):
return SimpleNamespace(
payload={
'ok': True,
'database': {'ok': True, 'message': '数据库正常'},
'redis': {'ok': True, 'message': 'Redis 正常'},
'crypto': {'ok': True, 'message': '加密组件正常'},
}
)
if arguments[0:2] == ('db', 'current'):
return SimpleNamespace(payload={'ok': True, 'currentRevision': '202604300001'})
if arguments[0:2] == ('ops', 'deps'):
return SimpleNamespace(payload={'ok': True, 'missingRequired': [], 'packages': {}, 'message': '依赖正常'})
if arguments[0:2] == ('ops', 'server-info'):
return SimpleNamespace(payload={'ok': True, 'server': {'sys': {}, 'cpu': {}, 'mem': {}}})
return SimpleNamespace(
payload={
'ok': True,
'dbSize': 27,
'info': {'redis_version': '7.2.6', 'connected_clients': 1},
'cacheNames': [],
}
)
monkeypatch.setattr(health_adapter.NESTED_CLI_SUPPORT, 'run', fake_run_nested_cli_command)
snapshot = health_adapter.DASHBOARD_ADAPTER.collect_snapshot('dev')
entry_panel = next(panel for panel in snapshot.panels if panel.title == '建议摘要')
assert entry_panel.status == 'ok'
assert any('聚焦:失败聚合 / 暂停任务 / 执行轨迹' in line for line in entry_panel.lines)
assert any('聚焦:高风险配置 / 值不一致 / 缓存漂移' in line for line in entry_panel.lines)
assert any('生成前校验' in line and '代码预览' in line for line in entry_panel.lines)
def test_collect_configs_page_snapshot_surfaces_failure_message(
monkeypatch: MonkeyPatch,
configs_adapter: ModuleType,
) -> None:
def fake_run_nested_cli_command(*arguments: str, parse_json: bool = False) -> SimpleNamespace:
del arguments, parse_json
return SimpleNamespace(
payload={
'ok': False,
'message': '读取参数配置诊断信息失败',
'error': 'database unavailable',
}
)
monkeypatch.setattr(configs_adapter.NESTED_CLI_SUPPORT, 'run', fake_run_nested_cli_command)
snapshot = configs_adapter.CONFIGS_BROWSER_ADAPTER.collect_snapshot('dev')
assert snapshot.title == '参数配置'
assert snapshot.records[0].status == 'fail'
assert snapshot.shared_sections[0].title == '总览判断'
assert snapshot.shared_sections[1].title == '配置巡检'
assert any('读取参数配置诊断信息失败' in line for line in snapshot.shared_sections[1].lines)
assert any('database unavailable' in line for line in snapshot.shared_sections[1].lines)
def test_configs_browser_adapter_collect_snapshot_exposes_search_context(
monkeypatch: MonkeyPatch,
configs_adapter: ModuleType,
) -> None:
def fake_run_nested_cli_command(*arguments: str, parse_json: bool = False) -> SimpleNamespace:
del parse_json
if arguments[0:2] == ('config', 'doctor'):
return SimpleNamespace(
payload={
'ok': True,
'databaseCount': 1,
'cacheCount': 1,
'missingInCacheCount': 0,
'orphanInCacheCount': 0,
'mismatchCount': 0,
'missingInCache': [],
'orphanInCache': [],
'mismatchKeys': [],
}
)
if arguments[0:2] == ('config', 'list'):
return SimpleNamespace(
payload={
'ok': True,
'page': {
'rows': [
{
'configId': 1,
'configKey': 'site_name',
'configName': '站点名称',
'configType': 'Y',
'configValue': 'ShiErFeng',
}
]
},
}
)
return SimpleNamespace(payload={'ok': False, 'message': 'unexpected'})
monkeypatch.setattr(configs_adapter.NESTED_CLI_SUPPORT, 'run', fake_run_nested_cli_command)
snapshot = configs_adapter.CONFIGS_BROWSER_ADAPTER.collect_snapshot('dev', query='site')
assert snapshot.title == '参数配置'
assert snapshot.search is not None
assert snapshot.search.query == 'site'
assert snapshot.records
assert snapshot.records[0].title == 'site_name'
def test_collect_configs_page_snapshot_builds_browser_records(
monkeypatch: MonkeyPatch,
configs_adapter: ModuleType,
) -> None:
calls: list[tuple[str, ...]] = []
def fake_run_nested_cli_command(*arguments: str, parse_json: bool = False) -> SimpleNamespace:
del parse_json
calls.append(arguments)
if arguments[0:2] == ('config', 'doctor'):
return SimpleNamespace(
payload={
'ok': True,
'databaseCount': 3,
'cacheCount': 3,
'missingInCacheCount': 0,
'orphanInCacheCount': 0,
'mismatchCount': 1,
'mismatchKeys': ['site_name'],
}
)
if arguments[0:2] == ('config', 'list'):
return SimpleNamespace(
payload={
'ok': True,
'page': {
'rows': [
{
'configId': 1,
'configKey': 'site_name',
'configName': '站点名称',
'configType': 'Y',
'configValue': 'ShiErFeng',
}
]
},
}
)
return SimpleNamespace(
payload={
'ok': True,
'key': 'site_name',
'source': 'both',
'inSync': False,
'database': {
'configId': 1,
'configKey': 'site_name',
'configName': '站点名称',
'configValue': 'ShiErFeng',
'configType': 'Y',
'remark': '数据库值',
},
'cache': {
'configId': 1,
'configKey': 'site_name',
'configName': '站点名称',
'configValue': 'ShiErFeng-Cache',
'configType': 'Y',
'remark': '缓存值',
},
}
)
monkeypatch.setattr(configs_adapter.NESTED_CLI_SUPPORT, 'run', fake_run_nested_cli_command)
snapshot = configs_adapter.CONFIGS_BROWSER_ADAPTER.collect_snapshot('dev')
assert snapshot.title == '参数配置'
assert (
snapshot.subtitle
== '聚焦:高风险配置 / 值不一致 / 缓存漂移 | 当前筛选:全部,已匹配 1 项配置,值不一致 1 项,缓存漂移 0 项'
)
assert snapshot.active_filter_key == 'all'
assert [option.key for option in snapshot.filters] == ['all', 'risky', 'mismatch', 'cache-drift']
assert len(snapshot.records) == 1
assert snapshot.records[0].title == 'site_name'
assert snapshot.records[0].status == 'fail'
detail_sections = snapshot.records[0].resolve_detail_sections()
assert [section.title for section in detail_sections] == ['同步状态', '数据库配置', '缓存配置']
assert any('数据库与缓存一致: 否' in line for line in detail_sections[0].lines)
assert any('键值: ShiErFeng' in line for line in detail_sections[1].lines)
assert any('键值: ShiErFeng-Cache' in line for line in detail_sections[2].lines)
assert snapshot.shared_sections[0].title == '总览判断'
assert any('值不一致: 1 项' in line for line in snapshot.shared_sections[0].lines)
assert snapshot.shared_sections[1].title == '配置巡检'
assert snapshot.shared_sections[2].title == '高风险配置'
assert snapshot.shared_sections[3].title == '异常样本'
assert snapshot.shared_sections[4].title == '配置变更入口'
assert any('config set site_name ShiErFeng --output=text' in line for line in snapshot.shared_sections[4].lines)
assert any(call[0:2] == ('config', 'get') for call in calls)
def test_collect_configs_page_snapshot_sorts_and_filters_risky_records(
monkeypatch: MonkeyPatch,
configs_adapter: ModuleType,
) -> None:
def fake_run_nested_cli_command(*arguments: str, parse_json: bool = False) -> SimpleNamespace:
del parse_json
if arguments[0:2] == ('config', 'doctor'):
return SimpleNamespace(
payload={
'ok': True,
'databaseCount': 3,
'cacheCount': 3,
'missingInCacheCount': 1,
'orphanInCacheCount': 1,
'mismatchCount': 1,
'missingInCache': ['upload_mode'],
'orphanInCache': ['legacy_toggle'],
'mismatchKeys': ['site_name'],
}
)
if arguments[0:2] == ('config', 'list'):
return SimpleNamespace(
payload={
'ok': True,
'page': {
'rows': [
{
'configId': 2,
'configKey': 'upload_mode',
'configName': '上传模式',
'configType': 'N',
'configValue': 'local',
},
{
'configId': 1,
'configKey': 'site_name',
'configName': '站点名称',
'configType': 'Y',
'configValue': 'ShiErFeng',
},
{
'configId': 3,
'configKey': 'normal_timeout',
'configName': '会话超时',
'configType': 'N',
'configValue': '30m',
},
]
},
}
)
return SimpleNamespace(payload={'ok': True, 'key': '-', 'source': 'both', 'inSync': True})
monkeypatch.setattr(configs_adapter.NESTED_CLI_SUPPORT, 'run', fake_run_nested_cli_command)
all_snapshot = configs_adapter.CONFIGS_BROWSER_ADAPTER.collect_snapshot('dev')
risky_snapshot = configs_adapter.CONFIGS_BROWSER_ADAPTER.collect_snapshot('dev', filter_key='risky')
mismatch_snapshot = configs_adapter.CONFIGS_BROWSER_ADAPTER.collect_snapshot('dev', filter_key='mismatch')
cache_drift_snapshot = configs_adapter.CONFIGS_BROWSER_ADAPTER.collect_snapshot('dev', filter_key='cache-drift')
assert [record.title for record in all_snapshot.records] == [
'site_name',
'upload_mode',
'legacy_toggle',
'normal_timeout',
]
assert [record.status for record in all_snapshot.records] == ['fail', 'warn', 'warn', 'ok']
assert any('[值不一致] site_name' in line for line in all_snapshot.shared_sections[2].lines)
assert any('[缓存缺失] upload_mode' in line for line in all_snapshot.shared_sections[2].lines)
assert any('[缓存孤立] legacy_toggle' in line for line in all_snapshot.shared_sections[2].lines)
assert risky_snapshot.active_filter_key == 'risky'
assert [record.title for record in risky_snapshot.records] == ['site_name', 'upload_mode', 'legacy_toggle']
assert [record.title for record in mismatch_snapshot.records] == ['site_name']
assert [record.title for record in cache_drift_snapshot.records] == ['upload_mode', 'legacy_toggle']
def test_collect_configs_page_snapshot_applies_query_filter(
monkeypatch: MonkeyPatch,
configs_adapter: ModuleType,
) -> None:
def fake_run_nested_cli_command(*arguments: str, parse_json: bool = False) -> SimpleNamespace:
del parse_json
if arguments[0:2] == ('config', 'doctor'):
return SimpleNamespace(
payload={
'ok': True,
'databaseCount': 2,
'cacheCount': 2,
'missingInCacheCount': 0,
'orphanInCacheCount': 0,
'mismatchCount': 0,
'missingInCache': [],
'orphanInCache': [],
'mismatchKeys': [],
}
)
if arguments[0:2] == ('config', 'list'):
return SimpleNamespace(
payload={
'ok': True,
'page': {
'rows': [
{
'configId': 1,
'configKey': 'site_name',
'configName': '站点名称',
'configType': 'Y',
'configValue': 'ShiErFeng',
},
{
'configId': 2,
'configKey': 'upload_mode',
'configName': '上传模式',
'configType': 'N',
'configValue': 'local',
},
]
},
}
)
return SimpleNamespace(payload={'ok': True, 'key': '-', 'source': 'both', 'inSync': True})
monkeypatch.setattr(configs_adapter.NESTED_CLI_SUPPORT, 'run', fake_run_nested_cli_command)
snapshot = configs_adapter.CONFIGS_BROWSER_ADAPTER.collect_snapshot('dev', query='site')
assert [record.title for record in snapshot.records] == ['site_name']
assert snapshot.search is not None
assert snapshot.search.query == 'site'