Chrono Mock
LimbaRomână

Referința liniei de comandă

Fiecare flag al ambelor comenzi, ambele tabele cu coduri de ieșire și cum se citește ce se întoarce. Versiunea narativă, cu raționamentul din spate, este pe pagina CLI și CI.

Două comenzi

chrono run pornește o aplicație la o altă dată și oră. chrono calc calculează o dată și îți spune ce o face interesantă. Au o singură gramatică de pași, așa că o deplasare scrisă pentru una înseamnă același lucru în cealaltă.

chrono version răspunde la o a treia întrebare, mult mai mică: ce build este, care dintre cele două nuclee este executabilul și ce versiune de protocol vorbește. O singură linie pe stdout, ca un script să o poată captura.

chrono license răspunde la a patra: licența sub care este distribuit acest build, declinarea garanției și componentele terțe legate în el. Spune și unde se află pe disc textul complet al licenței și notele despre componentele terțe sau recunoaște că exemplarul pe care îl rulezi nu le are alături. --components listează fiecare componentă inclusă cu versiunea ei, în loc de un rezumat.

chrono presets listează catalogul de presetări așa cum îl citește --preset: fiecare presetare din folder, scrisă cu cuvintele pe care le citește gramatica calculatorului, și fiecare fișier pe care l-ar refuza, cu motivul. --json scrie chronomock.presets/1, iar --dir indică alt folder.

chrono run <target> [options]
chrono calc [options]
chrono version        # chrono 0.4.0 (x64, protocol 1)
chrono license        # GPL-3.0-only, și ce este inclus
chrono presets        # catalogul, așa cum îl citește --preset
chrono --help          # utilizarea tuturor

chrono run - opțiuni

