Skip to content

Commit

Permalink
Merge pull request #178 from lbulanti-ms/issue-98-junit-report
Browse files Browse the repository at this point in the history
Issue 98 - create test report in JUnit format
  • Loading branch information
lbulanti-ms authored May 1, 2024
2 parents b2b4362 + cfe08c1 commit 2024438
Show file tree
Hide file tree
Showing 10 changed files with 457 additions and 63 deletions.
2 changes: 2 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ Options:
-p, --pattern <pattern> Path to the pattern file to use. May be a file path or a URL.
-i, --instantiation <instantiation> Path to the pattern instantiation file to use. May be a file path or a URL.
-m, --metaSchemasLocation <metaSchemaLocation> The location of the directory of the meta schemas to be loaded (default: "../calm/draft/2024-03/meta")
-f, --format <format> The format of the output (choices: "json", "junit", default: "json")
-o, --output <output> Path location at which to output the generated file.
-v, --verbose Enable verbose logging. (default: false)
-h, --help display help for command

Expand Down
79 changes: 72 additions & 7 deletions cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
"graphviz-cli": "^2.0.0",
"json-pointer": "^0.6.2",
"lodash": "^4.17.21",
"js-yaml": "^4.1.0",
"junit-report-builder": "^3.2.1",
"mkdirp": "^3.0.1",
"ts-graphviz": "^2.1.1",
"tsconfig-paths": "^4.2.0",
Expand All @@ -37,6 +39,8 @@
"@types/jest": "^29.5.12",
"@types/json-pointer": "^1.0.34",
"@types/lodash": "^4.17.0",
"@types/js-yaml": "^4.0.9",
"@types/junit-report-builder": "^3.0.2",
"@types/node": "^20.11.30",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"eslint": "^8.57.0",
Expand Down
116 changes: 116 additions & 0 deletions cli/src/commands/validate/junit-report/junit.report.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { ValidationOutput } from '../validation.output';
import createJUnitReport from './junit.report';

const jsonSchemaValidationOutput: ValidationOutput[] = [
new ValidationOutput(
'json-schema',
'error',
'must be integer',
'/path/to/node',
'#/node'
)
];

const spectralValidationOutput: ValidationOutput[] = [
new ValidationOutput(
'no-empty-properties',
'error',
'Must not contain string properties set to the empty string or numerical properties set to zero',
'/relationships/0/relationship-type/connects/destination/interface'
),
new ValidationOutput(
'no-placeholder-properties-numerical',
'warning',
'Numerical placeholder (-1) detected in instantiated pattern.',
'/nodes/0/interfaces/0/port'
)
];

const ruleset = ['rules-number-1', 'rule-number-2', 'no-placeholder-properties-numerical', 'no-empty-properties'];


