ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OpenEMR 多版本矩阵 CI 架构实战:基于 Docker Compose 组合扩展的自动化测试体系

OpenEMR 多版本矩阵 CI 架构实战:基于 Docker Compose 组合扩展的自动化测试体系 医疗健康后端【免费下载链接】openemrThe most popular open source electronic health records and medical practice management solution.项目地址https://gitcode.com/GitHub_Trending/op/openemr点击查看免费下载导读本文围绕 OpenEMR 仓库中的 ci/README.md 及其配套源码完整解析这套自动化测试基础设施它如何在 GitHub Actions 中根据ci/目录下的docker-compose.yml动态构建跨 Web 服务器、PHP 版本与数据库版本的测试矩阵如何通过 Docker Compose 多文件组合compose file merging实现 DRY 的共享配置以及如何把单元测试、E2E 浏览器测试、API 测试与代码覆盖率采集串成一条流水线。读完本文你将掌握目录命名约定、ciLibrary.source共享测试库的核心函数、x-includes组合模式、覆盖率采集原理以及本地复现/调试整套 CI 环境的完整命令。一、CI 目录布局与命名约定ci/目录承载着 OpenEMR 面向多种版本与部署组合的自动化测试配置供 GitHub Actions 工作流 .github/workflows/test.yml 调用。凡是包含docker-compose.yml的子目录都对应一套独立测试环境目录名即环境描述遵循统一模式{webserver}_{phpversion}[_{dbversion}]例如apache_83_116表示Web 服务器ApachePHP 版本8.3MariaDB/MySQL 版本11.6目录名只是标签真正决定行为的是其中的docker-compose.yml。若目录名以_no-e2e结尾则该配置会跳过端到端E2E测试——这一判断由 ci/parse_docker_dir.sh 中的[[ ${docker_dir} *_no-e2e ]]完成。从当前仓库实际内容看ci/下同时覆盖了 Apache 与 Nginx 两大阵营例如apache_83_123、apache_84_123、apache_85_114、nginx_83~nginx_87以及带_upgrade升级链路测试和_redis_sentinel*Redis 哨兵高可用后缀的扩展组合全部作为workflow_dispatch的手动触发选项列在 test.yml 中。所有测试共用同一份源码脚本 ci/ciLibrary.source它负责搭建环境可选启用覆盖率采集并提供一组 shell 函数供每个测试套件调用。二、动态测试矩阵系统GitHub Actions 工作流不写死环境清单而是基于ci/下的目录动态构建矩阵工作流解析目录名提取 Web 服务器、PHP 版本与数据库版本读取该目录的docker-compose.yml确定具体数据库镜像为 GitHub Actions 生成一条针对该组合的测试配置。解析逻辑全部落在 ci/parse_docker_dir.sh 中核心步骤用yq读取services.mysql.image去掉sha256:...摘要后缀后按:切分得到数据库厂商与版本如mariadb:11.4.13→ databasemariadb、db11.4.13按_切分目录名得到 webserver 与 PHP 版本如apache_85_114→ apache / 8.5通过yq读取x-includes下的node-version、selenium-template、webserver-template、database-template、mailpit-template与可选的redis-sentinel-template拼接出COMPOSE_FILE环境变量多文件组合的完整-f列表输出 JSON 供工作流写入GITHUB_OUTPUT与GITHUB_ENV。工作流的setupjob 解析配置后会计算测试套件列表test.yml基础套件为[api,services,email,webui若e2e_enabledtrue则追加e2e若启用了 Redis 哨兵模板则追加redis-failover而 README 提到的common、controllers、fixtures、validators、unit套件则由integration-tests.yml覆盖。这样新增环境组合时无需改动工作流文件本身。三、测试套件全景CI 按顺序/并行运行多组测试套件ci/README.md 列出的核心套件如下套件内容Unit Tests针对单个函数与类的基础单元测试E2E Tests基于 Panther ChromeDriver经 Selenium Grid的端到端浏览器测试API TestsREST API 端点测试Fixtures Tests数据库 fixtures 测试Services Tests服务类测试Validators Tests数据校验类测试Controllers Tests控制器类测试Common Tests公共工具函数测试工作流实际还会运行email邮件发送依托 Mailpit与webui套件。套件的统一入口是ciLibrary.source中的build_test()ciLibrary.source按套件名分发——api走 PHPUnit 并附加 API 目录覆盖率参数e2e转发给build_test_e2eredis-failover转发给build_test_redis_failover其余套件走通用 PHPUnit 分支并附带coverage_args中声明的覆盖率过滤目录apis、gacl、interface、library、modules、oauth2、portal、sites、src、tests。build_test_e2e()ciLibrary.source完整展示了 E2E 链路启动selenium/video容器 → 检查 chromedriver 版本 → 以--testsuite e2e运行 PHPUnit内存上限 8G启用覆盖率时加-d xdebug.modecoverage→ 停止容器并抽取录屏video.mp4→ 若存在时间线文件则调用ci/e2e-video-chapters.php为视频生成章节索引WebVTT方便评审者直接跳转到关心的测试用例。四、共享测试库 ciLibrary.source 深度解析ciLibrary.source是整套 CI 的大脑以set -xeuo pipefail起手严格模式提供以下关键函数dc()docker compose $的短包装所有后续编排命令统一走它ciLibrary.source。with_retry()指数退避重试工具。Docker Hub 在 CI 中会出现瞬时拉取超时issue #12423不重试则一次抖动会让整个矩阵任务失败。用法with_retry MAX_ATTEMPTS DELAY cmd args...ciLibrary.source。pull_images()与dockers_env_start()先带重试拉取全部镜像dc pull --quiet --ignore-buildable再用dc up --detach --quiet-pull --wait --wait-timeout 300拉起整套环境RUNNER_TEMP下的标记文件保证每个 job 只拉取一次ciLibrary.source。_exec()在openemr容器内以OPENEMR_DIR为工作目录执行命令启用覆盖率时自动注入XDEBUG_MODEcoverageciLibrary.source。web_user_in_openemr()探测容器内 Web 用户——Apache 镜像用apachenginxphp-fpm 镜像用www-data从而让同一套封装代码横跨整个矩阵ciLibrary.source。dump_database()/import_database()在mysql容器内自动检测mariadb-dump/mysqldump或mariadb/mysql实现 MariaDB/MySQL 双兼容的数据库快照导出导入供测试任务并行恢复同一份初始数据ciLibrary.source。install_configure()把docker/flex/auto_configure.php拷入容器后以 Web 用户身份运行contrib/util/installScripts/InstallerAuto.php rootpassroot servermysql loginhost%完成静默安装随后通过 MySQL 直接改写globals表开启rest_api、rest_fhir_api、rest_portal_api、rest_system_scopes_api设为 1、oauth_password_grant与ccda_alt_service_enable设为 3并写入product_registration退出遥测ciLibrary.source。post_install_upgrade()从 flex 镜像内置的 5.0.0 演示数据 dump 重新灌库再沿sql/下的升级脚本链式升到当前版本复刻开发者本地openemr-cmd driddev-reset-install-demodata的流程升级后需重写一遍 CI 专属 globalsciLibrary.source。dump_error_log()按 webserver 类型导出 Apache error.log 或提示 php-fpm 日志在容器日志中ciLibrary.source。此外ciLibrary.source还内置了 Redis 哨兵故障转移测试build_test_redis_failover覆盖 TLS/mTLS 模式、故障前写入验证、哨兵选举轮询、故障后健康恢复与数据存活校验以及 coredump 采集诊断enable_coredumps/capture_coredumps用于定位 Apache worker segfault 与原生扩展问题属于 README 之外、源码中真实存在的进阶能力。五、Docker Compose 扩展系统DRY 的多文件组合整套 CI 依赖 Docker Compose 的多文件组合compose file merging来避免在多个测试环境间重复配置。共享基线配置如下共享文件职责compose-shared-selenium/docker-compose.ymlSelenium GridE2E与录屏容器总是被包含compose-shared-apache.ymlApache 基础配置不含数据库专属项compose-shared-nginx/compose.ymlNginx 基础配置不含数据库专属项compose-shared-mariadb.ymlMariaDB 专属项compose-shared-mysql.ymlMySQL 专属项compose-shared-mailpit/compose.ymlMailpit 邮件测试配置每个测试目录如apache_85_114的docker-compose.yml只负责两件事声明使用哪两个基础配置Web 服务器 数据库并挑选具体数据库版本与 PHP 版本。其标准骨架如下# 注意x-includes 不会被 Docker Compose 真正解析而是供脚本parse_docker_dir.sh # 读取来构建多文件组合的命令行参数。 x-includes: node-version: 24 selenium-template: compose-shared-selenium/docker-compose.yml webserver-template: compose-shared-apache.yml database-template: compose-shared-mariadb.yml mailpit-template: compose-shared-mailpit/compose.yml services: mysql: image: mariadb:11.4.13sha256:611a2fcc5fa7c6ceb8644c6f74b25ede004ff6c3a6b38c8f8c23d3bbf6c26430 openemr: image: openemr/openemr:flex-3.24-php-8.5sha256:71f93832be5cf1d0c0d27a66bba6c6c92b9d732a64c31a908372f3845c8746bb注意数据库服务必须命名为mysql以兼容测试脚本的固定引用。五种组合模板新增配置时按目标组合选择模板ci/README.md 给出了四种标准形态Apache MariaDBx-includes: selenium-template: compose-shared-selenium/docker-compose.yml webserver-template: compose-shared-apache.yml database-template: compose-shared-mariadb.yml services: mysql: image: mariadb:version # 指定 MariaDB 版本 openemr: image: openemr/openemr:tag # 指定 PHP 版本Apache MySQLx-includes: selenium-template: compose-shared-selenium/docker-compose.yml webserver-template: compose-shared-apache.yml database-template: compose-shared-mysql.yml services: mysql: image: mysql:version # 指定 MySQL 版本 openemr: image: openemr/openemr:tag # 指定 PHP 版本Nginx MariaDB / Nginx MySQLx-includes: selenium-template: compose-shared-selenium/docker-compose.yml webserver-template: compose-shared-nginx/compose.yml database-template: compose-shared-mariadb.yml # 或 compose-shared-mysql.yml services: mysql: image: mariadb:version # 或 mysql:version openemr: image: openemr/dev-php-fpm:php-version # Nginx 侧使用 php-fpm 镜像共享基线内的关键配置Selenium Gridcompose-shared-selenium/docker-compose.ymlselenium/standalone-chromium镜像通过profiles: [selenium, video-recording]默认不启动只在需要时激活暴露 4444 端口1920×1080 虚拟屏healthcheck 探测/wd/hub/statusvideo容器selenium/video:ffmpeg-*用于录屏同时给openemr注入SELENIUM_USE_GRIDtrue、SELENIUM_HOSTselenium。Apache 基线compose-shared-apache.yml映射 80/443 端口把仓库根目录绑定挂载到/var/www/localhost/htdocs/openemr设置OPENEMR_DEPRECATION_MODE: error把弃用告警升级为错误、OPENEMR_ENABLE_CI_PHP: 1、ENABLE_COVERAGE/PCOV_ON随外部环境变量透传SELENIUM_BASE_URL: http://openemr并关闭种子患者的生日弹窗OPENEMR_SETTING_patient_birthday_alert: 0见 issue #11980healthcheck 每 10 秒探测https://localhost/meta/health/readyzstart_period: 10m。数据库基线MariaDB 侧以mariadbd --character-set-serverutf8mb4启动、root 密码rootMySQL 侧以mysqld启动两者都要求openemr服务depends_on数据库达到service_healthy才启动。Mailpitcompose-shared-mailpit/compose.ymlaxllent/mailpit镜像MP_MAX_MESSAGES: 5000并通过OPENEMR_SETTING_EMAIL_METHOD: SMTP、OPENEMR_SETTING_SMTP_HOST: mailpit、端口 1025 等环境变量把 OpenEMR 的邮件全部导向 Mailpit实现邮件测试零外部依赖。新增与修改配置的规范新增一套测试配置的步骤按{webserver}_{phpversion}[_{dbversion}][_no-e2e]创建新目录决定 Apache 还是 Nginx分别用compose-shared-apache.yml或compose-shared-nginx/compose.yml决定 MariaDB 还是 MySQL分别用compose-shared-mariadb.yml或compose-shared-mysql.yml在目录内写入docker-compose.yml套用上文五类模板确保数据库服务名为mysql需要跳过 E2E 时给目录名加_no-e2e后缀按需微调本配置专属的额外设置。修改共享配置时需特别注意改动compose-shared-selenium、compose-shared-apache、compose-shared-nginx、compose-shared-mariadb、compose-shared-mysql、compose-shared-mailpit会影响所有引用它们的测试环境因此要么保持向后兼容要么同步更新各环境文件并在多个环境中验证改动。六、CI 环境变量流水线依赖的环境变量由 ci/parse_docker_dir.sh 写入GITHUB_ENV变量含义DOCKER_DIR包含 Docker Compose 配置的目录名ENABLE_COVERAGE是否启用代码覆盖率采集true/false作为工作流输入透传OPENEMR_DIROpenEMR 在容器内的路径Apache 为/var/www/localhost/htdocs/openemrNginx 为/usr/share/nginx/html/openemrCOMPOSE_FILE多文件组合模板列表冒号分隔parse_docker_dir.sh负责拼接COMPOSE_FILE的第一个文件必须是数据库模板MariaDB 或 MySQL且必须直接位于ci/目录下不能放在子目录因为 Docker Compose 会以第一个文件所在目录为基准解析所有相对路径——这正是compose-shared-mariadb.yml/compose-shared-mysql.yml放在ci/根、而 selenium/mailpit 模板允许在子目录的原因。其余依次为 Web 服务器模板、Selenium Grid 模板、Mailpit 模板以及各配置自身的docker-compose.yml。容器内部还透传若干环境变量参与测试行为除上节提到的之外覆盖率场景下XDEBUG_MODEcoverage、INFERNO_TESTtrue区分 Inferno 认证测试请求也在 ci/README-COVERAGE.md 中有完整记录。七、代码覆盖率采集机制覆盖率报告只在apache_84_114配置下启用README 的表述当前仓库实际目录为apache_85_114等启用与否由工作流的enable_coverage输入控制。启用后为覆盖率采集配置 Xdebug实际运行中优先探测更快的 pcov见configure_coverage()ciLibrary.source汇总所有测试套件的覆盖率数据生成 Clover XML 与 HTML 报告以 GitHub Actions artifact 形式上传。对于 E2E/API/Inferno 这类走 HTTP 请求的测试常规 PHPUnit 行内覆盖采集不到 Web SAPI 的执行路径因此仓库实现了前后置书签方案详见 ci/README-COVERAGE.mdPrepend/Shutdown 书签ci/auto_prepend.php 作为auto_prepend_file在每个 HTTP 请求前启动覆盖率采集ENABLE_COVERAGEtrue时请求结束时由 shutdown handler 把原始 Xdebug 覆盖数组写入/tmp/openemr-coverage/{e2e,api,inferno}/coverage.*.raw.php测试类型依据INFERNO_TESTtrue环境变量与请求 URI 是否含/apis/*自动判定。配置注入setup_e2e_bookends()ciLibrary.source检测 PHP 配置扫描目录写入含auto_prepend_file与pcov.directory的 INI 文件并拷贝进容器重启openemr后用 marker 文件验证 prepend/shutdown 钩子确实执行。转换convert_coverage()ciLibrary.source在容器内运行ci/convert-coverageCLI 工具——因为原始数组包含容器绝对路径必须在容器内解析——对每个源码目录传入--coverage-filter填充 CodeCoverage Filter输出 PHPUnit 格式的.cov文件与 Clover XML。合并最终由phpcov merge把所有.cov单元、api、e2e 等合并为最终报告。E2E 在开启覆盖率时还会把 Selenium 页面加载超时提升到 180 秒enable_e2e_coverage()ciLibrary.source以抵消auto_prepend.php埋点带来的性能开销同时刻意不覆盖SELENIUM_IMPLICIT_WAIT避免隐式等待与显式等待冲突导致超时被一次耗尽。八、本地调试复现与排查整套 CI所有调试命令都在仓库根目录下执行。把命令中的apache_84_114替换为你要测试的配置目录把compose-shared-mariadb.yml与compose-shared-apache.yml替换为该配置docker-compose.yml中x-includes声明的数据库与 Web 服务器模板。查看合并后的完整配置docker compose -f ci/compose-shared-mariadb.yml -f ci/compose-shared-apache.yml -f ci/compose-shared-selenium/docker-compose.yml -f ci/compose-shared-mailpit/compose.yml -f ci/apache_84_114/docker-compose.yml config本地启动整套环境docker compose -f ci/compose-shared-mariadb.yml -f ci/compose-shared-apache.yml -f ci/compose-shared-selenium/docker-compose.yml -f ci/compose-shared-mailpit/compose.yml -f ci/apache_84_114/docker-compose.yml up -d直接进入 OpenEMR 测试容器docker compose -f ci/compose-shared-mariadb.yml -f ci/compose-shared-apache.yml -f ci/compose-shared-selenium/docker-compose.yml -f ci/compose-shared-mailpit/compose.yml -f ci/apache_84_114/docker-compose.yml exec -it openemr sh关停并清理卷含数据库数据docker compose -f ci/compose-shared-mariadb.yml -f ci/compose-shared-apache.yml -f ci/compose-shared-selenium/docker-compose.yml -f ci/compose-shared-mailpit/compose.yml -f ci/apache_84_114/docker-compose.yml down -v重要提示README 原文强调组合命令中第一个-f条目必须在ci/根目录下若其位于子目录则会破坏相对路径解析。此外进入容器后可直接复用ciLibrary.source提供的函数例如. ci/ciLibrary.source convert_coverage /tmp/openemr-coverage/e2e coverage/coverage.e2e.cov --clovercoverage.e2e.clover.xmlCI 失败而本地通过的排查清单当 CI 失败但本地通过时按 ci/README.md 的指引依次检查PHP 版本兼容性问题数据库版本的专属特性差异Web 服务器配置差异Apache vs Nginx 的目录路径、php.ini 注入方式不同容器环境之间的路径差异尤其涉及覆盖率原始数据的容器绝对路径。结合ciLibrary.source的源码还可以进一步定位查看 Apache error.logdump_error_log apache、检查容器健康状态compose-shared 各文件中的 healthcheck 均探测readyz端点、用pull_images的重试机制规避 Docker Hub 瞬时超时等。结语OpenEMR 的 CI 体系是一个约定优于配置的典型实践新增一个测试组合只需在ci/下放一个按命名规范命名的目录和一份十几行的docker-compose.yml矩阵构建、环境拉起、测试分发与覆盖率汇总全部由 ci/parse_docker_dir.sh、ci/ciLibrary.source 与 .github/workflows/test.yml 自动完成。理解这套机制无论你是要在本地复现某次 CI 失败、新增一套 PHP/数据库组合还是改造覆盖率流水线都能从仓库源码中找到一一对应的实现依据。赞分享医疗健康后端【免费下载链接】openemrThe most popular open source electronic health records and medical practice management solution.项目地址https://gitcode.com/GitHub_Trending/op/openemr点击查看免费下载相关推荐MXNet 容器化多架构构建与测试实战指南基于 ci/build.py 的 Docker 构建体系详解MXNet 容器化多架构构建与测试实战指南基于 ci/build.py 的 Docker 构建体系详解 本指南围绕 MXNet 仓库 ci/ 目录下的容器化构深度学习机器学习人工智能Aspire CLI 端到端测试指南基于 Hex1b 终端自动化的 E2E 测试体系与 CI 并行矩阵Aspire CLI 端到端测试指南基于 Hex1b 终端自动化的 E2E 测试体系与 CI 并行矩阵 本文档围绕 Aspire 仓库中的 CLI 端到端测试云原生后端微服务可观测性开发工具n 项目测试指南基于 bats 与 Docker Compose 的 Node 版本管理工具自动化测试体系n 项目测试指南基于 bats 与 Docker Compose 的 Node 版本管理工具自动化测试体系 导读 本文围绕 n Node 版本管理器仓库中开发工具CLI上一篇PojavLauncher iOS在移动设备上运行Minecraft Java版的技术实现深度解析下一篇TypeScript类型测试神器推荐基于gh_mirrors/ut/utilities的完整实践教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表