Skip to content

Commit ddc5fa4

Browse files
authored
Merge pull request #2133 from actions/danwkennedy/test-blob-stream-timeout
Test: add a timeout test for downloading chunks from the stream
2 parents 714f93a + 9b08f07 commit ddc5fa4

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

packages/artifact/__tests__/download-artifact.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff 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+
114124
const 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
})

packages/artifact/src/internal/download/download-artifact.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ async function streamExtract(
6464

6565
export 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()

0 commit comments

Comments
 (0)