mirror of https://github.com/actions/checkout.git
154 lines
4.4 KiB
TypeScript
154 lines
4.4 KiB
TypeScript
import {
|
|
jest,
|
|
describe,
|
|
it,
|
|
expect,
|
|
beforeAll,
|
|
beforeEach,
|
|
afterAll
|
|
} from '@jest/globals'
|
|
|
|
let info: string[] = []
|
|
|
|
// Mock @actions/core before loading retry-helper
|
|
jest.unstable_mockModule('@actions/core', () => ({
|
|
info: jest.fn((message: string) => {
|
|
info.push(message)
|
|
}),
|
|
debug: jest.fn(),
|
|
warning: jest.fn(),
|
|
error: jest.fn()
|
|
}))
|
|
|
|
// Dynamic imports after mocking
|
|
const {RetryHelper} = await import('../src/retry-helper.js')
|
|
|
|
describe('retry-helper tests', () => {
|
|
beforeAll(() => {
|
|
// @actions/core is mocked at module load above; nothing to set up here.
|
|
})
|
|
|
|
beforeEach(() => {
|
|
// Reset info
|
|
info = []
|
|
})
|
|
|
|
afterAll(() => {
|
|
jest.restoreAllMocks()
|
|
})
|
|
|
|
it('first attempt succeeds', async () => {
|
|
const retryHelper: any = new RetryHelper(3, 1, 10)
|
|
const sleep = jest.fn().mockResolvedValue(undefined)
|
|
retryHelper.sleep = sleep
|
|
|
|
const actual = await retryHelper.execute(async () => {
|
|
return 'some result'
|
|
})
|
|
expect(actual).toBe('some result')
|
|
expect(info).toHaveLength(0)
|
|
expect(sleep).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('second attempt succeeds', async () => {
|
|
const retryHelper: any = new RetryHelper(3, 1, 10)
|
|
const sleep = jest.fn().mockResolvedValue(undefined)
|
|
retryHelper.sleep = sleep
|
|
let attempts = 0
|
|
const actual = await retryHelper.execute(() => {
|
|
if (++attempts == 1) {
|
|
throw new Error('some error')
|
|
}
|
|
|
|
return Promise.resolve('some result')
|
|
})
|
|
expect(attempts).toBe(2)
|
|
expect(actual).toBe('some result')
|
|
expect(info).toHaveLength(2)
|
|
expect(info[0]).toBe('some error')
|
|
expect(info[1]).toBe('Waiting 1 seconds before trying again')
|
|
expect(sleep).toHaveBeenCalledTimes(1)
|
|
expect(sleep).toHaveBeenCalledWith(1)
|
|
})
|
|
|
|
it('third attempt succeeds', async () => {
|
|
const retryHelper: any = new RetryHelper(3, 1, 10)
|
|
const sleep = jest.fn().mockResolvedValue(undefined)
|
|
retryHelper.sleep = sleep
|
|
let attempts = 0
|
|
const actual = await retryHelper.execute(() => {
|
|
if (++attempts < 3) {
|
|
throw new Error(`some error ${attempts}`)
|
|
}
|
|
|
|
return Promise.resolve('some result')
|
|
})
|
|
expect(attempts).toBe(3)
|
|
expect(actual).toBe('some result')
|
|
expect(info).toHaveLength(4)
|
|
expect(info[0]).toBe('some error 1')
|
|
expect(info[1]).toBe('Waiting 1 seconds before trying again')
|
|
expect(info[2]).toBe('some error 2')
|
|
expect(info[3]).toBe('Waiting 2 seconds before trying again')
|
|
expect(sleep).toHaveBeenCalledTimes(2)
|
|
expect(sleep).toHaveBeenNthCalledWith(1, 1)
|
|
expect(sleep).toHaveBeenNthCalledWith(2, 2)
|
|
})
|
|
|
|
it('all attempts fail succeeds', async () => {
|
|
const retryHelper: any = new RetryHelper(3, 1, 10)
|
|
const sleep = jest.fn().mockResolvedValue(undefined)
|
|
retryHelper.sleep = sleep
|
|
let attempts = 0
|
|
let error: Error = null as unknown as Error
|
|
try {
|
|
await retryHelper.execute(() => {
|
|
throw new Error(`some error ${++attempts}`)
|
|
})
|
|
} catch (err) {
|
|
error = err as Error
|
|
}
|
|
expect(error.message).toBe('some error 3')
|
|
expect(attempts).toBe(3)
|
|
expect(info).toHaveLength(4)
|
|
expect(info[0]).toBe('some error 1')
|
|
expect(info[1]).toBe('Waiting 1 seconds before trying again')
|
|
expect(info[2]).toBe('some error 2')
|
|
expect(info[3]).toBe('Waiting 2 seconds before trying again')
|
|
expect(sleep).toHaveBeenCalledTimes(2)
|
|
expect(sleep).toHaveBeenNthCalledWith(1, 1)
|
|
expect(sleep).toHaveBeenNthCalledWith(2, 2)
|
|
})
|
|
|
|
it('server-side 500 errors are retried with exponential backoff', async () => {
|
|
const retryHelper: any = new RetryHelper(4, 2, 10)
|
|
const sleep = jest.fn().mockResolvedValue(undefined)
|
|
retryHelper.sleep = sleep
|
|
let attempts = 0
|
|
|
|
const actual = await retryHelper.execute(() => {
|
|
if (++attempts < 3) {
|
|
const error: Error & {status?: number} = new Error(
|
|
`server error ${attempts}`
|
|
)
|
|
error.status = 500
|
|
throw error
|
|
}
|
|
|
|
return Promise.resolve('some result')
|
|
})
|
|
|
|
expect(actual).toBe('some result')
|
|
expect(attempts).toBe(3)
|
|
expect(info).toEqual([
|
|
'server error 1',
|
|
'Waiting 2 seconds before trying again',
|
|
'server error 2',
|
|
'Waiting 4 seconds before trying again'
|
|
])
|
|
expect(sleep).toHaveBeenCalledTimes(2)
|
|
expect(sleep).toHaveBeenNthCalledWith(1, 2)
|
|
expect(sleep).toHaveBeenNthCalledWith(2, 4)
|
|
})
|
|
})
|