Skip to content

Commit 636f3db

Browse files
author
Vishal Shingala
committed
Fixed issue causing incorrect suggested fixes for params in validation
1 parent 3cc2185 commit 636f3db

File tree

3 files changed

+96
-34
lines changed

3 files changed

+96
-34
lines changed

lib/schemaUtils.js

Lines changed: 76 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2810,6 +2810,43 @@ module.exports = {
28102810
return jsonContentType;
28112811
},
28122812

2813+
/**
2814+
* Converts existing JSON values of mismatch objects to serialised value based on
2815+
* serilasation params defined in schema.
2816+
*
2817+
* @param {Array} mismatches - Array of mismatch objects
2818+
* @param {Array} resolvedSchemaParams - All resolved schema params
2819+
* @param {Object} components - Components in the spec that the schema might refer to
2820+
* @param {Object} schemaCache - object storing schemaFaker and schmeResolution caches
2821+
* @param {Object} options - Global options
2822+
* @returns {Array} - Array of mismatch objects with updated value
2823+
*/
2824+
convertToSerialisedValues: function (mismatches, resolvedSchemaParams, components, schemaCache, options) {
2825+
// fetches property name from schem path
2826+
let getPropNameFromSchemPath = (schemaPath) => {
2827+
let regex = /\.properties\[(.+)\]/gm;
2828+
return _.last(regex.exec(schemaPath));
2829+
};
2830+
2831+
return _.map(mismatches, (mismatchObj) => {
2832+
if (!_.isEmpty(mismatchObj)) {
2833+
let propertyName = getPropNameFromSchemPath(mismatchObj.schemaJsonPath),
2834+
schemaParam = _.find(resolvedSchemaParams, (param) => { return param.name === propertyName; }),
2835+
serializedParamValue;
2836+
2837+
if (schemaParam) {
2838+
// serialize param value (to be used in suggested value)
2839+
serializedParamValue = _.get(this.convertParamsWithStyle(schemaParam, _.get(mismatchObj,
2840+
'suggestedFix.suggestedValue'), PARAMETER_SOURCE.REQUEST, components, schemaCache, options),
2841+
'[0].value');
2842+
_.set(mismatchObj, 'suggestedFix.actualValue', schemaParam.actualValue);
2843+
_.set(mismatchObj, 'suggestedFix.suggestedValue', serializedParamValue);
2844+
}
2845+
}
2846+
return mismatchObj;
2847+
});
2848+
},
2849+
28132850
/**
28142851
*
28152852
* @param {String} property - one of QUERYPARAM, PATHVARIABLE, HEADER, BODY, RESPONSE_HEADER, RESPONSE_BODY
@@ -3355,7 +3392,8 @@ module.exports = {
33553392
resolvedSchemaParams.push({
33563393
name: propName,
33573394
schema: propSchema,
3358-
isResolvedParam: true,
3395+
required: param.required || false, // treat exploded param as required if parent param is required
3396+
isResolvedParam: !_.includes(['array', 'object'], _.get(propSchema, 'type')),
33593397
pathPrefix
33603398
});
33613399
});
@@ -3389,10 +3427,21 @@ module.exports = {
33893427
// assign parameter example(s) as schema examples;
33903428
this.assignParameterExamples(schemaParam);
33913429

3392-
if (!schemaParam.isResolvedParam) {
3430+
if (schemaParam.isResolvedParam === false) {
3431+
// simply parse value which will be not serialised and is stringified
3432+
try {
3433+
resolvedParamValue = JSON.parse(pQuery.value);
3434+
}
3435+
catch (err) {
3436+
console.warn(`Unable to parse value for parameter ${schemaParam.name}`);
3437+
}
3438+
}
3439+
else if (!schemaParam.isResolvedParam) {
33933440
resolvedParamValue = this.deserialiseParamValue(schemaParam, pQuery.value, PARAMETER_SOURCE.REQUEST,
33943441
components, schemaCache);
33953442
}
3443+
// store existing value to be used in mismatch object
3444+
schemaParam.actualValue = pQuery.value;
33963445

33973446
// query found in spec. check query's schema
33983447
setTimeout(() => {
@@ -3414,7 +3463,7 @@ module.exports = {
34143463
let mismatches = [],
34153464
mismatchObj;
34163465

3417-
_.each(_.filter(schemaParams, (q) => { return q.required; }), (qp) => {
3466+
_.each(_.filter(resolvedSchemaParams, (q) => { return q.required; }), (qp) => {
34183467
if (!_.find(requestQueryParams, (param) => { return param.key === qp.name; })) {
34193468

34203469
// assign parameter example(s) as schema examples;
@@ -3443,7 +3492,11 @@ module.exports = {
34433492
mismatches.push(mismatchObj);
34443493
}
34453494
});
3446-
return callback(null, _.concat(_.flatten(res), mismatches));
3495+
3496+
mismatches = this.convertToSerialisedValues(_.concat(_.flatten(res), mismatches), resolvedSchemaParams,
3497+
components, schemaCache, options);
3498+
3499+
return callback(null, mismatches);
34473500
});
34483501
},
34493502

@@ -3864,7 +3917,8 @@ module.exports = {
38643917
resolvedSchemaParams.push({
38653918
name: key,
38663919
schema: value,
3867-
isResolvedParam: true
3920+
required: resolvedProp.required || false, // treat exploded param as required if parent param is required
3921+
isResolvedParam: !_.includes(['array', 'object'], _.get(propSchema, 'type'))
38683922
});
38693923
});
38703924
}
@@ -3894,7 +3948,16 @@ module.exports = {
38943948
return cb(null, mismatches);
38953949
}
38963950

3897-
if (!schemaParam.isResolvedParam) {
3951+
if (schemaParam.isResolvedParam === false) {
3952+
// simply parse value which will be not serialised and is stringified
3953+
try {
3954+
resolvedParamValue = JSON.parse(uParam.value);
3955+
}
3956+
catch (err) {
3957+
console.warn(`Unable to parse value for parameter ${schemaParam.name}`);
3958+
}
3959+
}
3960+
else if (!schemaParam.isResolvedParam) {
38983961
resolvedParamValue = this.deserialiseParamValue(schemaParam, uParam.value, PARAMETER_SOURCE.REQUEST,
38993962
components, schemaCache);
39003963
}
@@ -3919,30 +3982,7 @@ module.exports = {
39193982
}, 0);
39203983
}, (err, res) => {
39213984
let mismatches = [],
3922-
mismatchObj,
3923-
// fetches property name from schem path
3924-
getPropNameFromSchemPath = (schemaPath) => {
3925-
let regex = /\.properties\[(.+)\]/gm;
3926-
return _.last(regex.exec(schemaPath));
3927-
};
3928-
3929-
// update actual value and suggested value from JSON to serialized strings
3930-
_.forEach(_.flatten(res), (mismatchObj) => {
3931-
if (!_.isEmpty(mismatchObj)) {
3932-
let propertyName = getPropNameFromSchemPath(mismatchObj.schemaJsonPath),
3933-
schemaParam = _.find(resolvedSchemaParams, (param) => { return param.name === propertyName; }),
3934-
serializedParamValue;
3935-
3936-
if (schemaParam) {
3937-
// serialize param value (to be used in suggested value)
3938-
serializedParamValue = _.get(this.convertParamsWithStyle(schemaParam, _.get(mismatchObj,
3939-
'suggestedFix.suggestedValue'), PARAMETER_SOURCE.REQUEST, components, schemaCache, options),
3940-
'[0].value');
3941-
_.set(mismatchObj, 'suggestedFix.actualValue', schemaParam.actualValue);
3942-
_.set(mismatchObj, 'suggestedFix.suggestedValue', serializedParamValue);
3943-
}
3944-
}
3945-
});
3985+
mismatchObj;
39463986

39473987
_.each(resolvedSchemaParams, (uParam) => {
39483988
// report mismatches only for reuired properties
@@ -3970,7 +4010,12 @@ module.exports = {
39704010
mismatches.push(mismatchObj);
39714011
}
39724012
});
3973-
return callback(null, _.concat(_.flatten(res), mismatches));
4013+
4014+
// update actual value and suggested value from JSON to serialized strings
4015+
mismatches = this.convertToSerialisedValues(_.concat(_.flatten(res), mismatches), resolvedSchemaParams,
4016+
components, schemaCache, options);
4017+
4018+
return callback(null, mismatches);
39744019
});
39754020
}
39764021
else {

test/data/validationData/urlencodedBodySpec.yaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,27 @@ paths:
5454
propSimple:
5555
type: integer
5656
example: 123
57+
propObjectMissing:
58+
type: object
59+
properties:
60+
prop1:
61+
type: string
62+
example: hola
63+
prop2:
64+
type: string
65+
example: world!
5766
required:
58-
- status
67+
- propObjectMissing
5968
encoding:
6069
propObjectExplodable:
6170
style: form
6271
explode: true
6372
propObjectNonExplodable:
6473
style: form
6574
explode: false
75+
propObjectMissing:
76+
style: form
77+
explode: false
6678
responses:
6779
'200':
6880
description: Pet updated.

test/unit/validator.test.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -641,15 +641,15 @@ describe('VALIDATE FUNCTION TESTS ', function () {
641641
resultObj,
642642
historyRequest = [],
643643
schemaPack = new Converter.SchemaPack({ type: 'string', data: urlencodedBodySpec },
644-
{ suggestAvailableFixes: true });
644+
{ suggestAvailableFixes: true, showMissingInSchemaErrors: true });
645645

646646
getAllTransactions(JSON.parse(urlencodedBodyCollection), historyRequest);
647647

648648
schemaPack.validateTransaction(historyRequest, (err, result) => {
649649
expect(err).to.be.null;
650650
expect(result).to.be.an('object');
651651
resultObj = result.requests[historyRequest[0].id].endpoints[0];
652-
expect(resultObj.mismatches).to.have.lengthOf(3);
652+
expect(resultObj.mismatches).to.have.lengthOf(4);
653653

654654
// for explodable property of type object named "propObjectExplodable",
655655
// second property named "prop2" is incorrect, while property "prop1" is correct
@@ -666,6 +666,11 @@ describe('VALIDATE FUNCTION TESTS ', function () {
666666
expect(resultObj.mismatches[2].transactionJsonPath).to.eql('$.request.body.urlencoded[4].value');
667667
expect(resultObj.mismatches[2].suggestedFix.actualValue).to.eql('999');
668668
expect(resultObj.mismatches[2].suggestedFix.suggestedValue).to.eql('exampleString');
669+
670+
// property named "propObjectMissing" is missing in request
671+
expect(resultObj.mismatches[3].reasonCode).to.eql('MISSING_IN_REQUEST');
672+
expect(resultObj.mismatches[3].suggestedFix.key).to.eql('propObjectMissing');
673+
expect(resultObj.mismatches[3].suggestedFix.suggestedValue).to.eql('prop3,hold,prop4,world!');
669674
done();
670675
});
671676
});

0 commit comments

Comments
 (0)