This commit is contained in:
Vishrut Shah 2017-05-24 14:56:09 -07:00
Родитель 615c46fec6
Коммит 7530c8e324
3 изменённых файлов: 16 добавлений и 247 удалений

Просмотреть файл

@ -1,4 +1,4 @@
# openapi-validation-tools
# openapi-validation-tools [oav]
Tools for validating OpenAPI (Swagger) files.
### What does the tool do? What issues does the tool catch?
@ -54,9 +54,19 @@ npm install -g oav
```
bash-3.2$ oav -h
Commands:
validate-example <spec-path> Performs validation of x-ms-examples and
examples present in the spec.
validate-spec <spec-path> Performs semantic validation of the spec.
extract-xmsexamples <spec-path> Extracts the x-ms-examples for a
<recordings> given swagger from the .NET session
recordings and saves them in a file.
generate-wireformat <spec-path> Transforms the x-ms-examples for a
given operation into raw
request/response format and saves
them in a markdown file.
resolve-spec <spec-path> Resolves the swagger spec based on
the selected options.
validate-example <spec-path> Performs validation of x-ms-examples
and examples present in the spec.
validate-spec <spec-path> Performs semantic validation of the
spec.
Options:
--version Show version number [boolean]
@ -65,7 +75,7 @@ Options:
[default: "warn"]
-f, --logFilepath Set the log file path. It must be an absolute filepath. By
default the logs will stored in a timestamp based log file
at "/Users/amarz/oav_output".
at "/Users/vishrut/oav_output".
-h, --help Show help [boolean]
bash-3.2$

Просмотреть файл

@ -1,6 +1,6 @@
{
"name": "oav",
"version": "0.4.1",
"version": "0.4.2",
"author": {
"name": "Microsoft Corporation",
"email": "azsdkteam@microsoft.com",

Просмотреть файл

@ -1,241 +0,0 @@
const util = require('util')
var fs = require('fs');
var glob = require('glob');
var pathlib = require('path');
var recursive = require('recursive-readdir')
var outputFolderName = ""
var swaggerSpecPath = ""
var pathToRecordings = ""
var outputExamples = ""
var outputSwagger = ""
var relativeExamplesPath = "../examples/"
exports.printUsage = function printUsage() {
console.log('\nUsage: node readrecording.js spec <local file-path to the swagger spec> recordings <local folder-path to the .Net test recordings> output <local folder-path to store output swagger and examples> [--matchApiVersion]\n');
console.log('Example: node readrecording.js spec "./arm-network/network.json" recordings "arm-network/SessionRecords/" output "arm-network"\n')
console.log('If examples should only be generated from recordings that match the api version of the spec, please include \'--matchApiVersion\' as the last option. \n')
process.exit(1);
}
var cmdSpec = process.argv[2];
if ((typeof cmdSpec == 'undefined') || cmdSpec === '-h' || cmdSpec === '--help' || cmdSpec === 'help') {
exports.printUsage();
}
var cmdSpecPath = process.argv[3];
var cmdRecordings = process.argv[4];
var cmdRecordingPath = process.argv[5];
var cmdOutput = process.argv[6];
var cmdOutputPath = process.argv[7];
var checkAPIVersion = process.argv[8]
if (cmdSpec !== 'spec' || cmdRecordings !== 'recordings' || cmdOutput !== 'output' || (typeof cmdOutputPath == 'undefined')) {
exports.printUsage();
}
checkAPIVersion = (checkAPIVersion === '--matchApiVersion')
swaggerSpecPath = cmdSpecPath
pathToRecordings = cmdRecordingPath
outputFolderName = cmdOutputPath
var mkdirSync = function (path) {
try {
fs.mkdirSync(path);
} catch (e) {
if (e.code != 'EEXIST') throw e;
}
}
mkdirSync(cmdOutputPath);
mkdirSync(cmdOutputPath + "/examples");
mkdirSync(cmdOutputPath + "/swagger");
outputExamples = outputFolderName + "/examples/"
relativeExamplesPath = "../examples/"
specName = swaggerSpecPath.split("/")
outputSwagger = outputFolderName + "/swagger/" + specName[specName.length - 1].split(".")[0] + ".json"
var swaggerObject = require(swaggerSpecPath)
var SwaggerParser = require('swagger-parser')
var parser = new SwaggerParser()
var example = {};
example['parameters'] = {}
example['responses'] = {}
var accErrors = {}
var getFileList = function (dir, filelist) {
var files = fs.readdirSync(dir);
filelist = filelist || [];
files.forEach(function (file) {
if (fs.statSync(pathlib.join(dir, file)).isDirectory()) {
filelist = getFileList(pathlib.join(dir, file), filelist);
}
else {
filelist.push(pathlib.join(dir, file));
}
});
return filelist;
};
var filesArray = []
getFileList(pathToRecordings, filesArray)
recordingFiles = filesArray
var example = {};
parser.parse(swaggerObject)
.then(function (api) {
console.log("API name: " + api.info.title)
specApiVersion = api.info.version
paths = api.paths
for (var recordingFile in recordingFiles) {
console.log("*****************")
console.log("Recording file: " + recordingFiles[recordingFile])
recordingFileName = recordingFiles[recordingFile]
try {
var recording = JSON.parse(fs.readFileSync(recordingFileName));
pathIndex = 0
var pathParams = {}
for (var path in paths) {
pathIndex++;
searchResult = path.match(/\/{\w*\}/g)
pathParts = path.split('/')
pathToMatch = path
pathParams = {}
for (var sr in searchResult) {
match = searchResult[sr]
splitRegEx = /[{}]/
pathParam = match.split(splitRegEx)[1]
for (var part in pathParts) {
pathPart = "/" + pathParts[part]
if (pathPart.localeCompare(match) == 0) {
pathParams[pathParam] = part
}
}
pathToMatch = pathToMatch.replace(match, "/[^\/]+");
}
newPathToMatch = pathToMatch.replace(/\//g, "\\/");
newPathToMatch = newPathToMatch + "$"
//for this API path (and method), try to find it in the recording file, and get the data
var entries = recording.Entries
entryIndex = 0
queryParams = {}
for (var entry in entries) {
entryIndex++;
recordingPath = JSON.stringify(entries[entry]["RequestUri"]);
recordingPathQueryParams = recordingPath.split('?')[1].slice(0, -1)
queryParamsArray = recordingPathQueryParams.split('&')
for (var part in queryParamsArray) {
queryParam = queryParamsArray[part].split('=')
queryParams[queryParam[0]] = queryParam[1]
}
// if commandline included check for API version, validate api-version from URI in recordings matches the api-version of the spec
if (!checkAPIVersion || (("api-version" in queryParams) && queryParams["api-version"] == specApiVersion)) {
recordingPath = recordingPath.replace(/\?.*/, '')
recordingPathParts = recordingPath.split('/')
match = recordingPath.match(newPathToMatch)
if (match != null) {
console.log("path: " + path)
console.log("recording path: " + recordingPath)
var pathParamsValues = {}
for (var p in pathParams) {
index = pathParams[p]
pathParamsValues[p] = recordingPathParts[index]
}
//found a match in the recording
requestMethodFromRecording = entries[entry]["RequestMethod"]
infoFromOperation = paths[path][requestMethodFromRecording.toLowerCase()]
if (typeof infoFromOperation != 'undefined') {
//need to consider each method in operation
fileName = recordingFileName.split('/')
fileName = fileName[fileName.length - 1]
fileName = fileName.split(".json")[0]
fileName = fileName.replace(/\//g, "-")
exampleFileName = fileName + "-" + requestMethodFromRecording + "-example-" + pathIndex + entryIndex + ".json";
ref = {}
ref["$ref"] = relativeExamplesPath + exampleFileName
exampleFriendlyName = fileName + requestMethodFromRecording + pathIndex + entryIndex
console.log(exampleFriendlyName)
if (!("x-ms-examples" in infoFromOperation)) {
infoFromOperation["x-ms-examples"] = {}
}
infoFromOperation["x-ms-examples"][fileName + requestMethodFromRecording + pathIndex + entryIndex] = ref
example = {};
example["parameters"] = {}
example["responses"] = {}
params = infoFromOperation["parameters"]
for (var param in pathParamsValues) {
example['parameters'][param] = pathParamsValues[param]
}
for (var param in queryParams) {
example['parameters'][param] = queryParams[param]
}
for (var param in infoFromOperation["parameters"]) {
if (params[param]["in"] == "body") {
bodyParamName = params[param]["name"]
bodyParamValue = entries[entry]["RequestBody"]
bodyParamExample = {};
bodyParamExample[bodyParamName] = bodyParamValue
if (bodyParamValue != "") {
example['parameters'][bodyParamName] = JSON.parse(bodyParamValue)
}
else {
example['parameters'][bodyParamName] = ""
}
}
}
responses = infoFromOperation["responses"]
for (var response in responses) {
statusCodeFromRecording = entries[entry]["StatusCode"]
responseBody = entries[entry]["ResponseBody"]
example['responses'][statusCodeFromRecording] = {}
if (responseBody != "") {
example['responses'][statusCodeFromRecording]['body'] = JSON.parse(responseBody)
}
else {
example['responses'][statusCodeFromRecording]['body'] = ""
}
}
fs.writeFile(outputExamples + exampleFileName, JSON.stringify(example, null, 2))
}
}
}
}
}
fs.writeFile(outputSwagger, JSON.stringify(swaggerObject, null, 2))
}
catch (err) {
accErrors[recordingFileName] = err.toString()
}
}
if (JSON.stringify(accErrors) != "{}") {
console.log()
console.log("---> Errors loading/parsing recording files:")
console.log(JSON.stringify(accErrors))
}
})
.catch(function (err) {
console.error(err)
;
})