Chrono Mock
JazykČeština

Reference příkazového řádku

Všechny přepínače obou příkazů, obě tabulky návratových kódů a jak číst to, co se vrátí. Vyprávěcí verze s odůvodněním je na stránce CLI a CI.

Dva příkazy

chrono run spustí aplikaci v jiném datu a čase. chrono calc vypočítá datum a řekne, čím je zajímavé. Sdílejí jednu gramatiku kroků, takže posun zapsaný pro jeden znamená totéž u druhého.

chrono version odpovídá na třetí, mnohem menší otázku: o které sestavení jde, které z obou jader je spustitelný soubor a jakou verzi protokolu používá. Jeden řádek na stdout, aby ho skript mohl zachytit.

chrono license odpovídá na čtvrtou: pod jakou licencí je toto sestavení šířeno, prohlášení o záruce a komponenty třetích stran, které jsou do něj zalinkované. Říká také, kde na disku najdete plné znění licence a upozornění k součástem třetích stran, nebo přizná, že spuštěná kopie je vedle sebe nemá. --components vypíše každou přibalenou komponentu s její verzí místo souhrnu.

chrono presets vypíše katalog presetů tak, jak ho čte --preset: každý preset ve složce zapsaný slovy, která čte gramatika kalkulačky, a každý soubor, který by odmítl, s důvodem. --json zapíše chronomock.presets/1 a --dir určí jinou složku.

chrono run <target> [options]
chrono calc [options]
chrono version        # chrono 0.4.0 (x64, protocol 1)
chrono license        # GPL-3.0-only a co je přibaleno
chrono presets        # katalog tak, jak ho čte --preset
chrono --help          # nápověda ke všem

chrono run - volby

