import { jest, describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from '@jest/globals'; import {fileURLToPath} from 'url'; import * as fs from 'fs'; import os from 'os'; import * as path from 'path'; import * as io from '@actions/io'; // Mock @actions/core before importing source modules that depend on it jest.unstable_mockModule('@actions/core', () => ({ info: jest.fn(), warning: jest.fn(), debug: jest.fn(), error: jest.fn(), notice: jest.fn(), setFailed: jest.fn(), setOutput: jest.fn(), getInput: jest.fn(), getBooleanInput: jest.fn(), getMultilineInput: jest.fn(), addPath: jest.fn(), exportVariable: jest.fn(), saveState: jest.fn(), getState: jest.fn(), setSecret: jest.fn(), isDebug: jest.fn(() => false), startGroup: jest.fn(), endGroup: jest.fn(), group: jest.fn((_name: string, fn: () => Promise) => fn()), toPlatformPath: jest.fn((p: string) => p), toWin32Path: jest.fn((p: string) => p), toPosixPath: jest.fn((p: string) => p) })); // Dynamic imports after mocking const core = await import('@actions/core'); const toolchains = await import('../src/toolchains.js'); const {M2_DIR, MVN_TOOLCHAINS_FILE} = await import('../src/constants.js'); const __dirname = path.dirname(fileURLToPath(import.meta.url)); const m2Dir = path.join(__dirname, M2_DIR); const toolchainsFile = path.join(m2Dir, MVN_TOOLCHAINS_FILE); describe('toolchains tests', () => { let spyOSHomedir: any; let spyInfo: any; beforeEach(async () => { await io.rmRF(m2Dir); spyOSHomedir = jest.spyOn(os, 'homedir'); spyOSHomedir.mockReturnValue(__dirname); spyInfo = core.info as jest.Mock; spyInfo.mockImplementation(() => null); }, 300000); afterAll(async () => { try { await io.rmRF(m2Dir); } catch { console.log('Failed to remove test directories'); } jest.resetAllMocks(); jest.clearAllMocks(); jest.restoreAllMocks(); }, 100000); it('creates toolchains.xml in alternate locations', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const altHome = path.join(__dirname, 'runner', 'toolchains'); const altToolchainsFile = path.join(altHome, MVN_TOOLCHAINS_FILE); await io.rmRF(altHome); // ensure it doesn't already exist await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: altHome, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(false); expect(fs.existsSync(toolchainsFile)).toBe(false); expect(fs.existsSync(altHome)).toBe(true); expect(fs.existsSync(altToolchainsFile)).toBe(true); expect(fs.readFileSync(altToolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( '', jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); await io.rmRF(altHome); }, 100000); it('creates toolchains.xml with minimal configuration', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 `; await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( '', jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( '', jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('reuses existing toolchains.xml files', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ` jdk 1.6 Sun sun_1.6 /opt/jdk/sun/1.6 `; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 jdk 1.6 Sun sun_1.6 /opt/jdk/sun/1.6 `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('does not discard custom elements in existing toolchain definitions', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ` jdk 1.6 Sun sun_1.6 foo /opt/jdk/sun/1.6 /usr/local/bin/bash `; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 jdk 1.6 Sun sun_1.6 foo /opt/jdk/sun/1.6 /usr/local/bin/bash `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('does not discard existing, custom toolchain definitions', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ` foo baz /usr/local/bin/foo `; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 foo baz /usr/local/bin/foo `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('does not duplicate existing toolchain definitions', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 `; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('does not duplicate existing toolchain definitions if multiple exist', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ` jdk 1.6 Sun sun_1.6 /opt/jdk/sun/1.6 jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 `; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 jdk 1.6 Sun sun_1.6 /opt/jdk/sun/1.6 `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('handles an empty list of existing toolchains correctly', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ` `; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('handles an empty existing toolchains.xml correctly', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ``; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('preserves custom root attributes on existing toolchains.xml', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ` jdk 1.6 Sun sun_1.6 /opt/jdk/sun/1.6 `; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 jdk 1.6 Sun sun_1.6 /opt/jdk/sun/1.6 `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('keeps partially-formed jdk toolchains without an id instead of crashing', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ` jdk 1.6 Sun /opt/jdk/sun/1.6 `; const result = ` jdk 17 Eclipse Temurin temurin_17 /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 jdk 1.6 Sun /opt/jdk/sun/1.6 `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: true }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ); expect( toolchains.generateToolchainDefinition( originalFile, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(result); }, 100000); it('does not overwrite existing toolchains.xml files', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', id: 'temurin_17', jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' }; const originalFile = ` jdk 1.6 Sun sun_1.6 /opt/jdk/sun/1.6 `; fs.mkdirSync(m2Dir, {recursive: true}); fs.writeFileSync(toolchainsFile, originalFile); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); await toolchains.createToolchainsSettings({ jdkInfo, settingsDirectory: m2Dir, overwriteSettings: false }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(originalFile); }, 100000); it('generates valid toolchains.xml with minimal configuration', () => { const jdkInfo = { version: 'JAVA_VERSION', vendor: 'JAVA_VENDOR', id: 'VENDOR_VERSION', jdkHome: 'JAVA_HOME' }; const expectedToolchains = ` jdk ${jdkInfo.version} ${jdkInfo.vendor} ${jdkInfo.id} ${jdkInfo.jdkHome} `; expect( toolchains.generateToolchainDefinition( '', jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome ) ).toEqual(expectedToolchains); }, 100000); it('creates toolchains.xml with correct id when none is supplied', async () => { const version = '17'; const distributionName = 'temurin'; const id = 'temurin_17'; const jdkHome = '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'; (core.getInput as jest.Mock).mockImplementation((name: string) => { if (name === 'settings-path') return m2Dir; return ''; }); await toolchains.configureToolchains( version, distributionName, jdkHome, undefined ); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( toolchains.generateToolchainDefinition( '', version, distributionName, id, jdkHome ) ); }, 100000); });