Тестирование дат в конвейере
Окно нужно для изучения. А это вторая половина: сборка для командной строки размером около 2,4 МБ, без среды выполнения, которую нужно устанавливать, чей код завершения — это вердикт о покрытии, а не код самого приложения.
Код завершения — это вердикт
Именно это проектное решение делает инструмент пригодным для скриптов. Когда сессия заканчивается, код завершения отвечает на вопрос «подействовала ли подмена времени», а не «что вернуло приложение». Поэтому конвейер может упасть на подмене, которая тихо не произошла, — а это та самая ошибка, на которой стоит падать, потому что всё, что идёт после неё, — тест, который ничего не доказал.
Собственный код завершения цели по-прежнему сообщается — в данных сессии.
| Код | Значение |
|---|---|
| 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-разрядных сборках.