Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: adapt runTest.js script to allow csaf 2.1 tests #220

Merged
merged 1 commit into from
Mar 3, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 117 additions & 35 deletions scripts/runTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,126 @@
/**
* @file Script to validate JSON files against given tests
*
* Usage: node <script-path>.js json/file/path.json mandatoryTest_6_1_1
* Usage: node <script-path>.js -f <json-file-path> -t <test-name> [-c <csaf-version>]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not fully convinced about -c as short for CSAF version. I also wrote that in an different ticket (csaf-poc/csaf-rust#22). Given that this is a more generic process (which might take a little longer), I suggest to accept this as -c for now and fix it once the decision has be made.

Therefore, tracked as separate ticket #221

*
* `mandatoryTest_6_1_1` is a sample here. You can insert any test name from lib/mandatoryTests.js,
* `lib/optionalTests.js`, `lib/schemaTests.js` and `lib/schemaTests.js`.
* -f <json-file-path>
* Specifies the path to the csaf json file to validate the given test against.
*
* -t <test-name>
* Specifies the test(s) to run. The values that you can pass here depend on the value
* of the `-c` option which specifies the used csaf version. If you use 2.0 here you
* can insert any test name from `mandatoryTests.js`, `optionalTests.js`,
* `informativeTests.js` and `schemaTests.js`.
* If you use 2.1 here you can insert any test name from `csaf_2_1/mandatoryTests.js`,
* `csaf_2_1/optionalTests.js`, `csaf_2_1/informativeTests.js` and `csaf_2_1/schemaTests.js`.
* Some presets are also allowed such as `mandatory`, `optional`, `informative`,
* `schema` and `base`.
*
* -c <csaf-version> (default: 2.0)
* Specifies the csaf version to use. The currently allowed versions are `2.0` (the default)
* and `2.1`.
*/

import { readFile } from 'fs/promises'
import * as schemaTests from '../schemaTests.js'
import * as mandatoryTests from '../mandatoryTests.js'
import * as optionalTests from '../optionalTests.js'
import * as informativeTests from '../informativeTests.js'
import validate from '../validate.js'
import { parseArgs } from 'node:util'
import assert from 'node:assert'

/**
* Types a function that can lazily load a set of tests. This is used to speed up the script
* by avoiding to load unused test sets.
*
* @typedef {() => Promise<Record<string, import('../lib/shared/types.js').DocumentTest>>} DocumentTestLoader
*/

/**
* This is the main function that reads the file, executes the resolved test
* and logs the result.
*
* @param {object} ctx
* @param {DocumentTestLoader} ctx.schemaTests
* @param {DocumentTestLoader} ctx.mandatoryTests
* @param {DocumentTestLoader} ctx.optionalTests
* @param {DocumentTestLoader} ctx.informativeTests
* @param {object} params
* @param {string} params.testName
* @param {string} params.filePath
*/
const main = async (
{ informativeTests, mandatoryTests, optionalTests, schemaTests },
{ testName, filePath }
) => {
const json = JSON.parse(await readFile(filePath, { encoding: 'utf-8' }))

const matchingTests =
testName === 'mandatory'
? Object.values(await mandatoryTests())
: testName === 'optional'
? Object.values(await optionalTests())
: testName === 'informative'
? Object.values(await informativeTests())
: testName === 'schema'
? Object.values(await schemaTests())
: testName === 'base'
? Object.values(await schemaTests()).concat(
Object.values(await mandatoryTests())
)
: Object.values(await mandatoryTests())
.concat(Object.values(await optionalTests()))
.concat(Object.values(await informativeTests()))
.concat(Object.values(await schemaTests()))
.filter((t) => t.name === testName)

if (!matchingTests.length)
throw new Error(`No test matching "${testName}" found`)
const result = await validate(matchingTests, json)
process.exitCode = result.isValid ? 0 : 1
console.log(JSON.stringify(result, null, 2))
}

const { values: cliOptions } = parseArgs({
options: {
file: {
type: 'string',
short: 'f',
},
'csaf-version': {
type: 'string',
short: 'c',
default: '2.0',
},
test: {
type: 'string',
short: 't',
},
},
})

const filePath = cliOptions.file
const testName = cliOptions.test
assert(filePath)
assert(testName)

const [, , filePath, testName] = process.argv

const json = JSON.parse(await readFile(filePath, { encoding: 'utf-8' }))

const matchingTests =
testName === 'mandatory'
? Object.values(mandatoryTests)
: testName === 'optional'
? Object.values(optionalTests)
: testName === 'informative'
? Object.values(informativeTests)
: testName === 'schema'
? Object.values(schemaTests)
: testName === 'base'
? Object.values(schemaTests).concat(Object.values(mandatoryTests))
: /** @type {Array<import('../lib/shared/types.js').DocumentTest>} */ (
Object.values(mandatoryTests)
)
.concat(Object.values(optionalTests))
.concat(Object.values(informativeTests))
.concat(Object.values(schemaTests))
.filter((t) => t.name === testName)

if (!matchingTests.length)
throw new Error(`No test matching "${testName}" found`)
const result = await validate(matchingTests, json)
process.exitCode = result.isValid ? 0 : 1
console.log(JSON.stringify(result, null, 2))
if (cliOptions['csaf-version'] === '2.0') {
await main(
{
mandatoryTests: () => import('../mandatoryTests.js'),
informativeTests: () => import('../informativeTests.js'),
optionalTests: () => import('../optionalTests.js'),
schemaTests: () => import('../schemaTests.js'),
},
{ filePath, testName }
)
} else if (cliOptions['csaf-version'] === '2.1') {
await main(
{
mandatoryTests: () => import('../csaf_2_1/mandatoryTests.js'),
informativeTests: () => import('../csaf_2_1/informativeTests.js'),
optionalTests: () => import('../csaf_2_1/optionalTests.js'),
schemaTests: () => import('../csaf_2_1/schemaTests.js'),
},
{ filePath, testName }
)
} else {
throw new Error('Unknown CSAF version')
}