import {afterEach, describe, expect, it, jest} from '@jest/globals'; import {HttpClient} from '@actions/http-client'; import packageDetails from '../data/redhat-package-details.json' with {type: 'json'}; import packages from '../data/redhat-packages.json' with {type: 'json'}; import {RedHatDistribution} from '../../src/distributions/redhat/installer.js'; const createDistribution = ( version: string, packageType = 'jdk' ): RedHatDistribution => { const distribution = new RedHatDistribution({ version, architecture: 'x64', packageType, checkLatest: false }); distribution['getOperatingSystem'] = () => 'linux'; distribution['getArchiveType'] = () => 'tar.xz'; return distribution; }; const mockDisco = ( packageResponse: unknown = packages, detailsResponse: unknown = packageDetails ) => jest.spyOn(HttpClient.prototype, 'getJson').mockImplementation(async url => ({ result: url.includes('/packages?') ? packageResponse : detailsResponse, statusCode: 200, headers: {} })); afterEach(() => { jest.restoreAllMocks(); }); describe('Red Hat package resolution', () => { it('resolves the newest matching release and authoritative checksum', async () => { const getJson = mockDisco(); const distribution = createDistribution('21'); const release = await distribution['findPackageForDownload']('21'); expect(release).toEqual({ version: '21.0.8+9', url: packageDetails.result[0].direct_download_uri, checksum: { algorithm: 'sha256', value: packageDetails.result[0].checksum, source: 'https://api.foojay.io/disco/v3.0/ids/redhat-21.0.8-jdk-linux-x64' } }); expect(getJson).toHaveBeenNthCalledWith( 1, expect.stringContaining( 'distro=redhat&release_status=ga&operating_system=linux&architecture=x64&package_type=jdk&archive_type=tar.xz&directly_downloadable=true' ) ); expect(getJson).toHaveBeenNthCalledWith( 2, 'https://api.foojay.io/disco/v3.0/ids/redhat-21.0.8-jdk-linux-x64' ); }); it('normalizes feature-only Disco versions before matching', async () => { mockDisco(undefined, { result: [ { ...packageDetails.result[0], direct_download_uri: 'https://developers.redhat.com/openjdk-9.tar.xz' } ], message: '' }); const distribution = createDistribution('9'); const release = await distribution['findPackageForDownload']('9'); expect(release.version).toBe('9.0.0+181'); }); it('selects the requested package type', async () => { const getJson = mockDisco(); const distribution = createDistribution('21', 'jre'); await distribution['findPackageForDownload']('21'); expect(getJson).toHaveBeenNthCalledWith( 1, expect.stringContaining('package_type=jre') ); expect(getJson).toHaveBeenNthCalledWith( 2, 'https://api.foojay.io/disco/v3.0/ids/redhat-21.0.8-jre-linux-x64' ); }); it('maps Windows to ZIP packages', async () => { const getJson = mockDisco(); const distribution = createDistribution('17'); distribution['getOperatingSystem'] = () => 'windows'; distribution['getArchiveType'] = () => 'zip'; await distribution['findPackageForDownload']('17'); expect(getJson).toHaveBeenNthCalledWith( 1, expect.stringContaining( 'operating_system=windows&architecture=x64&package_type=jdk&archive_type=zip' ) ); expect(getJson).toHaveBeenNthCalledWith( 2, 'https://api.foojay.io/disco/v3.0/ids/redhat-17.0.16-jdk-windows-x64' ); }); it('rejects Alpine before requesting glibc package metadata', async () => { const getJson = mockDisco(); const distribution = new RedHatDistribution({ version: '21', architecture: 'x64', packageType: 'jdk', checkLatest: false }); expect(() => distribution['getOperatingSystem'](true)).toThrow( "Distribution 'redhat' does not support Alpine Linux because Red Hat portable archives require glibc." ); expect(getJson).not.toHaveBeenCalled(); }); it('rejects early-access versions before requesting metadata', async () => { const getJson = mockDisco(); const distribution = createDistribution('21-ea'); await expect(distribution['findPackageForDownload']('21')).rejects.toThrow( 'Early access versions are not supported' ); expect(getJson).not.toHaveBeenCalled(); }); it('reports available versions when no release matches', async () => { mockDisco(); const distribution = createDistribution('25'); await expect(distribution['findPackageForDownload']('25')).rejects.toThrow( "No matching version found for SemVer '25'.\nDistribution: RedHat" ); }); it('fails when the package detail has no direct Red Hat URL', async () => { mockDisco(packages, {result: [], message: ''}); const distribution = createDistribution('21'); await expect(distribution['findPackageForDownload']('21')).rejects.toThrow( 'returned no direct Red Hat download URL' ); }); it('fails when the package detail has no SHA-256 checksum', async () => { mockDisco(packages, { result: [{...packageDetails.result[0], checksum: ''}], message: '' }); const distribution = createDistribution('21'); await expect(distribution['findPackageForDownload']('21')).rejects.toThrow( 'returned no SHA-256 checksum' ); }); it('fails with a targeted error when package metadata is missing', async () => { mockDisco(null); const distribution = createDistribution('21'); await expect(distribution['findPackageForDownload']('21')).rejects.toThrow( 'Could not fetch Red Hat package metadata from Foojay Disco' ); }); });