forked from Shared/esg
Introduce plate, chassis, and third-party car endpoints, a wall-clock inquiry deadline with transport-only retries, and ownership-safe no-match errors so another person's identity never leaks. Co-authored-by: Cursor <cursoragent@cursor.com>
50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
import {
|
|
INQUIRY_DEADLINE_MS,
|
|
createAttemptTrail,
|
|
runWithProviderResilience,
|
|
toAttemptErrorFields,
|
|
} from '../../src/common/helpers/provider-resilience.helper';
|
|
import { ProviderExecutionContext } from '../../src/common/interfaces/inquiry-provider.interface';
|
|
|
|
describe('timeout / deadline resilience bugs', () => {
|
|
it('maps withTimeout ETIMEDOUT errors to PROVIDER_TIMEOUT (not PROVIDER_ERROR)', () => {
|
|
const error = new Error('PARSIAN request timed out after 20000ms');
|
|
(error as NodeJS.ErrnoException).code = 'ETIMEDOUT';
|
|
|
|
expect(toAttemptErrorFields(error)).toMatchObject({
|
|
code: 'PROVIDER_TIMEOUT',
|
|
messageFa: expect.stringMatching(/زمان/),
|
|
});
|
|
});
|
|
|
|
it('caps attempt timeout by inquiry deadline even when provider timeout is higher', async () => {
|
|
const context: ProviderExecutionContext = {
|
|
requestId: 'req',
|
|
trackingCode: 'trk',
|
|
deadlineAt: Date.now() + 80,
|
|
attemptTrail: createAttemptTrail(),
|
|
};
|
|
|
|
const started = Date.now();
|
|
await expect(
|
|
runWithProviderResilience(
|
|
() => new Promise((resolve) => setTimeout(() => resolve('late'), 500)),
|
|
{
|
|
providerName: 'PARSIAN',
|
|
maxAttempts: 1,
|
|
timeoutMs: 30_000,
|
|
context,
|
|
label: 'PARSIAN request',
|
|
},
|
|
),
|
|
).rejects.toMatchObject({ code: 'ETIMEDOUT' });
|
|
|
|
expect(Date.now() - started).toBeLessThan(250);
|
|
});
|
|
|
|
it('default inquiry deadline must exceed a single slow CentInsur SOAP (~30s)', () => {
|
|
// thirdPartyCar may need two SOAP calls over a proxy; 20s was killing successful ~28s responses
|
|
expect(INQUIRY_DEADLINE_MS).toBeGreaterThanOrEqual(60_000);
|
|
});
|
|
});
|