Skip to content

Commit 5894ef6

Browse files
authored
Consolidate JDK metadata retry handling (#1162)
* Consolidate JDK metadata retries Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a5e2549a-0d89-4c8f-b7f3-411ad21c8a06 * Expand distribution retry coverage Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a5e2549a-0d89-4c8f-b7f3-411ad21c8a06 --------- Copilot-Session: a5e2549a-0d89-4c8f-b7f3-411ad21c8a06
1 parent e1ce3a3 commit 5894ef6

8 files changed

Lines changed: 792 additions & 213 deletions

File tree

‎.github/workflows/e2e-versions.yml‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ jobs:
8383
- distribution: oracle
8484
os: ubuntu-latest
8585
version: 21
86+
- distribution: oracle-openjdk
87+
os: macos-15-intel
88+
version: 21
89+
- distribution: oracle-openjdk
90+
os: windows-latest
91+
version: 21
92+
- distribution: oracle-openjdk
93+
os: ubuntu-latest
94+
version: 21
8695
- distribution: graalvm
8796
os: macos-latest
8897
version: 17.0.12

‎__tests__/distributors/base-installer.test.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,31 @@ describe('setupJava', () => {
605605
expect(spyCoreSetOutput).not.toHaveBeenCalled();
606606
});
607607

608+
it('should not repeat version resolution when downloadTool fails', async () => {
609+
mockJavaBase = new EmptyJavaBase({
610+
version: '11',
611+
architecture: 'x86',
612+
packageType: 'jdk',
613+
checkLatest: false,
614+
forceDownload: true
615+
});
616+
const findPackageForDownload = jest.fn(async () => ({
617+
version: '11.0.9',
618+
url: 'https://example.com/jdk.tar.gz'
619+
}));
620+
const downloadError = new Error('download failed');
621+
const downloadTool = jest.fn(async () => {
622+
throw downloadError;
623+
});
624+
mockJavaBase['findPackageForDownload'] = findPackageForDownload;
625+
mockJavaBase['downloadTool'] = downloadTool;
626+
627+
await expect(mockJavaBase.setupJava()).rejects.toBe(downloadError);
628+
629+
expect(findPackageForDownload).toHaveBeenCalledTimes(1);
630+
expect(downloadTool).toHaveBeenCalledTimes(1);
631+
});
632+
608633
it.each([
609634
[
610635
{

‎__tests__/distributors/distribution-factory.test.ts‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,38 @@
11
import {getJavaDistribution} from '../../src/distributions/distribution-factory.js';
2+
import {RetryingHttpClient} from '../../src/retrying-http-client.js';
23

34
describe('getJavaDistribution', () => {
5+
it.each([
6+
'adopt',
7+
'adopt-hotspot',
8+
'adopt-openj9',
9+
'temurin',
10+
'zulu',
11+
'liberica',
12+
'liberica-nik',
13+
'microsoft',
14+
'semeru',
15+
'corretto',
16+
'oracle',
17+
'dragonwell',
18+
'sapmachine',
19+
'graalvm',
20+
'graalvm-community',
21+
'jetbrains',
22+
'kona',
23+
'oracle-openjdk'
24+
])('uses the shared retrying HTTP client for %s', distributionName => {
25+
const distribution = getJavaDistribution(distributionName, {
26+
version: '21',
27+
architecture: 'x64',
28+
packageType: 'jdk',
29+
checkLatest: false
30+
});
31+
32+
expect(distribution).not.toBeNull();
33+
expect(distribution!['http']).toBeInstanceOf(RetryingHttpClient);
34+
});
35+
436
it("rejects java-package 'jdk+jmods' for non-Temurin distributions", () => {
537
expect(() =>
638
getJavaDistribution('zulu', {

‎__tests__/distributors/jetbrains-installer.test.ts‎

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import {
99
afterAll
1010
} from '@jest/globals';
1111
import https from 'https';
12-
import {HttpClient} from '@actions/http-client';
12+
import {HttpClient, HttpClientResponse} from '@actions/http-client';
13+
import type {IncomingMessage} from 'http';
14+
import {Readable} from 'stream';
1315

1416
import manifestData from '../data/jetbrains.json' with {type: 'json'};
1517
import os from 'os';
@@ -44,6 +46,18 @@ jest.unstable_mockModule('@actions/core', () => ({
4446
const core = await import('@actions/core');
4547
const {JetBrainsDistribution} =
4648
await import('../../src/distributions/jetbrains/installer.js');
49+
const {RetryingHttpClient} = await import('../../src/retrying-http-client.js');
50+
51+
function response(
52+
statusCode: number,
53+
body = '',
54+
headers: IncomingMessage['headers'] = {}
55+
): HttpClientResponse {
56+
const message = Readable.from([Buffer.from(body)]) as IncomingMessage;
57+
message.statusCode = statusCode;
58+
message.headers = headers;
59+
return new HttpClientResponse(message);
60+
}
4761

4862
describe('getAvailableVersions', () => {
4963
let spyHttpClient: any;
@@ -95,6 +109,42 @@ describe('getAvailableVersions', () => {
95109
os.platform() === 'win32' ? manifestData.length : manifestData.length + 2;
96110
expect(availableVersions.length).toBe(length);
97111
}, 10_000);
112+
113+
it('retries a GitHub rate limit using Retry-After', async () => {
114+
spyHttpClient.mockRestore();
115+
const sleep = jest.fn(async () => undefined);
116+
const requestRaw = jest
117+
.spyOn(HttpClient.prototype, 'requestRaw')
118+
.mockResolvedValueOnce(response(429, '', {'retry-after': '2'}))
119+
.mockResolvedValueOnce(response(200, '[]'))
120+
.mockResolvedValueOnce(response(200))
121+
.mockResolvedValueOnce(response(200));
122+
const distribution = new JetBrainsDistribution({
123+
version: '17',
124+
architecture: 'x64',
125+
packageType: 'jdk',
126+
checkLatest: false
127+
});
128+
distribution['http'] = new RetryingHttpClient('test', {
129+
sleep,
130+
random: () => 0
131+
});
132+
133+
const availableVersions = await distribution['getAvailableVersions']();
134+
135+
expect(availableVersions).toHaveLength(2);
136+
expect(requestRaw).toHaveBeenCalledTimes(4);
137+
expect(requestRaw.mock.calls[0][0].options.path).toBe(
138+
requestRaw.mock.calls[1][0].options.path
139+
);
140+
expect(requestRaw.mock.calls[0][0].options.path).toContain(
141+
'/repos/JetBrains/JetBrainsRuntime/releases'
142+
);
143+
expect(sleep).toHaveBeenCalledWith(2000);
144+
expect(core.info).toHaveBeenCalledWith(
145+
'Request attempt 1 of 4 failed (HTTP 429); retrying in 2000 ms'
146+
);
147+
});
98148
});
99149

100150
describe('findPackageForDownload', () => {

0 commit comments

Comments
 (0)