安装与更新端到端测试
这些测试旨在回答一个核心问题:在已发布的版本中,用户是否能够访问到该代码提交?
每个测试步骤都会先安装一个旧版本的已发布软件,然后再将其升级到最新版本。在安装和升级过程中,实际的用户界面流程会被完整执行。这些测试步骤不会使用模拟对象,也不会借助无头代理来模拟图形界面操作。
测试结构层次
该测试系列由四个层次构成,每个层次承担特定的功能:
scripts/sandbox/generate-e2e-matrix.mjs文件用于定义支持矩阵。它会列出所有{操作系统, 安装方式, 升级方式}的组合,并根据选定的发布版本标签对这些组合进行筛选。该文件并不了解 CI 环境能够运行哪些组合。.github/workflows/install-e2e.yml是主要的流水线文件。它负责选择发布版本标签,运行生成器脚本,然后为每种操作系统创建一个对应的测试任务。此外,它还会在运行摘要中生成计划图表和结果图表。- 各个运行流水线负责处理具体的功能实现。
install-e2e-run.yml用于 Linux 系统,install-e2e-windows-run.yml用于 Windows 系统,而install-e2e-macos-run.yml则会根据需要选择共享脚本驱动或 macOS 图形界面驱动。在任务级别,通过if:条件语句来筛选出受支持的组合,其余组合则直接被跳过,并以灰色显示。 - 最后由相应的驱动脚本执行实际操作。
tests/install/installer-script-e2e.sh用于处理 POSIX 脚本安装,tests/install/macos-desktop-e2e.sh用于处理 macOS dmg 安装,tests/install/windows-e2e.ps1则用于处理 Windows 系统的安装。安装和升级方式作为独立的维度,需遵循各自流水线所设定的功能限制条件。 要声明新方法,需编辑生成器。若要实现某方法,则需在运行工作流中切换相关开关,并扩展驱动程序。
隔离技巧
驱动程序在处理 Git 操作时不会接入网络。每个驱动程序都会在 serve.git 处创建一个基础克隆版本,然后让所有的 Git 进程都指向这个克隆版本。其实现机制是驱动程序拥有一个 GIT_CONFIG_GLOBAL 文件,其中通过 url.<file://serve.git>.insteadOf 的重写规则,针对标准仓库地址进行了处理。
驱动程序会将 serve.git 中的 main 分支锁定在旧版本状态。安装程序运行时会加载该旧版本的内容。之后,驱动程序再将 main 分支移动到 HEAD 位置。这样一来,更新即可像普通用户一样正常应用。
安装脚本不会被下载。安装阶段会从旧的 Git 参考地址获取代码副本——这正是该版本用户所使用的代码版本;而更新阶段则会从 HEAD 位置获取最新代码。
各阶段的职能
使用脚本驱动程序的每个阶段包含以下步骤:
- 准备阶段:创建一个基础克隆版本,并将
main分支指向旧版本的代码。 - 安装阶段:运行旧版本自带的安装脚本。需确保当前检出的是旧版本的代码,并且
hermes --version能正常执行。 - 桌面应用功能测试:通过已安装的 CLI 运行
hermes desktop --build-only命令。该步骤用于验证已安装版本具备构建桌面应用的能力。如果安装版本不支持此命令,该阶段将跳过并继续后续操作。 - 更新阶段:将
main分支移至最新提交位置,然后选择一种更新方式。需确保当前检出的是最新版本的代码,并且hermes --version能正常执行。 - 再次进行桌面应用功能测试:在最新版本代码基础上再次执行上述测试步骤。
当使用 desktop-installer@latest 作为安装方式时,Windows GUI 驱动程序会替代第 2 和第 4 阶段的操作。该驱动程序会下载已发布的 Hermes-Setup.exe 文件,通过 AutoHotkey 自动操作安装向导窗口,再利用 Playwright 在运行中的应用程序中点击“立即更新”。
旧版本处理
旧版本的客户端仍可安装数月前的发布版本。驱动程序不得假设旧版本具备当前版本的 CLI 接口。核心原则是:主动检测,切勿臆断。
- 对于安装脚本,需从旧版本代码对应的脚本文本中读取相关参数。
- 对于已安装的 CLI,可通过
--help参数向程序查询可用选项。 - 若未找到某项参数,则无需使用该参数,这不属于错误情况。
安装方式
installer-script:平台的单行命令(Linux和MacOS上为curl | bash,Windows上为irm | iex)。installer-script+desktop:在开启桌面应用构建选项(通过--include-desktop/-IncludeDesktop参数)后的相同单行命令。该选项会在安装过程中构建桌面应用;在Windows系统中还会注册开始菜单和桌面快捷方式,而在Linux和MacOS系统中则仅在检查点内构建应用,不会注册任何操作系统入口点。desktop-installer@latest:通过标准用户流程生成的图形界面安装程序(Windows上为Hermes-Setup.exe,MacOS上为Hermes-Setup.dmg)。
两种应用更新方式
由于桌面应用存在两种启动路径,因此对应两种应用更新方法。两种方式均需在正在运行的应用中点击“立即更新”。二者的区别在于应用的启动方式。
-
open-app-update:应用从已安装的应用入口点启动。在 Windows 系统上,桌面安装程序和installer-script+desktop都会创建快捷方式,因此这两种方式都支持该启动路径。而在 Linux 和 macOS 上,脚本中的可选桌面阶段会在构建过程中直接生成,而不会注册任何操作系统级入口点。因此,macOS 版本需要通过桌面安装程序进行安装;Linux 则没有对应的open-app-update路径。 -
hermes-desktop-app-update:应用通过hermes desktop命令启动。在所有提供桌面应用的操作系统中,每种安装方式都会提供该命令。在 Linux 系统上,这是唯一的应用启动方式——该系统既没有桌面安装程序,也没有任何打包好的桌面应用程序文件。驱动程序会使用e2e-assets/launch-capture/sitecustomize.py工具捕获产品自身的启动参数(argv、cwd、环境变量),然后在 Playwright 环境中重新执行这些参数,由 Playwright 来控制应用并触发更新流程。
跳过
出现灰色路径是正常现象,其原因主要有两点:
- 该路径对虽已声明但无法运行:要么该路径对应的操作系统级入口点不存在(通过普通脚本安装后使用
open-app-update时没有可用的启动入口),要么相应的驱动程序尚未开发完成。运行工作流中的筛选机制会列出那些可以运行的路径对。 - 应用的初始发布版本早于正在测试的界面版本。例如,某个版本未包含
apps/desktop组件,因此没有可启动的窗口。主工作流中的tag_has_desktop标签注释会用于标记这类版本。 运行摘要中的结果图表会显示每个测试环节的运行状态,即通过、失败或跳过。已确认的历史升级限制记录了在目标版本中无法解决的故障,并附有具体的发布提交信息及CI测试证据。这些并非简单的跳过操作:原有的测试路径依然会执行。签名完全匹配的情况不会标记为红色,而是被单独归类为已知故障,并在结果图表底部的脚注中予以说明。同一标签下出现的无关错误仍会导致测试失败。
触发条件与成本
该矩阵不会在拉取请求时运行。因为每个测试环节都需要安装真实的工具链,耗时超过10分钟。触发条件包括:
- 定时任务,每12小时执行一次,用于检测上游代码的变动。
- 发布标签推送,即起始版本集合发生变化的时刻。
- 手动启动。用户可自行选择测试路径和标签数量:
gh workflow run install-e2e.yml --ref <branch> -f route=both -f tag-count=2
每次运行的成本其实早已明确:每个被采样标签需要执行41次检测(Windows 18、macOS 15、Linux 8系统),因此计划性运行和发布标签相关的运行会分别对2个标签进行采样,总检测次数最高可达82次。而手动调度的默认值为每个标签3次检测,总次数最高可达123次。一次常规的检测通常在7到15分钟内完成,单次检测的时间上限为60分钟。若想降低检测成本,可选用特定的路由方案:update(仅适用于Linux系统,每标签8次检测)、windows-desktop(Windows 18系统,每标签18次检测)、macos-desktop(macOS 15系统,每标签15次检测)。tag-count的值必须在1到10之间。GitHub规定的256个任务限制是针对每个操作系统组合单独计算的,而非所有检测次数的总和;当使用10个标签时,不同系统组合分别可容纳180个Windows任务、150个macOS任务以及80个Linux任务。若使用15个标签,Windows系统的任务数将率先超过这一限制(达到270个)。
不建议在本地直接运行驱动程序,除非是在临时虚拟机中。Windows系统的驱动程序在关闭时会终止所有名为Hermes的进程,而macOS系统的驱动程序则运行在 /Applications/Hermes.app 目录下;如果在已安装真实Hermes版本的机器上运行这些驱动程序,它们会与该程序产生冲突。
构建产物
每个执行环节都会将其日志作为构建产物上传。同时,每个环节还会记录整个运行过程的屏幕画面:复合操作 .github/actions/e2e-screen-record 会安装 ffmpeg,并利用操作系统的屏幕捕获功能(Linux 上使用 x11grab,Windows 上使用 gdigrab,MacOS 上使用 avfoundation)进行录制;如果缺少录制内容或帧数为零,则该环节会执行失败。由于 Linux 环境中没有显示设备,因此该操作会首先启动 Xvfb :99,并为后续所有步骤设置 DISPLAY 环境变量——这样被测试的应用程序与屏幕捕获工具就能共享同一显示界面。而基于 Windows GUI 的执行环节则会上传截图以及更新结果文件,可通过命令 gh run download <run-id> 获取这些内容。