PřepínačCo dělá
--at <moment> Okamžik, ve kterém se začne, v pásmu sezení. Absolutní (2038-01-19T03:14:07) nebo relativní s úvodním znaménkem (+1d, -2h). Jednotky: s m h d w mo q y - m jsou minuty a mo jsou měsíce. Bez tohoto přepínače začínají hodiny sezení na skutečném aktuálním čase, takže samotné --mode xN jednoduše spustí cíl rychleji.
--zone +HH:MM Pásmo sezení: pásmo, ve kterém je okamžik zapsán a které hlásí volání místního času v cíli. Pevný posun, bez letního času. Bez něj pásmo samotného hostitele.
--mode flow|frozen|xN flow běží skutečnou rychlostí, frozen drží hodiny na místě, xN je pustí N-krát rychleji (x60 promění hodinu v minutu, x1440 den).
--scale-duration Zrychlit i osu uplynulého času: čítače tiků, čas přerušení, uspání a časovače. Čekání na objekty se počítají a zachovávají svou skutečnou délku. Ve výchozím stavu vypnuto, protože nástěnné hodiny a stopky jsou různé otázky. Časovač nebo zpoždění nastavené na konkrétní datum a čas sleduje hodiny sezení s touto volbou i bez ní.
--scale-qpc Škáluje i čítač s vysokým rozlišením, ze kterého čtou uplynulý čas Python 3.13+ monotonic, .NET Stopwatch a Java nanoTime. Ve výchozím stavu vypnuto: aplikace, která podle toho čítače měří vykreslování, může vypadat zkresleně.
--ticks N Ukončí sezení po N tepech, každý trvá jednu skutečnou vteřinu, a ohlásí výsledek. Bez něj zůstává nástroj připojený, dokud neskončí cíl a každý jím spuštěný program, který běží na hodinách sezení - spouštěč, který skončí okamžitě, nechává sezení aplikaci, kterou spustil.
--timeout <s> Po tolika vteřinách to vzdá a skončí s kódem 6, pro pipeline, která nesmí viset. Nezávisle na tomto přepínači se jádro, které 15 sekund nic neřekne, zastaví a také skončí s kódem 6 - v obou případech je běh přerušen, takže nemá verdikt.
--args "..." Argumenty pro cíl jako jeden řetězec, rozdělené podle stejného pravidla, jaké používá Windows - takže argument obsahující mezery přežije. U cíle Chromium jsou --user-data-dir a --remote-debugging-port odmítnuty, ne přepsány: sezení potřebuje vlastní izolovaný profil a tiše běžet na vašem skutečném profilu prohlížeče je jediná věc, která se nesmí stát.
--cwd <dir> Spustí cíl v tomto adresáři. Bez něj cíl zdědí náš, což dělal každý běh, než tento přepínač vznikl. Prázdná hodnota je chyba použití, ne „žádný adresář“ - chybějící a prázdné jsou různé věci a Windows lze předat jen chybějící. Adresář, který neexistuje, zastaví sezení s target.cwd_missing dřív, než se cokoli spustí, místo aby se to později projevilo jako cíl, který se nespustí.
--preset <id> Převezme okamžik a rychlost z presets/<id>.json. Vylučuje se s --at, --mode a --scale-duration, protože preset je pak jediným zdrojem obojího.
--param id=value Vyplní parametr presetu. Lze opakovat, vyžaduje --preset. Pouze u run se počáteční datum zkušební doby ve výchozím stavu bere z data vytvoření spustitelného souboru cíle, takže preset zkušební doby počítá ode dne, kdy byla aplikace nainstalována, aniž byste to zadávali.
--set-after T:M V tepu T změní rychlost na M. Za běhu je násobitel alespoň 1 - zastavení hodin uprostřed sezení se zde nenabízí.
--jump-after T:moment V tepu T skočí hodinami na daný okamžik, absolutní nebo relativní, v pásmu sezení.
--force Ponechá sezení, i když úvodní verdikt říká, že náhrada času nezabrala - ve výchozím stavu se cíl místo toho zastaví, protože sezení, které nic neprokázalo, je horší než žádné sezení. Verdikt se nemění a návratový kód také ne. Rozhoduje to jen o tom, zda cíl běží dál.
--no-embedded Nechá webové stránky uvnitř aplikace (WebView2, Qt WebEngine) na skutečných hodinách a neotevře žádný ladicí port. Bez něj sezení požádá takový engine, aby otevřel místní port, a jeho stránky přes něj přepne na hodiny sezení - dokud je port otevřený, může ho kterýkoli jiný program na tomto počítači použít k tomu, aby se k těm stránkám dostal.
--elevated-embedded Pro aplikaci spuštěnou jako správce, z Chrono Mock, který běží také jako správce. WebView2 u takové aplikace ignoruje nastavení, kterým se sezení dostává k jejím stránkám, takže sezení po dobu svého trvání zapíše do registru počítače jednu hodnotu (HKLM, pojmenovanou podle .exe aplikace) a na konci ji odstraní. Dokud aplikace běží, může se k jejím stránkám přes port dostat kterýkoli jiný program na tomto počítači a aplikace má práva správce. Ne s --no-embedded.
--keep-background-timers Spustí webový engine - prohlížeč aplikace Chromium nebo Electron, nebo engine uvnitř aplikace - s vypnutým zpomalováním časovačů ve skrytých oknech, takže minimalizované okno zachová rychlost sezení. Aplikace pak pracuje plnou rychlostí i tehdy, když je skrytá. Aplikace spuštěná jako správce přes --elevated-embedded ji nedostane.
--dry-run Vypíše, jaké by sezení bylo, a nic nespustí: vyřešený okamžik a pásmo a odkud pocházejí, čím preset vyplnil jednotlivé parametry, argumenty po rozdělení a který ze dvou mechanismů by cíl použil. Nespustí se žádný proces a nezapíše se žádný soubor, včetně toho, který pojmenovává --report. Skončí kódem 0 pro proveditelný plán a 2 pro cíl, který neexistuje, což je kód, který pro stejné zjištění vrací skutečný běh. Plán nemá verdikt a říká to - verdikt má jen skutečné sezení. S --json je plán datem, včetně session.elevated_embedded a session.elevated_embedded_value, tedy názvu souboru, podle kterého by se pojmenovala hodnota v registru, když se volba vztahuje na cíl .exe, jinak null. Název tam není příslib zápisu: sezení hodnotu zapíše, jen když sám Chrono Mock běží jako správce.
--report <path> Zapíše zprávu pro lidi do souboru. Verdikt jiný než funguje začíná tento soubor bannerem o nespolehlivých důkazech, protože důkaz, který skrývá vlastní pochybnost, je horší než žádný. Tento banner dostane i sezení s verdiktem funguje, když aplikace nepřečetla žádné z hodin, které sezení nahrazuje, nebo když jde o program v Go, k jehož nástěnným hodinám Chrono Mock nedosáhne. Soubor také pojmenuje samotný běh: verzi, čas spuštění, cíl, jeho složku a přepínače.
--report-args Spolu s --report zapíše do toho souboru i argumenty cíle, doslova. Ve výchozím stavu vypnuto, protože argument může obsahovat heslo - soubor pak uvede jen jejich počet.
--json Vypíše sezení jako strojově čitelné záznamy místo zprávy - stejný proud, který spotřebovává samotné okno. Vlastní výstup konzolové aplikace jde na standardní chybový výstup, takže standardní výstup obsahuje záznamy a nic jiného. Aplikace, která ještě běží, když sezení skončí, tam dál zapisuje, takže cokoli čte standardní chybový výstup až do konce, na ni čeká, a běh to oznámí.

