Chrono Mock
语言简体中文

在流水线中做日期测试

窗口用来探索,这里是另一半:一个约 2.4 MB 的命令行版本,无需安装任何运行时,它的退出码是覆盖情况的判定,而不是目标程序自己的退出码。

退出码就是判定

这个设计决定让该工具可以被脚本调用。会话结束时,退出码回答的是“时间替换有没有生效”,而不是“应用返回了什么”。因此,流水线可以在替换悄悄没有发生时直接失败——这正是值得为之失败的情形,因为它之后的一切都是什么也没证明的测试。

目标程序自己的退出码仍然会被报告,记录在会话数据中。

退出码含义
0生效——所有读取过时间的进程看到的都是会话时钟
10部分生效——部分通道已覆盖,部分未覆盖
11未生效——替换没有到达关键通道
4无法确定——无法确认覆盖情况
1用法错误——参数错误或表达式错误
2无法启动目标程序,或无法向其注入
12目标程序消失了,这表明它可能是单实例应用
3内部错误——引擎无法启动、遇到意外状态,或在关闭会话之前就停止了(无论目标程序自己的退出码是什么)。这样的运行不带判定
5此版本未内置该操作
6运行被中途截断——--timeout 到期,或者引擎 15 秒没有响应而被停止。这不是判定:会话被中断了,因此对目标程序无论哪种情况都说明不了什么
7已有另一个会话在运行,一次只能运行一个会话。等它结束后重试即可
8会话已得出判定,但证据没有写入 --report 指定的文件:磁盘已满,或另一个程序打开着旧文件,旧文件因此保持不变。判定仍在命令输出的报告中

两个命令的所有参数,以及计算器对应的同一张表,都在命令行参考中。

限定时长的运行

流水线不能等人去关闭一个桌面应用。--ticks N 会在 N 次心跳(每次一个真实秒)之后结束会话,并报告到那一刻为止的发现。覆盖情况本来就是在进程启动的最初阶段确定的,所以通常设一个较短的上限就够了。

# 运行十秒,然后停止并报告
chrono run ".\build\test.exe" --preset year-rollover --ticks 10 --report evidence.txt

机器输出与证据

  • --json 以机器可读的记录输出会话,而不是给人读的报告——事实完全相同,包括逐个通道的覆盖情况。
  • --report <path> 把给人读的报告写入文件,作为构建产物很合适。判定不是生效的会话,会在该文件开头放一条证据不可靠的横幅,而不是把这个提醒埋在末尾。
  • 计算器同样支持 --json,所以流水线可以算出需要的日期,再把它传回去使用。
# 先算出日期,再按该日期运行
chrono calc --base today --snap eom --json
chrono run ".\build\test.exe" --preset month-end --ticks 10 --json

一个步骤的大致写法

- name: Month-end behaviour
  shell: pwsh
  run: |
    .\chrono.exe run ".\build\test.exe" --preset month-end --ticks 10 --report evidence.txt
    # 这里退出码非零,说明替换没有生效,所以
    # 它后面的测试什么也证明不了

- name: Keep the evidence
  uses: actions/upload-artifact@v7
  with:
    name: chrono-evidence
    path: evidence.txt

关于运行器的两点如实说明

  • 它需要 Windows 运行器。没有 Linux 或 macOS 版本,以后也不会有——在 Linux 上,libfaketime 已经能胜任这件事。
  • 托管运行器上的杀毒软件可能会拦截注入。改变时间需要把一个库注入目标进程,这是一种有文档记载的 Windows 技术,恶意软件也在使用。被运行器拦截时,你得到的是说明此事的退出码,而不是一次虚假的通过——但这是你在依赖它之前就该弄清楚的事。

出于同样的原因,本项目自己的端到端测试套件在真实机器上运行,而不是在托管运行器上。它的持续集成会构建并对所有内容做单元测试;至于替换本身,则在每次发布之前,由人工在 32 位和 64 位两种构建上针对真实应用逐一验证。

亲自试试