mirror of
https://github.com/actions/setup-python.git
synced 2026-07-18 06:19:58 +08:00
Refactor error handling in isRateLimitError function for improved clarity
This commit is contained in:
parent
9737be46d4
commit
0bc3767d34
3 changed files with 8 additions and 12 deletions
|
|
@ -57,7 +57,6 @@ describe('getManifest', () => {
|
||||||
|
|
||||||
it('should fall back to URL if repo returns a truncated/empty manifest', async () => {
|
it('should fall back to URL if repo returns a truncated/empty manifest', async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
// Simulate a truncated response that parses to an empty array.
|
|
||||||
(tc.getManifestFromRepo as jest.Mock).mockResolvedValue([]);
|
(tc.getManifestFromRepo as jest.Mock).mockResolvedValue([]);
|
||||||
(httpm.HttpClient.prototype.getJson as jest.Mock).mockResolvedValue({
|
(httpm.HttpClient.prototype.getJson as jest.Mock).mockResolvedValue({
|
||||||
result: mockManifest
|
result: mockManifest
|
||||||
|
|
@ -71,9 +70,7 @@ describe('getManifest', () => {
|
||||||
it('should retry on a transient invalid manifest and then succeed', async () => {
|
it('should retry on a transient invalid manifest and then succeed', async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
(tc.getManifestFromRepo as jest.Mock)
|
(tc.getManifestFromRepo as jest.Mock)
|
||||||
// First attempt returns a truncated/empty body.
|
|
||||||
.mockResolvedValueOnce([])
|
.mockResolvedValueOnce([])
|
||||||
// Retry returns a valid manifest.
|
|
||||||
.mockResolvedValueOnce(mockManifest);
|
.mockResolvedValueOnce(mockManifest);
|
||||||
const promise = getManifest();
|
const promise = getManifest();
|
||||||
await jest.runAllTimersAsync();
|
await jest.runAllTimersAsync();
|
||||||
|
|
@ -84,13 +81,12 @@ describe('getManifest', () => {
|
||||||
|
|
||||||
it('should fail loudly when the manifest is truncated/empty on every source', async () => {
|
it('should fail loudly when the manifest is truncated/empty on every source', async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
// Both the API and the raw URL keep returning truncated/empty bodies.
|
|
||||||
(tc.getManifestFromRepo as jest.Mock).mockResolvedValue([]);
|
(tc.getManifestFromRepo as jest.Mock).mockResolvedValue([]);
|
||||||
(httpm.HttpClient.prototype.getJson as jest.Mock).mockResolvedValue({
|
(httpm.HttpClient.prototype.getJson as jest.Mock).mockResolvedValue({
|
||||||
result: []
|
result: []
|
||||||
});
|
});
|
||||||
const promise = getManifest();
|
const promise = getManifest();
|
||||||
// Attach a rejection handler before advancing timers to avoid unhandled rejection warnings.
|
// Prevent unhandled rejection before timers advance.
|
||||||
const catchPromise = promise.catch(() => {});
|
const catchPromise = promise.catch(() => {});
|
||||||
await jest.runAllTimersAsync();
|
await jest.runAllTimersAsync();
|
||||||
await catchPromise;
|
await catchPromise;
|
||||||
|
|
@ -107,8 +103,6 @@ describe('getManifest', () => {
|
||||||
(httpm.HttpClient.prototype.getJson as jest.Mock).mockResolvedValue({
|
(httpm.HttpClient.prototype.getJson as jest.Mock).mockResolvedValue({
|
||||||
result: mockManifest
|
result: mockManifest
|
||||||
});
|
});
|
||||||
// No fake timers needed: a rate-limit error must short-circuit retries
|
|
||||||
// (and their backoff) and fall straight through to the URL fallback.
|
|
||||||
const manifest = await getManifest();
|
const manifest = await getManifest();
|
||||||
expect(manifest).toEqual(mockManifest);
|
expect(manifest).toEqual(mockManifest);
|
||||||
expect(tc.getManifestFromRepo as jest.Mock).toHaveBeenCalledTimes(1);
|
expect(tc.getManifestFromRepo as jest.Mock).toHaveBeenCalledTimes(1);
|
||||||
|
|
|
||||||
4
dist/setup/index.js
vendored
4
dist/setup/index.js
vendored
|
|
@ -55725,8 +55725,8 @@ function sleep(ms) {
|
||||||
}
|
}
|
||||||
// HTTP 403/429 from http-client (`statusCode`) or tool-cache (`httpStatusCode`).
|
// HTTP 403/429 from http-client (`statusCode`) or tool-cache (`httpStatusCode`).
|
||||||
function isRateLimitError(err) {
|
function isRateLimitError(err) {
|
||||||
const status = err.httpStatusCode ??
|
const e = err;
|
||||||
err.statusCode;
|
const status = e?.httpStatusCode ?? e?.statusCode;
|
||||||
return status === 403 || status === 429;
|
return status === 403 || status === 429;
|
||||||
}
|
}
|
||||||
// Fetches and validates a manifest, retrying transient failures with backoff.
|
// Fetches and validates a manifest, retrying transient failures with backoff.
|
||||||
|
|
|
||||||
|
|
@ -151,9 +151,11 @@ function sleep(ms: number): Promise<void> {
|
||||||
|
|
||||||
// HTTP 403/429 from http-client (`statusCode`) or tool-cache (`httpStatusCode`).
|
// HTTP 403/429 from http-client (`statusCode`) or tool-cache (`httpStatusCode`).
|
||||||
function isRateLimitError(err: unknown): boolean {
|
function isRateLimitError(err: unknown): boolean {
|
||||||
const status =
|
const e = err as
|
||||||
(err as {httpStatusCode?: number}).httpStatusCode ??
|
| {httpStatusCode?: number; statusCode?: number}
|
||||||
(err as {statusCode?: number}).statusCode;
|
| null
|
||||||
|
| undefined;
|
||||||
|
const status = e?.httpStatusCode ?? e?.statusCode;
|
||||||
return status === 403 || status === 429;
|
return status === 403 || status === 429;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue