mirror of https://github.com/actions/toolkit
180 lines
4.2 KiB
TypeScript
180 lines
4.2 KiB
TypeScript
import {retry, retryTypedResponse} from '../src/internal/requestUtils'
|
|
import {HttpClientError} from '@actions/http-client'
|
|
import * as requestUtils from '../src/internal/requestUtils'
|
|
|
|
interface ITestResponse {
|
|
statusCode: number
|
|
result: string | null
|
|
error: Error | null
|
|
}
|
|
|
|
function TestResponse(
|
|
action: number | Error,
|
|
result: string | null = null
|
|
): ITestResponse {
|
|
if (action instanceof Error) {
|
|
return {
|
|
statusCode: -1,
|
|
result,
|
|
error: action
|
|
}
|
|
} else {
|
|
return {
|
|
statusCode: action,
|
|
result,
|
|
error: null
|
|
}
|
|
}
|
|
}
|
|
|
|
async function handleResponse(
|
|
response: ITestResponse | undefined
|
|
): Promise<ITestResponse> {
|
|
if (!response) {
|
|
fail('Retry method called too many times')
|
|
}
|
|
|
|
if (response.error) {
|
|
throw response.error
|
|
} else {
|
|
return Promise.resolve(response)
|
|
}
|
|
}
|
|
|
|
async function testRetryExpectingResult(
|
|
responses: ITestResponse[],
|
|
expectedResult: string | null
|
|
): Promise<void> {
|
|
responses = responses.reverse() // Reverse responses since we pop from end
|
|
|
|
const actualResult = await retry(
|
|
'test',
|
|
async () => handleResponse(responses.pop()),
|
|
(response: ITestResponse) => response.statusCode,
|
|
2, // maxAttempts
|
|
0 // delay
|
|
)
|
|
|
|
expect(actualResult.result).toEqual(expectedResult)
|
|
}
|
|
|
|
async function testRetryConvertingErrorToResult(
|
|
responses: ITestResponse[],
|
|
expectedStatus: number,
|
|
expectedResult: string | null
|
|
): Promise<void> {
|
|
responses = responses.reverse() // Reverse responses since we pop from end
|
|
|
|
const actualResult = await retry(
|
|
'test',
|
|
async () => handleResponse(responses.pop()),
|
|
(response: ITestResponse) => response.statusCode,
|
|
2, // maxAttempts
|
|
0, // delay
|
|
(e: Error) => {
|
|
if (e instanceof HttpClientError) {
|
|
return {
|
|
statusCode: e.statusCode,
|
|
result: null,
|
|
error: null
|
|
}
|
|
}
|
|
}
|
|
)
|
|
|
|
expect(actualResult.statusCode).toEqual(expectedStatus)
|
|
expect(actualResult.result).toEqual(expectedResult)
|
|
}
|
|
|
|
async function testRetryExpectingError(
|
|
responses: ITestResponse[]
|
|
): Promise<void> {
|
|
responses = responses.reverse() // Reverse responses since we pop from end
|
|
|
|
expect(
|
|
retry(
|
|
'test',
|
|
async () => handleResponse(responses.pop()),
|
|
(response: ITestResponse) => response.statusCode,
|
|
2, // maxAttempts,
|
|
0 // delay
|
|
)
|
|
).rejects.toBeInstanceOf(Error)
|
|
}
|
|
|
|
test('retry works on successful response', async () => {
|
|
await testRetryExpectingResult([TestResponse(200, 'Ok')], 'Ok')
|
|
})
|
|
|
|
test('retry works after retryable status code', async () => {
|
|
await testRetryExpectingResult(
|
|
[TestResponse(503), TestResponse(200, 'Ok')],
|
|
'Ok'
|
|
)
|
|
})
|
|
|
|
test('retry fails after exhausting retries', async () => {
|
|
await testRetryExpectingError([
|
|
TestResponse(503),
|
|
TestResponse(503),
|
|
TestResponse(200, 'Ok')
|
|
])
|
|
})
|
|
|
|
test('retry fails after non-retryable status code', async () => {
|
|
await testRetryExpectingError([TestResponse(501), TestResponse(200, 'Ok')])
|
|
})
|
|
|
|
test('retry works after error', async () => {
|
|
await testRetryExpectingResult(
|
|
[TestResponse(new Error('Test error')), TestResponse(200, 'Ok')],
|
|
'Ok'
|
|
)
|
|
})
|
|
|
|
test('retry returns after client error', async () => {
|
|
await testRetryExpectingResult(
|
|
[TestResponse(400), TestResponse(200, 'Ok')],
|
|
null
|
|
)
|
|
})
|
|
|
|
test('retry converts errors to response object', async () => {
|
|
await testRetryConvertingErrorToResult(
|
|
[TestResponse(new HttpClientError('Test error', 409))],
|
|
409,
|
|
null
|
|
)
|
|
})
|
|
|
|
test('retryTypedResponse gives an error with error message', async () => {
|
|
const httpClientError = new HttpClientError(
|
|
'The cache filesize must be between 0 and 10 * 1024 * 1024 bytes',
|
|
400
|
|
)
|
|
jest.spyOn(requestUtils, 'retry').mockReturnValue(
|
|
new Promise(resolve => {
|
|
resolve(httpClientError)
|
|
})
|
|
)
|
|
try {
|
|
await retryTypedResponse<string>(
|
|
'reserveCache',
|
|
async () =>
|
|
new Promise(resolve => {
|
|
resolve({
|
|
statusCode: 400,
|
|
result: '',
|
|
headers: {},
|
|
error: httpClientError
|
|
})
|
|
})
|
|
)
|
|
} catch (error) {
|
|
expect(error).toHaveProperty(
|
|
'message',
|
|
'The cache filesize must be between 0 and 10 * 1024 * 1024 bytes'
|
|
)
|
|
}
|
|
})
|