import {retry} from '../src/internal/requestUtils' import {HttpClientError} from '@actions/http-client' 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 { if (!response) { // eslint-disable-next-line no-undef 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 { 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 { 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 { 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(500), 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 ) })