Files
setup-godot/.gdunit4_action/unit-test/index.js

132 lines
4.0 KiB
JavaScript

const pathLib = require("path");
const {spawnSync } = require("node:child_process");
const RETURN_SUCCESS = 0;
const RETURN_ERROR = 100;
const RETURN_WARNING = 101;
const RETURN_ERROR_HEADLESS_NOT_SUPPORTED = 103;
const RETURN_ERROR_GODOT_VERSION_NOT_SUPPORTED = 104;
const RETURN_ERROR_ABNORMAL_TERMINATED = 444;
function getProjectPath(project_dir) {
if (!process.env.GITHUB_WORKSPACE) {
throw new Error("GITHUB_WORKSPACE environment variable not set");
}
return pathLib.join(process.env.GITHUB_WORKSPACE, project_dir);
}
function console_info(message) {
console.log('\x1b[94m', message, '\x1b[0m');
}
async function runTests(exeArgs, core) {
try {
const {
project_dir = '',
paths = "",
arguments = '',
timeout = 10,
retries = 0,
warningsAsErrors = false
} = exeArgs;
// Split by newline or comma, map, trim, and filter empty strings
const pathsArray = paths.split(/[\r\n,]+/).map((entry) => entry.trim()).filter(Boolean);
// verify support of multi paths/fixed since v4.2.1
if (pathsArray.length > 1 && process.env.GDUNIT_VERSION === "v4.2.0") {
core.warning(`Multiple path arguments not supported by GdUnit ${process.env.GDUNIT_VERSION}, please upgrade to GdUnit4 v4.2.1`);
pathsArray.length = 1;
core.warning(`Use only the first entry of paths, ${pathsArray}!`);
}
const args = [
"--auto-servernum",
"./addons/gdUnit4/runtest.sh",
"--audio-driver Dummy",
"--display-driver x11",
"--rendering-driver opengl3",
"--single-window",
"--continue",
...pathsArray.map((path) => `--add ${path}`),
`${arguments}`
];
const working_dir = getProjectPath(project_dir);
console_info(`Running GdUnit4 ${process.env.GDUNIT_VERSION} tests at ${working_dir} with arguments: ${args}`);
console_info(`project_dir: ${project_dir}`);
console_info(`arguments: ${arguments}`);
console_info(`timeout: ${timeout}m`);
console_info(`retries: ${retries}`);
console_info(`warningsAsErrors: ${warningsAsErrors}`);
let retriesCount = 0;
let exitCode = 0;
while (retriesCount <= retries) {
const child = spawnSync("xvfb-run", args, {
cwd: working_dir,
timeout: timeout * 1000 * 60,
encoding: "utf-8",
shell: true,
stdio: ["inherit", "inherit", "inherit"],
env: process.env,
});
// Handle spawn errors
if (child.error) {
core.setFailed(`Run Godot process ends with error: ${child.error}`);
return RETURN_ERROR_ABNORMAL_TERMINATED;
}
exitCode = child.status;
if (exitCode === RETURN_SUCCESS) {
break; // Exit loop if successful
}
retriesCount++;
if (retriesCount <= retries) {
core.warning(`Test run failed, retrying... ${retriesCount} of ${retries}`);
}
}
switch (exitCode) {
case RETURN_SUCCESS:
if (retriesCount > 0 && retries > 0) {
core.warning(`The tests was successfully after ${retriesCount} retries with exit code: ${exitCode}`);
} else {
console_info(`The tests was successfully with exit code: ${exitCode}`);
}
break;
case RETURN_ERROR:
core.setFailed(`The tests was failed after ${retries} retries with exit code: ${exitCode}`);
break;
case RETURN_WARNING:
if (warningsAsErrors === true) {
core.setFailed(`Tests completed with warnings (treated as errors)`);
} else {
core.warning('Tests completed successfully with warnings');
}
break;
case RETURN_ERROR_HEADLESS_NOT_SUPPORTED:
core.setFailed('Headless mode not supported');
break;
case RETURN_ERROR_GODOT_VERSION_NOT_SUPPORTED:
core.setFailed('Godot version not supported');
break;
default:
core.setFailed(`Tests failed with unknown error code: ${exitCode}`);
}
return exitCode;
} catch (error) {
core.setFailed(`Tests failed: ${error.message}`);
return RETURN_ERROR;
}
}
module.exports = {
runTests
};