Add Node version validation and manifest fetch retry

This commit is contained in:
Jitender Pal Singh 2026-07-09 11:12:00 +05:30
parent 04be95cf35
commit 349d704a2a
4 changed files with 24325 additions and 730 deletions

View file

@ -129,7 +129,11 @@ describe('setup-node', () => {
// @actions/exec
getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
getExecOutputSpy.mockImplementation(() => 'v16.15.0');
getExecOutputSpy.mockImplementation(async () => ({
stdout: 'v16.15.0',
stderr: '',
exitCode: 0
}));
});
afterEach(() => {
@ -250,6 +254,11 @@ describe('setup-node', () => {
whichSpy.mockImplementation(cmd => {
return `some/${cmd}/path`;
});
getExecOutputSpy.mockImplementation(async (cmd: string) => ({
stdout: cmd === 'node' ? `v${resolvedVersion}` : '1.0.0',
stderr: '',
exitCode: 0
}));
await main.run();
@ -627,7 +636,7 @@ describe('setup-node', () => {
`Attempting to download ${versionSpec}...`
);
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
}, 10000);
});
describe('LTS version', () => {
@ -800,9 +809,9 @@ describe('setup-node', () => {
'Getting manifest from actions/node-versions@main'
);
expect(cnSpy).toHaveBeenCalledWith(
`::error::Unable to download manifest${osm.EOL}`
`::error::Failed to fetch a valid manifest after 3 attempts. Last error: Unable to download manifest${osm.EOL}`
);
});
}, 10000);
});
describe('latest alias syntax', () => {
@ -824,10 +833,13 @@ describe('setup-node', () => {
await main.run();
// assert
expect(logSpy).toHaveBeenCalledWith('Unable to download manifest');
expect(logSpy).toHaveBeenCalledWith(
'Failed to fetch a valid manifest after 3 attempts. Last error: Unable to download manifest'
);
expect(logSpy).toHaveBeenCalledWith('getting latest node version...');
}
},
10000
);
});
@ -898,4 +910,91 @@ describe('setup-node', () => {
);
}
}, 100000);
describe('manifest retry and validation', () => {
beforeEach(() => {
os.platform = 'linux';
os.arch = 'x64';
inputs['node-version'] = 'lts/erbium';
findSpy.mockImplementation(() => '');
});
it('retries fetching the manifest and succeeds on a later attempt', async () => {
let calls = 0;
getManifestSpy.mockImplementation(() => {
calls++;
if (calls < 2) {
throw new Error('transient network failure');
}
return <tc.IToolRelease[]>nodeTestManifest;
});
dlSpy.mockImplementation(async () => '/some/temp/path');
const toolPath = path.normalize('/cache/node/12.16.2/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
getExecOutputSpy.mockImplementation(async () => ({
stdout: `v${path.basename(path.dirname(toolPath))}\n`,
stderr: '',
exitCode: 0
}));
await main.run();
expect(calls).toBe(2);
expect(logSpy).toHaveBeenCalledWith('Retrying to fetch the manifest...');
expect(dbgSpy).toHaveBeenCalledWith(
`Found LTS release '12.16.2' for Node version 'lts/erbium'`
);
}, 10000);
it('rejects an empty manifest as invalid and retries', async () => {
getManifestSpy.mockImplementation(() => []);
await main.run();
expect(getManifestSpy).toHaveBeenCalledTimes(3);
expect(cnSpy).toHaveBeenCalledWith(
`::error::Failed to fetch a valid manifest after 3 attempts. Last error: The manifest fetched is empty, truncated, or does not contain any valid tool release entries.${osm.EOL}`
);
}, 10000);
});
describe('node version verification', () => {
beforeEach(() => {
os.platform = 'linux';
os.arch = 'x64';
inputs['node-version'] = '12';
});
it('fails when the installed node version does not match the expected version', async () => {
const toolPath = path.normalize('/cache/node/12.16.1/x64');
findSpy.mockReturnValue(toolPath);
getExecOutputSpy.mockImplementation(async () => ({
stdout: 'v10.0.0\n',
stderr: '',
exitCode: 0
}));
await main.run();
expect(cnSpy).toHaveBeenCalledWith(
`::error::Node v12.16.1 installation failed, likely due to an incomplete or corrupted download.${osm.EOL}`
);
});
it('fails when the node executable cannot be invoked', async () => {
const toolPath = path.normalize('/cache/node/12.16.1/x64');
findSpy.mockReturnValue(toolPath);
getExecOutputSpy.mockImplementation(async () => {
throw new Error('node not found');
});
await main.run();
expect(cnSpy).toHaveBeenCalledWith(
`::error::Node installation failed. Node may not be installed or not on PATH: node not found${osm.EOL}`
);
});
});
});