chrono run - návratové kódy

Návratový kód je verdikt sezení, ne to, co vrátila aplikace. Vlastní návratový kód aplikace se hlásí zvlášť, ve zprávě a v datech sezení - proč je to uděláno takto, vysvětluje stránka CLI a CI.

KódVýznam
0funguje - každý proces, který četl čas, viděl hodiny sezení
10funguje částečně - některé kanály pokryté, jiné ne
11nefunguje - náhrada času se nedostala ke klíčovým kanálům
4neurčeno - pokrytí se nepodařilo zjistit. Upřímné „nedokážu říct“, nikdy předstíraný úspěch
12cíl zmizel hned po injektáži a nezanechal nic, co by běželo na hodinách sezení, což naznačuje aplikaci s jedinou instancí, která předává řízení už běžící kopii, nebo předání programu, do kterého sezení nemohlo vstoupit, obvykle s opačnou bitovostí. Cíl, který spustí aplikaci a skončí, je spouštěč a sezení pokračuje pro aplikaci
1chyba použití - špatný přepínač, špatný výraz nebo preset, který tento příkaz nepřijme
2cíl se nepodařilo spustit nebo do něj injektovat
3vnitřní chyba - jádro se nepodařilo spustit, narazilo na nečekaný stav, nebo se zastavilo dřív, než sezení uzavřelo (bez ohledu na vlastní návratový kód cíle). Takový běh nemá verdikt
5operace není v tomto vydání sestavena - například preset, jehož okamžik potřebuje kalendář, který run zatím nedokáže načíst. Záměrně odlišné od chyby použití: požádali jste o něco, co zatím neexistuje, ne o něco špatného
6běh byl přerušen - vypršel --timeout, nebo jádro přestalo na 15 sekund odpovídat a bylo zastaveno. Není to verdikt: sezení bylo přerušeno, takže nic o cíli neprokazuje ani jedním směrem
7už běží jiné sezení - vždy jen jedno sezení naráz. Stačí to zkusit znovu, až skončí
8sezení došlo k verdiktu, ale jeho důkaz není v souboru, který určuje --report - disk byl plný, nebo jiný program držel starý soubor otevřený, a ten pak zůstane beze změny. Verdikt je dál ve zprávě, kterou příkaz vypíše

Jak číst zprávu

Bez --json sezení končí prostou zprávou. Každý řádek je buď fakt, který sezení pozorovalo, nebo chybí - nic se nedoplňuje věrohodnou výchozí hodnotou.

Chrono Mock - session report
  target:   .\build\test.exe
  verdict:  WORKS - time substitution took effect  (processes: 1)
            every process that read time saw the session clock
  session:  fake clock reached 2038-01-19T03:14:08
            real elapsed 1.3s, fake elapsed 1.3s
  exited:   the target closed itself with code 3
  covered channels (substituted, with call counts, 10 calls in all):
            - pid 21240: GetSystemTimeAsFileTime (5 calls)
            - pid 21240: GetLocalTime (5 calls)
  observed channels (hooked but left real):
            - pid 21240: NtCreateUserProcess (0 calls)
  warnings:
            - the target opened a network connection ...
  • verdict - verdikt celé rodiny přes rodičovský a všechny podřízené procesy, s počtem procesů. Právě toto číslo nese návratový kód.
  • exited - vlastní návratový kód aplikace, a to jen když se zavřela sama. Běh omezený --ticks nechává cíl běžet, sezení Chromium je takové, které nástroj zavírá sám, a sezení, které se nikdy nespustilo, takový kód nemá - řádek pak chybí, místo aby ukazoval vymyšlenou nulu. Kód pádu přichází jako velké záporné číslo, proto dostává i hexadecimální podobu.
  • covered - kanály, ke kterým se náhrada času dostala, s počtem skutečných volání každého, po procesech. Počty se mezi procesy nikdy nesčítají: audit jednoho procesu si nesmí půjčovat čísla jiného. Čítač se zastaví na 1048576 a pak ukazuje nejméně tolik.
  • observed - kanály zachycené, ale záměrně ponechané skutečné, například čekání na objekty a multimediální časovače. Mají vlastní kategorii, aby se nikdy nečetly jako nahrazené.
  • uncovered - kanály, na které se aplikace zeptala a sezení je nepokrylo. To mění verdikt na částečný.
  • not fully cleaned up - cokoli, co úklid nedokázal odstranit. Při čistém konci, tedy v běžném případě, chybí.

