- 新增 ConfsTask(ITask,与 HttpTask 同构):ConfigStore + INI/JSON 取值 + get/list/reload/health 四路由,协议与 Python confs 逐字节兼容 - 新增 ConfsLogC 异步日志客户端(沿用 confs2 LogC,服务名 confs) - main.cpp 新增 --confs <port> 选项与 CONFS_* 环境变量;不传则行为不变 - Makefile 链接 -lus_msg,版本 0.0.4 → 0.1.0 - _run.sh 启用 --confs 8010;_set.sh 自建 configs → ../confs/configs 链接 - init.txt 移除 confs2 自启动行(由 core 内嵌承担) - 黑盒对比测试 16/16 通过(tests/blackbox/test_core_confs.py)
121 lines
4.3 KiB
Python
121 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""core 内嵌 confs 黑盒测试 — 与 Python confs 行为对比
|
|
|
|
前置条件:
|
|
- Python confs 运行于 :8010(基线)
|
|
- core (nidus.out) 以 --confs 8012 启动
|
|
|
|
用法: python3 test_core_confs.py [core_port] [py_port]
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, '/opt/micro_servers/pymsg')
|
|
from pymsg.rpc import RpcClient, RpcError
|
|
|
|
CORE_PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8012
|
|
PY_PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 8010
|
|
CONFIG_DIR = '/opt/micro_servers/confs/configs'
|
|
|
|
|
|
def call(port, route, payload=None):
|
|
return RpcClient('127.0.0.1', port, 'test').call(route, payload)
|
|
|
|
|
|
def call_err(port, route, payload=None):
|
|
"""返回错误信息字符串;若未报错则返回 None"""
|
|
try:
|
|
call(port, route, payload)
|
|
return None
|
|
except RpcError as e:
|
|
return str(e)
|
|
|
|
|
|
passed = failed = 0
|
|
|
|
|
|
def check(label, cond):
|
|
global passed, failed
|
|
if cond:
|
|
passed += 1
|
|
print(f' [PASS] {label}')
|
|
else:
|
|
failed += 1
|
|
print(f' [FAIL] {label}')
|
|
|
|
|
|
def main():
|
|
print('========== 1. health ==========')
|
|
h = call(CORE_PORT, 'health')
|
|
print(' core:', h)
|
|
check('status=ok', h['status'] == 'ok')
|
|
check('service=confs', h['service'] == 'confs')
|
|
check('config_dir 指向 confs/configs', h['config_dir'].endswith('confs/configs'))
|
|
|
|
print('========== 2. list ==========')
|
|
l2, l0 = call(CORE_PORT, 'list'), call(PY_PORT, 'list')
|
|
n2 = sorted(c['name'] for c in l2['configs'])
|
|
n0 = sorted(c['name'] for c in l0['configs'])
|
|
print(' core:', n2)
|
|
check('文件清单一致', n2 == n0)
|
|
check('size 一致',
|
|
{c['name']: c['size'] for c in l2['configs']}
|
|
== {c['name']: c['size'] for c in l0['configs']})
|
|
|
|
print('========== 3. get 全文 (db.ini) ==========')
|
|
g2 = call(CORE_PORT, 'get', {'name': 'db.ini'})
|
|
g0 = call(PY_PORT, 'get', {'name': 'db.ini'})
|
|
check('content 一致', g2['content'] == g0['content'])
|
|
check('size 一致', g2['size'] == g0['size'])
|
|
|
|
print('========== 4. get INI 键 ==========')
|
|
import configparser
|
|
cp = configparser.ConfigParser(interpolation=None)
|
|
cp.read(os.path.join(CONFIG_DIR, 'db.ini'))
|
|
sec = cp.sections()[0]
|
|
opt = list(cp[sec].keys())[0]
|
|
key = f'{sec}.{opt}'
|
|
k2 = call(CORE_PORT, 'get', {'name': 'db.ini', 'key': key})
|
|
k0 = call(PY_PORT, 'get', {'name': 'db.ini', 'key': key})
|
|
print(f' key={key} core={k2["value"]!r} py={k0["value"]!r}')
|
|
check('INI 键值一致', k2['value'] == k0['value'])
|
|
|
|
print('========== 5. 错误用例(两边都应报错且信息一致) ==========')
|
|
for label, payload in [('不存在的配置', {'name': 'nope.ini'}),
|
|
('路径穿越', {'name': '../etc/x.ini'}),
|
|
('非法类型', {'name': 'x.exe'}),
|
|
('缺 name', None),
|
|
('键不存在', {'name': 'db.ini', 'key': 'no.such'})]:
|
|
e2 = call_err(CORE_PORT, 'get', payload)
|
|
e0 = call_err(PY_PORT, 'get', payload)
|
|
print(f' {label}: core={e2!r} py={e0!r}')
|
|
check(f'{label} 错误一致', e2 is not None and e2 == e0)
|
|
|
|
print('========== 6. reload ==========')
|
|
r2 = call(CORE_PORT, 'reload', {'name': 'db.ini'})
|
|
r0 = call(PY_PORT, 'reload', {'name': 'db.ini'})
|
|
check('reload 单个', r2 == r0 == {'reloaded': ['db.ini']})
|
|
r2, r0 = call(CORE_PORT, 'reload'), call(PY_PORT, 'reload')
|
|
check('reload 全部返回集合一致', sorted(r2['reloaded']) == sorted(r0['reloaded']))
|
|
|
|
print('========== 7. INI option 大小写不敏感 ==========')
|
|
ku2 = call(CORE_PORT, 'get', {'name': 'db.ini', 'key': f'{sec}.{opt.upper()}'})
|
|
check('大写 option 取值一致', ku2['value'] == k0['value'])
|
|
|
|
print('========== 8. JSON 配置(若存在) ==========')
|
|
jsons = [f for f in os.listdir(CONFIG_DIR) if f.endswith('.json')]
|
|
if jsons:
|
|
j2 = call(CORE_PORT, 'get', {'name': jsons[0]})
|
|
j0 = call(PY_PORT, 'get', {'name': jsons[0]})
|
|
check(f'{jsons[0]} content 一致', j2['content'] == j0['content'])
|
|
else:
|
|
print(' (无 .json 配置,跳过)')
|
|
|
|
print()
|
|
print(f'结果: {passed} 通过, {failed} 失败')
|
|
return 1 if failed else 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|