300 строки
16 KiB
TypeScript
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.`
|
|
);
|
|
});
|
|
});
|
|
});
|