chrono calc - volby

Žádný přirozený jazyk: každý přepínač je jeden krok a pořadí přepínačů je pořadí kroků. Výsledek po každém kroku se vypíše, takže špatný krok je vidět, ne zasypaný.

PřepínačCo dělá
--base today|now|<moment> Kde začít, výchozí je today. Vyhodnocuje se v pásmu sezení. Nemožný den, například 2025-02-31, se odmítne, nikdy se tiše nepřevede na další měsíc.
--base-utc <moment> Jako --base, ale začátek je okamžik v UTC s volitelným koncovým Z, ne údaj nástěnných hodin v pásmu sezení.
--shift ±N<unit> Lze opakovat. Znaménko je povinné. Jednotky: s m h d w mo q y bd nebo jejich plné názvy. m jsou minuty, mo jsou měsíce. Měsíce, čtvrtletí a roky se promítají na kalendářní datum s oříznutím, takže měsíc po 31. lednu je konec února, ne pevný počet ticků. bd (pracovní dny) vyžaduje --calendar.
--set-time HH:MM:SSNastaví čas dne na aktuálním výsledku.
--snap <target> Skočí na hranici období: som eom soq eoq soy eoy (začátek nebo konec měsíce, čtvrtletí, roku). Začátek je první den v 00:00:00, konec poslední den v 23:59:59.
--nearest nbd|pbd Nejbližší pracovní den dopředu nebo zpět, včetně aktuálního dne, pokud už pracovním je. Vyžaduje --calendar.
--to-zone +HH:MM Krok: vyjádří tentýž okamžik v jiném pevném posunu. Okamžik se zachová, takže hodnota epochy se nehýbe a mění se jen občanská pole. Nezaměňovat s --zone.
--zone +HH:MM Pásmo sezení, používané k vyhodnocení today a now a k zobrazení výsledku. Bez něj pásmo hostitele.
--calendar us-banking|us-federal|pl Načte kalendář svátků. Přidá do metadat pracovní den a svátek a zapne bd a --nearest. Oba americké kalendáře se liší tím, jak řeší svátek připadající na víkend, což je přesně ten druh chyby o jeden den, který má test odhalit. Každý kalendář odpovídá za rozsah let: pl od roku 2002, us-federal od roku 1960 a us-banking od roku 2008. Krok v pracovních dnech, který dosáhne dne před tímto rozsahem, je odmítnut s kódem 1 a datum před ním je zobrazeno jako neposouzené. Pokud byly svátky kalendáře naposledy ověřeny podle zákona před více než rokem, pozdější den, který posoudil, nese značku calendar_outdated, protože může chybět novější svátek.
--preset <id> --param id=value Pojmenovaný okamžik z presets/<id>.json s vyplněnými parametry. Vylučuje se s přepínači kroků a s --analyze a kombinuje se s --calendar, --zone a --format.
--analyze <date> Přečte vložené datum zpět a řekne, co to je. Nejednoznačné 04/08 se ukáže v obou čteních, americkém i polském, místo aby se hádalo - tato nejednoznačnost je skutečným zdrojem chybných hlášení chyb.
--format <mask> Vypíše výsledek i ve vaší vlastní masce, aby odpovídal formátu testované aplikace: yyyy-MM-dd HH:mm:ss. Tokeny rozlišují velikost písmen ve smyslu .NET a Javy - M je měsíc, m je minuta.
--json Strojový výstup (chronomock.calc/1) pro cokoli z výše uvedeného, aby pipeline mohla vypočítat datum a rovnou ho předat zpět do chrono run.
# Poslední pracovní den čtvrtletí, americký bankovní kalendář
chrono calc --base today --snap eoq --nearest pbd --calendar us-banking

chrono calc - návratové kódy

Samostatná, menší tabulka: kalkulačka nemá verdikt o pokrytí, který by hlásila.

KódVýznam
0vypočteno
1chyba použití - špatný přepínač, nemožné datum, přetečení rozsahu nebo soubor kalendáře, ve kterém není žádný pracovní den
5krok nebo jednotka není v tomto vydání sestavena, nebo krok potřebuje kalendář, který jste nezadali. Záměrně oddělené od chyby použití, aby skript dokázal rozlišit „ještě ne“ od „špatně“

Dále