Unit Test (#12)
* annoying tests.. * update test * udpate * update the tests
This commit is contained in:
@@ -41,17 +41,17 @@ jobs:
|
||||
- name: Lint
|
||||
id: npm-lint
|
||||
run: npm run lint
|
||||
# - name: Test
|
||||
# id: npm-ci-test
|
||||
# run: npm run ci-test
|
||||
|
||||
- name: Test
|
||||
id: npm-ci-test
|
||||
run: npm run ci-test
|
||||
|
||||
test-attest-sbom-with-local-sbom-file:
|
||||
name: Test attest-sbom action with local sbom file
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
contents: write
|
||||
id-token: write
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -71,9 +71,8 @@ jobs:
|
||||
name: Test attest-sbom action
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
contents: write
|
||||
id-token: write
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Unit tests for the action's entrypoint, src/index.ts
|
||||
*/
|
||||
|
||||
import * as main from '../src/main'
|
||||
|
||||
// Mock the action's entrypoint
|
||||
const runMock = jest.spyOn(main, 'run').mockImplementation()
|
||||
|
||||
describe('index', () => {
|
||||
it('calls run when imported', async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
require('../src/index')
|
||||
|
||||
expect(runMock).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,112 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as main from '../src/main'
|
||||
import * as fs from 'fs'
|
||||
import os from 'os'
|
||||
import * as path from 'path'
|
||||
|
||||
// Mock the GitHub Actions core library
|
||||
jest.mock('@actions/core')
|
||||
const getInputMock = jest.spyOn(core, 'getInput')
|
||||
const setOutputMock = jest.spyOn(core, 'setOutput')
|
||||
const setFailedMock = jest.spyOn(core, 'setFailed')
|
||||
|
||||
// Ensure that setFailed doesn't set an exit code during tests
|
||||
setFailedMock.mockImplementation(() => {})
|
||||
|
||||
describe('SBOM Action', () => {
|
||||
let tempDir = '/'
|
||||
let outputs = {} as Record<string, string>
|
||||
|
||||
beforeEach(() => {
|
||||
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sbom'))
|
||||
|
||||
jest.resetAllMocks()
|
||||
setOutputMock.mockImplementation((key, value) => {
|
||||
outputs[key] = value
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmdirSync(tempDir, { recursive: true })
|
||||
outputs = {}
|
||||
})
|
||||
|
||||
it('successfully processes an SBOM', async () => {
|
||||
const spdxSBOM = JSON.stringify({
|
||||
spdxVersion: 'SPDX-2.2',
|
||||
SPDXID: 'SPDXRef-DOCUMENT',
|
||||
packages: []
|
||||
})
|
||||
const filePath = path.join(tempDir, 'spdxSBOM.json')
|
||||
fs.writeFileSync(filePath, spdxSBOM)
|
||||
|
||||
const inputs = {
|
||||
'sbom-path': filePath
|
||||
}
|
||||
getInputMock.mockImplementation(mockInput(inputs))
|
||||
const originalEnv = process.env
|
||||
process.env = { ...originalEnv, RUNNER_TEMP: '/tmp' }
|
||||
|
||||
// Run the main function
|
||||
await main.run()
|
||||
|
||||
// Verify that outputs were set correctly
|
||||
expect(setOutputMock).toHaveBeenCalledTimes(2)
|
||||
expect(setOutputMock).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'predicate-type',
|
||||
'https://spdx.dev/Document/v2.2'
|
||||
)
|
||||
expect(outputs['predicate-path']).toBeTruthy()
|
||||
const predicatePath = outputs['predicate-path']
|
||||
|
||||
// Verify that the temporary file exists
|
||||
expect(fs.existsSync(predicatePath)).toBe(true)
|
||||
|
||||
// Read the content of the temporary file
|
||||
const fileContent = fs.readFileSync(predicatePath, 'utf-8')
|
||||
|
||||
// Verify that the content matches the predicate params
|
||||
expect(JSON.parse(fileContent)).toEqual(JSON.parse(spdxSBOM))
|
||||
|
||||
// Clean up the temporary file
|
||||
fs.unlinkSync(predicatePath)
|
||||
|
||||
process.env = originalEnv
|
||||
})
|
||||
|
||||
it('fails when an error occurs without input', async () => {
|
||||
await main.run()
|
||||
expect(setFailedMock).toHaveBeenCalledWith(
|
||||
'TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined'
|
||||
)
|
||||
})
|
||||
|
||||
it('fails when an error occurs with wrong sbom format', async () => {
|
||||
const spdxSBOM = JSON.stringify({
|
||||
SPDXID: 'SPDXRef-DOCUMENT'
|
||||
})
|
||||
const filePath = path.join(tempDir, 'spdxSBOM.json')
|
||||
fs.writeFileSync(filePath, spdxSBOM)
|
||||
|
||||
const inputs = {
|
||||
'sbom-path': filePath
|
||||
}
|
||||
getInputMock.mockImplementation(mockInput(inputs))
|
||||
const originalEnv = process.env
|
||||
process.env = { ...originalEnv, RUNNER_TEMP: '/tmp' }
|
||||
|
||||
// Run the main function
|
||||
await main.run()
|
||||
expect(setFailedMock).toHaveBeenCalledWith('Unsupported SBOM format')
|
||||
})
|
||||
})
|
||||
|
||||
function mockInput(inputs: Record<string, string>): typeof core.getInput {
|
||||
return (name: string): string => {
|
||||
if (name in inputs) {
|
||||
return inputs[name]
|
||||
}
|
||||
return ''
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import {
|
||||
storePredicate,
|
||||
parseSBOMFromPath,
|
||||
generateSBOMPredicate,
|
||||
SBOM
|
||||
} from '../src/sbom'
|
||||
import type { Predicate } from '@actions/attest'
|
||||
import * as fs from 'fs'
|
||||
import os from 'os'
|
||||
import * as path from 'path'
|
||||
|
||||
describe('parseSBOMFromPath', () => {
|
||||
let tempDir = '/'
|
||||
|
||||
beforeEach(() => {
|
||||
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sbom'))
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmdirSync(tempDir, { recursive: true })
|
||||
})
|
||||
|
||||
it('correctly parses an SPDX file', async () => {
|
||||
const spdxSBOM = JSON.stringify({
|
||||
spdxVersion: 'SPDX-2.2',
|
||||
SPDXID: 'SPDXRef-DOCUMENT'
|
||||
})
|
||||
const filePath = path.join(tempDir, 'spdxSBOM.json')
|
||||
fs.writeFileSync(filePath, spdxSBOM)
|
||||
await expect(parseSBOMFromPath(filePath)).resolves.toEqual({
|
||||
type: 'spdx',
|
||||
object: JSON.parse(spdxSBOM)
|
||||
})
|
||||
})
|
||||
|
||||
it('correctly parses a CycloneDX file', async () => {
|
||||
const cycloneDXSBOM = JSON.stringify({
|
||||
bomFormat: 'CycloneDX',
|
||||
serialNumber: '123',
|
||||
specVersion: '1.2'
|
||||
})
|
||||
const filePath = path.join(tempDir, 'cyclonedxSBOM.json')
|
||||
fs.writeFileSync(filePath, cycloneDXSBOM)
|
||||
|
||||
await expect(parseSBOMFromPath(filePath)).resolves.toEqual({
|
||||
type: 'cyclonedx',
|
||||
object: JSON.parse(cycloneDXSBOM)
|
||||
})
|
||||
})
|
||||
|
||||
it('throws an error for unsupported SBOM formats', async () => {
|
||||
const filePath = path.join(tempDir, 'random.json')
|
||||
fs.writeFileSync(filePath, JSON.stringify({ random: 'value' }))
|
||||
await expect(parseSBOMFromPath(filePath)).rejects.toThrow(
|
||||
'Unsupported SBOM format'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('storePredicate', () => {
|
||||
it('should store the predicate to a temporary file', () => {
|
||||
const predicate = { params: { key: 'value' } } as Predicate
|
||||
|
||||
// Mocking the process.env['RUNNER_TEMP'] value
|
||||
const originalEnv = process.env
|
||||
process.env = { ...originalEnv, RUNNER_TEMP: '/tmp' }
|
||||
|
||||
const tempFile = storePredicate(predicate)
|
||||
|
||||
// Verify that the temporary file exists
|
||||
expect(fs.existsSync(tempFile)).toBe(true)
|
||||
|
||||
// Read the content of the temporary file
|
||||
const fileContent = fs.readFileSync(tempFile, 'utf-8')
|
||||
|
||||
// Verify that the content matches the predicate params
|
||||
expect(JSON.parse(fileContent)).toEqual(predicate.params)
|
||||
|
||||
// Clean up the temporary file
|
||||
fs.unlinkSync(tempFile)
|
||||
|
||||
// Restore the original process.env
|
||||
process.env = originalEnv
|
||||
})
|
||||
|
||||
it('should throw an error if RUNNER_TEMP environment variable is missing', () => {
|
||||
const predicate = { params: { key: 'value' } } as Predicate
|
||||
|
||||
// Mocking the process.env['RUNNER_TEMP'] value
|
||||
const originalEnv = process.env
|
||||
process.env = {}
|
||||
|
||||
// Verify that an error is thrown
|
||||
expect(() => storePredicate(predicate)).toThrow(
|
||||
'Missing RUNNER_TEMP environment variable'
|
||||
)
|
||||
|
||||
// Restore the original process.env
|
||||
process.env = originalEnv
|
||||
})
|
||||
})
|
||||
|
||||
describe('generateSBOMPredicate', () => {
|
||||
it('generates SPDX predicate correctly', () => {
|
||||
const sbom = { type: 'spdx', object: { spdxVersion: 'SPDX-2.2' } } as SBOM
|
||||
const result = generateSBOMPredicate(sbom)
|
||||
expect(result.type).toContain('https://spdx.dev/Document/v2.2')
|
||||
expect(result.params).toEqual(sbom.object)
|
||||
})
|
||||
|
||||
it('generates CycloneDX predicate correctly', () => {
|
||||
const sbom = { type: 'cyclonedx', object: {} } as SBOM
|
||||
const result = generateSBOMPredicate(sbom)
|
||||
expect(result.type).toEqual('https://cyclonedx.org/bom')
|
||||
expect(result.params).toEqual(sbom.object)
|
||||
})
|
||||
|
||||
it('throws error for unsupported SBOM formats', () => {
|
||||
const sbom = { type: 'spdx', object: {} }
|
||||
// @ts-expect-error test error case
|
||||
expect(() => generateSBOMPredicate(sbom)).toThrow(
|
||||
'Cannot find spdxVersion in the SBOM'
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
process.stdout.write = jest.fn()
|
||||
@@ -46,6 +46,9 @@
|
||||
"js",
|
||||
"ts"
|
||||
],
|
||||
"setupFilesAfterEnv": [
|
||||
"./jest.setup.js"
|
||||
],
|
||||
"testMatch": [
|
||||
"**/*.test.ts"
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user