FlagCe face
--at <moment> Momentul la care pornește, în fusul sesiunii. Absolut (2038-01-19T03:14:07) sau relativ, cu semn în față (+1d, -2h). Unități: s m h d w mo q y - m înseamnă minute, iar mo înseamnă luni. Fără acest flag, ceasul sesiunii pornește de la ora reală curentă, așa că --mode xN folosit singur doar rulează ținta mai repede.
--zone +HH:MM Fusul sesiunii: fusul în care este scris momentul și cel pe care îl raportează apelurile de oră locală ale țintei. Un decalaj fix, fără ora de vară. Fără el, fusul propriu al gazdei.
--mode flow|frozen|xN flow rulează la viteză reală, frozen ține ceasul pe loc, xN îl rulează de N ori mai repede (x60 face dintr-o oră un minut, x1440 dintr-o zi).
--scale-duration Accelerează și axa timpului scurs: contoare de tick-uri, timpul de întrerupere, pauze și timere. Așteptările pe obiecte sunt numărate și își păstrează durata reală. Dezactivat implicit, pentru că un ceas de perete și un cronometru sunt întrebări diferite. Un timer sau o întârziere setată pentru o dată și o oră urmează ceasul sesiunii cu sau fără această opțiune.
--scale-qpc Scalează și contorul de înaltă rezoluție, de unde citesc timpul scurs monotonic din Python 3.13+, .NET Stopwatch și Java nanoTime. Dezactivat implicit: o aplicație care își cronometrează randarea după acel contor poate arăta deformată.
--ticks N Încheie sesiunea după N bătăi de inimă, câte o secundă reală fiecare, și raportează. Fără el, instrumentul rămâne atașat până când ținta și fiecare program pornit de ea care rulează pe ceasul sesiunii s-au închis - un lansator care se încheie imediat lasă sesiunea în seama aplicației pe care a pornit-o.
--timeout <s> Renunță după atâtea secunde și iese cu 6, pentru un pipeline care nu are voie să se blocheze. Independent de acest flag, un nucleu care nu spune nimic timp de 15 secunde este oprit și iese tot cu 6 - în ambele cazuri rularea este întreruptă, deci nu are verdict.
--args "..." Argumentele pentru țintă, ca un singur șir, împărțite după aceeași regulă pe care o folosește Windows - astfel un argument care conține spații supraviețuiește. Pentru o țintă Chromium, --user-data-dir și --remote-debugging-port sunt refuzate, nu suprascrise: sesiunea are nevoie de propriul profil izolat, iar rularea pe tăcute pe profilul tău real de browser este singurul lucru care nu are voie să se întâmple.
--cwd <dir> Pornește ținta în acel director. Fără el, ținta îl moștenește pe al nostru, cum făcea fiecare rulare înainte să existe acest flag. O valoare goală este o eroare de utilizare, nu „niciun director” - absent și gol sunt lucruri diferite, iar doar absent poate fi dat lui Windows. Un director care nu există oprește sesiunea cu target.cwd_missing înainte să fie lansat ceva, în loc să iasă la iveală mai târziu ca o țintă care nu pornește.
--preset <id> Ia momentul și viteza din presets/<id>.json. Se exclude cu --at, --mode și --scale-duration, deoarece presetul este atunci singura sursă pentru amândouă.
--param id=value Completează un parametru al presetului. Se poate repeta, cere --preset. Doar în run, data de început a unei probe are ca valoare implicită data de creare a executabilului țintă, așa că un preset de probă numără de la ziua în care a fost instalată aplicația, fără să o tastezi.
--set-after T:M La bătaia T, schimbă viteza la M. În timpul sesiunii multiplicatorul este cel puțin 1 - oprirea ceasului la mijlocul sesiunii nu este oferită aici.
--jump-after T:moment La bătaia T, mută ceasul la acel moment, absolut sau relativ, în fusul sesiunii.
--force Păstrează sesiunea chiar și când verdictul de deschidere spune că înlocuirea nu a avut efect - implicit ținta este oprită, pentru că o sesiune care nu a dovedit nimic este mai rea decât nicio sesiune. Verdictul nu se schimbă, și nici codul de ieșire. Acesta decide doar dacă ținta continuă să ruleze.
--no-embedded Lasă paginile web din interiorul aplicației (WebView2, Qt WebEngine) pe ceasul real și nu deschide niciun port de depanare. Fără el, sesiunea cere unui astfel de motor să deschidă un port local și îi pune paginile pe ceasul sesiunii prin el - cât timp portul este deschis, orice alt program de pe acest calculator îl poate folosi ca să ajungă la acele pagini.
--elevated-embedded Pentru o aplicație care rulează ca administrator, dintr-un Chrono Mock care rulează și el ca administrator. WebView2 ignoră pentru o astfel de aplicație setarea prin care sesiunea ajunge la paginile ei, așa că sesiunea scrie pe durata sa o valoare în registrul mașinii (HKLM, denumită după .exe al aplicației) și o elimină la final. Cât timp aplicația rulează, orice alt program de pe acest calculator poate ajunge la paginile ei prin port, iar aplicația are drepturi de administrator. Nu împreună cu --no-embedded.
--keep-background-timers Pornește motorul web - browserul unei aplicații Chromium sau Electron, ori motorul din interiorul unei aplicații - cu încetinirea temporizatoarelor din ferestrele ascunse oprită, ca o fereastră minimizată să păstreze viteza sesiunii. Aplicația lucrează atunci cu viteză deplină și cât timp este ascunsă. O aplicație pornită ca administrator prin --elevated-embedded nu o primește.
--dry-run Afișează ce ar fi sesiunea și nu pornește nimic: momentul și fusul rezolvate și de unde provin, cu ce a completat un preset fiecare parametru, argumentele după împărțire și care dintre cele două mecanisme ar folosi ținta. Nu pornește niciun proces și nu scrie niciun fișier, inclusiv cel numit de --report. Iese cu 0 pentru un plan realizabil și cu 2 pentru o țintă care nu există, adică exact codul pe care îl dă o rulare reală pentru același fapt. Un plan nu are verdict și o spune - doar o sesiune reală are unul. Cu --json planul este dat ca date, inclusiv session.elevated_embedded și session.elevated_embedded_value, numele fișierului după care ar fi denumită valoarea din registru când opțiunea se aplică unei ținte .exe, altfel null. Un nume acolo nu este o promisiune de scriere: sesiunea scrie valoarea doar când Chrono Mock însuși rulează ca administrator.
--report <path> Scrie raportul pentru oameni într-un fișier. Un verdict altul decât funcționează deschide fișierul cu un banner de dovezi nesigure, pentru că dovezile care își ascund propria îndoială sunt mai rele decât lipsa lor. Și o sesiune cu verdictul funcționează primește acest banner când aplicația nu a citit niciunul dintre ceasurile pe care sesiunea le înlocuiește, sau când este un program Go, al cărui ceas de perete Chrono Mock nu îl atinge. Fișierul numește și rularea însăși: versiunea, momentul pornirii, ținta, folderul ei și opțiunile.
--report-args Împreună cu --report, scrie în acel fișier și argumentele țintei, cuvânt cu cuvânt. Dezactivat implicit, pentru că un argument poate conține o parolă - fișierul spune atunci doar câte au fost.
--json Emite sesiunea ca înregistrări care se pot citi automat, în locul raportului - același flux pe care îl consumă și fereastra. Ieșirea proprie a unei aplicații de consolă merge la eroarea standard, deci ieșirea standard conține înregistrările și nimic altceva. O aplicație încă în execuție când se încheie sesiunea continuă să scrie acolo, așa că orice citește eroarea standard până la capăt o așteaptă, iar rularea spune asta.

