File tree Expand file tree Collapse file tree 2 files changed +42
-4
lines changed Expand file tree Collapse file tree 2 files changed +42
-4
lines changed Original file line number Diff line number Diff line change @@ -111,6 +111,16 @@ const mockGetArtifactSuccess = jest.fn(() => {
111111 }
112112} )
113113
114+ const mockGetArtifactHung = jest . fn ( ( ) => {
115+ const message = new http . IncomingMessage ( new net . Socket ( ) )
116+ message . statusCode = 200
117+ // Don't push any data or call push(null) to end the stream
118+ // This creates a stream that hangs and never completes
119+ return {
120+ message
121+ }
122+ } )
123+
114124const mockGetArtifactFailure = jest . fn ( ( ) => {
115125 const message = new http . IncomingMessage ( new net . Socket ( ) )
116126 message . statusCode = 500
@@ -611,4 +621,32 @@ describe('download-artifact', () => {
611621 } )
612622 } )
613623 } )
624+
625+ describe ( 'streamExtractExternal' , ( ) => {
626+ it ( 'should fail if the timeout is exceeded' , async ( ) => {
627+ const mockSlowGetArtifact = jest . fn ( mockGetArtifactHung )
628+
629+ const mockHttpClient = ( HttpClient as jest . Mock ) . mockImplementation (
630+ ( ) => {
631+ return {
632+ get : mockSlowGetArtifact
633+ }
634+ }
635+ )
636+
637+ try {
638+ await streamExtractExternal (
639+ fixtures . blobStorageUrl ,
640+ fixtures . workspaceDir ,
641+ { timeout : 2 }
642+ )
643+ expect ( true ) . toBe ( false ) // should not be called
644+ } catch ( e ) {
645+ expect ( e ) . toBeInstanceOf ( Error )
646+ expect ( e . message ) . toContain ( 'did not respond in 2ms' )
647+ expect ( mockHttpClient ) . toHaveBeenCalledWith ( getUserAgentString ( ) )
648+ expect ( mockSlowGetArtifact ) . toHaveBeenCalledTimes ( 1 )
649+ }
650+ } )
651+ } )
614652} )
Original file line number Diff line number Diff line change @@ -64,7 +64,8 @@ async function streamExtract(
6464
6565export async function streamExtractExternal (
6666 url : string ,
67- directory : string
67+ directory : string ,
68+ opts : { timeout : number } = { timeout : 30 * 1000 }
6869) : Promise < StreamExtractResponse > {
6970 const client = new httpClient . HttpClient ( getUserAgentString ( ) )
7071 const response = await client . get ( url )
@@ -74,18 +75,17 @@ export async function streamExtractExternal(
7475 )
7576 }
7677
77- const timeout = 30 * 1000 // 30 seconds
7878 let sha256Digest : string | undefined = undefined
7979
8080 return new Promise ( ( resolve , reject ) => {
8181 const timerFn = ( ) : void => {
8282 const timeoutError = new Error (
83- `Blob storage chunk did not respond in ${ timeout } ms`
83+ `Blob storage chunk did not respond in ${ opts . timeout } ms`
8484 )
8585 response . message . destroy ( timeoutError )
8686 reject ( timeoutError )
8787 }
88- const timer = setTimeout ( timerFn , timeout )
88+ const timer = setTimeout ( timerFn , opts . timeout )
8989
9090 const hashStream = crypto . createHash ( 'sha256' ) . setEncoding ( 'hex' )
9191 const passThrough = new stream . PassThrough ( )
You can’t perform that action at this time.
0 commit comments