Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
5 changes: 5 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change Log - oav

## 02/08/2021 2.2.7

- Add new rules of 'LRO_RESPONSE_HEADER' and 'LRO_RESPONSE_CODE'.
- Add option of 'isArmCall' to differentiate rulesets for Arm and RpaaS in validation apis.

## 03/12/2021 2.2.6

- Fixed the mock value of 'location' header and 'azure_AsyncOperation' header.
Expand Down
4 changes: 3 additions & 1 deletion lib/liveValidation/liveValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ interface Meta {
export interface ValidateOptions {
readonly includeErrors?: ExtendedErrorCode[];
readonly includeOperationMatch?: boolean;
isArmCall?: boolean;
}

export enum LiveValidatorLoggingLevels {
Expand Down Expand Up @@ -383,7 +384,8 @@ export class LiveValidator {
liveResponse,
info,
this.loader,
options.includeErrors
options.includeErrors,
options.isArmCall
);
} catch (resValidationError) {
const msg =
Expand Down
58 changes: 57 additions & 1 deletion lib/liveValidation/operationValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ export const validateSwaggerLiveResponse = async (
response: LiveResponse,
info: OperationContext,
loader?: LiveValidatorLoader,
includeErrors?: ExtendedErrorCode[]
includeErrors?: ExtendedErrorCode[],
isArmCall?: boolean
) => {
const { operation } = info.operationMatch!;
const { statusCode, body } = response;
Expand Down Expand Up @@ -126,6 +127,9 @@ export const validateSwaggerLiveResponse = async (
const headers = transformLiveHeader(response.headers ?? {}, rsp);
if (rsp.schema !== undefined) {
validateContentType(operation.produces!, headers, false, result);
if (isArmCall) {
validateLroOperation(operation, statusCode, headers, result);
}
}

const ctx = {
Expand Down Expand Up @@ -256,6 +260,58 @@ const schemaValidateIssueToLiveValidationIssue = (
}
};

const validateLroOperation = (
operation: Operation,
statusCode: string,
headers: StringMap<string>,
result: LiveValidationIssue[]
) => {
if (operation["x-ms-long-running-operation"] === true) {
if (operation._method === "patch" || operation._method === "post") {
if (statusCode !== "202" && statusCode !== "201") {
Comment thread
jianyexi marked this conversation as resolved.
result.push(issueFromErrorCode("LRO_RESPONSE_CODE", { statusCode }, operation.responses));
} else {
validateLroHeader(operation, headers, result);
}
} else if (operation._method === "delete") {
if (statusCode !== "202" && statusCode !== "204") {
result.push(issueFromErrorCode("LRO_RESPONSE_CODE", { statusCode }, operation.responses));
}
if (statusCode === "202") {
validateLroHeader(operation, headers, result);
}
} else if (operation._method === "put") {
if (statusCode === "202" || statusCode === "201") {
validateLroHeader(operation, headers, result);
} else if (statusCode !== "200") {
result.push(issueFromErrorCode("LRO_RESPONSE_CODE", { statusCode }, operation.responses));
}
}
}
};

const validateLroHeader = (
operation: Operation,
headers: StringMap<string>,
result: LiveValidationIssue[]
) => {
if (
(headers.location === undefined || headers.location === "") &&
(headers["azure-AsyncOperation"] === undefined || headers["azure-AsyncOperation"] === "") &&
(headers["azure-asyncoperation"] === undefined || headers["azure-asyncoperation"] === "")
) {
result.push(
issueFromErrorCode(
"LRO_RESPONSE_HEADER",
{
header: "location or azure-AsyncOperation",
},
operation.responses
)
);
}
};

export const issueFromErrorCode = (
code: ExtendedErrorCode,
param: any,
Expand Down
3 changes: 3 additions & 0 deletions lib/swagger/swaggerTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
xmsSkipUrlEncoding,
xNullable,
xmsAzureResource,
xmsLongRunningOperationOptions,
xmsLongRunningOperationOptionsField,
} from "../util/constants";
import { $id } from "./jsonLoader";

Expand Down Expand Up @@ -143,6 +145,7 @@ export interface Operation {
security?: Security[];
tags?: string[];
[xmsLongRunningOperation]?: boolean;
[xmsLongRunningOperationOptions]?: { [xmsLongRunningOperationOptionsField]: string };
[xmsExamples]?: { [description: string]: SwaggerExample };

// TODO check why do we need provider
Expand Down
2 changes: 2 additions & 0 deletions lib/swaggerValidator/schemaValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export const validateErrorMessages: { [key in ExtendedErrorCode]?: (params: any)
INVALID_RESPONSE_BODY: strTemplate`Body is required in response but not provided`,
INVALID_RESPONSE_HEADER: strTemplate`Header ${"missingProperty"} is required in response but not provided`,
MISSING_RESOURCE_ID: strTemplate`id is required to return in response of GET/PUT resource calls but not provided`,
LRO_RESPONSE_CODE: strTemplate`Patch/Post long running operation must return 201 or 202, Delete long running operation must return 202 or 204, Put long running operation must return 202 or 201 or 200, but ${"statusCode"} returned`,
LRO_RESPONSE_HEADER: strTemplate`Long running operation should return ${"header"} in header but not provided`,

DISCRIMINATOR_VALUE_NOT_FOUND: strTemplate`Discriminator value "${"data"}" not found`,
ANY_OF_MISSING: strTemplate`Data does not match any schemas from 'anyOf'`,
Expand Down
4 changes: 4 additions & 0 deletions lib/util/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export const xmsSkipUrlEncoding = "x-ms-skip-url-encoding";

export const xmsLongRunningOperation = "x-ms-long-running-operation";

export const xmsLongRunningOperationOptions = "x-ms-long-running-operation-options";

export const xmsLongRunningOperationOptionsField = "final-state-via";

export const xmsDiscriminatorValue = "x-ms-discriminator-value";

export const xmsEnum = "x-ms-enum";
Expand Down
2 changes: 2 additions & 0 deletions lib/util/validationError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ const errorConstants = {
INVALID_RESPONSE_HEADER: { severity: Severity.Error, docUrl: "" },
INVALID_RESPONSE_BODY: { severity: Severity.Critical, docUrl: "" },
MISSING_RESOURCE_ID: { severity: Severity.Critical, docUrl: "" },
LRO_RESPONSE_CODE: { severity: Severity.Critical, docUrl: "" },
LRO_RESPONSE_HEADER: { severity: Severity.Critical, docUrl: "" },
};

const wrapperErrorConstants = {
Expand Down
2 changes: 1 addition & 1 deletion 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": "2.2.6",
"version": "2.2.7",
"author": {
"name": "Microsoft Corporation",
"email": "azsdkteam@microsoft.com",
Expand Down
Loading