chrono run - coduri de ieșire

Codul de ieșire este verdictul sesiunii, nu ce a returnat aplicația. Codul de ieșire propriu al aplicației este raportat separat, în raport și în datele sesiunii - de ce s-a ales această variantă explică pagina CLI și CI.

CodSemnificație
0funcționează - fiecare proces care a citit ora a văzut ceasul sesiunii
10funcționează parțial - unele canale acoperite, altele nu
11nu funcționează - înlocuirea nu a ajuns la canalele cheie
4nedeterminat - acoperirea nu a putut fi stabilită. Un „nu pot spune” sincer, niciodată o trecere prefăcută
12ținta a dispărut imediat după injecție și nu a lăsat nimic în execuție pe ceasul sesiunii, ceea ce sugerează o aplicație cu o singură instanță care predă controlul unei copii deja pornite, sau o predare către un program în care sesiunea nu a putut intra, de obicei unul cu cealaltă lățime pe biți. O țintă care pornește aplicația și se încheie este un lansator, iar sesiunea continuă pentru aplicație
1eroare de utilizare - un flag greșit, o expresie greșită sau un preset pe care această comandă nu îl acceptă
2ținta nu a putut fi lansată sau injectată
3eroare internă - motorul nu a putut porni, a întâlnit o stare neașteptată sau s-a oprit înainte să închidă sesiunea (indiferent de codul de ieșire al țintei). O astfel de rulare nu are verdict
5operațiunea nu este inclusă în această versiune - de exemplu un preset al cărui moment are nevoie de un calendar, pe care run nu îl poate încărca încă. Distinct în mod deliberat de o eroare de utilizare: ai cerut ceva ce nu există încă, nu ceva greșit
6rularea a fost întreruptă - --timeout a expirat sau motorul a încetat să răspundă timp de 15 secunde și a fost oprit. Nu este un verdict: sesiunea a fost întreruptă, deci nu dovedește nimic despre țintă, într-un sens sau altul
7rulează deja o altă sesiune - o singură sesiune odată. Ajunge să încercați din nou după ce se încheie
8sesiunea a ajuns la un verdict, dar dovezile ei nu sunt în fișierul indicat de --report - discul era plin sau alt program ținea deschis fișierul vechi, care rămâne atunci neschimbat. Verdictul rămâne în raportul afișat de comandă

Citirea raportului

Fără --json, sesiunea se încheie cu un raport simplu. Fiecare linie este fie un fapt observat de sesiune, fie lipsește - nimic nu este completat cu o valoare implicită plauzibilă.

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 - verdictul familiei, peste procesul părinte și toate procesele copil, cu numărul de procese. Acesta este numărul pe care îl poartă codul de ieșire.
  • exited - codul de ieșire propriu al aplicației, și doar când s-a închis singură. O rulare limitată de --ticks lasă ținta în execuție, o sesiune Chromium este una pe care instrumentul o închide el însuși, iar o sesiune care nu a pornit niciodată nu are un asemenea cod - linia lipsește atunci, în loc să arate un zero inventat. Un cod de blocare vine ca un număr negativ mare, așa că primește și forma lui hexazecimală.
  • covered - canalele la care a ajuns înlocuirea, cu de câte ori a fost apelat efectiv fiecare, pe proces. Numărătorile nu se adună niciodată între procese: auditul unui proces nu trebuie să împrumute cifrele altuia. Un contor se oprește la 1048576 și arată atunci cel puțin acest număr.
  • observed - canale interceptate, dar lăsate deliberat reale, cum ar fi așteptările pe obiecte și temporizatoarele multimedia. Au propria categorie, ca să nu fie citite niciodată drept înlocuite.
  • uncovered - canale pe care aplicația le-a cerut și sesiunea nu le-a acoperit. Asta transformă un verdict în parțial.
  • not fully cleaned up - tot ce închiderea nu a putut elimina. Lipsește la un final curat, adică în cazul normal.

