Chrono Mock

Date testing in a pipeline

The window is for exploring. This is the other half: a command-line build of about 1.6 MB with no runtime to install, whose exit code is the coverage verdict rather than the target's own.

The exit code is the verdict

This is the design decision that makes the tool scriptable. When a session ends, the exit code answers "did the time substitution take effect", not "what did the application return". A pipeline can therefore fail on a substitution that silently did not happen - which is the failure worth failing on, because everything downstream of it is a test that proved nothing.

The target's own exit code is still reported, in the session data.

CodeMeaning
0works - every process that read time saw the session clock
10works partially - some channels covered, some not
11does not work - the substitution did not reach the key channels
4undetermined - coverage could not be established
1usage error - a bad flag or a bad expression
2the target could not be launched or injected
12the target vanished, suggesting a single-instance application
3internal error - the engine could not start or hit an unexpected state
5the operation is not built in this release

Every flag of both commands, and the same table for the calculator, are on the command line reference.

Bounded runs

A pipeline cannot wait for a desktop application to be closed by a human. --ticks N ends the session after N heartbeats - one real second each - and reports what it found up to that point. Coverage is established in the first moments of the process anyway, so a short bound is usually all that is needed.

# Ten seconds, then stop and report
chrono run ".\build\test.exe" --preset year-rollover --ticks 10 --report evidence.txt

Machine output and evidence

  • --json emits the session as machine-readable records rather than the human report - the same facts, including the per-channel coverage.
  • --report <path> writes the human report to a file, which makes a reasonable build artefact. A session whose verdict is anything but works leads that file with an unreliable-evidence banner rather than burying the caveat at the bottom.
  • The calculator speaks --json too, so a pipeline can compute the date it needs and feed it back in.
# Work out the date, then run at it
chrono calc --base today --snap eom --json
chrono run ".\build\test.exe" --preset month-end --ticks 10 --json

A step, roughly

- name: Month-end behaviour
  shell: pwsh
  run: |
    .\chrono.exe run ".\build\test.exe" --preset month-end --ticks 10 --report evidence.txt
    # a non-zero exit here means the substitution did not take, so the
    # test below it would have proven nothing

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

Two honest caveats about runners

  • It needs a Windows runner. There is no Linux or macOS build, and there will not be - on Linux, libfaketime already covers this.
  • Antivirus on a hosted runner may block the injection. Shifting time means injecting a library into the target process, which is a documented Windows technique that malware also uses. A runner that blocks it produces an exit code saying so rather than a false pass - but it is a thing to find out before you depend on it.

For the same reason, this project's own end-to-end suite runs on real machines rather than on a hosted runner. Its continuous integration builds and unit-tests everything, and the substitution itself is exercised by hand against real applications on both 32-bit and 64-bit builds before a release.

Try it