Change validation input when version is 3.1.x

if the option includeWebhooks is false and there are no paths (only webhooks or componentes) throw error.
This commit is contained in:
Luis Tejeda
2022-02-09 12:46:31 -06:00
parent 02e22e8825
commit 50ba85ce68
8 changed files with 58 additions and 80 deletions

View File

@@ -6,10 +6,11 @@ module.exports = {
* OpenAPI 3.1 only openapi and info are always required,
* but the document must also contain at least one of paths or webhooks or components.
* @param {Object} spec OpenAPI spec
* @param {Object} options computed process options
* @return {Object} Validation result
*/
validateSpec: function (spec) {
validateSpec: function (spec, options) {
const includeWebhooksOption = options.includeWebhooks;
if (!spec.hasOwnProperty('openapi')) {
return {
result: false,
@@ -24,7 +25,15 @@ module.exports = {
};
}
if (!spec.hasOwnProperty('paths') && !spec.hasOwnProperty('webhooks') && !spec.hasOwnProperty('components')) {
if (!spec.hasOwnProperty('paths') && !includeWebhooksOption) {
return {
result: false,
reason: 'Specification must contain Paths Object for the available operational paths'
};
}
if (includeWebhooksOption && !spec.hasOwnProperty('paths') &&
!spec.hasOwnProperty('webhooks') && !spec.hasOwnProperty('components')) {
return {
result: false,
reason: 'Specification must contain either Paths, Webhooks or Components sections'

View File

@@ -13,11 +13,12 @@ module.exports = {
/**
* Parses an OAS 3.1.X string/object as a YAML or JSON
* @param {YAML/JSON} openApiSpec - The OAS 3.1.x specification specified in either YAML or JSON
* @param {Object} options computed process options
* @returns {Object} - Contains the parsed JSON-version of the OAS spec, or an error
* @no-unit-test
*/
parseSpec: function (openApiSpec) {
return schemaUtilsCommon.parseSpec(openApiSpec, inputValidation31X);
parseSpec: function (openApiSpec, options) {
return schemaUtilsCommon.parseSpec(openApiSpec, inputValidation31X, options);
},
inputValidation: inputValidation31X,

View File

@@ -10,10 +10,11 @@ module.exports = {
* Parses an OAS string/object as a YAML or JSON
* @param {YAML/JSON} openApiSpec - The OAS 3.x specification specified in either YAML or JSON
* @param {object} inputValidation - Concrete validator according to version
* @param {Object} options computed process options
* @returns {Object} - Contains the parsed JSON-version of the OAS spec, or an error
* @no-unit-test
*/
parseSpec: function (openApiSpec, inputValidation) {
parseSpec: function (openApiSpec, inputValidation, options) {
var openApiObj = openApiSpec,
obj,
rootValidation;
@@ -32,7 +33,7 @@ module.exports = {
// spec is a valid JSON object at this point
// Validate the root level object for semantics
rootValidation = inputValidation.validateSpec(openApiObj);
rootValidation = inputValidation.validateSpec(openApiObj, options);
if (!rootValidation.result) {
return {
result: false,

View File

@@ -34,58 +34,6 @@ module.exports = {
}
},
/**
* Validate Spec to check if some of the required fields are present.
*
* @param {Object} spec OpenAPI spec
* @return {Object} Validation result
*/
validateSpec: function (spec) {
// Checking for the all the required properties in the specification
if (!spec.hasOwnProperty('openapi')) {
return {
result: false,
reason: 'Specification must contain a semantic version number of the OAS specification'
};
}
if (!spec.hasOwnProperty('paths')) {
return {
result: false,
reason: 'Specification must contain Paths Object for the available operational paths'
};
}
if (!spec.hasOwnProperty('info')) {
return {
result: false,
reason: 'Specification must contain an Info Object for the meta-data of the API'
};
}
if (!spec.info.hasOwnProperty('$ref')) {
if (!spec.info.hasOwnProperty('title')) {
return {
result: false,
reason: 'Specification must contain a title in order to generate a collection'
};
}
if (!spec.info.hasOwnProperty('version')) {
return {
result: false,
reason: 'Specification must contain a semantic version number of the API in the Info Object'
};
}
}
// Valid specification
return {
result: true,
openapi: spec
};
},
/** Converts OpenAPI input to OpenAPI Object
* @param {String} openApiSpec OpenAPI input in string
* @returns {Object} oasObject
@@ -129,10 +77,11 @@ module.exports = {
*
* @param {Array} input input object that contains files array
* @param {Object} inputValidation Validator according to version
* @param {Object} options computed process options
* @param {Object} files Files map
* @return {String} rootFile
*/
getRootFiles: function (input, inputValidation, files = {}) {
getRootFiles: function (input, inputValidation, options, files = {}) {
let rootFilesArray = [],
filesPathArray = input.data,
origin = input.origin || '';
@@ -160,7 +109,7 @@ module.exports = {
else {
throw new Error(obj.reason);
}
if (inputValidation.validateSpec(oasObject).result) {
if (inputValidation.validateSpec(oasObject, options).result) {
rootFilesArray.push(filePath.fileName);
}
}

View File

@@ -108,7 +108,7 @@ class SchemaPack {
return this.validationResult;
}
specParseResult = concreteUtils.parseSpec(json);
specParseResult = concreteUtils.parseSpec(json, this.computedOptions);
if (!specParseResult.result) {
// validation failed
@@ -190,7 +190,7 @@ class SchemaPack {
}
try {
rootFiles = parse.getRootFiles(input, concreteUtils.inputValidation, files);
rootFiles = parse.getRootFiles(input, concreteUtils.inputValidation, this.computedOptions, files);
}
catch (e) {
return cb(null, {

View File

@@ -69,44 +69,64 @@ const { expect } = require('chai'),
describe('validateSpec method', function () {
it('should return true with a valid simple spec with webhooks', function () {
const validationResult = validateSpec(correctMockedEntryWH);
const validationResult = validateSpec(correctMockedEntryWH, { includeWebhooks: true });
expect(validationResult.result).to.be.true;
});
it('should return true with a valid simple spec with paths', function () {
const validationResult = validateSpec(correctMockedEntryPath);
const validationResult = validateSpec(correctMockedEntryPath, { includeWebhooks: true });
expect(validationResult.result).to.be.true;
});
it('should return true with a valid simple spec with components', function () {
const validationResult = validateSpec(correctMockedEntryComponent);
const validationResult = validateSpec(correctMockedEntryComponent, { includeWebhooks: true });
expect(validationResult.result).to.be.true;
});
it('should return true with a valid simple spec with components webhooks y paths', function () {
const validationResult = validateSpec(correctMockedEntry);
const validationResult = validateSpec(correctMockedEntry, { includeWebhooks: true });
expect(validationResult.result).to.be.true;
});
it('should return false with an invalid input without openapi field', function () {
const validationResult = validateSpec(incorrectMockedEntryNoOpenapi);
const validationResult = validateSpec(incorrectMockedEntryNoOpenapi, { includeWebhooks: true });
expect(validationResult.result).to.be.false;
expect(validationResult.reason)
.to.equal('Specification must contain a semantic version number of the OAS specification');
});
it('should return false with an invalid input without info field', function () {
const validationResult = validateSpec(incorrectMockedEntryNoInfo);
const validationResult = validateSpec(incorrectMockedEntryNoInfo, { includeWebhooks: true });
expect(validationResult.result).to.be.false;
expect(validationResult.reason)
.to.equal('Specification must contain an Info Object for the meta-data of the API');
});
it('should return false with an invalid input without path components and webhooks', function () {
const validationResult = validateSpec(incorrectMockedEntryNOPathsComponentsWebhooks);
const validationResult = validateSpec(incorrectMockedEntryNOPathsComponentsWebhooks, { includeWebhooks: true });
expect(validationResult.result).to.be.false;
expect(validationResult.reason)
.to.equal('Specification must contain either Paths, Webhooks or Components sections');
});
it('should return false with a valid simple spec with only webhooks but include webhooks is false', function () {
const validationResult = validateSpec(correctMockedEntryWH, { includeWebhooks: false });
expect(validationResult.result).to.be.false;
});
it('should return true with a valid simple spec with paths and webhooks include webhooks is false', function () {
const validationResult = validateSpec(correctMockedEntryPath, { includeWebhooks: false });
expect(validationResult.result).to.be.true;
});
it('should return false with a valid simple spec with only components and include webhooks is false', function () {
const validationResult = validateSpec(correctMockedEntryComponent, { includeWebhooks: false });
expect(validationResult.result).to.be.false;
});
it('should return false with input without path components or webhooks include webhooks is false', function () {
const validationResult = validateSpec(incorrectMockedEntryNOPathsComponentsWebhooks, { includeWebhooks: false });
expect(validationResult.result).to.be.false;
});
});

View File

@@ -7,7 +7,7 @@ const { expect } = require('chai'),
describe('parseSpec method', function () {
it('should return true and a parsed specification', function () {
let fileContent = fs.readFileSync(valid31xFolder + '/webhooks.json', 'utf8');
const parsedSpec = concreteUtils.parseSpec(fileContent);
const parsedSpec = concreteUtils.parseSpec(fileContent, { includeWebhooks: true });
expect(parsedSpec.result).to.be.true;
expect(parsedSpec.openapi.openapi).to.equal('3.1.0');
expect(parsedSpec.openapi.webhooks).to.not.be.undefined;
@@ -15,14 +15,14 @@ describe('parseSpec method', function () {
it('should return false and invalid format message when input content is sent', function () {
let fileContent = fs.readFileSync(invalid31xFolder + '/empty-spec.yaml', 'utf8');
const parsedSpec = concreteUtils.parseSpec(fileContent);
const parsedSpec = concreteUtils.parseSpec(fileContent, { includeWebhooks: false });
expect(parsedSpec.result).to.be.false;
expect(parsedSpec.reason).to.equal('Invalid format. Input must be in YAML or JSON format.');
});
it('should return false and Spec must contain info object', function () {
let fileContent = fs.readFileSync(invalid31xFolder + '/invalid-no-info.json', 'utf8');
const parsedSpec = concreteUtils.parseSpec(fileContent);
const parsedSpec = concreteUtils.parseSpec(fileContent, { includeWebhooks: false });
expect(parsedSpec.result).to.be.false;
expect(parsedSpec.reason).to.equal('Specification must contain an Info Object for the meta-data of the API');
});

View File

@@ -668,7 +668,7 @@ describe('Webhooks support', function() {
});
});
it('Should resolve a file with only webhooks but includeWebhooks is false', function() {
it('Should return the validation error with a file with only webhooks but includeWebhooks is false', function () {
const fileSource = path.join(__dirname, OPENAPI_31_FOLDER + '/webhooks/payments-webhooks.yaml'),
fileData = fs.readFileSync(fileSource, 'utf8'),
input = {
@@ -676,12 +676,10 @@ describe('Webhooks support', function() {
data: fileData
},
converter = new SchemaPack(input, { includeWebhooks: false });
converter.convert((err, result) => {
expect(err).to.be.null;
expect(result.result).to.be.true;
expect(result.output[0].data.item.length).to.eql(0);
});
expect(converter.validated).to.be.false;
expect(converter.validationResult.result).to.be.false;
expect(converter.validationResult.reason)
.to.equal('Specification must contain Paths Object for the available operational paths');
});
it('Should resolve correctly a file with only webhooks, folderStrategy as tag', function() {