chrono calc - opțiuni

Fără limbaj natural: fiecare flag este un pas, iar ordinea flag-urilor este ordinea pașilor. Rezultatul după fiecare pas este afișat, așa că un pas greșit se vede, nu rămâne îngropat.

FlagCe face
--base today|now|<moment> De unde începe, implicit today. Rezolvat în fusul sesiunii. O zi imposibilă, cum ar fi 2025-02-31, este refuzată, niciodată normalizată pe tăcute în luna următoare.
--base-utc <moment> Ca --base, dar începutul este un moment în UTC, cu un Z final opțional, nu o citire a ceasului de perete în fusul sesiunii.
--shift ±N<unit> Se poate repeta. Semnul este obligatoriu. Unități: s m h d w mo q y bd sau numele lor complete. m înseamnă minute, mo înseamnă luni. Lunile, trimestrele și anii se aplică pe data calendaristică cu limitare la sfârșitul lunii, deci o lună după 31 ianuarie înseamnă sfârșitul lui februarie, nu un număr fix de tick-uri. bd (zile lucrătoare) are nevoie de --calendar.
--set-time HH:MM:SSSetează ora din zi pe rezultatul curent.
--snap <target> Sare la o limită de perioadă: som eom soq eoq soy eoy (începutul sau sfârșitul lunii, trimestrului, anului). Un început este prima zi la 00:00:00, un sfârșit ultima zi la 23:59:59.
--nearest nbd|pbd Cea mai apropiată zi lucrătoare înainte sau înapoi, ziua curentă inclusă dacă este deja una. Are nevoie de --calendar.
--to-zone +HH:MM Un pas: exprimă același moment într-un alt decalaj fix. Momentul se păstrează, deci valoarea epoch nu se mișcă, iar doar câmpurile civile se schimbă. A nu se confunda cu --zone.
--zone +HH:MM Fusul sesiunii, folosit pentru a rezolva today și now și pentru a afișa rezultatul. Fără el, fusul gazdei.
--calendar us-banking|us-federal|pl Încarcă un calendar de sărbători. Adaugă zi lucrătoare și sărbătoare la metadate și activează bd și --nearest. Cele două calendare americane diferă prin felul în care tratează o sărbătoare căzută în weekend, adică exact genul de diferență de o zi pe care un test trebuie să o găsească. Fiecare calendar răspunde pentru un interval de ani: pl din 2002, us-federal din 1960 și us-banking din 2008. Un pas în zile lucrătoare care ajunge la o zi dinaintea lui este refuzat cu codul 1, iar o dată dinaintea lui este afișată ca neevaluată. Când sărbătorile unui calendar au fost verificate cu legea acum mai bine de un an, o zi ulterioară pe care a evaluat-o poartă marcajul calendar_outdated, pentru că poate lipsi o sărbătoare mai nouă.
--preset <id> --param id=value Un moment cu nume din presets/<id>.json, cu parametrii completați. Se exclude cu flag-urile de pas și cu --analyze, și se combină cu --calendar, --zone și --format.
--analyze <date> Citește înapoi o dată lipită și spune ce este. Un 04/08 ambiguu este afișat în ambele citiri, americană și poloneză, în loc să fie ghicit - această ambiguitate este o sursă reală de rapoarte de bug greșite.
--format <mask> Afișează rezultatul și în masca ta, ca să se potrivească formatului aplicației testate: yyyy-MM-dd HH:mm:ss. Token-urile țin cont de literele mari și mici în sensul .NET și Java - M este luna, m este minutul.
--json Ieșire pentru mașini (chronomock.calc/1) pentru oricare dintre cele de mai sus, ca un pipeline să poată calcula o dată și s-o trimită direct înapoi în chrono run.
# Ultima zi lucrătoare a trimestrului, calendarul bancar american
chrono calc --base today --snap eoq --nearest pbd --calendar us-banking

chrono calc - coduri de ieșire

Un tabel separat, mai mic: calculatorul nu are un verdict de acoperire de raportat.

CodSemnificație
0calculat
1eroare de utilizare - un flag greșit, o dată imposibilă, o depășire de interval sau un fișier de calendar în care nu există nicio zi lucrătoare
5pasul sau unitatea nu este inclusă în această versiune sau pasul are nevoie de un calendar pe care nu l-ai dat. Separat de o eroare de utilizare în mod intenționat, ca un script să poată deosebi „încă nu” de „greșit”

Mai departe