Files
Codewalkers/apps/server/agent/lifecycle/retry-policy.test.ts
Lukas May 34578d39c6 refactor: Restructure monorepo to apps/server/ and apps/web/ layout
Move src/ → apps/server/ and packages/web/ → apps/web/ to adopt
standard monorepo conventions (apps/ for runnable apps, packages/
for reusable libraries). Update all config files, shared package
imports, test fixtures, and documentation to reflect new paths.

Key fixes:
- Update workspace config to ["apps/*", "packages/*"]
- Update tsconfig.json rootDir/include for apps/server/
- Add apps/web/** to vitest exclude list
- Update drizzle.config.ts schema path
- Fix ensure-schema.ts migration path detection (3 levels up in dev,
  2 levels up in dist)
- Fix tests/integration/cli-server.test.ts import paths
- Update packages/shared imports to apps/server/ paths
- Update all docs/ files with new paths
2026-03-03 11:22:53 +01:00

146 lines
4.4 KiB
TypeScript

/**
* RetryPolicy Tests — Verify retry logic for different error types.
*/
import { describe, it, expect, beforeEach } from 'vitest';
import { DefaultRetryPolicy, type AgentError } from './retry-policy.js';
describe('DefaultRetryPolicy', () => {
let retryPolicy: DefaultRetryPolicy;
beforeEach(() => {
retryPolicy = new DefaultRetryPolicy();
});
describe('configuration', () => {
it('should have correct max attempts', () => {
expect(retryPolicy.maxAttempts).toBe(3);
});
it('should have exponential backoff delays', () => {
expect(retryPolicy.backoffMs).toEqual([1000, 2000, 4000]);
});
});
describe('shouldRetry', () => {
it('should retry auth failures', () => {
const error: AgentError = {
type: 'auth_failure',
message: 'Unauthorized',
isTransient: true,
requiresAccountSwitch: false,
shouldPersistToDB: true
};
expect(retryPolicy.shouldRetry(error, 1)).toBe(true);
expect(retryPolicy.shouldRetry(error, 2)).toBe(true);
expect(retryPolicy.shouldRetry(error, 3)).toBe(false); // At max attempts
});
it('should not retry usage limit errors', () => {
const error: AgentError = {
type: 'usage_limit',
message: 'Rate limit exceeded',
isTransient: false,
requiresAccountSwitch: true,
shouldPersistToDB: true
};
expect(retryPolicy.shouldRetry(error, 1)).toBe(false);
expect(retryPolicy.shouldRetry(error, 2)).toBe(false);
});
it('should retry missing signal errors', () => {
const error: AgentError = {
type: 'missing_signal',
message: 'No signal.json found',
isTransient: true,
requiresAccountSwitch: false,
shouldPersistToDB: false
};
expect(retryPolicy.shouldRetry(error, 1)).toBe(true);
expect(retryPolicy.shouldRetry(error, 2)).toBe(true);
expect(retryPolicy.shouldRetry(error, 3)).toBe(false); // At max attempts
});
it('should retry transient process crashes', () => {
const error: AgentError = {
type: 'process_crash',
message: 'Process died',
isTransient: true,
requiresAccountSwitch: false,
shouldPersistToDB: true
};
expect(retryPolicy.shouldRetry(error, 1)).toBe(true);
expect(retryPolicy.shouldRetry(error, 2)).toBe(true);
});
it('should not retry non-transient process crashes', () => {
const error: AgentError = {
type: 'process_crash',
message: 'Segmentation fault',
isTransient: false,
requiresAccountSwitch: false,
shouldPersistToDB: true
};
expect(retryPolicy.shouldRetry(error, 1)).toBe(false);
expect(retryPolicy.shouldRetry(error, 2)).toBe(false);
});
it('should retry timeouts', () => {
const error: AgentError = {
type: 'timeout',
message: 'Process timed out',
isTransient: true,
requiresAccountSwitch: false,
shouldPersistToDB: true
};
expect(retryPolicy.shouldRetry(error, 1)).toBe(true);
expect(retryPolicy.shouldRetry(error, 2)).toBe(true);
expect(retryPolicy.shouldRetry(error, 3)).toBe(false); // At max attempts
});
it('should not retry unknown errors', () => {
const error: AgentError = {
type: 'unknown',
message: 'Something weird happened',
isTransient: false,
requiresAccountSwitch: false,
shouldPersistToDB: true
};
expect(retryPolicy.shouldRetry(error, 1)).toBe(false);
expect(retryPolicy.shouldRetry(error, 2)).toBe(false);
});
it('should not retry when at max attempts regardless of error type', () => {
const error: AgentError = {
type: 'auth_failure',
message: 'Unauthorized',
isTransient: true,
requiresAccountSwitch: false,
shouldPersistToDB: true
};
expect(retryPolicy.shouldRetry(error, 3)).toBe(false);
expect(retryPolicy.shouldRetry(error, 4)).toBe(false);
});
});
describe('getRetryDelay', () => {
it('should return correct delay for each attempt', () => {
expect(retryPolicy.getRetryDelay(1)).toBe(1000);
expect(retryPolicy.getRetryDelay(2)).toBe(2000);
expect(retryPolicy.getRetryDelay(3)).toBe(4000);
});
it('should cap delay at maximum for high attempts', () => {
expect(retryPolicy.getRetryDelay(4)).toBe(4000);
expect(retryPolicy.getRetryDelay(10)).toBe(4000);
});
});
});