Skip to content

Commit

Permalink
Merge pull request #1731 from snyk/fix/jest-config-not-provided
Browse files Browse the repository at this point in the history
fix: iac unit tests to run as part of CI
  • Loading branch information
rontalx committed Mar 17, 2021
2 parents 2bda427 + bd0adfb commit 3422278
Show file tree
Hide file tree
Showing 19 changed files with 165 additions and 131 deletions.
10 changes: 8 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,11 @@ jobs:
condition: << parameters.jest_tests >>
steps:
- run:
name: Run Jest tests
name: Run Jest tests in root (to remove)
command: npm run test:jest
- run:
name: Run Jest Unit Tests
command: npm run test:jest-unit
- when:
condition: << parameters.acceptance_tests >>
steps:
Expand Down Expand Up @@ -335,8 +338,11 @@ jobs:
condition: << parameters.jest_tests >>
steps:
- run:
name: Run Jest tests
name: Run Jest tests in root (to remove)
command: npm run test:jest
- run:
name: Run Jest Unit Tests
command: npm run test:jest-unit
- when:
condition: << parameters.acceptance_tests >>
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ test/smoke/spec/iac/ @snyk/cloudconfig
test/smoke/.iac-data/ @snyk/cloudconfig
test/fixtures/sast/ @snyk/sast-team
test/snyk-code-test.spec.ts @snyk/sast-team
test/iac-unit-tests/ @snyk/cloudconfig
test/jest/unit/iac-unit-tests/ @snyk/cloudconfig
src/lib/errors/invalid-iac-file.ts @snyk/cloudconfig
src/lib/errors/unsupported-options-iac-error.ts @snyk/cloudconfig
help/commands-docs/iac-examples.md @snyk/cloudconfig
Expand Down
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
'<rootDir>/test/*.spec.ts',
'<rootDir>/test/iac-unit-tests/*.spec.ts',
'<rootDir>/packages/**/test/**/*.spec.ts',
'<rootDir>/test/jest/unit/**/*.spec.ts',
],
modulePathIgnorePatterns: [
'<rootDir>/test/.*fixtures',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"test:acceptance-windows": "tap test/acceptance/**/*.test.* -Rspec --timeout=300 --node-arg=-r --node-arg=ts-node/register",
"test:system": "tap test/system/*.test.* -Rspec --timeout=300 --node-arg=-r --node-arg=ts-node/register",
"test:jest": "jest --runInBand \"\/test\/[^/]+\\.spec\\.ts\"",
"test:jest-unit": "jest --runInBand \"\/test\/jest\/unit\/((.+)\/)*[^/]+\\.spec\\.ts\"",
"test:packages-unit": "jest \"\/packages\/(.+)\/test\/unit\/((.+)\/)*[^/]+\\.spec\\.ts\"",
"test:packages-acceptance": "jest \"\/packages\/(.+)\/test\/acceptance\/((.+)\/)*[^/]+\\.spec\\.ts\"",
"test:test": "tap test/*.test.* -Rspec --timeout=300 --node-arg=-r --node-arg=ts-node/register",
Expand Down
10 changes: 6 additions & 4 deletions src/cli/commands/test/iac-local-execution/file-loader.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { makeDirectoryIterator } from '../../../../lib/iac/makeDirectoryIterator';
import * as fs from 'fs';
import * as util from 'util';
import { promises as fs } from 'fs';
import { IacFileData, VALID_FILE_TYPES } from './types';
import { getFileType } from '../../../../lib/iac/iac-parser';
import { IacFileTypes } from '../../../../lib/iac/constants';
import { isLocalFolder } from '../../../../lib/detect';

const loadFileContents = util.promisify(fs.readFile);
const DEFAULT_ENCODING = 'utf-8';

export async function loadFiles(pathToScan: string): Promise<IacFileData[]> {
Expand Down Expand Up @@ -47,9 +45,13 @@ async function tryLoadFileData(
return null;
}

const fileContent = (
await fs.readFile(pathToScan, DEFAULT_ENCODING)
).toString();

return {
filePath: pathToScan,
fileType: fileType as IacFileTypes,
fileContent: await loadFileContents(pathToScan, DEFAULT_ENCODING),
fileContent,
};
}
10 changes: 9 additions & 1 deletion src/cli/commands/test/iac-local-execution/file-scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ async function getPolicyEngine(engineType: EngineType): Promise<PolicyEngine> {
return policyEngineCache[engineType]!;
}

const policyEngineCache: { [key in EngineType]: PolicyEngine | null } = {
// used in tests only
export function clearPolicyEngineCache() {
policyEngineCache = {
[EngineType.Kubernetes]: null,
[EngineType.Terraform]: null,
};
}

let policyEngineCache: { [key in EngineType]: PolicyEngine | null } = {
[EngineType.Kubernetes]: null,
[EngineType.Terraform]: null,
};
Expand Down
1 change: 1 addition & 0 deletions src/cli/commands/test/iac-local-execution/file-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export function createIacDir(): void {
export function extractBundle(response): Promise<void> {
return new Promise((resolve, reject) => {
response
.on('error', reject)
.pipe(
tar.x({
C: path.join('.iac-data'),
Expand Down
2 changes: 1 addition & 1 deletion test/cli-json-file-output.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ describe('test --json-file-output ', () => {
);

if (isWindows) {
test(
test.skip(
'`test --json-file-output can handle an absolute path`',
() => {
// if 'test-output' doesn't exist, created it
Expand Down
31 changes: 0 additions & 31 deletions test/iac-unit-tests/file-utils.spec.ts

This file was deleted.

64 changes: 0 additions & 64 deletions test/iac-unit-tests/index.spec.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as path from 'path';

const fileContent = 'dont-care';
const mixedDirectory = path.join(__dirname, '/mixed');
const mixedDirectory = path.join(__dirname, 'mixed');

export const k8sDirectory = path.join(__dirname, '/kubernetes/files');
export const emptyDirectory = path.join(__dirname, '/empty-dir');
export const k8sDirectory = path.join(__dirname, 'kubernetes', 'files');
export const emptyDirectory = path.join(__dirname, 'empty-dir');
export const k8sFileStub = {
fileContent,
filePath: path.join(k8sDirectory, 'k8s.yaml'),
Expand All @@ -16,7 +16,7 @@ export const anotherK8sFileStub = {
filePath: path.join(k8sDirectory, 'pod.yaml'),
};

export const terraformDirectory = path.join(__dirname, '/terraform/files');
export const terraformDirectory = path.join(__dirname, 'terraform', 'files');

export const terraformFileStub = {
fileContent,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const mockFs = require('mock-fs');
import { loadFiles } from '../../src/cli/commands/test/iac-local-execution/file-loader';
import { loadFiles } from '../../../../src/cli/commands/test/iac-local-execution/file-loader';
import {
k8sFileStub,
anotherK8sFileStub,
Expand Down Expand Up @@ -95,7 +95,7 @@ describe('loadFiles', () => {
anotherTerraformFileStub.fileContent,
});

const loadedFiles = await loadFiles('./');
const loadedFiles = await loadFiles('.');
expect(loadedFiles).toEqual([
k8sFileStub,
anotherK8sFileStub,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
EngineType,
IacFileData,
IacFileParsed,
} from '../../src/cli/commands/test/iac-local-execution/types';
} from '../../../../src/cli/commands/test/iac-local-execution/types';

const kubernetesFileContent = `
apiVersion: v1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { parseFiles } from '../../src/cli/commands/test/iac-local-execution/file-parser';
import { parseFiles } from '../../../../src/cli/commands/test/iac-local-execution/file-parser';
import {
expectedKubernetesParsingResult,
expectedTerraformParsingResult,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {
EngineType,
IacFileParsed,
PolicyMetadata,
} from '../../src/cli/commands/test/iac-local-execution/types';
import { SEVERITY } from '../../src/lib/snyk-test/common';
} from '../../../../src/cli/commands/test/iac-local-execution/types';
import { SEVERITY } from '../../../../src/lib/snyk-test/common';

export const expectedViolatedPoliciesForK8s: Array<PolicyMetadata> = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
const mockFs = require('mock-fs');
import * as path from 'path';
import { scanFiles } from '../../src/cli/commands/test/iac-local-execution/file-scanner';
import { IacFileParsed } from '../../src/cli/commands/test/iac-local-execution/types';
import {
scanFiles,
clearPolicyEngineCache,
} from '../../../../src/cli/commands/test/iac-local-execution/file-scanner';
import { IacFileParsed } from '../../../../src/cli/commands/test/iac-local-execution/types';

import {
paresdKubernetesFileStub,
Expand All @@ -16,18 +19,19 @@ describe('scanFiles', () => {
parsedTerraformFileStub,
];

beforeAll(() => {
mockFs({
[path.resolve(__dirname, '../../.iac-data')]: mockFs.load(
path.resolve(__dirname, '../smoke/.iac-data'),
),
});
afterEach(() => {
mockFs.restore();
clearPolicyEngineCache();
});

afterAll(mockFs.restore);

describe('with parsed files', () => {
it('returns the expected viloated policies', async () => {
mockFs({
[path.resolve(__dirname, '../../../../.iac-data')]: mockFs.load(
path.resolve(__dirname, '../../../smoke/.iac-data'),
),
});

const scanResults = await scanFiles(parsedFiles);
expect(scanResults[0].violatedPolicies).toEqual(
expectedViolatedPoliciesForK8s,
Expand All @@ -43,7 +47,7 @@ describe('scanFiles', () => {
describe('missing policy engine wasm files', () => {
it('throws an error', async () => {
mockFs({
[path.resolve(__dirname, '../../.iac-data')]: {},
[path.resolve(__dirname, '../../../../.iac-data')]: {},
});

await expect(scanFiles(parsedFiles)).rejects.toThrow();
Expand Down
35 changes: 35 additions & 0 deletions test/jest/unit/iac-unit-tests/file-utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { extractBundle } from '../../../../src/cli/commands/test/iac-local-execution/file-utils';
import * as tar from 'tar';
import { PassThrough } from 'stream';

describe('extractBundle', () => {
jest.mock('fs');

it('fails to write the file on disk', async () => {
const mockReadable = new PassThrough();
const mockError = new Error('A stream error');

const actualPromise = extractBundle(mockReadable);
mockReadable.emit('error', mockError);

await expect(actualPromise).rejects.toThrow(mockError);
});

it('resolves data successfully', async () => {
const tarSpy = jest.spyOn(tar, 'x');

let receivedBundleData = '';
const mockUntarStream = new PassThrough();
mockUntarStream.on('data', (evt) => (receivedBundleData += evt.toString()));
tarSpy.mockReturnValueOnce(mockUntarStream);

const mockBundleStream = new PassThrough();
const extractBundlePromise = extractBundle(mockBundleStream);
mockBundleStream.write('zipped data');
mockBundleStream.end();

await expect(extractBundlePromise).resolves.toEqual(undefined);
expect(tarSpy).toBeCalledWith({ C: expect.stringMatching('.iac-data') });
expect(receivedBundleData).toEqual('zipped data');
});
});
Loading

0 comments on commit 3422278

Please sign in to comment.