Chrono Mock
ЯзыкРусский

Тестирование дат в конвейере

Окно нужно для изучения. А это вторая половина: сборка для командной строки размером около 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-разрядных сборках.

Попробуйте