Pruebas de fechas en un pipeline
La ventana sirve para explorar. Esta es la otra mitad: una compilación de línea de comandos de unos 2,4 MB sin entorno de ejecución que instalar, cuyo código de salida es el veredicto de cobertura y no el del propio objetivo.
El código de salida es el veredicto
Esta es la decisión de diseño que hace la herramienta scriptable. Cuando termina una sesión, el código de salida responde a «¿tuvo efecto la sustitución del tiempo?», no a «¿qué devolvió la aplicación?». Un pipeline puede entonces fallar ante una sustitución que silenciosamente no ocurrió - que es el fallo por el que merece la pena fallar, porque todo lo que viene después es una prueba que no demostró nada.
El código de salida del propio objetivo se sigue informando, en los datos de la sesión.
| Código | Significado |
|---|---|
| 0 | funciona - todo proceso que leyó la hora vio el reloj de la sesión |
| 10 | funciona parcialmente - algunos canales cubiertos, otros no |
| 11 | no funciona - la sustitución no llegó a los canales clave |
| 4 | indeterminado - no se pudo establecer la cobertura |
| 1 | error de uso - una opción o una expresión incorrecta |
| 2 | el objetivo no se pudo lanzar ni inyectar |
| 12 | el objetivo desapareció, lo que sugiere una aplicación de instancia única |
| 3 | error interno - el motor no pudo arrancar, llegó a un estado inesperado o se detuvo antes de cerrar la sesión (sea cual sea su propio código de salida). Una ejecución así no lleva veredicto |
| 5 | la operación no está incluida en esta versión |
| 6 | la ejecución se cortó - venció --timeout, o el motor dejó de responder durante 15 segundos y se detuvo. No es un veredicto: la sesión se interrumpió, así que no demuestra nada sobre el objetivo en ningún sentido |
| 7 | ya hay otra sesión en marcha - solo una sesión a la vez. Basta con volver a intentarlo cuando termine |
| 8 | la sesión llegó a un veredicto, pero su evidencia no está en el archivo que indica --report - el disco estaba lleno, u otro programa mantenía abierto el archivo anterior, que entonces queda como estaba. El veredicto sigue en el informe que imprime el comando |
Todas las opciones de ambos comandos, y la misma tabla para la calculadora, están en la referencia de la línea de comandos.
Ejecuciones acotadas
Un pipeline no puede esperar a que una persona cierre una aplicación de escritorio.
--ticks N termina la sesión tras N latidos - de un segundo real cada uno - e informa
de lo que encontró hasta ese momento. La cobertura se establece en los primeros instantes del
proceso de todos modos, así que un límite corto suele bastar.
# Diez segundos, luego parar e informar chrono run ".\build\test.exe" --preset year-rollover --ticks 10 --report evidence.txt
Salida para máquinas y evidencias
--jsonemite la sesión como registros legibles por máquina en lugar del informe para personas - los mismos hechos, incluida la cobertura por canal.--report <path>escribe el informe para personas en un archivo, que sirve como artefacto de compilación. Una sesión cuyo veredicto no sea funciona abre ese archivo con un aviso de evidencia poco fiable en lugar de enterrar la salvedad al final.- La calculadora también entiende
--json, de modo que un pipeline puede calcular la fecha que necesita y devolverla.
# Calcular la fecha y luego ejecutar en ella chrono calc --base today --snap eom --json chrono run ".\build\test.exe" --preset month-end --ticks 10 --json
Un paso, más o menos
- name: Month-end behaviour
shell: pwsh
run: |
.\chrono.exe run ".\build\test.exe" --preset month-end --ticks 10 --report evidence.txt
# un código de salida distinto de cero aquí significa que la sustitución no tuvo efecto,
# así que la prueba siguiente no habría demostrado nada
- name: Keep the evidence
uses: actions/upload-artifact@v7
with:
name: chrono-evidence
path: evidence.txt
Dos salvedades honestas sobre los runners
- Necesita un runner de Windows. No hay versión para Linux ni macOS, y no la habrá - en Linux, libfaketime ya cubre este caso.
- El antivirus de un runner alojado puede bloquear la inyección. Desplazar el tiempo implica inyectar una biblioteca en el proceso objetivo, una técnica documentada de Windows que también usa el malware. Un runner que la bloquee produce un código de salida que lo dice en vez de un falso éxito - pero conviene averiguarlo antes de depender de ello.
Por la misma razón, la suite de pruebas de extremo a extremo de este proyecto se ejecuta en máquinas reales y no en un runner alojado. Su integración continua compila y prueba todo con pruebas unitarias, y la sustitución en sí se ejercita a mano con aplicaciones reales, tanto en compilaciones de 32 como de 64 bits, antes de cada versión.