Files
continue/core/util/withExponentialBackoff.test.ts
2024-12-09 13:20:54 -08:00

143 lines
3.6 KiB
TypeScript

// Generated by continue
import {
withExponentialBackoff,
APIError,
RETRY_AFTER_HEADER,
} from "./withExponentialBackoff";
describe.skip("withExponentialBackoff", () => {
it("should return result when apiCall succeeds on first attempt", async () => {
// Arrange
const apiCall = jest.fn().mockResolvedValue("Success");
// Act
const result = await withExponentialBackoff(apiCall);
// Assert
expect(result).toBe("Success");
expect(apiCall).toHaveBeenCalledTimes(1);
});
it("should throw error when apiCall fails with non-429 error", async () => {
// Arrange
const error = new Error("Some error");
const apiCall = jest.fn().mockRejectedValue(error);
// Act & Assert
await expect(withExponentialBackoff(apiCall)).rejects.toThrow("Some error");
expect(apiCall).toHaveBeenCalledTimes(1);
});
it("should retry when apiCall fails with 429 and no Retry-After header", async () => {
// Arrange
const apiCall = jest.fn();
const firstError: APIError = new Error("Rate limit");
firstError.response = {
status: 429,
headers: {
get: () => null, // No Retry-After header
},
} as unknown as Response;
// First call fails with 429, second call succeeds
apiCall.mockRejectedValueOnce(firstError).mockResolvedValueOnce("Success");
// Act
const result = await withExponentialBackoff(
apiCall,
5,
0.01, // initialDelaySeconds
);
// Assert
expect(result).toBe("Success");
expect(apiCall).toHaveBeenCalledTimes(2);
});
it("should retry when apiCall fails with 429 and Retry-After header", async () => {
// Arrange
const apiCall = jest.fn();
const firstError: APIError = new Error("Rate limit");
firstError.response = {
status: 429,
headers: {
get: (headerName: string) => {
if (headerName === RETRY_AFTER_HEADER) {
return "0.02";
}
return null;
},
},
} as unknown as Response;
// First call fails with 429, second call succeeds
apiCall.mockRejectedValueOnce(firstError).mockResolvedValueOnce("Success");
jest.useFakeTimers();
const promise = withExponentialBackoff(apiCall, 5, 0.01);
// Advance timers to cover the delay
await jest.advanceTimersByTimeAsync(20);
const result = await promise;
// Assert
expect(result).toBe("Success");
expect(apiCall).toHaveBeenCalledTimes(2);
jest.useRealTimers();
});
it("should throw error after maxTries reached", async () => {
// Arrange
const apiCall = jest.fn();
const error: APIError = new Error("Rate limit");
error.response = {
status: 429,
headers: {
get: () => null,
},
} as unknown as Response;
apiCall.mockRejectedValue(error);
const maxTries = 3;
const initialDelaySeconds = 0.01;
// Act & Assert
await expect(
withExponentialBackoff(apiCall, maxTries, initialDelaySeconds),
).rejects.toThrow("Failed to make API call after max tries");
expect(apiCall).toHaveBeenCalledTimes(maxTries);
});
it("should not call if maxTries is 0", async () => {
const apiCall = jest.fn();
const error: APIError = new Error("Rate limit");
error.response = {
status: 429,
headers: {
get: () => null,
},
} as unknown as Response;
apiCall.mockRejectedValue(error);
const maxTries = 0;
const initialDelaySeconds = 0.01;
await expect(
withExponentialBackoff(apiCall, maxTries, initialDelaySeconds),
).rejects.toThrow("Failed to make API call after max tries");
expect(apiCall).toHaveBeenCalledTimes(0);
});
});