oav/test/semanticValidatorTests.ts

300 строки
16 KiB
TypeScript

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import assert from "assert";
import * as constants from "../lib/util/constants";
import * as validate from "../lib/validate";
const testPath = __dirname;
describe("Semantic validation", () => {
describe("simple validation", () => {
it("a valid minimal swagger should pass semantic validation", async () => {
const specPath = `${testPath}/semanticValidation/specification/simple/minimalSwagger.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(
result.validityStatus === true,
`swagger "${specPath}" contains semantic validation errors.`
);
});
it("a valid minimal method should pass semantic validation", async () => {
const specPath = `${testPath}/semanticValidation/specification/simple/minimalMethod.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(
result.validityStatus === true,
`swagger "${specPath}" contains semantic validation errors.`
);
});
});
describe("loadSwagger", () => {
// JSON_PARSING_ERROR
it("should fail when validating a JSON file which cannot be parsed successfully", async () => {
const specPath = `${testPath}/semanticValidation/specification/loadSwagger/JSON_PARSING_ERROR.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(
result.validateSpec?.errors?.[0].code,
constants.ErrorCodes.JsonParsingError.name
);
});
// UNRESOLVABLE_REFERENCE
it("should fail when validating a swagger with unresolvable reference", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateSwaggerSchema/UNRESOLVABLE_REFERENCE.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "UNRESOLVABLE_REFERENCE");
});
it("should validate correctly when the spec contains an x-ms-parameterized-host", async () => {
const specPath = `${testPath}/semanticValidation/specification/parameterizedhost/face.json`;
const result = await validate.validateSpec(specPath, undefined);
// console.dir(result, { depth: null })
assert(
result.validityStatus === true,
`swagger "${specPath}" contains semantic validation errors.`
);
});
it("should validate correctly when the spec does not contain a definitions section", async () => {
const specPath = `${testPath}/semanticValidation/specification/definitions/definitions.json`;
const result = await validate.validateSpec(specPath, undefined);
// console.dir(result, { depth: null })
assert(
result.validityStatus === true,
`swagger "${specPath}" contains semantic validation errors.`
);
});
it("should fail when validating a swagger with invalid internal reference", async () => {
const specPath = `${testPath}/semanticValidation/specification/invalidReference/searchindex.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
});
it("should pass when validating a swagger with using arm-id format for string type", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateCompile/Swagger-with-xms-extension.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(
result.validityStatus === true,
`swagger "${specPath}" contains semantic validation errors.`
);
});
});
describe("internalErrors", () => {
// internalErrors: INTERNAL_ERROR
it("should fail when validating a swagger with internal error", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateSwaggerSchema/internalErrors/INTERNAL_ERROR.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(
result.validateSpec?.errors?.[0].code,
constants.ErrorCodes.InternalError.name
);
});
// error path
it("should report truly error when error path contains '/providers/Microsoft'", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateSwaggerSchema/internalErrors/errorPath.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "ENUM_MISMATCH");
assert.strictEqual(result.validateSpec?.errors?.[0].message, "No enum match for: false");
assert.strictEqual(
result.validateSpec?.errors?.[0].jsonPath,
".paths['/providers/Microsoft.ErrorPath/{name}'].get.parameters[0].required"
);
});
});
describe("validateSwaggerSchema", () => {
// OBJECT_ADDITIONAL_PROPERTIES
it("should fail when adding properties not allowed", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateSwaggerSchema/AddPropertiesNotAllowed.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "OBJECT_ADDITIONAL_PROPERTIES");
});
// ARRAY_UNIQUE
it("should fail when have array which items are not unique", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateSwaggerSchema/ARRAY_UNIQUE.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "ARRAY_UNIQUE");
});
// ENUM_MISMATCH
it("should fail when validating a swagger with No enum match error", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateSwaggerSchema/ENUM_MISMATCH.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "ENUM_MISMATCH");
});
// NOT_PASSED
it("error message should be unique when reporting error about api path started without slash", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateSwaggerSchema/notPassed/pathNotStartWithSlash.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "NOT_PASSED");
assert.strictEqual(result.validateSpec?.errors?.[0].message, "path DOES NOT start with /");
assert.strictEqual(result.validateSpec?.errors?.[0].jsonPath, ".paths['hello']");
});
});
describe("validateCompile", () => {
// INTERNAL_ERROR
it("should fail when cannot compile validator on operation", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateCompile/Compile-INTERNAL_ERROR.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "INTERNAL_ERROR");
assert.strictEqual(
result.validateSpec?.errors?.[0].message.slice(0, 40),
"Failed to compile validator on operation"
);
});
it("should ignore unknown format when compile schema", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateCompile/Swagger-with-unknown-format.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === true);
});
});
describe("validateDiscriminator", () => {
// DISCRIMINATOR_NOT_REQUIRED
it("should fail when discriminator is not a required property", async () => {
const specPath = `${testPath}/semanticValidation/specification/discriminator/notRequiredDiscriminator.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "DISCRIMINATOR_NOT_REQUIRED");
});
// OBJECT_MISSING_REQUIRED_PROPERTY_DEFINITION
it("should fail when missing required property in definition", async () => {
const specPath = `${testPath}/semanticValidation/specification/discriminator/OBJECT_MISSING_REQUIRED_PROPERTY_DEFINITION.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(
result.validateSpec?.errors?.[0].code,
"OBJECT_MISSING_REQUIRED_PROPERTY_DEFINITION"
);
});
// INVALID_DISCRIMINATOR_TYPE
it("should fail when discriminator property type is not string", async () => {
const specPath = `${testPath}/semanticValidation/specification/discriminator/INVALID_DISCRIMINATOR_TYPE.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "INVALID_DISCRIMINATOR_TYPE");
});
// INVALID_XMS_DISCRIMINATOR_VALUE
it("should fail when discriminator value is not in enum list", async () => {
const specPath = `${testPath}/semanticValidation/specification/discriminator/INVALID_XMS_DISCRIMINATOR_VALUE.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "INVALID_XMS_DISCRIMINATOR_VALUE");
});
// DISCRIMINATOR_PROPERTY_NOT_FOUND
it("should fail when parent's discriminator is missing", async () => {
const specPath = `${testPath}/semanticValidation/specification/discriminator/DISCRIMINATOR_PROPERTY_NOT_FOUND.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "DISCRIMINATOR_PROPERTY_NOT_FOUND");
});
});
describe("validateSchemaRequiredProperties", () => {
// OBJECT_MISSING_REQUIRED_PROPERTY_SCHEMA
it("should fail when validating a swagger with missing required property", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateSchemaRequiredProperties/OBJECT_MISSING_REQUIRED_PROPERTY_SCHEMA.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(
result.validateSpec?.errors?.[0].code,
"OBJECT_MISSING_REQUIRED_PROPERTY_SCHEMA"
);
});
});
describe("validateOperation", () => {
// EMPTY_PATH_PARAMETER_DECLARATION
it("should fail when has empty path parameter declaration", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/EMPTY_PATH_PARAMETER_DECLARATION.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "EMPTY_PATH_PARAMETER_DECLARATION");
});
// EQUIVALENT_PATH
it("should fail when equivalent path already exists", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/EQUIVALENT_PATH.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "EQUIVALENT_PATH");
});
// DUPLICATE_OPERATIONID
it("should fail when has multiple operations with the same operationId", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/DUPLICATE_OPERATIONID.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "DUPLICATE_OPERATIONID");
});
// DUPLICATE_PARAMETER
it("should fail when operation has duplicate parameters", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/DUPLICATE_PARAMETER.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "DUPLICATE_PARAMETER");
});
// MULTIPLE_BODY_PARAMETERS
it("should fail when operation has multiple body parameters", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/MULTIPLE_BODY_PARAMETERS/MULTIPLE_BODY_PARAMETERS.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "MULTIPLE_BODY_PARAMETERS");
});
it("should pass when operation has multiple formData parameters and consumes has multipart/form-data", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/MULTIPLE_BODY_PARAMETERS/multipartFormData.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === true);
});
// INVALID_PARAMETER_COMBINATION
it("should fail when operation has a body parameter and a formData parameter", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/INVALID_PARAMETER_COMBINATION.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(result.validateSpec?.errors?.[0].code, "INVALID_PARAMETER_COMBINATION");
});
// MISSING_PATH_PARAMETER_DECLARATION
it("should fail when path parameter is defined but is not declared", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/MISSING_PATH_PARAMETER_DECLARATION.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(
result.validateSpec?.errors?.[0].code,
"MISSING_PATH_PARAMETER_DECLARATION"
);
});
// MISSING_PATH_PARAMETER_DEFINITION
it("should fail when path parameter is declared but is not defined", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/MISSING_PATH_PARAMETER_DEFINITION.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === false);
assert.strictEqual(
result.validateSpec?.errors?.[0].code,
"MISSING_PATH_PARAMETER_DEFINITION"
);
});
it("should succeed when path args defined in path parameters", async () => {
const specPath = `${testPath}/semanticValidation/specification/validateOperation/pathParameterDefinition.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === true);
});
it("should succeed when discriminator is not a required property and the error is suppressed", async () => {
const specPath = `${testPath}/semanticValidation/specification/discriminator/notRequiredDiscriminatorWithSuppression.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(result.validityStatus === true);
});
it("should validate without additionalProperty Error on the refWithReadOnly property injected by oav", async () => {
const specPath = `${testPath}/modelValidation/swaggers/specification/refWithReadOnlyProperyError/cognitiveservices.json`;
const result = await validate.validateSpec(specPath, undefined);
assert(
result.validityStatus === true,
`swagger "${specPath}" contains semantic validation errors.`
);
});
});
});