diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml new file mode 100644 index 000000000..813847c0b --- /dev/null +++ b/.github/workflows/test-scripts.yml @@ -0,0 +1,48 @@ +name: "Cross platform script test" + +on: + push: + branches: + - master + - develop + - 'feature/**' + pull_request: + +jobs: + test-scripts: + strategy: + fail-fast: false + matrix: + os: [ubuntu-20.04, windows-2022] + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout repository + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + + - name: Set up Java + uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 + with: + distribution: 'temurin' + java-version: '17' + + - name: Read node version from `.nvmrc` file + id: nvmrc + shell: bash + run: echo "NODE_VERSION=$(cat .nvmrc)" >> $GITHUB_OUTPUT + + - name: Install required node.js version + uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 + with: + node-version: ${{ steps.nvmrc.outputs.NODE_VERSION }} + + - name: Install OSCAL CLI + run: make configure + + - name: Run Constraint script tests + shell: bash + run: | + set -e + npm run constraint resource-has-title + env: + CI: true \ No newline at end of file diff --git a/features/steps/fedramp_extensions_steps.ts b/features/steps/fedramp_extensions_steps.ts index b2ebc683e..0dcebcf76 100644 --- a/features/steps/fedramp_extensions_steps.ts +++ b/features/steps/fedramp_extensions_steps.ts @@ -81,7 +81,7 @@ function getConstraintTests() { ); const files = readdirSync(constraintTestDir); const filteredFiles = files - .filter((file) => file.endsWith(".yaml") || file.endsWith(".yml")) + .filter((file) => file.endsWith(".yaml") || file.endsWith(".yml")).sort() .map((file) => ` | ${file} |`) .join("\n"); return filteredFiles; @@ -97,7 +97,7 @@ async function getConstraintIds() { ); const files = readdirSync(constraintDir); const xmlFiles = files - .filter((file) => file.endsWith(".xml")) + .filter((file) => file.endsWith(".xml")).sort() .filter((file) => !file.endsWith(ignoreDocument)); let allConstraintIds = []; @@ -142,7 +142,7 @@ Given("I have Metaschema extensions documents", function (dataTable) { ); const files = readdirSync(constraintDir); metaschemaDocuments = files - .filter((file) => file.endsWith(".xml")) + .filter((file) => file.endsWith(".xml")).sort() .filter((x) => !x.startsWith("oscal")) //temporary .map((file) => join(constraintDir, file)); }); @@ -431,8 +431,8 @@ Given("I have loaded all Metaschema extensions documents", function () { ); const files = readdirSync(constraintDir); metaschemaDocuments = files - .filter((file) => file.endsWith(".xml")) - .map((file) => join(constraintDir, file)); + .filter((file) => file.endsWith(".xml")).sort() + .map((file) => join(constraintDir, file)) console.log( `Loaded ${metaschemaDocuments.length} Metaschema extension documents` ); @@ -545,7 +545,7 @@ Given( "unit-tests" ); yamlTestFiles = readdirSync(testDir) - .filter((file) => file.endsWith(".yaml") || file.endsWith(".yml")) + .filter((file) => file.endsWith(".yaml") || file.endsWith(".yml")).sort() .map((file) => join(testDir, file)); console.log(`Collected ${yamlTestFiles.length} YAML test files`); } diff --git a/src/scripts/dev-constraint.js b/src/scripts/dev-constraint.js index 9f36c470f..c804b65bc 100644 --- a/src/scripts/dev-constraint.js +++ b/src/scripts/dev-constraint.js @@ -6,14 +6,16 @@ import {JSDOM} from "jsdom" import { execSync } from 'child_process'; import inquirer from 'inquirer'; import xmlFormatter from 'xml-formatter'; +import { fileURLToPath } from 'url'; const prompt = inquirer.createPromptModule(); -const __dirname = new URL('.', import.meta.url).pathname; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); -const constraintsDir = path.join(__dirname, '../../src', 'validations', 'constraints'); -const testDir = path.join(__dirname, '../../src', 'validations', 'constraints', 'unit-tests'); -const featureFile = path.join(__dirname,"../../features/", 'fedramp_extensions.feature'); +const constraintsDir = path.join(__dirname, '..','..','src', 'validations', 'constraints'); +const testDir = path.join(__dirname, '..','..','src', 'validations', 'constraints', 'unit-tests'); +const featureFile = path.join(__dirname,'..','..',"features", 'fedramp_extensions.feature'); const ignoreDocument = "oscal-external-constraints.xml"; @@ -86,7 +88,6 @@ async function getAllConstraints() { allConstraints.push(id); allContext[id] = context; - console.log(`Constraint ${id} context: ${context}`); // Debug log } else { console.log(`Warning: No context found for constraint ${id}`); } @@ -345,8 +346,9 @@ function getScenarioLineNumbers(featureFile, constraintId,tests) { const content = fs.readFileSync(featureFile, 'utf8'); const lines = content.split('\n'); const scenarioLines = []; + console.log(featureFile,tests,constraintId); for (let i = 0; i < lines.length; i++) { - if (lines[i].includes(`${tests.fail_file}`) || lines[i].includes(`${tests.pass_file}`)) { + if (lines[i].includes(`${tests.fail}`) || lines[i].includes(`${tests.pass}`)||lines[i].includes(`${tests.fail_file}`) || lines[i].includes(`${tests.pass_file}`)) { scenarioLines.push(i + 1); // +1 because line numbers start at 1, not 0 } } @@ -387,9 +389,9 @@ async function runCucumberTest(constraintId, testFiles) { } const nodeOptions = '--loader ts-node/esm --no-warnings --experimental-specifier-resolution=node'; - const cucumberCommand = `NODE_OPTIONS="${nodeOptions}" npx cucumber-js`; + const cucumberCommand = `npx cucumber-js`; - let scenarioLines = getScenarioLineNumbers(featureFile, constraintId,testFiles); + let scenarioLines = getScenarioLineNumbers(featureFile, constraintId, testFiles); if (scenarioLines.length === 0) { console.error(`No scenarios found for constraintId: ${constraintId}`); @@ -397,17 +399,20 @@ async function runCucumberTest(constraintId, testFiles) { shell: true, stdio: 'ignore', cwd: path.join(__dirname, '..', '..') - }); - scenarioLines = getScenarioLineNumbers(featureFile, constraintId,testFiles); - if(scenarioLines.length===0){ - return false; + }); + scenarioLines = getScenarioLineNumbers(featureFile, constraintId, testFiles); + if (scenarioLines.length === 0) { + return false; } } try { + const isWindows = process.platform === 'win32'; for (const line of scenarioLines) { - const command = `${cucumberCommand} ${featureFile}:${line}`; - execSync(command, { stdio: 'inherit' }); + const command = isWindows + ? `set "NODE_OPTIONS=${nodeOptions}" && ${cucumberCommand} "${featureFile}:${line}"` + : `NODE_OPTIONS="${nodeOptions}" ${cucumberCommand} "${featureFile}:${line}"`; + execSync(command, { stdio: 'inherit', shell: true }); } console.log(`Cucumber tests for ${constraintId} passed successfully.`); return true;