59 lines
2.9 KiB
TypeScript
59 lines
2.9 KiB
TypeScript
// Load-aware timeouts and the one retry under load (tests/helpers/load.ts, testScope().concurrent in
|
|
// tests/helpers/browser.ts): a timeout on a loaded machine runs once more; an assertion failure never does.
|
|
import { describe, expect, test } from 'bun:test';
|
|
import { retryUnderLoad, WaitTimeout, withBudget } from './helpers/browser';
|
|
import { loadFactor, RETRY_MARK, scaled } from './helpers/load';
|
|
|
|
describe('load factor', () => {
|
|
test('load ÷ cores from the larger of the 1- and 5-minute averages, between 1 and the cap', () => {
|
|
expect(loadFactor({}, [5, 2, 1], 10)).toBe(1);
|
|
expect(loadFactor({}, [30, 45, 50], 10)).toBe(4.5);
|
|
expect(loadFactor({}, [577, 300, 100], 10)).toBe(5);
|
|
expect(loadFactor({ STOREBOUND_LOAD_FACTOR: '3' }, [0, 0, 0], 10)).toBe(3);
|
|
expect(loadFactor({ STOREBOUND_LOAD_FACTOR: '50' }, [0, 0, 0], 10)).toBe(5);
|
|
expect(scaled(1000, 2.5)).toBe(2500);
|
|
});
|
|
});
|
|
|
|
describe('one retry, only for a timeout under load', () => {
|
|
const run = async (err: () => unknown, factor: number) => {
|
|
const said: string[] = [];
|
|
let n = 0;
|
|
let failed: unknown = null;
|
|
await retryUnderLoad('t', async () => { if (++n === 1) throw err(); }, () => factor, m => said.push(m)).catch(e => { failed = e; });
|
|
return { n, said, failed };
|
|
};
|
|
test('a wait timeout or a Playwright TimeoutError under load: retried once and reported', async () => {
|
|
for (const err of [() => new WaitTimeout('timed out after 1 ms'), () => Object.assign(new Error('locator.click: Timeout 50ms exceeded'), { name: 'TimeoutError' })]) {
|
|
const r = await run(err, 3);
|
|
expect(r.n).toBe(2);
|
|
expect(r.failed).toBeNull();
|
|
expect(r.said).toHaveLength(1);
|
|
expect(r.said[0]!.startsWith(`${RETRY_MARK} t (load x3)`)).toBe(true);
|
|
}
|
|
});
|
|
test('an assertion failure is never retried, under any load', async () => {
|
|
const r = await run(() => { try { expect(1).toBe(2); } catch (e) { return e; } }, 5);
|
|
expect(r.n).toBe(1);
|
|
expect(r.failed).not.toBeNull();
|
|
expect(r.said).toEqual([]);
|
|
});
|
|
test('a timeout on a quiet machine (factor <= 2) is final', async () => {
|
|
const r = await run(() => new WaitTimeout('timed out'), 2);
|
|
expect(r.n).toBe(1);
|
|
expect(r.failed).toBeInstanceOf(WaitTimeout);
|
|
});
|
|
test('a second timeout fails the test (one retry only)', async () => {
|
|
let n = 0;
|
|
const e = await retryUnderLoad('t', async () => { n++; throw new WaitTimeout('again'); }, () => 4, () => {}).catch(x => x);
|
|
expect(n).toBe(2);
|
|
expect(e).toBeInstanceOf(WaitTimeout);
|
|
});
|
|
test('the test budget: a run past it fails as a timeout, and the settle runs either way', async () => {
|
|
let settled = 0;
|
|
const e = await withBudget(() => Bun.sleep(200), 20, async () => { settled++; }).catch(x => x);
|
|
expect(e).toBeInstanceOf(WaitTimeout);
|
|
await withBudget(async () => {}, 1000, async () => { settled++; });
|
|
expect(settled).toBe(2);
|
|
});
|
|
});
|