Windmill 集成测试体系深度解析:基于 docker-compose 的升级兼容性与端到端回归方案
2026/9/14 14:46:03 网站建设 项目流程

Windmill 集成测试体系深度解析:基于 docker-compose 的升级兼容性与端到端回归方案

【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill

Windmill 集成测试(integration tests)是该开源工作流引擎为保障"每次提交到 main 分支"后的端到端质量而设计的自动化测试体系:先部署最新发布的稳定镜像,再升级到本次提交构建的 dev 镜像,并借助WMILL_RUNNING_DEV环境变量验证"旧数据 + 新版本"的升级兼容性。读完本文,你将掌握该测试套件的完整执行流程、docker-compose 测试基础设施、各测试用例的断言逻辑,以及如何在本地复现这套端到端回归方案。

测试定位与核心设计思想

集成测试位于仓库的 integration_tests 目录,其设计目标非常明确:在每次 push 到 main 分支时(排除 tag 提交)自动运行,验证 Windmill 全链路功能在真实部署环境下的可用性。

该体系最核心的设计思想是升级兼容性验证。传统集成测试往往只在单一版本上运行,而 Windmill 的这套测试采用"先跑稳定版、再跑 dev 版"的双轮模式:

  1. 第一轮:拉取[version.txt](https://link.gitcode.com/i/8a71e67f94201581555595ad68a4c777)中记录的最新已发布镜像,部署完整的 Windmill 栈,运行全部测试;
  2. 第二轮:将栈升级到本次提交构建的 dev 镜像(tag 为dev),再次运行全部测试。

两轮之间,脚本、Flow、Schedule 等实体对象不会被删除,而是带着第一轮部署的数据直接进入第二轮。此时WMILL_RUNNING_DEV环境变量被置为1,测试代码据此切换行为——这正是验证"在旧版本 Windmill 上部署的 scripts/flows/schedules,升级后不会损坏"的关键机制。部分测试只有在WMILL_RUNNING_DEV == 1时才跳过或才运行,从而将"升级回归"与"纯 dev 新功能验证"两类场景清晰隔离。

测试流水线的四个阶段

整个流程由 run.sh 脚本驱动(set -euo pipefail保证任何一步失败即中止):

阶段操作说明
1. 准备 Python 环境python -m venv .venv/pip install -r requirements.txt创建独立虚拟环境,避免污染系统 Python
2. 启动稳定版栈WM_IMAGE=... WM_VERSION=... docker compose up -d部署[docker-compose.yml](https://link.gitcode.com/i/9c908a919323cb4999ba606daf37bc0c)定义的完整服务
3. 第一轮测试.venv/bin/python -m unittest -v test针对已发布稳定版本运行全部测试类
4. 升级并重测WM_VERSION=dev docker compose up -d,然后WMILL_RUNNING_DEV=1 python -m unittest -v test升级到 dev 镜像后重跑,并同步收集日志到./logs/docker-compose.log

其中docker compose logs --no-color --follow会将容器日志重定向到integration_tests/logs目录,便于 CI 失败时归档排查。依赖清单见 requirements.txt,核心为httpx(HTTP 客户端)、docker(容器管理,用于 agent worker 测试)与gitpython

测试基础设施:docker-compose 服务拓扑

docker-compose.yml 定义了测试所需的完整服务栈,共 5 个服务:

  • dbpostgres:14,暴露5432端口,通过 healthcheck(pg_isready)等待就绪,数据持久化到db_data卷。注释指出如需外部数据库,可将 replicas 设为 0 并在.env中指定DATABASE_URL
  • windmill_server${WM_IMAGE}:${WM_VERSION},暴露8000端口,设置DATABASE_URLMODE=server,healthcheck 用curl -f http://localhost:8000/api/version探测 API 可用性,并依赖 db 健康;
  • windmill_worker:同样使用${WM_IMAGE}:${WM_VERSION}MODE=workerWORKER_GROUP=default,限制 1 CPU / 2048M 内存,挂载 Docker socket(允许 worker 内部运行 Docker 容器)及worker_dependency_cache卷;注释提示调试时可KEEP_JOB_DIR=true并挂载/tmp/windmill
  • npm_registryverdaccio/verdaccio(端口4873),为 SDK 测试提供私有 NPM registry,配置见 verdaccio/config.yaml——监听localhost:4873npm_registry:4873,包默认代理到官方 npmjs;
  • pypi_serverpypiserver/pypiserver:latest(端口8080),为 Python SDK 测试提供私有 PyPI 服务。

镜像与版本由 common.sh 统一注入:

export WM_VERSION=$(cat ${root_dirpath}/version.txt) export WM_VERSION_DEV="dev" export WM_IMAGE="ghcr.io/windmill-labs/windmill-ee"

即:稳定版版本号取自 version.txt(当前仓库为1.809.0),dev 版固定为dev标签,镜像统一使用 Enterprise 版镜像windmill-ee

测试用例集:从多语言脚本到 Agent Worker

所有测试类通过 test/init.py 聚合导出,python -m unittest -v test会自动发现并运行它们。

多语言脚本回归测试

test/identity_script_test.py 验证 Windmill 支持的 6 种脚本语言(bash、bun、deno、go、python3、php)能否正确执行"恒等函数"并回传结果:

  • 第一轮(非 dev)创建脚本:create_script(path="u/admin/{lang}_identity_script", content=..., language=lang)
  • 每个语言一个独立测试方法,断言run_sync返回原值。有趣的是 bash 断言为字符串"5",注释说明"bash only knows strings"——体现了对不同语言类型系统的差异化处理;
  • dev 轮(WMILL_RUNNING_DEV=1)则删除脚本,完成对旧版本部署脚本的清理验证。

跨语言 Flow 流水线测试

test/increment_flow_test.py 是测试套件中最具代表性的用例:构建一个 5 模块的 Flow(deno → bun → python3 → go → bash),每个模块对输入x执行+1,并通过input_transforms串联:

{ "id": "b", "value": { "type": "rawscript", "content": "export async function main(x: number) {\\n return x + 1\\n}\\n", "language": "bun", "input_transforms": { "x": { "expr": "results.a", "type": "javascript" } } } }

最终断言输入x=5经过+5(第一个模块的flow_input.x + 5)再加 4 次+1后,bash 输出字符串"15"。这同时验证了跨语言数据传递、results.{id}引用语法与 Flow 调度引擎的正确性。

Schedule 定时调度测试

test/schedule_test.py 创建基于脚本(u/admin/scheduled_script)和基于 Flow(u/admin/scheduled_flow)的两个 Schedule,cron 表达式为*/5 * * * * *(每 5 秒),时区Europe/Paris。测试轮询jobs/list?script_path_exact=...接口,等待 30 秒内出现created_at晚于测试开始时间的运行记录,从而证明调度器在稳定版与升级后的 dev 版上都能持续触发任务。

Agent Worker 测试

test/agent_workers.py 是套件中依赖 Docker SDK 的特殊用例,覆盖 Windmill 的 Agent 模式:

  • 通过/api/agent_workers/create_agent_token生成jwt_agent_前缀的 JWT token,并解析 payload 断言worker_grouptagsexp字段;
  • 用 Docker SDK 启动一个MODE=agent+AGENT_TOKEN=...的容器,通过get_workers_list轮询确认 Agent 成功连接;
  • 创建一个带agent_test自定义标签的 bash 脚本并同步运行,验证标签路由让任务落到 Agent worker 上。

容器清理通过atexit.register(cleanup_docker_container)兜底,防止测试崩溃后残留容器。

WindmillClient:测试与后端 API 的桥梁

所有测试都复用 test/wmill_integration_test_utils.py 中的WindmillClient,它封装了完整的 API 交互,是理解测试原理的关键:

  • 登录与会话:向/api/auth/loginPOSTadmin@windmill.dev / changeme(与 docker-compose 的默认管理员一致),换取 Bearer token,client 超时设为 60 秒——注释说明"Go/Rust 首次编译可能耗时 10 秒以上";
  • License 注入_set_license_key读取LICENSE_KEY环境变量并 POST 到/api/settings/global/license_key,这就是 README 中WM_LICENSE_KEY_CI的落地方式——Enterprise 版本必须携带有效 license key,全部测试才能运行
  • Workspace 管理:自动创建integration-tests工作区(已存在则跳过),对应真实用户按 workspace 隔离资源的模型;
  • 核心执行方法run_sync(path, args, type):POST 到/api/w/{workspace}/jobs/run_wait_result/{type}/{path}type="p"运行脚本、type="f"运行 Flow。该端点在后端实现于 jobs.rs 的run_wait_result_script_by_path,会先校验 license key(check_license_key_valid)、校验 scope(jobs:run:scripts:{path})、执行参数预处理,再调用内部实现排队执行并等待结果;
  • 部署状态轮询create_script提交后轮询/scripts/deployment_status/h/{hash},直至lock字段非空(部署成功)或出现lock_error_logs(部署失败),并带有 60 秒超时;
  • 此外还封装了 Flow、Schedule、Variable、Resource、Git Sync 配置、fork workspace、Gitea 客户端等大量辅助方法。

本地运行指南:免镜像的轻量调试

README 明确指出,本地直接跑测试并不轻松——因为需要一份包含最新代码的 Docker 镜像。但测试本质上只是向http://localhost:8000发起 API 调用,因此可以绕过容器直接用本地编译的二进制运行。

前置条件:WindmillEnterprise 版本,需要 license key,设置为环境变量WM_LICENSE_KEY_CI

以运行identity_script_test.py为例,终端 1 启动本地服务:

cargo run --features enterprise

终端 2 运行测试:

python -m unittest -v test.TestIdentityScript

这种"真实后端 + Python 测试客户端"的模式让开发者无需构建 Docker 镜像即可快速验证单点功能。注意部分测试需要额外准备(详见下文 SDK 测试)。

SDK 测试的特殊准备:私有 registry 发布

README 特别提示:SDK 相关测试需要 Windmill SDK 包先发布到私有 NPM registry 或 PyPI 服务器,自定义准备逻辑封装在 build.sh 中。该脚本的完整流程为:

  1. source common.sh读取镜像与版本变量,docker pull稳定版与 dev 版镜像;
  2. 调用.github/change-versions.sh将版本号临时改为${WM_VERSION}-dev
  3. 启动npm_registry服务,通过 curl 向 Verdaccio 注册windmill用户(密码changeme),再用npm-cli-login完成登录;
  4. 执行 typescript-client/publish.sh 将 TypeScript SDK 发布到http://localhost:4873
  5. docker compose down清理,并通过change-versions.sh恢复原版本号。

脚本末尾的注释# TODO: publish Python SDK to private PyPI registry表明 Python SDK 的发布逻辑尚未实现——这也解释了 README TODO 列表中"Test Python SDK"的由来。

CI 集成:与镜像构建流水线的联动

这套测试并非孤立运行,而是作为 Docker 镜像发布流水线的质量关卡。在 .github/workflows/docker-image.yml 中,run_integration_testjob 依赖build_ee(Enterprise 镜像构建),运行在ubicloud上,步骤为:

- name: Prepare test run run: cd integration_tests && ./build.sh - name: Test run timeout-minutes: 15 env: LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }} run: cd integration_tests && ./run.sh - name: Archive logs uses: actions/upload-artifact@v4 with: path: integration_tests/logs

两个步骤都带有条件! startsWith(github.ref, 'refs/tags/v'),与 README 所述"每次 push 到 main(排除 tags)"一致;测试失败时日志会作为 artifact 归档;tag_latestjob 又依赖run_integration_test集成测试通过后才允许打latesttag,可见该套件是发布门禁的重要一环。

已知缺口:待补充的测试场景

README 的 TODO 列表清晰标注了当前套件尚未覆盖的领域,对希望贡献测试代码的开发者是很好的切入点:

  • 测试 Python SDK
  • 测试 job 失败场景(当前主要验证成功路径)
  • 测试专用 worker(dedicated workers)
  • Schedule 的 Error handlers 与 Recovery handlers
  • 并发限制(Concurrency limits)

小结

Windmill 的集成测试体系提供了一套可复用的"升级兼容性 + 端到端回归"参考范式:以 docker-compose 构建接近生产的服务拓扑,用轻量 Python 客户端直连真实 API,通过环境变量切换"旧数据跑新版本"的验证模式,并让该套件嵌入 CI 作为发布门禁。对于需要保障"数据库与已部署实体跨版本不破坏"的开发者,这套方案的思路(稳定版播种 → dev 版回归 → 差异化断言)可以直接借鉴。

【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询