@checksum-ai/runtime 4.16.2 → 4.16.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +1 -1
- package/README.md +8 -9
- package/checksum-root/checksum.config.ts +2 -2
- package/checksumlib.js +1 -1
- package/cli.js +115 -122
- package/index.d.ts +0 -2
- package/index.js +1 -1
- package/package.json +2 -2
- package/scripts/patch.js +1 -11
- package/scripts/playwright_patches/1.41.2.js +16 -31
- package/scripts/playwright_patches/1.46.0.js +6 -59
- package/scripts/playwright_patches/1.51.0.js +6 -70
- package/scripts/playwright_patches/1.52.0.js +5 -53
- package/scripts/playwright_patches/1.56.1.js +5 -47
- package/scripts/playwright_patches/1.59.0.js +5 -47
- package/scripts/playwright_patches/1.62.1.js +562 -0
- package/test-run-monitor.js +1 -1
package/test-run-monitor.js
CHANGED
|
@@ -164,7 +164,7 @@ Actual: `+_.attribValue);else{var J=_.tag,le=_.tags[_.tags.length-1]||_;J.ns===l
|
|
|
164
164
|
`)?t:`${t}
|
|
165
165
|
`)},"writeStderrLine");var n0=a(t=>{let e=t.kind??"event",r=t.outcome?` ${t.outcome}`:"",n=typeof t.duration_ms=="number"?` ${t.duration_ms}ms`:"";return`${e}${r}${n}`.trim()},"defaultMessage"),i0=a((t,e,r)=>{let n=Date.now(),i={timestamp:new Date().toISOString(),kind:t,...e},s=!1,o={set(c){return Object.assign(i,c),o},emit(c){s||(s=!0,c&&Object.assign(i,c),i.duration_ms===void 0&&(i.duration_ms=Date.now()-n),r(i))}};return o},"startHandle"),s0=a((t={})=>{let e=t.decide??(()=>!0),r=t.deriveMessage??n0,n=t.label??"[wide-event]",i=t.sink??(c=>kp(c)),s=a(c=>{if(!e(c))return;let l={severity:Rp(c),message:c.message??r(c),...c};try{i(l)}catch(u){try{Mp(`${n} emit failed: ${String(u)}`)}catch{}}},"emit");return{emit:s,emitWideEvent:a((c,l={})=>{s({timestamp:new Date().toISOString(),kind:c,...l})},"emitWideEvent"),wideEvent:a((c,l={})=>i0(c,l,s),"wideEvent"),configureSink:a(c=>{i=c},"configureSink")}},"createWideEvents"),Pp=a(t=>t==="true"||t==="1","truthy"),Np=a(()=>Pp(process.env.CHECKSUM_WIDE_EVENTS)||Pp(process.env.WIDE_EVENT_PRETTY),"wideEventsEnabled"),xo=s0({decide:a(()=>Np(),"decide")}),Io=xo.configureSink,Zr=a((t,e={})=>xo.wideEvent(t,e),"wideEvent"),mr=a((t,e={})=>{xo.emitWideEvent(t,e)},"emitWideEvent"),tt=a(t=>t instanceof Error?{type:t.name,message:t.message}:{type:"UnknownError",message:String(t)},"toErrorField");async function Lp(t,e){let r;try{r=await t.json()}catch{r=void 0}return a0({ok:t.ok,status:t.status,body:r},e)}a(Lp,"assertOkJson");function a0(t,e){let r=t.body&&typeof t.body=="object"?t.body:void 0;if(!t.ok){let i=o0(r?.message);throw c0(new Error(`${e.resource} failed (HTTP ${t.status})`+(i?`: ${i}`:".")),t.status)}if(!r)throw new Error(`${e.resource} (HTTP ${t.status}) returned a non-object body; expected JSON.`);let n=(e.requiredFields??[]).filter(i=>!r[i]);if(n.length>0)throw new Error(`${e.resource} (HTTP ${t.status}) response is missing required field${n.length>1?"s":""}: ${n.join(", ")}.`);return r}a(a0,"assertJsonBody");function o0(t){return typeof t=="string"?t:Array.isArray(t)?t.filter(e=>typeof e=="string").join("; "):""}a(o0,"extractMessage");function c0(t,e){return Object.assign(t,{status:e})}a(c0,"withStatus");var Ji=a(t=>typeof t=="number"&&t>=400&&t<500&&t!==408&&t!==429,"isNonRetryableStatus");var Zi={uploadTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_TIMEOUT_MS",fallback:6e5,min:5e3,max:36e5},noProgressAbortMs:{env:"CHECKSUM_RUNTIME_UPLOAD_NO_PROGRESS_MS",fallback:6e4,min:5e3,max:6e5},assetDeadlineMs:{env:"CHECKSUM_RUNTIME_UPLOAD_ASSET_DEADLINE_MS",fallback:12e5,min:3e4,max:54e5},maxAttempts:{env:"CHECKSUM_RUNTIME_UPLOAD_MAX_ATTEMPTS",fallback:6,min:1,max:20},stallTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_STALL_TIMEOUT_MS",fallback:6e5,min:3e4,max:36e5},minProgressBytes:{env:"CHECKSUM_RUNTIME_UPLOAD_MIN_PROGRESS_BYTES",fallback:65536,min:1,max:67108864},finalizeBudgetMs:{env:"CHECKSUM_RUNTIME_UPLOAD_FINALIZE_BUDGET_MS",fallback:18e5,min:6e4,max:54e5},finalizeCeilingMs:{env:"CHECKSUM_RUNTIME_UPLOAD_FINALIZE_CEILING_MS",fallback:24e5,min:12e4,max:72e5},cliHardCapMs:{env:"CHECKSUM_RUNTIME_UPLOAD_CLI_HARD_CAP_MS",fallback:27e5,min:12e4,max:72e5},watchTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_WATCH_TIMEOUT_MS",fallback:12e4,min:5e3,max:18e5},ipcTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_IPC_TIMEOUT_MS",fallback:5e3,min:500,max:6e4},onEndFlushTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_ONEND_FLUSH_TIMEOUT_MS",fallback:5e3,min:500,max:6e4},resumableChunkBytes:{env:"CHECKSUM_RUNTIME_UPLOAD_RESUMABLE_CHUNK_BYTES",fallback:8388608,min:262144,max:268435456},connectTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_CONNECT_TIMEOUT_MS",fallback:1e4,min:1e3,max:6e4},headersTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_HEADERS_TIMEOUT_MS",fallback:3e5,min:5e3,max:18e5},bodyTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_BODY_TIMEOUT_MS",fallback:3e5,min:5e3,max:18e5},maxConcurrentUploads:{env:"CHECKSUM_RUNTIME_UPLOAD_MAX_CONCURRENT",fallback:15,min:1,max:64}};function l0(t,e,r,n){if(t===void 0||t.trim()==="")return e;let i=Number(t);return Number.isInteger(i)?Math.min(n,Math.max(r,i)):e}a(l0,"clampEnvInt");var u0=[["cliHardCapMs",["finalizeCeilingMs"],.9],["finalizeCeilingMs",["finalizeBudgetMs"],1],["finalizeBudgetMs",["stallTimeoutMs","assetDeadlineMs","watchTimeoutMs"],1],["assetDeadlineMs",["uploadTimeoutMs"],1],["uploadTimeoutMs",["noProgressAbortMs"],.5]];function d0(t){let e={...t},r=[];for(let[n,i,s]of u0)for(let o of i){let c=Math.floor(e[n]*s);e[o]>c&&(r.push(`${Zi[o].env} (${e[o]}ms) exceeds its bound under ${Zi[n].env} (${e[n]}ms); using ${c}ms`),e[o]=c)}return{tunables:e,warnings:r}}a(d0,"coerceScopeHierarchy");function Ao(t){let e={};for(let r of Object.keys(Zi)){let n=Zi[r];e[r]=l0(t[n.env],n.fallback,n.min,n.max)}return e.resumableChunkBytes=Math.max(1,Math.floor(e.resumableChunkBytes/262144))*262144,d0(e)}a(Ao,"resolveUploadTunablesDetailed");function f0(t){return Ao(t).tunables}a(f0,"resolveUploadTunables");var Dp=f0({});var Up=new WeakMap,Co=new WeakMap;function $p(t,e){t.loadedBytes=0,t.committedBytes??=0,t.lastProgress=e,Up.set(t,t.committedBytes),Co.set(t,0)}a($p,"beginUpload");function Ro(t){t.loadedBytes=0,Co.set(t,0)}a(Ro,"resetAttemptBytes");var Fp=a(t=>(e,r,n,i)=>{let s=t.get(e)??0;return r-s<n?!1:(e.lastProgress=i,t.set(e,r),!0)},"stamperFor"),p0=Fp(Co),m0=Fp(Up);function Oo(t,e,r,n){return t.loadedBytes=e,p0(t,e,r,n)}a(Oo,"recordSent");function ko(t,e,r,n){let i=Math.max(t.committedBytes??0,e);return t.committedBytes=i,m0(t,i,r,n)}a(ko,"recordCommitted");var Xi=require("fs"),jp=require("stream");function Yi(t,{baseMs:e,capMs:r,random:n=Math.random}){let i=Math.min(r,e*2**(t-1));return i/2+n()*(i/2)}a(Yi,"jitteredBackoffMs");async function Yr(t){await t.body?.cancel().catch(()=>{})}a(Yr,"drainBody");var No=a(t=>t===200||t===201,"isStored"),Hp=a(t=>t===308,"isResumeIncomplete"),h0=a(t=>t===404||t===410,"isSessionGoneStatus"),zp=a((t,e)=>{let r=t?.match(/bytes=0-(\d+)/);return r?Number(r[1])+1:e},"nextOffsetFromRange"),g0=a((t,e,r)=>e<=t?`bytes */${r}`:`bytes ${t}-${e-1}/${r}`,"contentRangeFor");function y0(t,e,r){let n=e,i=new TransformStream({transform(s,o){n+=s.byteLength,r?.(n),o.enqueue(s)}});return jp.Readable.toWeb(t).pipeThrough(i)}a(y0,"countingBody");var rt=class extends Error{constructor(r,n){super(r);this.status=n;this.name="ResumableUploadError"}static{a(this,"ResumableUploadError")}},Gp=a(t=>t instanceof rt?t.status:void 0,"statusOf"),_0=a(t=>{let e=Gp(t);return e!==void 0&&h0(e)},"isSessionGone"),b0=a(t=>Ji(Gp(t)),"isPermanent");async function w0(t,e,r,n){let i=await r(t,{method:"POST",headers:{"x-goog-resumable":"start","Content-Type":e,"Content-Length":"0"},signal:n});if(await Yr(i),!No(i.status))throw new rt(`resumable init failed with status ${i.status}`,i.status);let s=i.headers.get("Location");if(!s)throw new rt("resumable init returned no Location");return s}a(w0,"initResumableSession");async function E0(t,e,r,n){let i=await r(t,{method:"PUT",headers:{"Content-Range":`bytes */${e}`},signal:n});if(await Yr(i),No(i.status))return{done:!0,offset:e};if(!Hp(i.status))throw new rt(`offset query failed with status ${i.status}`,i.status);return{done:!1,offset:zp(i.headers.get("Range"),0)}}a(E0,"queryCommittedOffset");async function Bp(t,e,{offset:r,endExclusive:n},i){let s=Math.max(0,(0,Xi.statSync)(t.filePath).size-r),o=Math.min(Math.max(0,n-r),s),c=r+o,l=o>0?(0,Xi.createReadStream)(t.filePath,{start:r,end:c-1}):void 0;try{let u={method:"PUT",headers:{"Content-Range":g0(r,c,t.size),"Content-Length":String(o)},duplex:"half",signal:i,...l?{body:y0(l,r,t.onSent)}:{}},d=await t.fetchImpl(e,u);if(await Yr(d),No(d.status))return{stored:!0,committed:t.size};if(Hp(d.status))return{stored:!1,committed:zp(d.headers.get("Range"),r)};throw new rt(`resumable PUT failed with status ${d.status}`,d.status)}finally{l?.destroy()}}a(Bp,"putChunk");async function T0(t,e,r,n){let i=r;for(;i<t.size;){let o=Math.min(i+t.chunkSizeBytes,t.size),{stored:c,committed:l}=await Bp(t,e,{offset:i,endExclusive:o},n);if(c){t.onCommitted?.(t.size);return}if(l<=i)throw new rt("resumable PUT made no forward progress");i=l,t.onCommitted?.(i)}let{stored:s}=await Bp(t,e,{offset:t.size,endExclusive:t.size},n);if(!s)throw new rt("resumable upload did not finalize");t.onCommitted?.(t.size)}a(T0,"sendFrom");async function v0(t,e,r){if(e.url)return e.url;if(!t.target.initUrl)throw new rt("no resumable target provided");return e.url=await w0(t.target.initUrl,t.contentType,t.fetchImpl,r),e.used=!1,e.url}a(v0,"openSession");async function S0(t,e,r,n){if(!r)return 0;let i=await E0(e,t.size,t.fetchImpl,n);if(!i.done)return t.onCommitted?.(i.offset),i.offset}a(S0,"resumePoint");async function x0(t,e,r){let n=await v0(t,e,r),i=await S0(t,n,e.used,r);if(e.used=!0,i===void 0){t.onCommitted?.(t.size);return}await T0(t,n,i,r)}a(x0,"runAttempt");function I0(t,e,r){return _0(t)&&e.target.initUrl?(r.url=void 0,r.used=!1,"retry"):b0(t)?"stop":"retry"}a(I0,"afterFailure");async function Vp(t){let e={url:t.target.sessionUrl,used:!1},r;for(let n=1;n<=t.maxAttempts&&!(t.now()>=t.deadlineAt);n++)try{await x0(t,e,t.makeSignal());return}catch(i){if(r=i,I0(i,t,e)==="stop"||n>=t.maxAttempts)break;await t.sleep(Yi(n,{baseMs:1e3,capMs:16e3,...t.random?{random:t.random}:{}}))}throw r instanceof Error?r:new rt(`resumable upload failed: ${String(r)}`)}a(Vp,"uploadResumable");var A0=a(t=>{if(typeof t!="object"||t===null)return"network_error";let e="name"in t&&typeof t.name=="string"?t.name:"";if(e==="TimeoutError")return"timeout";if(e==="AbortError")return"no_progress_abort";let r="cause"in t?t.cause:void 0,n=typeof r=="object"&&r!==null&&"code"in r&&typeof r.code=="string"?r.code:void 0;if(n==="UND_ERR_CONNECT_TIMEOUT"||n==="UND_ERR_HEADERS_TIMEOUT"||n==="UND_ERR_BODY_TIMEOUT")return"timeout";if(n!==void 0&&n.length>0)return`network_error:${n}`;let i="message"in t&&typeof t.message=="string"?t.message:"";return i.startsWith("Upload failed with status")?"http_error":i.startsWith("get-upload-url")?"signed_url_error":i.includes("No upload URL")?"signed_url_missing":"network_error"},"classifyUploadError"),C0=a(t=>Math.max(1e3,Math.min(1e4,Math.floor(t/4))),"noProgressPollMs"),Qi=class{constructor(e,r,n,i,s=!1,o={start:a(u=>{},"start"),complete:a(u=>{},"complete"),error:a((u,d)=>{},"error")},c,l={}){this.apiBaseURL=e;this.apiKey=r;this.uploadTimeout=n;this.makeGetUploadUrlAPIPath=i;this.isolationMode=s;this.reporter=o;this.sessionId=c;this.SIGNED_URL_TIMEOUT_MS=3e4;this.tunables=l.tunables??Dp,this.fetchImpl=l.fetchImpl??globalThis.fetch,this.now=l.now??Date.now,this.MAX_ATTEMPTS=this.tunables.maxAttempts,this.PUT_NO_PROGRESS_ABORT_MS=this.tunables.noProgressAbortMs,this.ASSET_DEADLINE_MS=this.tunables.assetDeadlineMs,this.MIN_PROGRESS_BYTES=this.tunables.minProgressBytes}static{a(this,"TestAssetUploader")}async uploadAsset(e){if(e.uploadStarted=!0,this.isolationMode){e.lastProgress=Date.now(),e.loadedBytes=0,e.sizeBytes=100,e.response=new Promise(o=>{setTimeout(()=>{e.complete=!0,e.lastProgress=Date.now(),e.loadedBytes=100,o({statusCode:200,ok:!0,body:"OK"})},10)});return}let{path:r}=e.info,n=this.now()+this.ASSET_DEADLINE_MS,i=Zr("asset_upload",{test_suite_run_id:this.sessionId,asset_type:e.info.type,file_name:e.info.fileName??(0,Wp.basename)(r),test_id:e.info.testId,project:e.info.project}),s=[];try{let c=(0,es.statSync)(r).size;e.sizeBytes=c,$p(e,this.now()),i.set({size_bytes:c}),this.reporter.start(r);let l;for(let u=1;u<=this.MAX_ATTEMPTS&&!(this.now()>=n);u++){let d={attempt:u};try{let f=this.now();if(await this.getSignedURLForUpload(e),d.signed_url_ms=this.now()-f,!e.uploadURL)throw new Error("No upload URL returned");let y=this.now();d.resumable=e.resumable===!0,e.resumable?await this.putResumable(e,r,c,n):await this.putWithWatchdog(e,r,c),d.put_ms=this.now()-y,d.loaded_bytes=e.loadedBytes,d.committed_bytes=e.committedBytes,s.push(d),this.reporter.complete(r),e.complete=!0,i.emit({outcome:"success",attempt_count:s.length,attempts:s,loaded_bytes:e.loadedBytes,committed_bytes:e.committedBytes});return}catch(f){l=f,d.loaded_bytes=e.loadedBytes,d.committed_bytes=e.committedBytes,d.failure_reason=A0(f),d.error=tt(f);let y=Ji(typeof f=="object"&&f!==null&&"status"in f?f.status:void 0);d.non_retryable=y,delete e.uploadURL;let h=y?"non_retryable":e.resumable?"resumable_owns_retries":u>=this.MAX_ATTEMPTS?"max_attempts":this.now()>=n?"asset_deadline":void 0;if(d.retry_stop_reason=h,s.push(d),h)break;await this.backoff(u,n)}}this.reporter.error(r,l),e.error=!0,i.emit({outcome:"error",attempt_count:s.length,attempts:s,loaded_bytes:e.loadedBytes,committed_bytes:e.committedBytes,size_bytes:e.sizeBytes,deadline_exceeded:this.now()>=n,error:tt(l)})}catch(o){this.reporter.error(r,o),e.error=!0,i.emit({outcome:"error",failure_reason:"pre_upload",attempt_count:s.length,attempts:s,error:tt(o)})}}async putWithWatchdog(e,r,n){let i=e.uploadURL;if(!i)throw new Error("No upload URL returned");let s=new AbortController,o=this.uploadTimeout??void 0;Ro(e);let c=this.armNoProgressWatchdog(e,()=>s.abort()),l=o!==void 0?setTimeout(()=>s.abort(new DOMException("upload attempt timeout","TimeoutError")),o):void 0,u=(0,es.createReadStream)(r),d=0,f=this.MIN_PROGRESS_BYTES,y=this.now,h=new TransformStream({transform(w,v){d+=w.byteLength,e.sizeBytes=n,Oo(e,d,f,y()),v.enqueue(w)}}),g=qp.Readable.toWeb(u).pipeThrough(h),b={method:"PUT",headers:{"Content-Type":vo[e.info.type]??""},body:g,duplex:"half",signal:s.signal};try{let w=await this.fetchImpl(i,b);if(!w.ok)throw await Yr(w),Object.assign(new Error(`Upload failed with status ${w.status}`),{status:w.status});ko(e,n,this.MIN_PROGRESS_BYTES,this.now()),e.response=Promise.resolve(await w.text())}finally{clearInterval(c),clearTimeout(l),u.destroy()}}armNoProgressWatchdog(e,r){let n=-1,i=this.now();return setInterval(()=>{let s=Math.max(e.loadedBytes??0,e.committedBytes??0);s>n?(n=s,i=this.now()):this.now()-i>this.PUT_NO_PROGRESS_ABORT_MS&&r()},C0(this.PUT_NO_PROGRESS_ABORT_MS))}async putResumable(e,r,n,i){let s=e.uploadURL;if(!s)throw new Error("No upload URL returned");Ro(e);let o=this.uploadTimeout??this.tunables.uploadTimeoutMs,c,l,u=a(()=>(clearInterval(l),c=new AbortController,l=this.armNoProgressWatchdog(e,()=>c?.abort()),c.signal),"armAttempt");try{await Vp({target:{initUrl:s},filePath:r,size:n,contentType:vo[e.info.type]??"",fetchImpl:this.fetchImpl,makeSignal:a(()=>AbortSignal.any([u(),AbortSignal.timeout(o)]),"makeSignal"),maxAttempts:this.MAX_ATTEMPTS,deadlineAt:i,chunkSizeBytes:this.tunables.resumableChunkBytes,now:this.now,sleep:a(d=>new Promise(f=>setTimeout(f,d)),"sleep"),onSent:a(d=>Oo(e,d,this.MIN_PROGRESS_BYTES,this.now()),"onSent"),onCommitted:a(d=>ko(e,d,this.MIN_PROGRESS_BYTES,this.now()),"onCommitted")})}finally{clearInterval(l)}e.response=Promise.resolve("OK")}async backoff(e,r){let n=Yi(e,{baseMs:1e3,capMs:16e3}),i=Math.max(0,Math.min(n,r-this.now()));i>0&&await new Promise(s=>setTimeout(s,i))}async getSignedURLForUpload(e){let r=new AbortController,n=setTimeout(()=>r.abort(),this.SIGNED_URL_TIMEOUT_MS);try{let i=JSON.stringify(e.info),s=`${this.apiBaseURL}/${this.makeGetUploadUrlAPIPath(e)}`,o={Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:this.apiKey},c=await this.fetchImpl(s,{method:"POST",headers:o,body:i,signal:r.signal}),{url:l,resumable:u}=await Lp(c,{resource:"get-upload-url",requiredFields:["url"]});e.uploadURL=l,e.resumable=u===!0}catch(i){throw delete e.uploadURL,i}finally{clearTimeout(n)}}};function ts(t,e,r=Date.now()){let n=t.filter(s=>!s.complete&&!s.error);if(n.length===0)return!1;let i=n.reduce((s,o)=>Math.max(s,o.lastProgress??0),0);return i>0&&r-i>e}a(ts,"isUploadStalled");function rs(t,e,r){return t!==void 0&&r-t>e}a(rs,"hasElapsedSinceTestEnd");function Kp(t,e,r){return rs(e.testRunEndTime,e.finalizeBudgetMs,r)?!0:t===void 0?!1:t.complete||t.error?!0:ts([t],e.stallTimeoutMs,r)}a(Kp,"shouldStopWaitingForReport");function Jp(t){return t.abandonedAssets.length===0}a(Jp,"mayCleanUpSources");function R0(t,e,r){if((e.length===0||ts(t.assets,t.stallTimeoutMs,r))&&rs(t.testRunEndTime,t.finalizeBudgetMs,r))return"budget";if(rs(t.testRunEndTime,t.finalizeCeilingMs,r))return"budget-ceiling"}a(R0,"backstopReason");function Zp(t,e){let r=t.assets.filter(s=>!s.complete&&!s.error),n=a(s=>({reason:s,abandonedAssets:r}),"decide"),i=R0(t,r,e);if(i!==void 0)return n(i);if(!(t.processingInProgress||!t.doneWaitingForReport)&&!(r.length>0&&!ts(t.assets,t.stallTimeoutMs,e))&&!(t.pendingWatchCount>0&&!rs(t.testRunEndTime,t.watchTimeoutMs,e)))return r.length>0?n("stall"):t.pendingWatchCount>0?n("watch-timeout"):n("complete")}a(Zp,"decideFinalize");var Yp=require("module");var O0=(0,Yp.createRequire)(__filename);function Xp(t){let e,r;try{e=O0("undici"),r=new e.Agent({connect:{timeout:t.connectTimeoutMs},headersTimeout:t.headersTimeoutMs,bodyTimeout:t.bodyTimeoutMs,keepAliveTimeout:1e4,keepAliveMaxTimeout:3e4})}catch(i){return mr("monitor_dispatcher_unavailable",{outcome:"error",error:tt(i)}),process.emitWarning("@checksum-ai/runtime: undici dispatcher unavailable; upload timeouts fall back to the platform defaults",{detail:String(i)}),globalThis.fetch}let n=e.fetch;return(i,s)=>{let o={...s,dispatcher:r};return n(i,o)}}a(Xp,"createMonitorFetch");var Lo=class{static{a(this,"CLIChannel")}constructor(){}sendToCLI(...e){let r=`{trm}${e.map(n=>n.toString()).join(`,
|
|
166
166
|
`)}{/trm}`;process.stdout.write(`${r}
|
|
167
|
-
`)}event(e,r){return new Promise(n=>{let i=r?`${e}=${r}`:e;setTimeout(()=>{this.sendToCLI(`monitor:${i}`),n(!0)},100)})}trace(e,r){let n=r?`${e}=${JSON.stringify(r)}`:e;setTimeout(()=>{this.sendToCLI(`trace:${n}`)},100)}log(e){return this.event("log",e)}debug(...e){this.sendToCLI(e)}wideEvent(e){let r=Buffer.from(JSON.stringify(e),"utf-8").toString("base64");this.sendToCLI(`wideevent:${r}`)}},ns=class{constructor(e,r=!1){this.config=e;this.isolationMode=r;this.tunablesResolution=Ao(process.env);this.tunables=this.tunablesResolution.tunables;this.MAX_UPLOADS=this.tunables.maxConcurrentUploads;this.MONITOR_INTERVAL=2500;this.UPLOAD_TIMEOUT=this.tunables.uploadTimeoutMs;this.UPLOAD_STALL_TIMEOUT=this.tunables.stallTimeoutMs;this.WATCH_TIMEOUT=this.tunables.watchTimeoutMs;this.FINALIZE_BUDGET=this.tunables.finalizeBudgetMs;this.FINALIZE_CEILING=this.tunables.finalizeCeilingMs;this.SHUTDOWN_FLUSH_TIMEOUT=2e3;this.assets=[];this.watchAssets=[];this.processingPaths=new Set;this.doneWaitingForReport=!1;this.processingInProgress=!1;this.pwTestIdToChecksumTestId={};this.checksumTestIdToUsingPlaceholder={};this.progressFlushInFlight=!1;this.stallEventEmitted=!1;this.channel=new Lo,Io(n=>this.channel.wideEvent(n)),this.testAssetUploader=new Qi(e.apiURL,e.apiKey,this.UPLOAD_TIMEOUT,()=>`client-api/test-runs/${this.config.sessionId}/get-upload-url`,this.isolationMode,{start:a(n=>this.channel.trace("Upload Start",{filename:n}),"start"),complete:a(n=>{if(!this.reportAsset||n!==this.reportAsset.info.path)try{(0,ce.unlinkSync)(n),this.channel.debug(`[TestAssetUploader] Deleted file after successful upload: ${n}`)}catch(i){this.channel.debug(`[TestAssetUploader] Failed to delete file after upload: ${n}`,i)}this.channel.trace("Upload Complete",{filename:n})},"complete"),error:a((n,i)=>this.channel.trace("Upload Failed",{filename:n,error:i}),"error")},e.sessionId,{fetchImpl:Xp(this.tunables),tunables:this.tunables}),this.uploadMonitorInterval=setInterval(this.monitorUploads.bind(this),this.MONITOR_INTERVAL);for(let n of this.tunablesResolution.warnings)this.channel.debug(`[upload-tunables] ${n}`),mr("upload_tunable_coerced",{warning:n});this.listenForMessages(),this.startServer()}static{a(this,"TestRunMonitor")}listenForMessages(){process.stdin.on("data",e=>{(async()=>{let r=e.toString().trim();if(!r.startsWith("cli:"))return;let[n,i]=r.substring(4).split("=");switch(this.channel.debug("Received message from CLI "+n+" "+i),n){case"report":if(this.testRunEndTime=Date.now(),i!=="false")try{let s=Buffer.from(i??"","base64").toString("utf-8"),o=JSON.parse(s);await this.handleReport(o)}catch(s){this.channel.debug("Error JSON parsing report payload, continue without report. Error: "+this.stringify(s)),this.stopWaitingForReport("failed")}else this.stopWaitingForReport("not-requested");this.monitorUploadsCompletion();break;case"shutdown":this.shutdown();break}})()})}async readMetadataFile(e){try{let r=await(0,em.readFile)(e,"utf-8");return JSON.parse(r)}catch(r){return this.channel.trace("Runtime Error",`Error reading checksum metadata file ${e}: ${r.message}`),{}}}async serveReport(e){try{let r=(0,Be.dirname)(e);await this.channel.log("Serving report in browser: "+r);let n=zi.isRepoMode?`yarn playwright show-report ${r}`:`npx playwright show-report ${r}`;(0,Qp.execSync)(n,{encoding:"utf8",stdio:"pipe"}),await this.channel.log("Success: Report opened in browser")}catch(r){await this.channel.log(`Error serving report in browser: ${r.message}`),r.stderr&&await this.channel.log(r.stderr.toString())}}async handleReport(e){let{reportPath:r,pathToChecksumMetadata:n,didFail:i,openReportCriteria:s,checksumRoot:o,projectRoot:c,isUploadReport:l,dedupeByChecksumTestId:u}=e;this.channel.debug(`Handling report ${this.isolationMode?"(isolation mode)":""}`+r),this.uploadReportData((0,Be.dirname)(r),l);let d=Zr("report_processing",{test_suite_run_id:this.config.sessionId,report_path:r,isolation_mode:this.isolationMode,is_upload_report:!!l});try{let f=await this.readMetadataFile(n),y=new Ki(r,this.config.sessionId,this.pwTestIdToChecksumTestId,f,{hosted:!this.isolationMode,...u?{dedupeByChecksumTestId:u}:{}},this.channel,o,c,this.checksumTestIdToUsingPlaceholder),h=this.initAsset({type:"report",path:""});this.reportAsset=h;try{let w=await y.process();h.info.path=y.getProcessedFilePath(),d.set({processed_path:h.info.path,...w}),this.uploadAsset(h)}catch(w){this.channel.debug("Error processing report, "+w.message),h.error=!0,d.set({error:tt(w)})}let g=y.getReportsStats();this.stats=g,_f(d,h.error?"error":"success",g),this.channel.debug("Checking watch assets");let b=this.watchAssets.filter(w=>!(w.type!=="trace"||y.testHasTrace(w.testId??"",w.project??"")));b.length>0&&(this.channel.debug("Removed watch assets - "),this.channel.debug(JSON.stringify(b.map(w=>w.path)))),this.watchAssets=this.watchAssets.filter(w=>w.type!=="trace"||y.testHasTrace(w.testId??"",w.project??""))}catch(f){this.channel.debug("Error processing report, "+this.stringify(f)),this.reportAsset&&(this.reportAsset.error=!0),d.emit({outcome:"error",error:tt(f)})}finally{if((s==="always"||s==="on-failure"&&i)&&await this.serveReport(r),n&&(0,ce.existsSync)(n))try{(0,ce.unlinkSync)(n)}catch(y){console.error(`Error deleting checksum metadata file ${n}: ${y.message}`)}}}async uploadReportData(e,r){let n=(0,Be.join)(e,"data");try{let i=(0,ce.readdirSync)(n),s=r?[".webm"]:[".zip",".webm"],o=i.filter(c=>!s.includes((0,Be.extname)(c)));this.channel.debug("Preparing to upload report data files,"+o);for(let c of o)this.channel.debug("Uploading report data file,"+c),this.addAsset({type:"report-data-file",fileName:c,path:`${n}/${c}`})}catch(i){this.channel.debug(`Error reading/adding report data files from dir ${n}`+i.message)}}shutdown(){clearInterval(this.uploadMonitorInterval);try{this.server?.closeAllConnections?.(),this.server?.close?.()}catch{}this.channel.debug("Received shutdown message from CLI"),process.stdout.write("",()=>process.exit(0)),setTimeout(()=>process.exit(0),this.SHUTDOWN_FLUSH_TIMEOUT).unref()}async monitorUploadsCompletion(){let e=Date.now();!this.doneWaitingForReport&&Kp(this.reportAsset,{testRunEndTime:this.testRunEndTime,stallTimeoutMs:this.UPLOAD_STALL_TIMEOUT,finalizeBudgetMs:this.FINALIZE_BUDGET},e)&&this.settleReport();let r=Zp({assets:this.assets,processingInProgress:this.processingInProgress,doneWaitingForReport:this.doneWaitingForReport,pendingWatchCount:this.watchAssets.length,testRunEndTime:this.testRunEndTime,stallTimeoutMs:this.UPLOAD_STALL_TIMEOUT,watchTimeoutMs:this.WATCH_TIMEOUT,finalizeBudgetMs:this.FINALIZE_BUDGET,finalizeCeilingMs:this.FINALIZE_CEILING},e);if(!r){await cs(1e3),this.monitorUploadsCompletion();return}this.finalizeRun(r,e)}stopWaitingForReport(e){this.doneWaitingForReport=!0,this.reportOutcome=e}reportAssetOutcome(){return this.reportAsset?.complete?"uploaded":this.reportAsset?.error?"failed":"abandoned"}settleReport(){this.stopWaitingForReport(this.reportAssetOutcome());let e="";try{let r=JSON.stringify(this.stats??{}),n=`checksum-stats-${(0,An.randomBytes)(8).toString("hex")}.json`;e=(0,Be.join)((0,im.tmpdir)(),n),(0,ce.writeFileSync)(e,r,"utf-8"),this.channel.debug(`Stats written to temporary file: ${e}`)}catch(r){this.channel.debug("Error writing stats to file"),this.channel.log(`[monitorUploadsCompletion] Error writing stats to file: ${r.message}`)}this.channel.event("report-complete",`${this.reportOutcome==="uploaded"?"true":"false"}:${e}`)}finalizeRun(e,r){e.reason==="stall"&&this.emitStallDetected(e.abandonedAssets,r),e.abandonedAssets.forEach(o=>{o.error=!0});let n=this.assets.some(o=>o.error)?"uploads-complete-with-errors":"uploads-complete",i=this.assets.filter(o=>o.error);mr("uploads_completion",{test_suite_run_id:this.config.sessionId,outcome:i.length>0?"error":"success",decision:n,total_assets:this.assets.length,completed:this.assets.filter(o=>o.complete).length,errored:i.length,stalled:e.abandonedAssets.length>0,stalled_count:e.abandonedAssets.length,finalize_reason:e.reason,finalize_budget_ms:this.FINALIZE_BUDGET,finalize_ceiling_ms:this.FINALIZE_CEILING,watch_remaining:this.watchAssets.length,report_outcome:this.reportOutcome,upload_finalize_ms:this.testRunEndTime?r-this.testRunEndTime:void 0,errored_assets:i.map(o=>this.assetSnapshot(o,r))});let s=n==="uploads-complete"?{}:{uploadErrors:i.map(o=>{try{return JSON.stringify(o)}catch{return o.info.path}}),watchAssets:this.watchAssets,testRunEndTime:this.testRunEndTime,now:r,finalizeReason:e.reason,abandonedAssets:e.abandonedAssets.map(o=>this.assetSnapshot(o,r))};if(Jp(e))try{this.cleanUp()}catch(o){this.channel.debug("cleanUp failed (ignored): "+o?.message)}else this.channel.debug(`skipping cleanUp: ${e.abandonedAssets.length} asset(s) abandoned (${e.reason})`);this.channel.event(n,JSON.stringify(s))}assetSnapshot(e,r){return{file_name:e.info.fileName??(0,Be.basename)(e.info.path),asset_type:e.info.type,test_id:e.info.testId,loaded_bytes:e.loadedBytes,committed_bytes:e.committedBytes,size_bytes:e.sizeBytes,last_progress_age_ms:e.lastProgress?r-e.lastProgress:void 0}}cleanUp(){let e;for(let r of this.assets)if(r.info.type==="rrweb-recording"){e=(0,Be.dirname)(r.info.path);break}e&&(0,ce.rmSync)(e,{recursive:!0,force:!0})}emitStallDetected(e,r){this.channel.log("Uploads are stalled"),!this.stallEventEmitted&&(this.stallEventEmitted=!0,mr("upload_stall_detected",{test_suite_run_id:this.config.sessionId,outcome:"error",timeout_ms:this.UPLOAD_STALL_TIMEOUT,total_assets:this.assets.length,pending_count:e.length,pending_assets:e.map(n=>this.assetSnapshot(n,r))}))}async startServer(){let e=await this.acquirePortNumber();this.channel.event("port",e.toString()),this.server=(0,rm.createServer)((r,n)=>{let i=a(o=>{n.writeHead(400,{"Content-Type":"text/plain"}),n.end(o)},"returnErrorWithMessage");if(r.method!=="POST"){n.writeHead(404,{"Content-Type":"text/plain"}),n.end("Method not allowed");return}let s="";r.on("data",o=>{s+=o.toString()}),r.on("end",()=>{let o;try{o=JSON.parse(s)}catch{i("Invalid body");return}let{type:c,payload:l,watch:u}=o;switch(this.channel.debug(`Server received message, ${c}, ${this.stringify(l)}`),c){case"asset":if(!l.path||!l.type){i("Missing arguments");return}u?this.watchAsset(l):this.processAsset(l);break;case"testInfo":if(!l.pwTestId||!l.checksumTestId){i("Missing arguments");return}this.pwTestIdToChecksumTestId[l.pwTestId]=l.checksumTestId,l.usingChecksumTestIdPlaceholder!==void 0&&(this.checksumTestIdToUsingPlaceholder[l.checksumTestId]=l.usingChecksumTestIdPlaceholder);break;case"checksumTestMetadata":{let d=l;if(!d.checksumTestId||!l.data){i("Missing arguments");return}this.channel.event("checksumTestMetadata",JSON.stringify({...d}));break}case"testStats":break;case"playwrightConfig":this.channel.event("playwrightConfig",JSON.stringify(l));break;case"runProgress":this.forwardProgress(l);break;default:i("Invalid message type");return}n.writeHead(200,{"Content-Type":"text/plain"}),n.end("OK")})}),this.server.listen(e)}forwardProgress(e){this.latestProgress=e,!this.progressFlushInFlight&&this.flushProgress()}async flushProgress(){this.progressFlushInFlight=!0;try{for(;this.latestProgress;){let e=this.latestProgress;this.latestProgress=void 0,await this.patchProgress(e)}}finally{this.progressFlushInFlight=!1}}async patchProgress(e){if(this.isolationMode)return;let r=new AbortController,n=setTimeout(()=>r.abort(),3e4);try{await fetch(`${this.config.apiURL}/client-api/test-runs/${this.config.sessionId}/progress`,{method:"PATCH",headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:this.config.apiKey},body:JSON.stringify({progress:e}),signal:r.signal})}catch(i){this.channel.debug("Failed to send run progress: "+i?.message)}finally{clearTimeout(n)}}stringify(e){try{return JSON.stringify(e)}catch{return"message"in e?e.message:e}}monitorUploads(){let{totalSizeBytes:e,totalUploadedBytes:r}=this.calculateUploadProgress();if(e>0&&!this.isolationMode){let s=(r/e*100).toFixed(2);this.channel.event("upload-progress",s)}let n=this.assets.filter(s=>!s.uploadStarted);if(n.length===0)return;let i=a(()=>this.assets.filter(s=>s.uploadStarted&&!s.complete&&!s.error).length,"getNumOfActiveUploads");if(!(i()>=this.MAX_UPLOADS))for(;n.length>0&&i()<this.MAX_UPLOADS;){let s=n.pop();if(s===void 0)break;this.uploadAsset(s)}}calculateUploadProgress(){let e=this.assets.reduce((n,{sizeBytes:i})=>n+(i??0),0),r=Math.min(e,this.assets.reduce((n,{loadedBytes:i})=>n+(i??0),0));return{totalSizeBytes:e,totalUploadedBytes:r}}getUploadLogMessage(e){switch(e.info.type){case"report":return"Uploading report";case"har":return`Uploading har file for test ${e.info.testId}`;case"trace":return`Uploading trace file for test ${e.info.testId}`;case"esra":return`Uploading metadata file for test ${e.info.testId}`;case"test-files":return`Uploading auto-healed test code for file ${e.info.path}`;default:return}}async uploadAsset(e){try{e.uploadStarted=!0;let r=this.getUploadLogMessage(e);r&&!this.isolationMode&&this.channel.event("log",r),await this.testAssetUploader.uploadAsset(e)}catch(r){e.error=!0,this.channel.debug("Error uploading asset"+this.stringify(r)),this.channel.trace("Upload Failed",{asset:e.info.fileName,error:String(r)})}}watchAsset(e){if(this.watchAssets.some(n=>n.path===e.path)){this.channel.debug(`Already watching file ${e.path}, skipping duplicate`);return}this.channel.debug("Watching file "+e.path),this.watchAssets.push({...e,addedAt:Date.now()});let r=a(async()=>{await this.waitForFileComplete(e.path)&&(this.processAsset(e),this.watchAssets=this.watchAssets.filter(i=>i.path!==e.path))},"waitForCompletion");if((0,ce.existsSync)(e.path))r();else{let n=(0,Be.dirname)(e.path),i=(0,Be.basename)(e.path),s=!1,o=(0,ce.watch)(n,(c,l)=>{(async()=>{if(!(l!==i||s))try{this.channel.debug("Watched file changed "+e.path),s=!0,await r()}finally{o.close()}})()})}}waitForFileComplete(e,r=1e3,n=6e4,i=1){return new Promise(s=>{let o=Date.now(),c=0,l=i,u=a(()=>{if(!(0,ce.existsSync)(e)){this.channel.debug(`Asset required for upload doesn't exist anymore ${e}`),s(!1);return}let d=(0,ce.statSync)(e).size;if(d===c){if(l>0){this.channel.debug(`File size has not changed, verifying stabilization, ${e}, size: ${d}, equalSizeValidationCountLeft: ${l}`),l--,setTimeout(u,r);return}this.channel.debug(`File size has not changed, stabilization verified, ${e}, size: ${d}`),s(!0);return}if(this.channel.debug(`File size changed, waiting for stabilization, ${e}, previous size: ${c}, current size: ${d}`),Date.now()-o>n){this.channel.debug(`Asset required for upload is taking over ${n} ms to write to disk ${e}`),s(!0);return}c=d,setTimeout(u,r)},"checkFile");u()})}processAsset(e){switch(e.type){case"trace":return this.processTrace(e.path,e.testId);case"har":return this.processHar();case"rrweb-recording":case"esra":case"test-files":return this.addAsset(e);default:return}}async processHar(){}async calculateFileSha1Streaming(e){let r=(0,An.createHash)("sha1"),n=(0,ce.createReadStream)(e);return await(0,tm.pipeline)(n,r),r.digest("hex")}async processTrace(e,r){if(this.processingPaths.has(e)){this.channel.debug(`Trace file ${e} already being processed, skipping`);return}this.processingPaths.add(e);let n;try{this.processingInProgress=!0,await cs(1e3),n=Zr("trace_processing",{test_suite_run_id:this.config.sessionId,test_id:r});let i=e;if(!this.isolationMode){this.channel.debug(`Preparing trace for upload (testId: ${r})...`),i=e.replace(".zip",".actual.zip"),(0,ce.renameSync)(e,i);let c="checksum-playwright-trace:"+Date.now().toString()+(0,An.randomBytes)(1024).toString("hex");(0,ce.writeFileSync)(e,c)}let o=await a(async()=>await this.calculateFileSha1Streaming(e)+(0,Be.extname)(e),"makePlaywrightHTMLReporterName")();this.channel.debug(`Trace file for test ${r} has been manipulated with file name ${o}, sending for upload...`),this.addAsset({type:"report-data-file",path:i,...r!==void 0?{testId:r}:{},fileName:o}),n.emit({outcome:"success",file_name:o})}catch(i){let s=String(i);this.channel.debug("Error processing trace file"+s),this.channel.trace("Trace Processing Error",{error:s}),n?.emit({outcome:"error",error:tt(i)})}finally{this.processingPaths.delete(e),this.processingInProgress=!1}}addAsset(e){this.channel.debug("Adding file "+e.path);let r=this.initAsset(e);return this.assets.push(r),r}initAsset(e){return{complete:!1,error:!1,info:e,removeAfterUpload:e.type==="rrweb-recording"}}async acquirePortNumber(){return new Promise((e,r)=>{let n=nm.createServer();n.unref(),n.on("error",r),n.listen(0,()=>{let i=n.address().port;n.close(()=>{e(i)})})})}},sm;try{sm=JSON.parse(process.argv[2]??"")}catch(t){console.error("Error starting test run monitor",t),process.exit(1)}new ns(sm,process.argv[3]==="isolated");0&&(module.exports={TestRunMonitor});
|
|
167
|
+
`)}event(e,r){return new Promise(n=>{let i=r?`${e}=${r}`:e;setTimeout(()=>{this.sendToCLI(`monitor:${i}`),n(!0)},100)})}trace(e,r){let n=r?`${e}=${JSON.stringify(r)}`:e;setTimeout(()=>{this.sendToCLI(`trace:${n}`)},100)}log(e){return this.event("log",e)}debug(...e){this.sendToCLI(e)}wideEvent(e){let r=Buffer.from(JSON.stringify(e),"utf-8").toString("base64");this.sendToCLI(`wideevent:${r}`)}},ns=class{constructor(e,r=!1){this.config=e;this.isolationMode=r;this.tunablesResolution=Ao(process.env);this.tunables=this.tunablesResolution.tunables;this.MAX_UPLOADS=this.tunables.maxConcurrentUploads;this.MONITOR_INTERVAL=2500;this.UPLOAD_TIMEOUT=this.tunables.uploadTimeoutMs;this.UPLOAD_STALL_TIMEOUT=this.tunables.stallTimeoutMs;this.WATCH_TIMEOUT=this.tunables.watchTimeoutMs;this.FINALIZE_BUDGET=this.tunables.finalizeBudgetMs;this.FINALIZE_CEILING=this.tunables.finalizeCeilingMs;this.SHUTDOWN_FLUSH_TIMEOUT=2e3;this.assets=[];this.watchAssets=[];this.processingPaths=new Set;this.doneWaitingForReport=!1;this.processingInProgress=!1;this.pwTestIdToChecksumTestId={};this.checksumTestIdToUsingPlaceholder={};this.progressFlushInFlight=!1;this.stallEventEmitted=!1;this.channel=new Lo,Io(n=>this.channel.wideEvent(n)),this.testAssetUploader=new Qi(e.apiURL,e.apiKey,this.UPLOAD_TIMEOUT,()=>`client-api/test-runs/${this.config.sessionId}/get-upload-url`,this.isolationMode,{start:a(n=>this.channel.trace("Upload Start",{filename:n}),"start"),complete:a(n=>{if(!this.reportAsset||n!==this.reportAsset.info.path)try{(0,ce.unlinkSync)(n),this.channel.debug(`[TestAssetUploader] Deleted file after successful upload: ${n}`)}catch(i){this.channel.debug(`[TestAssetUploader] Failed to delete file after upload: ${n}`,i)}this.channel.trace("Upload Complete",{filename:n})},"complete"),error:a((n,i)=>this.channel.trace("Upload Failed",{filename:n,error:i}),"error")},e.sessionId,{fetchImpl:Xp(this.tunables),tunables:this.tunables}),this.uploadMonitorInterval=setInterval(this.monitorUploads.bind(this),this.MONITOR_INTERVAL);for(let n of this.tunablesResolution.warnings)this.channel.debug(`[upload-tunables] ${n}`),mr("upload_tunable_coerced",{warning:n});this.listenForMessages(),this.startServer()}static{a(this,"TestRunMonitor")}listenForMessages(){process.stdin.on("data",e=>{(async()=>{let r=e.toString().trim();if(!r.startsWith("cli:"))return;let[n,i]=r.substring(4).split("=");switch(this.channel.debug("Received message from CLI "+n+" "+i),n){case"report":if(this.testRunEndTime=Date.now(),i!=="false")try{let s=Buffer.from(i??"","base64").toString("utf-8"),o=JSON.parse(s);await this.handleReport(o)}catch(s){this.channel.debug("Error JSON parsing report payload, continue without report. Error: "+this.stringify(s)),this.stopWaitingForReport("failed")}else this.stopWaitingForReport("not-requested");this.monitorUploadsCompletion();break;case"shutdown":this.shutdown();break}})()})}async readMetadataFile(e){try{let r=await(0,em.readFile)(e,"utf-8");return JSON.parse(r)}catch(r){return this.channel.trace("Runtime Error",`Error reading checksum metadata file ${e}: ${r.message}`),{}}}async serveReport(e){try{let r=(0,Be.dirname)(e);await this.channel.log("Serving report in browser: "+r);let n=zi.isRepoMode?`yarn playwright show-report ${r}`:`npx playwright show-report ${r}`;(0,Qp.execSync)(n,{encoding:"utf8",stdio:"pipe"}),await this.channel.log("Success: Report opened in browser")}catch(r){await this.channel.log(`Error serving report in browser: ${r.message}`),r.stderr&&await this.channel.log(r.stderr.toString())}}async handleReport(e){let{reportPath:r,pathToChecksumMetadata:n,didFail:i,openReportCriteria:s,checksumRoot:o,projectRoot:c,isUploadReport:l,dedupeByChecksumTestId:u}=e;this.channel.debug(`Handling report ${this.isolationMode?"(isolation mode)":""}`+r),this.uploadReportData((0,Be.dirname)(r),l);let d=Zr("report_processing",{test_suite_run_id:this.config.sessionId,report_path:r,isolation_mode:this.isolationMode,is_upload_report:!!l});try{let f=await this.readMetadataFile(n),y=new Ki(r,this.config.sessionId,this.pwTestIdToChecksumTestId,f,{hosted:!this.isolationMode,...u?{dedupeByChecksumTestId:u}:{}},this.channel,o,c,this.checksumTestIdToUsingPlaceholder),h=this.initAsset({type:"report",path:""});this.reportAsset=h;try{let w=await y.process();h.info.path=y.getProcessedFilePath(),d.set({processed_path:h.info.path,...w}),this.uploadAsset(h)}catch(w){this.channel.debug("Error processing report, "+w.message),h.error=!0,d.set({error:tt(w)})}let g=y.getReportsStats();this.stats=g,_f(d,h.error?"error":"success",g),this.channel.debug("Checking watch assets");let b=this.watchAssets.filter(w=>!(w.type!=="trace"||y.testHasTrace(w.testId??"",w.project??"")));b.length>0&&(this.channel.debug("Removed watch assets - "),this.channel.debug(JSON.stringify(b.map(w=>w.path)))),this.watchAssets=this.watchAssets.filter(w=>w.type!=="trace"||y.testHasTrace(w.testId??"",w.project??""))}catch(f){this.channel.debug("Error processing report, "+this.stringify(f)),this.reportAsset&&(this.reportAsset.error=!0),d.emit({outcome:"error",error:tt(f)})}finally{if((s==="always"||s==="on-failure"&&i)&&await this.serveReport(r),n&&(0,ce.existsSync)(n))try{(0,ce.unlinkSync)(n)}catch(y){console.error(`Error deleting checksum metadata file ${n}: ${y.message}`)}}}async uploadReportData(e,r){let n=(0,Be.join)(e,"data");try{let i=(0,ce.readdirSync)(n),s=r?[".webm"]:[".zip",".webm"],o=i.filter(c=>!s.includes((0,Be.extname)(c)));this.channel.debug("Preparing to upload report data files,"+o);for(let c of o)this.channel.debug("Uploading report data file,"+c),this.addAsset({type:"report-data-file",fileName:c,path:`${n}/${c}`})}catch(i){this.channel.debug(`Error reading/adding report data files from dir ${n}`+i.message)}}shutdown(){clearInterval(this.uploadMonitorInterval);try{this.server?.closeAllConnections?.(),this.server?.close?.()}catch{}this.channel.debug("Received shutdown message from CLI"),process.stdout.write("",()=>process.exit(0)),setTimeout(()=>process.exit(0),this.SHUTDOWN_FLUSH_TIMEOUT).unref()}async monitorUploadsCompletion(){let e=Date.now();!this.doneWaitingForReport&&Kp(this.reportAsset,{testRunEndTime:this.testRunEndTime,stallTimeoutMs:this.UPLOAD_STALL_TIMEOUT,finalizeBudgetMs:this.FINALIZE_BUDGET},e)&&this.settleReport();let r=Zp({assets:this.assets,processingInProgress:this.processingInProgress,doneWaitingForReport:this.doneWaitingForReport,pendingWatchCount:this.watchAssets.length,testRunEndTime:this.testRunEndTime,stallTimeoutMs:this.UPLOAD_STALL_TIMEOUT,watchTimeoutMs:this.WATCH_TIMEOUT,finalizeBudgetMs:this.FINALIZE_BUDGET,finalizeCeilingMs:this.FINALIZE_CEILING},e);if(!r){await cs(1e3),this.monitorUploadsCompletion();return}this.finalizeRun(r,e)}stopWaitingForReport(e){this.doneWaitingForReport=!0,this.reportOutcome=e}reportAssetOutcome(){return this.reportAsset?.complete?"uploaded":this.reportAsset?.error?"failed":"abandoned"}settleReport(){this.stopWaitingForReport(this.reportAssetOutcome());let e="";try{let r=JSON.stringify(this.stats??{}),n=`checksum-stats-${(0,An.randomBytes)(8).toString("hex")}.json`;e=(0,Be.join)((0,im.tmpdir)(),n),(0,ce.writeFileSync)(e,r,"utf-8"),this.channel.debug(`Stats written to temporary file: ${e}`)}catch(r){this.channel.debug("Error writing stats to file"),this.channel.log(`[monitorUploadsCompletion] Error writing stats to file: ${r.message}`)}this.channel.event("report-complete",`${this.reportOutcome==="uploaded"?"true":"false"}:${e}`)}finalizeRun(e,r){e.reason==="stall"&&this.emitStallDetected(e.abandonedAssets,r),e.abandonedAssets.forEach(o=>{o.error=!0});let n=this.assets.some(o=>o.error)?"uploads-complete-with-errors":"uploads-complete",i=this.assets.filter(o=>o.error);mr("uploads_completion",{test_suite_run_id:this.config.sessionId,outcome:i.length>0?"error":"success",decision:n,total_assets:this.assets.length,completed:this.assets.filter(o=>o.complete).length,errored:i.length,stalled:e.abandonedAssets.length>0,stalled_count:e.abandonedAssets.length,finalize_reason:e.reason,finalize_budget_ms:this.FINALIZE_BUDGET,finalize_ceiling_ms:this.FINALIZE_CEILING,watch_remaining:this.watchAssets.length,report_outcome:this.reportOutcome,upload_finalize_ms:this.testRunEndTime?r-this.testRunEndTime:void 0,errored_assets:i.map(o=>this.assetSnapshot(o,r))});let s=n==="uploads-complete"?{}:{uploadErrors:i.map(o=>{try{return JSON.stringify(o)}catch{return o.info.path}}),watchAssets:this.watchAssets,testRunEndTime:this.testRunEndTime,now:r,finalizeReason:e.reason,abandonedAssets:e.abandonedAssets.map(o=>this.assetSnapshot(o,r))};if(Jp(e))try{this.cleanUp()}catch(o){this.channel.debug("cleanUp failed (ignored): "+o?.message)}else this.channel.debug(`skipping cleanUp: ${e.abandonedAssets.length} asset(s) abandoned (${e.reason})`);this.channel.event(n,JSON.stringify(s))}assetSnapshot(e,r){return{file_name:e.info.fileName??(0,Be.basename)(e.info.path),asset_type:e.info.type,test_id:e.info.testId,loaded_bytes:e.loadedBytes,committed_bytes:e.committedBytes,size_bytes:e.sizeBytes,last_progress_age_ms:e.lastProgress?r-e.lastProgress:void 0}}cleanUp(){let e;for(let r of this.assets)if(r.info.type==="rrweb-recording"){e=(0,Be.dirname)(r.info.path);break}e&&(0,ce.rmSync)(e,{recursive:!0,force:!0})}emitStallDetected(e,r){this.channel.log("Uploads are stalled"),!this.stallEventEmitted&&(this.stallEventEmitted=!0,mr("upload_stall_detected",{test_suite_run_id:this.config.sessionId,outcome:"error",timeout_ms:this.UPLOAD_STALL_TIMEOUT,total_assets:this.assets.length,pending_count:e.length,pending_assets:e.map(n=>this.assetSnapshot(n,r))}))}async startServer(){let e=await this.acquirePortNumber();this.channel.event("port",e.toString()),this.server=(0,rm.createServer)((r,n)=>{let i=a(o=>{n.writeHead(400,{"Content-Type":"text/plain"}),n.end(o)},"returnErrorWithMessage");if(r.method!=="POST"){n.writeHead(404,{"Content-Type":"text/plain"}),n.end("Method not allowed");return}let s="";r.on("data",o=>{s+=o.toString()}),r.on("end",()=>{let o;try{o=JSON.parse(s)}catch{i("Invalid body");return}let{type:c,payload:l,watch:u}=o;switch(this.channel.debug(`Server received message, ${c}, ${this.stringify(l)}`),c){case"asset":if(!l.path||!l.type){i("Missing arguments");return}u?this.watchAsset(l):this.processAsset(l);break;case"testInfo":if(!l.pwTestId||!l.checksumTestId){i("Missing arguments");return}this.pwTestIdToChecksumTestId[l.pwTestId]=l.checksumTestId,l.usingChecksumTestIdPlaceholder!==void 0&&(this.checksumTestIdToUsingPlaceholder[l.checksumTestId]=l.usingChecksumTestIdPlaceholder);break;case"checksumTestMetadata":{let d=l;if(!d.checksumTestId||!l.data){i("Missing arguments");return}this.channel.event("checksumTestMetadata",JSON.stringify({...d}));break}case"testStats":break;case"playwrightConfig":this.channel.event("playwrightConfig",JSON.stringify(l));break;case"runProgress":this.forwardProgress(l);break;default:i("Invalid message type");return}n.writeHead(200,{"Content-Type":"text/plain"}),n.end("OK")})}),this.server.listen(e)}forwardProgress(e){this.latestProgress=e,!this.progressFlushInFlight&&this.flushProgress()}async flushProgress(){this.progressFlushInFlight=!0;try{for(;this.latestProgress;){let e=this.latestProgress;this.latestProgress=void 0,await this.patchProgress(e)}}finally{this.progressFlushInFlight=!1}}async patchProgress(e){if(this.isolationMode)return;let r=new AbortController,n=setTimeout(()=>r.abort(),3e4);try{await fetch(`${this.config.apiURL}/client-api/test-runs/${this.config.sessionId}/progress`,{method:"PATCH",headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:this.config.apiKey},body:JSON.stringify({progress:e}),signal:r.signal})}catch(i){this.channel.debug("Failed to send run progress: "+i?.message)}finally{clearTimeout(n)}}stringify(e){try{return JSON.stringify(e)}catch{return"message"in e?e.message:e}}monitorUploads(){let{totalSizeBytes:e,totalUploadedBytes:r}=this.calculateUploadProgress();if(e>0&&!this.isolationMode){let s=(r/e*100).toFixed(2);this.channel.event("upload-progress",s)}let n=this.assets.filter(s=>!s.uploadStarted);if(n.length===0)return;let i=a(()=>this.assets.filter(s=>s.uploadStarted&&!s.complete&&!s.error).length,"getNumOfActiveUploads");if(!(i()>=this.MAX_UPLOADS))for(;n.length>0&&i()<this.MAX_UPLOADS;){let s=n.pop();if(s===void 0)break;this.uploadAsset(s)}}calculateUploadProgress(){let e=this.assets.reduce((n,{sizeBytes:i})=>n+(i??0),0),r=Math.min(e,this.assets.reduce((n,{loadedBytes:i})=>n+(i??0),0));return{totalSizeBytes:e,totalUploadedBytes:r}}getUploadLogMessage(e){switch(e.info.type){case"report":return"Uploading report";case"har":return`Uploading har file for test ${e.info.testId}`;case"trace":return`Uploading trace file for test ${e.info.testId}`;case"esra":return`Uploading metadata file for test ${e.info.testId}`;case"test-files":return`Uploading auto-healed test code for file ${e.info.path}`;default:return}}async uploadAsset(e){try{e.uploadStarted=!0;let r=this.getUploadLogMessage(e);r&&!this.isolationMode&&this.channel.event("log",r),await this.testAssetUploader.uploadAsset(e)}catch(r){e.error=!0,this.channel.debug("Error uploading asset"+this.stringify(r)),this.channel.trace("Upload Failed",{asset:e.info.fileName,error:String(r)})}}watchAsset(e){if(this.watchAssets.some(n=>n.path===e.path)){this.channel.debug(`Already watching file ${e.path}, skipping duplicate`);return}this.channel.debug("Watching file "+e.path),this.watchAssets.push({...e,addedAt:Date.now()});let r=a(async()=>{await this.waitForFileComplete(e.path)&&(this.processAsset(e),this.watchAssets=this.watchAssets.filter(i=>i.path!==e.path))},"waitForCompletion");if((0,ce.existsSync)(e.path))r();else{let n=(0,Be.dirname)(e.path),i=(0,Be.basename)(e.path),s=!1,o=(0,ce.watch)(n,(c,l)=>{(async()=>{if(!(l!==i||s))try{this.channel.debug("Watched file changed "+e.path),s=!0,await r()}finally{o.close()}})()})}}waitForFileComplete(e,r=1e3,n=6e4,i=1){return new Promise(s=>{let o=Date.now(),c=0,l=i,u=a(()=>{if(!(0,ce.existsSync)(e)){this.channel.debug(`Asset required for upload doesn't exist anymore ${e}`),s(!1);return}let d=(0,ce.statSync)(e).size;if(d===c){if(l>0){this.channel.debug(`File size has not changed, verifying stabilization, ${e}, size: ${d}, equalSizeValidationCountLeft: ${l}`),l--,setTimeout(u,r);return}this.channel.debug(`File size has not changed, stabilization verified, ${e}, size: ${d}`),s(!0);return}if(this.channel.debug(`File size changed, waiting for stabilization, ${e}, previous size: ${c}, current size: ${d}`),Date.now()-o>n){this.channel.debug(`Asset required for upload is taking over ${n} ms to write to disk ${e}`),s(!0);return}c=d,setTimeout(u,r)},"checkFile");u()})}processAsset(e){switch(e.type){case"trace":return this.processTrace(e.path,e.testId);case"har":return;case"rrweb-recording":case"esra":case"test-files":return this.addAsset(e);default:return}}async calculateFileSha1Streaming(e){let r=(0,An.createHash)("sha1"),n=(0,ce.createReadStream)(e);return await(0,tm.pipeline)(n,r),r.digest("hex")}async processTrace(e,r){if(this.processingPaths.has(e)){this.channel.debug(`Trace file ${e} already being processed, skipping`);return}this.processingPaths.add(e);let n;try{this.processingInProgress=!0,await cs(1e3),n=Zr("trace_processing",{test_suite_run_id:this.config.sessionId,test_id:r});let i=e;if(!this.isolationMode){this.channel.debug(`Preparing trace for upload (testId: ${r})...`),i=e.replace(".zip",".actual.zip"),(0,ce.renameSync)(e,i);let c="checksum-playwright-trace:"+Date.now().toString()+(0,An.randomBytes)(1024).toString("hex");(0,ce.writeFileSync)(e,c)}let o=await a(async()=>await this.calculateFileSha1Streaming(e)+(0,Be.extname)(e),"makePlaywrightHTMLReporterName")();this.channel.debug(`Trace file for test ${r} has been manipulated with file name ${o}, sending for upload...`),this.addAsset({type:"report-data-file",path:i,...r!==void 0?{testId:r}:{},fileName:o}),n.emit({outcome:"success",file_name:o})}catch(i){let s=String(i);this.channel.debug("Error processing trace file"+s),this.channel.trace("Trace Processing Error",{error:s}),n?.emit({outcome:"error",error:tt(i)})}finally{this.processingPaths.delete(e),this.processingInProgress=!1}}addAsset(e){this.channel.debug("Adding file "+e.path);let r=this.initAsset(e);return this.assets.push(r),r}initAsset(e){return{complete:!1,error:!1,info:e,removeAfterUpload:e.type==="rrweb-recording"}}async acquirePortNumber(){return new Promise((e,r)=>{let n=nm.createServer();n.unref(),n.on("error",r),n.listen(0,()=>{let i=n.address().port;n.close(()=>{e(i)})})})}},sm;try{sm=JSON.parse(process.argv[2]??"")}catch(t){console.error("Error starting test run monitor",t),process.exit(1)}new ns(sm,process.argv[3]==="isolated");0&&(module.exports={TestRunMonitor});
|
|
168
168
|
/*! Bundled license information:
|
|
169
169
|
|
|
170
170
|
@langchain/core/dist/utils/js-sha256/hash.js:
|