Skip to content

Commit

Permalink
Add Passed opeartions to the report (#1044)
Browse files Browse the repository at this point in the history
* add pass operations to reports

* update package.json, package-lock.json and ChangeLog.md
  • Loading branch information
ms-zhenhua authored Sep 13, 2024
1 parent d24383e commit 9a2fcc1
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 7 deletions.
4 changes: 4 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log - oav

## 09/12/2024 3.5.0

- Add names of `Passed Operations` in the HTML and JSON reports.

## 07/12/2024 3.4.0

- During example generation, fields `password`, `adminPassword`, and `pwd` are all generated with a single value of "<a-password-goes-here>" instead of random characters.
Expand Down
5 changes: 5 additions & 0 deletions lib/apiScenario/coverageCalculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface OperationCoverageResult {
coveredOperationNumber: number;
totalOperationNumber: number;
coverage: number;
coveredOperationIds: string[];
uncoveredOperationIds: string[];
}

Expand All @@ -22,6 +23,7 @@ export class CoverageCalculator {
coveredOperationNumber: 0,
totalOperationNumber: 0,
coverage: 0,
coveredOperationIds: [],
uncoveredOperationIds: [],
};

Expand Down Expand Up @@ -55,6 +57,7 @@ export class CoverageCalculator {
allOperationIds.size === 0 ? 0 : coverageOperationIds.size / allOperationIds.size;
ret.coveredOperationNumber = coverageOperationIds.size;
ret.totalOperationNumber = allOperationIds.size;
ret.coveredOperationIds = [...coverageOperationIds];
const difference = [...allOperationIds].filter((x) => !coverageOperationIds.has(x));
ret.uncoveredOperationIds = difference;
return ret;
Expand All @@ -70,6 +73,7 @@ export class CoverageCalculator {
coveredOperationNumber: 0,
totalOperationNumber: 0,
coverage: 0,
coveredOperationIds: [],
uncoveredOperationIds: [],
};

Expand Down Expand Up @@ -102,6 +106,7 @@ export class CoverageCalculator {
allOperationIds.size === 0 ? 0 : coverageOperationIds.size / allOperationIds.size;
result.coveredOperationNumber = coverageOperationIds.size;
result.totalOperationNumber = allOperationIds.size;
result.coveredOperationIds = [...coverageOperationIds];
const difference = [...allOperationIds].filter((x) => !coverageOperationIds.has(x));
result.uncoveredOperationIds = difference;

Expand Down
3 changes: 3 additions & 0 deletions lib/apiScenario/postmanCollectionGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@ class PostmanCollectionRunner {
apiVersion: getApiVersionFromFilePath(specPath),
unCoveredOperations: result.uncoveredOperationIds.length,
coveredOperations: result.totalOperationNumber - result.uncoveredOperationIds.length,
coveredOperationsList: result.coveredOperationIds.map((id) => {
return { operationId: id };
}),
validationFailOperations: new Set(
trafficValidationResult
.filter((it) => key.indexOf(it.specFilePath!) !== -1 && it.errors!.length > 0)
Expand Down
72 changes: 69 additions & 3 deletions lib/report/generateReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as path from "path";
import * as Mustache from "mustache";
import {
OperationCoverageInfo,
OperationMeta,
TrafficValidationIssue,
TrafficValidationOptions,
} from "../swaggerValidator/trafficValidator";
Expand Down Expand Up @@ -52,9 +53,18 @@ export interface ErrorDefinition {
link?: string;
}

export interface ValidationPassOperationsFormatInner extends OperationMeta {
readonly key: string;
}

export interface ValidationPassOperationsFormat {
readonly operationIdList: ValidationPassOperationsFormatInner[];
}

export interface OperationCoverageInfoForRendering extends OperationCoverageInfo {
specLinkLabel?: string;
validationPassOperations?: number;
validationPassOperationList: ValidationPassOperationsFormat[];
generalErrorsInnerList: TrafficValidationIssueForRenderingInner[];
}

Expand Down Expand Up @@ -201,18 +211,77 @@ export class CoverageView {
runtimeExceptions: element.runtimeExceptions,
});
});

const generalErrorsInnerOrigin = this.validationResultsForRendering.filter((x) => {
return x.errors && x.errors.length > 0;
});

this.coverageResults.forEach((element) => {
const specLink = this.overrideLinkInReport
? `${this.specLinkPrefix}/${element.spec?.substring(
element.spec?.indexOf("specification")
)}`
: `${element.spec}`;

let errorOperationIds = generalErrorsInnerOrigin.map(
(item) => item.operationInfo?.operationId
);
let passOperations: ValidationPassOperationsFormatInner[] = element.coveredOperationsList
.filter((item) => errorOperationIds.indexOf(item.operationId) === -1)
.map((item) => {
return {
key: item.operationId.split("_")[0],
operationId: item.operationId,
};
});

const passOperationsInnerList: ValidationPassOperationsFormatInner[][] = Object.values(
passOperations.reduce(
(res: { [key: string]: ValidationPassOperationsFormatInner[] }, item) => {
/* eslint-disable no-unused-expressions */
res[item.key] ? res[item.key].push(item) : (res[item.key] = [item]);
/* eslint-enable no-unused-expressions */
return res;
},
{}
)
);

const passOperationsListFormat: ValidationPassOperationsFormat[] = [];
passOperationsInnerList.forEach((element) => {
passOperationsListFormat.push({
operationIdList: element,
});
});

/**
* Sort untested operationId by bubble sort
* Controlling the results of localeCompare can set the sorting method
* X.localeCompare(Y) > 0 descending sort
* X.localeCompare(Y) < 0 ascending sort
*/
for (let i = 0; i < passOperationsListFormat.length - 1; i++) {
for (let j = 0; j < passOperationsListFormat.length - 1 - i; j++) {
if (
passOperationsListFormat[j].operationIdList[0].key.localeCompare(
passOperationsListFormat[j + 1].operationIdList[0].key
) > 0
) {
var temp = passOperationsListFormat[j];
passOperationsListFormat[j] = passOperationsListFormat[j + 1];
passOperationsListFormat[j + 1] = temp;
}
}
}

this.coverageResultsForRendering.push({
spec: specLink,
specLinkLabel: element.spec?.substring(element.spec?.lastIndexOf("/") + 1),
apiVersion: element.apiVersion,
coveredOperations: element.coveredOperations,
coveredOperationsList: element.coveredOperationsList,
validationPassOperations: element.coveredOperations - element.validationFailOperations,
validationPassOperationList: passOperationsListFormat,
validationFailOperations: element.validationFailOperations,
unCoveredOperations: element.unCoveredOperations,
unCoveredOperationsList: element.unCoveredOperationsList,
Expand All @@ -235,9 +304,6 @@ export class CoverageView {
} as any;
});

const generalErrorsInnerOrigin = this.validationResultsForRendering.filter((x) => {
return x.errors && x.errors.length > 0;
});
const generalErrorsInnerFormat: TrafficValidationIssueForRendering[][] = Object.values(
generalErrorsInnerOrigin.reduce(
(res: { [key: string]: TrafficValidationIssueForRendering[] }, item) => {
Expand Down
17 changes: 17 additions & 0 deletions lib/swaggerValidator/trafficValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export interface OperationCoverageInfo {
readonly spec: string;
readonly apiVersion: string;
readonly coveredOperations: number;
readonly coveredOperationsList: OperationMeta[];
readonly validationFailOperations: number;
readonly unCoveredOperations: number;
readonly unCoveredOperationsList: OperationMeta[];
Expand Down Expand Up @@ -290,11 +291,13 @@ export class TrafficValidator {
let coveredOperations: number;
let coverageRate: number;
let validationFailOperations: number;
let coveredOperationsList: OperationMeta[];
let unCoveredOperationsList: unCoveredOperationsFormatInner[];
this.operationSpecMapper.forEach((value: string[], key: string) => {
// identify the spec has been match traffic file
let isMatch: boolean = true;
const unCoveredOperationsListFormat: unCoveredOperationsFormat[] = [];
coveredOperationsList = [];
unCoveredOperationsList = [];
if (this.trafficOperation.get(key) === undefined) {
coveredOperations = 0;
Expand All @@ -308,6 +311,7 @@ export class TrafficValidator {
this.coverageData.set(key, coverageRate);
const unValidatedOperations = [...value];
validatedOperations!.forEach((element) => {
coveredOperationsList.push({ operationId: element });
unValidatedOperations.splice(unValidatedOperations.indexOf(element), 1);
});
unValidatedOperations.forEach((element) => {
Expand Down Expand Up @@ -356,6 +360,18 @@ export class TrafficValidator {
return 0;
});

const sortedCoveredOperationsList = coveredOperationsList.sort(function (op1, op2) {
const opId1 = op1.operationId;
const opId2 = op2.operationId;
if (opId1 < opId2) {
return -1;
}
if (opId1 > opId2) {
return 1;
}
return 0;
});

/**
* Sort untested operationId by bubble sort
* Controlling the results of localeCompare can set the sorting method
Expand Down Expand Up @@ -385,6 +401,7 @@ export class TrafficValidator {
unCoveredOperations: value.length - coveredOperations,
totalOperations: value.length,
validationFailOperations: validationFailOperations,
coveredOperationsList: sortedCoveredOperationsList,
unCoveredOperationsList: sortedUnCoveredOperationsList,
unCoveredOperationsListGen: unCoveredOperationsListFormat,
});
Expand Down
78 changes: 77 additions & 1 deletion lib/templates/baseLayout.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,52 @@
white-space: nowrap;
}
.testPassed {
margin-bottom: 40px;
}
.testPassed table {
border: none;
}
.testPassed .table-body {
border: none;
}
.testPassed .table-body>table>tbody>tr>td {
border: none;
}
.testPassed .table-body table tbody tr td {
border-bottom: 1px solid var(--border-color);
}
.testPassed table tbody tr td:nth-child(-n + 2) {
text-align: center;
word-break: break-all;
}
.testPassed .operationTag {
text-align: left;
}
.testPassed .operationTag .tag {
color: var(--report-base-colo);
background-color: var(--report-bg-blue);
border: 1px solid var(--report-bg-blue);
display: inline-block;
height: 32px;
padding: 0 10px;
margin: 4px 2px;
line-height: 30px;
font-size: 14px;
border-radius: 4px;
box-sizing: border-box;
white-space: nowrap;
}
.notTested table,
.testPassed table,
.testFailed table,
.runtimeExceptions table,
.innerTable table {
Expand Down Expand Up @@ -556,7 +601,11 @@
</span>
( {{validationFailOperations}} )
</th>
<th style="background-color: var(--report-bg-green);">Pass ( {{validationPassOperations}} )</th>
<th style="background-color: var(--report-bg-green);">
Pass<span class="hashLinkClass" data-hash-link="testPassed_{{index}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" class="svg_dd790ee3 x-hidden-focus" focusable="false" width="25" height="15" style="vertical-align: middle;"><path d="M1707 715q76 27 139 75t108 111 69 138 25 156q0 106-40 199t-110 162-163 110-199 41h-512q-106 0-199-40t-162-110-110-163-41-199q0-106 40-199t110-162 163-110 199-41h171q0 35-13 66t-37 54-55 36-66 14q-71 0-133 27t-108 73-73 109-27 133q0 71 27 133t73 108 108 73 133 27h512q70 0 132-27t109-73 73-108 27-133q0-92-46-168t-124-123V715zM171 683q0 91 46 167t124 124v189q-76-27-139-75T94 977 25 839 0 683q0-106 40-199t110-162 163-110 199-41h512q106 0 199 40t162 110 110 163 41 199q0 106-40 199t-110 162-163 110-199 41H853q0-35 13-66t37-54 54-37 67-14q70 0 132-27t109-73 73-108 27-133q0-70-26-132t-73-109-109-74-133-27H512q-71 0-133 27t-108 73-73 109-27 133z" class="x-hidden-focus"></path></svg>
( {{validationPassOperations}} )
</span>
</th>
<th style="background-color: var(--report-bg-blue);">
<div class="file">
{{specLinkLabel}}<a target="_blank" href="{{spec}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" class="svg_dd790ee3 x-hidden-focus" focusable="false" width="25" height="15" style="vertical-align: middle;"><path d="M1707 715q76 27 139 75t108 111 69 138 25 156q0 106-40 199t-110 162-163 110-199 41h-512q-106 0-199-40t-162-110-110-163-41-199q0-106 40-199t110-162 163-110 199-41h171q0 35-13 66t-37 54-55 36-66 14q-71 0-133 27t-108 73-73 109-27 133q0 71 27 133t73 108 108 73 133 27h512q70 0 132-27t109-73 73-108 27-133q0-92-46-168t-124-123V715zM171 683q0 91 46 167t124 124v189q-76-27-139-75T94 977 25 839 0 683q0-106 40-199t110-162 163-110 199-41h512q106 0 199 40t162 110 110 163 41 199q0 106-40 199t-110 162-163 110-199 41H853q0-35 13-66t37-54 54-37 67-14q70 0 132-27t109-73 73-108 27-133q0-70-26-132t-73-109-109-74-133-27H512q-71 0-133 27t-108 73-73 109-27 133z" class="x-hidden-focus"></path></svg></a>
Expand Down Expand Up @@ -667,6 +716,33 @@
</article>
</section>

<section class="testPassed">
<h2 class="title" id="testPassed_{{index}}">Passed Operations ( {{validationPassOperations}} )</h2>
<article>
<div class="table-body">
<table summary="Operations Test Passed" cellspacing="0" cellpadding="0">
<colgroup>
<col style="width: 15%" />
<col style="width: 85%" />
</colgroup>
<tbody>
{{#validationPassOperationList}}
<tr>
<td colspan="2">
<div class="operationTag">
{{#operationIdList}}
<span class="tag">{{operationId}}<a target="_blank" href="{{spec}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" class="svg_dd790ee3 x-hidden-focus" focusable="false" width="25" height="15" style="vertical-align: middle;"><path d="M1707 715q76 27 139 75t108 111 69 138 25 156q0 106-40 199t-110 162-163 110-199 41h-512q-106 0-199-40t-162-110-110-163-41-199q0-106 40-199t110-162 163-110 199-41h171q0 35-13 66t-37 54-55 36-66 14q-71 0-133 27t-108 73-73 109-27 133q0 71 27 133t73 108 108 73 133 27h512q70 0 132-27t109-73 73-108 27-133q0-92-46-168t-124-123V715zM171 683q0 91 46 167t124 124v189q-76-27-139-75T94 977 25 839 0 683q0-106 40-199t110-162 163-110 199-41h512q106 0 199 40t162 110 110 163 41 199q0 106-40 199t-110 162-163 110-199 41H853q0-35 13-66t37-54 54-37 67-14q70 0 132-27t109-73 73-108 27-133q0-70-26-132t-73-109-109-74-133-27H512q-71 0-133 27t-108 73-73 109-27 133z" class="x-hidden-focus"></path></svg></a></span>
{{/operationIdList}}
</div>
</td>
</tr>
{{/validationPassOperationList}}
</tbody>
</table>
</div>
</article>
</section>

</div>
{{/resultsForRendering}}
</div>
Expand Down
12 changes: 12 additions & 0 deletions lib/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,18 @@ export async function validateTraffic(
operationIds: item.unCoveredOperationsList.map((opeartion) => opeartion.operationId),
};
}),
passedOperationsList: validator.operationCoverageResult.map((item) => {
return {
spec: item.spec,
operationIds: item.coveredOperationsList
.map((opeartion) => opeartion.operationId)
.filter((id) => {
return !trafficValidationResult.some(
(error) => error.operationInfo?.operationId === id
);
}),
};
}),
failedOperations: validator.operationCoverageResult
.map((item) => item.validationFailOperations)
.reduce((a, b) => a + b, 0),
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "oav",
"version": "3.4.0",
"version": "3.5.0",
"author": {
"name": "Microsoft Corporation",
"email": "[email protected]",
Expand Down
8 changes: 8 additions & 0 deletions test/__snapshots__/trafficValidatorTests.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ Object {
"apiVersion": "2019-02-02",
"coverageRate": 0.14285714285714285,
"coveredOperations": 2,
"coveredOperationsList": Array [
Object {
"operationId": "Table_Delete",
},
Object {
"operationId": "Table_Query",
},
],
"totalOperations": 14,
"unCoveredOperations": 12,
"unCoveredOperationsList": Array [
Expand Down

0 comments on commit 9a2fcc1

Please sign in to comment.