
TDengine TDgpt 服务管理单元测试实战指南从环境搭建到源码级用例解读【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengineTDgpt 是 TDengine 内置的时序数据分析智能体而taosanode_service.py则是负责 taosanode 主服务与 AI 模型服务生命周期管理的核心脚本。本文以 tools/tdgpt/tests/README.md 为骨架结合 taosanode_service.py 的真实实现与测试用例系统讲解该测试套件的环境准备、运行方式、测试结构与覆盖范围并逐一解读ProcessManager、Config、TaosanodeService、ModelService四大被测类的底层逻辑。读完本文你将能够独立运行、扩展并理解这一套跨平台Linux/Windows服务管理单元测试也能借此掌握 taosanode 进程治理与模型编排的完整实现脉络。测试套件定位守护 TDgpt 服务管理核心TDgpt 服务管理系统的核心职责由 tools/tdgpt/script/taosanode_service.py 承担它对外暴露一组命令行接口CLIpython taosanode_service.py start # 启动 taosanode 主服务 python taosanode_service.py stop # 停止 taosanode 主服务 python taosanode_service.py status # 查看主服务状态 python taosanode_service.py model-start tdtsfm # 启动指定模型服务 python taosanode_service.py model-start all # 启动全部模型服务 python taosanode_service.py model-stop all # 停止全部模型服务 python taosanode_service.py model-status # 查看所有模型状态 python taosanode_service.py wait-ready # 等待 /status 就绪 python taosanode_service.py install-service # 安装 Windows 服务 python taosanode_service.py uninstall-service # 卸载 Windows 服务 python taosanode_service.py start-service # 启动 Windows 服务 python taosanode_service.py stop-service # 停止 Windows 服务tools/tdgpt/tests/目录下的单元测试正是为这套管理系统而写目标是在不实际启动真实进程、不下载模型权重的前提下验证 PID 文件读写、进程存活检测、优雅/强制终止、服务等待超时、配置加载、模型编排等关键路径的正确性。环境准备与依赖安装运行测试前需安装 Python 测试依赖README 中的 Prerequisites 部分pip install pytest pytest-mock pytest-covpytest测试框架与用例收集、断言、skipif 标记的基础pytest-mock提供mockerfixture用于 Mock 子进程调用与文件操作pytest-cov生成覆盖率报告支持 HTML/XML 输出。值得注意的一点是conftest.py在sys.path中插入了../script目录直接from taosanode_service import Config, ModelService, ProcessManager, TaosanodeService导入被测模块见 conftest.py因此测试运行无需先安装 taosanode也不要求虚拟环境或模型目录真实存在——这正是该套件轻量、可 CI 化的关键设计。运行测试的完整命令矩阵README 提供了从粗到细、从基础到 CI 集成的完整运行方式全部命令均可在仓库根目录或tools/tdgpt/下执行。运行全部测试pytest tests/运行指定测试文件pytest tests/test_process_manager.py pytest tests/test_config.py pytest tests/test_taosanode_service.py pytest tests/test_model_service.py注意README 中使用的文件名与仓库实际文件名存在命名差异。仓库tools/tdgpt/tests/下实际文件名为process_manager_test.py、config_test.py、taosanode_service_test.py、model_service_test.py同时还有anomaly_test.py、forecast_test.py、restful_api_test.py、service_registry_sync_test.py等更多用例文件。运行时应以仓库实际文件名为准例如pytest tests/process_manager_test.py pytest tests/config_test.py pytest tests/taosanode_service_test.py pytest tests/model_service_test.py运行指定测试类pytest tests/process_manager_test.py::TestProcessManager运行指定测试方法pytest tests/process_manager_test.py::TestProcessManager::test_read_pid_file_exists详细输出模式pytest -v tests/-v会打印每个用例的完整名称、状态PASSED/SKIPPED/FAILED与执行耗时是定位平台跳过用例最直接的方式。生成 HTML 覆盖率报告pytest --covscript/taosanode_service --cov-reporthtml tests/报告生成于htmlcov/index.html可直观看到taosanode_service.py中每个函数、每个分支的覆盖情况。若需要与代码覆盖率平台集成可使用 XML 输出见下文 CI 小节。按标记筛选用例# 运行除平台跳过标记外的全部用例README 中两条命令均为该意图 pytest -m not skipif tests/更精确的用法是直接利用用例上的pytest.mark.skipif条件让 pytest 在运行前自动判断平台并跳过详见平台差异与 skipif一节无需手工筛选。测试结构五类文件各司其职README 将测试文件分为五类角色文件职责conftest.py共享 pytest fixtures 与测试配置process_manager_test.py测试ProcessManager进程生命周期管理config_test.py测试Config配置加载与默认值taosanode_service_test.py测试TaosanodeService主服务生命周期model_service_test.py测试ModelService模型编排conftest.py 的 fixture 设计conftest.py 提供五个关键 fixturemocker一个自实现的pytest-mock兼容 helper_SimpleMocker包装unittest.mock.patch/patch.object在用例结束时统一stopall()避免 patch 泄漏到其他用例temp_dir通过tempfile.mkdtemp()创建临时目录测试后自动清理保证 PID 文件、日志目录等测试产物不污染仓库mock_config构造一个Config实例将install_dir、log_dir、data_dir、cfg_dir、pid_file、model_dir、venv_dir等路径全部重定向到临时目录并预置bind 0.0.0.0:6035、workers 2同时真实创建所需目录process_manager基于mock_config构造ProcessManager(mock_config)taosanode_service/model_service分别构造TaosanodeService与ModelService实例。这一 fixture 链体现了清晰的测试分层配置隔离 → 进程管理 → 主服务/模型服务各层之间通过依赖注入解耦测试代码与真实代码保持相同的构造方式。四大被测类的覆盖要点与源码印证ProcessManagerPID 与进程生命周期ProcessManager 是套件中用例最多、覆盖最细的类process_manager_test.py 的覆盖点与源码一一对应1. PID 文件操作读/写/删除read_pid、write_pid、remove_pid三个方法围绕 PID 文件展开源码 L401-L423。测试通过patch.object(process_manager, _get_pid_file, return_valuepid_file)将 PID 文件指向临时文件分别验证文件存在且内容为1234时read_pid(test) 1234文件不存在时返回None内容非法如not_a_number时因ValueError被捕获而返回Nonewrite_pid(5678, ...)后文件内容为5678remove_pid(...)后文件消失。2. 进程存活检测Windows 与 Unix 双路径is_running源码 L484-L520实现了两种平台的检测策略Unixos.kill(pid, 0)发送信号 0 探测进程是否存在进程不存在时抛出ProcessLookupError被捕获返回False。测试用当前进程 PIDos.getpid()验证存在场景用超大 PID999999验证不存在场景Windows调用tasklist /FI PID eq pid /NH并精确解析输出第二列为 PID同时通过_matches_expected_process做二次校验——检查进程命令行中是否包含taosanode_service.py、taosanalytics.app、gunicorn等标记避免PID 复用导致误判源码 L445-L482。测试通过 mocksubprocess.run的返回值模拟有/无匹配行。3. 进程终止优雅与强制kill_process(pid, force)源码 L531-L545WindowsforceFalse时执行taskkill /PID pidforceTrue时追加/F强制标志Unix分别发送signal.SIGTERM与signal.SIGKILL。测试用mocker.patch(subprocess.run)/mocker.patch(os.kill)断言命令行参数与信号类型完全正确。4. 服务等待与超时wait_for_service源码 L522-L529以 0.5 秒为间隔轮询is_running直到超时。测试覆盖三种场景立即成功、超时失败、延迟启动通过side_effect[False, False, True]模拟前两次未就绪第三次就绪。Config配置加载与容错Config 负责加载cfg/taosanode.config.py。config_test.py 的覆盖点包括1. 默认值与模型定义默认bind 0.0.0.0:6035、workers 2与 taosanode.config.py 一致models字典非空包含六个模型tdtsfm、timemoe、moirai、chronos、timesfm、moment必需模型tdtsfm、timemoerequiredTrue缺失即报错可选模型chronos、timesfm、moirai、momentrequiredFalse目录缺失时跳过启动模型脚本与端口断言tdtsfm → tdtsfm-server.py / 6061、timemoe → timemoe-server.py / 6062、chronos → chronos-server.py / 6063。六个模型在配置中的完整端口与端点定义如下来自 taosanode.config.py模型启动脚本默认模型端口端点必需tdtsfmtdtsfm-server.py无6061/tdtsfm是timemoetimemoe-server.pyMaple728/TimeMoE-200M6062/ds_predict是moiraimoirai-server.pySalesforce/moirai-moe-1.0-R-small6064/ds_predict否chronoschronos-server.pyamazon/chronos-bolt-base6063/ds_predict否timesfmtimesfm-server.pygoogle/timesfm-2.5-200m-pytorch6065/ds_predict否momentmoment-server.pyAutonLab/MOMENT-1-base6066/imputation否2. 路径创建与校验mock_config断言log_dir、data_dir、cfg_dir、model_dir均真实存在且所有路径字段install_dir、pid_file、app_log、venv_dir等均为字符串类型防止配置类型错误在运行时才暴露。3. 自定义配置加载与缺失回退test_config_with_custom_path演示了如何通过Config(config_file)传入自定义配置文件并加载bind、workers、modelstest_config_fallback_on_missing_file则验证配置文件不存在时全部回退到默认值。这对应源码中_load_config的完整异常兜底逻辑源码 L192-L296配置文件缺失时仅记录 warning 后继续使用默认路径加载异常时同样逐项回退确保服务管理脚本在任何安装状态下都能弱可用。4. gunicorn 配置契约test_gunicorn_threads_is_integer直接加载 taosanode.config.py断言threads为整数且不小于 2——该值由max(multiprocessing.cpu_count() // 4 1, 2)推导是 Linux 端 gunicorn 工作线程数的契约性校验。TaosanodeService主服务生命周期与启动诊断TaosanodeService 管理 taosanode 主服务。taosanode_service_test.py 的覆盖点包括1. 状态查询与优雅停止status()返回{service: taosanode, running: True, pid: 1234, bind: 0.0.0.0:6035}服务未运行时stop()返回True并清理 PID 文件运行中停止时先kill_process(pid, forceFalse)优雅终止若仍存活再强制终止对应 stop() 源码 L1320-L1342。2. 启动预检模式Preflight_get_requested_preflight_mode通过环境变量控制预检开关TAOSANODE_PREFLIGHT_MODEfull/heavy→ 完整预检off/false/0/none→ 关闭light/basic→ 关闭并告警轻量预检已移除TAOSANODE_FULL_PREFLIGHT/TAOSANODE_LIGHT_PREFLIGHT布尔开关默认模式为off即 Windows 启动默认直接拉起进程。测试验证了默认off、light环境变量映射为off并触发告警两条路径。3. 启动失败诊断与冷却_handle_startup_failure将失败分类为bind端口占用、import_native依赖缺失/原生库加载失败、serve、unknown四类ImportError如缺少 waitress→import_native触发完整诊断逐模块 import probeOSError(EADDRINUSE)→bind不触发完整诊断后台进程提前退出如 Windows access violation0xc0000005→ 判定为原生失败并采集诊断。同时TAOSANODE_STARTUP_DIAGNOSTIC_COOLDOWN默认 300 秒通过taosanode-startup-diagnostics.json时间戳抑制自动重启期间的重复诊断输出——测试用两次连续失败验证诊断只执行一次。4. 就绪等待wait-readywait_ready源码 L1359-L1402轮询http://127.0.0.1:port/status响应 200 且包含ready即视为就绪在 Windows 服务模式下即使进程检测暂时失败只要 SCM 状态为START_PENDING/RUNNING就继续等待。测试用side_effect模拟三次探测两次异常 一次 ready 响应并配合 mock 服务状态序列验证该容错逻辑。ModelService多模型并发编排ModelService 负责模型服务的启动/停止/状态查询。model_service_test.py 的覆盖点包括未知模型名返回False模型已运行时start幂等返回True必需模型目录缺失返回True但记录跳过源码中该行为用于目录未下载则跳过的容忍策略可选模型目录缺失同样跳过且不影响整体正常启动路径mock_get_python_exe、subprocess.Popen、wait_for_service、PID 读写后断言成功停止路径未运行模型直接返回True并清理 PID。并发编排_start_all/_stop_all使用ThreadPoolExecutor(max_workers3)并发启动/停止六个模型源码 L1686-L1776并输出包含 Started / Skipped缺少模型目录/ Failed 分类的汇总日志——这与 README 中Concurrent model operations / Required vs optional model handling的覆盖描述完全对应。平台差异与 skipif 标记由于进程管理与信号机制在 Windows/Unix 上差异巨大测试用例通过平台常量配合skipif实现自动跳过IS_WINDOWS platform.system().lower() windows pytest.mark.skipif(not IS_WINDOWS, reasonWindows-only test) def test_is_running_windows_process_exists(self, process_manager, mocker): ... pytest.mark.skipif(IS_WINDOWS, reasonUnix-only test) def test_kill_process_unix_graceful(self, process_manager, mocker): ...规则非常直观Windows-only 用例pytest.mark.skipif(not IS_WINDOWS, reasonWindows-only test)在非 Windows 平台跳过Unix-only 用例pytest.mark.skipif(IS_WINDOWS, reasonUnix-only test)在 Windows 平台跳过。这样同一套测试代码可在 CI 的 Linux 与 Windows runner 上复用pytest 在收集阶段即完成平台筛选-v输出中会以SKIPPED标注被跳过的用例。Mocking 策略不碰真实进程的隔离测试README 明确测试通过unittest.mock与pytest-mock对四类资源进行隔离Mock 目标典型方法子进程调用mocker.patch(subprocess.run)、mocker.patch(subprocess.Popen)文件操作mocker.patch(os.path.exists)、mocker.patch(builtins.open)、临时目录 fixture进程管理mocker.patch.object(process_manager, is_running)、mocker.patch(os.kill)日志调用mocker.patch.object(logger, warning)、logger.handlers.clear()这套策略的核心价值在于测试永远不会真正拉起 Python 进程、下载模型权重或占用 6035/6061 等真实端口所有副作用都停留在 Mock 层因此用例可以在无 GPU、无虚拟环境、无网络的本机与 CI 上稳定运行。接入 CI/CD 流水线README 末尾给出了 CI/CD 集成命令pytest tests/ --covscript/taosanode_service --cov-reportxml --junit-xmltest-results.xml该命令一次产出两类报告--cov-reportxml生成coverage.xml可对接 SonarQube、Codecov 等覆盖率平台--junit-xmltest-results.xml生成 JUnit XML 格式结果可被 Jenkins、GitLab CI 等流水线直接解析用于失败归因与趋势统计。实际落地 CI 时可结合仓库内的测试基础设施参考执行入口例如 test/ci/pytest.sh 与 test/ci/run.sh 展示了 pytest 在 TDengine CI 中的标准运行方式同时建议在 CI 矩阵中同时包含 Linux 与 Windows runner以完整覆盖skipif两侧的用例分支。小结TDgpt 服务管理测试套件围绕taosanode_service.py的四大类ProcessManager、Config、TaosanodeService、ModelService构建了从 PID 文件操作、进程探测、优雅/强制终止、超时等待到配置回退、启动失败诊断、多模型并发编排的完整覆盖网络。它以Mock 一切副作用、隔离一切真实资源为原则配合平台感知的skipif标记与 conftest fixture 分层既适合本地快速验证也天然适配 Linux/Windows 双平台 CI。后续若需为 taosanode 增加新的能力如新增模型、新的启动诊断规则可遵循同样的模式在 taosanode_service.py 中实现逻辑在tools/tdgpt/tests/中补充对应测试文件最后在 taosanode.config.py 中登记模型配置即可获得与既有用例一致的隔离验证与 CI 保障。【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考