describe('createJUnitReport', () => {
it('should create a report with only JSON Schema Validations errors', async () => {
const actual = createJUnitReport(jsonSchemaValidationOutput, [], ruleset);

const expected = `<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="5" failures="1" errors="0" skipped="0">
<testsuite name="JSON Schema Validation" tests="1" failures="1" errors="0" skipped="0">
<testcase name="must be integer at #/node">
<failure/>
</testcase>
</testsuite>
<testsuite name="Spectral Suite" tests="4" failures="0" errors="0" skipped="0">
<testcase name="rules-number-1"/>
<testcase name="rule-number-2"/>
<testcase name="no-placeholder-properties-numerical"/>
<testcase name="no-empty-properties"/>
</testsuite>
</testsuites>`;

expect(actual.replace(/\s/g, '')).toBe(expected.replace(/\s/g, ''));
});

it('should create a report with only Spectral issues', async () => {
const actual = createJUnitReport([], spectralValidationOutput, ruleset);

const expected = `<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="5" failures="1" errors="0" skipped="0">
<testsuite name="JSON Schema Validation" tests="1" failures="0" errors="0" skipped="0">
<testcase name="JSON Schema Validation succeeded"/>
</testsuite>
<testsuite name="Spectral Suite" tests="4" failures="1" errors="0" skipped="0">
<testcase name="rules-number-1"/>
<testcase name="rule-number-2"/>
<testcase name="no-placeholder-properties-numerical"/>
<testcase name="no-empty-properties">
<failure/>
</testcase>
</testsuite>
</testsuites>`;
expect(actual.replace(/\s/g, '')).toBe(expected.replace(/\s/g, ''));

});

it('should create a report with Spectral issues and JSON Schema errors', async () => {
const actual = createJUnitReport(jsonSchemaValidationOutput, spectralValidationOutput, ruleset);

const expected = `<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="5" failures="2" errors="0" skipped="0">
<testsuite name="JSON Schema Validation" tests="1" failures="1" errors="0" skipped="0">
<testcase name="must be integer at #/node">
<failure/>
</testcase>
</testsuite>
<testsuite name="Spectral Suite" tests="4" failures="1" errors="0" skipped="0">
<testcase name="rules-number-1"/>
<testcase name="rule-number-2"/>
<testcase name="no-placeholder-properties-numerical"/>
<testcase name="no-empty-properties">
<failure/>
</testcase>
</testsuite>
</testsuites>`;
expect(actual.replace(/\s/g, '')).toBe(expected.replace(/\s/g, ''));
});

it('should create a report with no Spectral issues and no JSON Schema errors', async () => {
const actual = createJUnitReport([], [], ruleset);

const expected = `<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="5" failures="0" errors="0" skipped="0">
<testsuite name="JSON Schema Validation" tests="1" failures="0" errors="0" skipped="0">
<testcase name="JSON Schema Validation succeeded"/>
</testsuite>
<testsuite name="Spectral Suite" tests="4" failures="0" errors="0" skipped="0">
<testcase name="rules-number-1"/>
<testcase name="rule-number-2"/>
<testcase name="no-placeholder-properties-numerical"/>
<testcase name="no-empty-properties"/>
</testsuite>
</testsuites>`;

expect(actual.replace(/\s/g, '')).toBe(expected.replace(/\s/g, ''));
});

});
55 changes: 55 additions & 0 deletions cli/src/commands/validate/junit-report/junit.report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import junitReportBuilder, { TestSuite } from 'junit-report-builder';
import { ValidationOutput } from '../validation.output';

export default function createJUnitReport(
jsonSchemaValidationOutput: ValidationOutput[],
spectralValidationOutput: ValidationOutput[],
spectralRulesName: string[]
): string {
const builder = junitReportBuilder.newBuilder();

const jsonSchemaSuite = createTestSuite(builder, 'JSON Schema Validation');

if (jsonSchemaValidationOutput.length <= 0) {
createSucceedingTestCase(jsonSchemaSuite, 'JSON Schema Validation succeeded');
} else {
jsonSchemaValidationOutput.forEach(jsonSchemaError => {
const testName = `${jsonSchemaError.message} at ${jsonSchemaError.schemaPath}`;
createFailingTestCase(jsonSchemaSuite, testName);
});
}

const spectralSuite = createTestSuite(builder, 'Spectral Suite');

if (spectralValidationOutput.length <= 0) {
spectralRulesName.forEach(ruleName => createSucceedingTestCase(spectralSuite,ruleName));
} else {
spectralRulesName.forEach(ruleName => {
if (spectralValidationOutput.filter(item => (item.code === ruleName) && item.severity === 'error').length > 0) {
createFailingTestCase(spectralSuite, ruleName);
} else {
createSucceedingTestCase(spectralSuite, ruleName);
}
});
}

return builder.build();
}

function createTestSuite(builder, testSuiteName: string){
return builder
.testSuite()
.name(testSuiteName);
}

function createSucceedingTestCase(testSuite: TestSuite, testName: string){
testSuite.testCase()
.name(testName);
}

function createFailingTestCase(testSuite: TestSuite, testName: string){
testSuite.testCase()
.name(testName)
.failure();
}

Loading

0 comments on commit 2024438

Please sign in to comment.