Skip to content

Commit

Permalink
added xml compare strategies
Browse files Browse the repository at this point in the history
  • Loading branch information
mamari90 committed Dec 4, 2024
1 parent 7f4f165 commit 14998cf
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 23 deletions.
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ This application relies on a configuration structure stored on the configured ta
| durationLimit | number. threshold, in milliseconds, over which a response time will trigger a failed availability test. to not be confused with `HTTP_CLIENT_TIMEOUT` env variable | yes |
| tags | json stringifyied. dictionary of tags to be added to the tracked metrics | yes |
| headers | json stringifyied. dictionary of headers to be sent in the http request | no |
| bodyCompareStrategy | strategy to be used when compating received response body to `expectedBoddy`. Possible values: `contains`, `containsKeys`, `listOfTypes`, `typeOf` | no |
| bodyCompareStrategy | strategy to be used when compating received response body to `expectedBoddy`. Possible values listed in the table below *Detail on compareStrategy* | no |
| expectedBody | json stringifyied. expected body type/content. used in conjunction with `bodyCompareStrategy` | no |

Note on the `type`: any value is accepted, it will be traced in the application insight availability panel as "runLocation".
Expand All @@ -34,12 +34,14 @@ suggested values are:

**Detail on compareStrategy**

| Method | Functionality | Applied to |
|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|
| contains | checks if all the fields defined in the expected body are present in the actual body, and if their value are equal (recursively). On object arrays, checks if the received array has exactly the same element of the expected, using this `contains` on each element for comparison. On primitive arrays, checks if all the expected elements are included n the received, using `Array.includes()` for comparison | objects |
| containsKeys | checks if all the fields defined in the expected body are present in the actual body, and if their value are of the expected type (recursively). Values associable to object keys: `bool` `string` `number` `array`, `object`. You can also define the array content type, using `["number"]` | objects |
| listOfTypes | checks if the response is a list containing the types defined in the `body` field. Uses the `containsKeys` logic to check each element of the list | array |
| typeOf | checks if the response type is as expected. supports all types returned by javascript `typeof` | any |
| Method | Functionality | Applied to |
|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|
| contains | checks if all the fields defined in the expected body are present in the actual body, and if their value are equal (recursively). On object arrays, checks if the received array has exactly the same element of the expected, using this `contains` on each element for comparison. On primitive arrays, checks if all the expected elements are included n the received, using `Array.includes()` for comparison | objects |
| containsKeys | checks if all the fields defined in the expected body are present in the actual body, and if their value are of the expected type (recursively). Values associable to object keys: `bool` `string` `number` `array`, `object`. You can also define the array content type, using `["number"]` | objects |
| listOfTypes | checks if the response is a list containing the types defined in the `body` field. Uses the `containsKeys` logic to check each element of the list | array |
| typeOf | checks if the response type is as expected. supports all types returned by javascript `typeof` | any |
| xmlContains | like contains; parses the reponse xml as json and then compares it to the expected | any |
| xmlContainsKeys | like containsKeys; but parses the reponse xml as json and then compares it to the expected | any |



Expand Down
46 changes: 32 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"dependencies": {
"@azure/data-tables": "^13.2.2",
"applicationinsights": "^2.9.1",
"axios": "^1.6.2"
"axios": "^1.6.2",
"fast-xml-parser": "4.0.0"
},
"devDependencies": {
"jest": "^29.7.0"
Expand Down
38 changes: 37 additions & 1 deletion src/comparator.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const {XMLParser} = require('fast-xml-parser');

function compare(strategyName, actual, expected){
if(strategyName in strategies){
return strategies[strategyName](actual, expected)
Expand All @@ -7,6 +9,8 @@ function compare(strategyName, actual, expected){
}
}



const contains = function (actual, expected) {
let result = true;
try {
Expand Down Expand Up @@ -109,11 +113,43 @@ const contains = function (actual, expected) {
return check;
}


const xmlContains = function (actual, expected) {
let result = true;
try{
const parser = new XMLParser();
let actualParsed = parser.parse(actual);
console.log(actualParsed)
result = this.contains(actualParsed, expected);
} catch (err) {
console.error(`failed check: ${err}`)
result = false;
}
return result;
}

const xmlContainsKeys = function (actual, expected) {
let result = true;
try{
const parser = new XMLParser();
let actualParsed = parser.parse(actual);
console.log("#####")
console.log(actualParsed)
result = this.containsKeys(actualParsed, expected);
} catch (err) {
console.error(`failed check: ${err}`)
result = false;
}
return result;
}

const strategies = {
contains,
containsKeys,
listOfTypes,
typeOf
typeOf,
xmlContains,
xmlContainsKeys
}


Expand Down
48 changes: 48 additions & 0 deletions tests/comparator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,29 @@ describe('containsKeys tests', () => {

})

describe('xmlContainsKeys tests', () => {
test('returns true when comparing expected objects', () => {
expect(comparator.compare("xmlContainsKeys", "<key>2</key>", {key: "number"})).toBeTruthy();
expect(comparator.compare("xmlContainsKeys", "<key></key><key></key>", {key: "array"})).toBeTruthy();
expect(comparator.compare("xmlContainsKeys", "<key><innerKey>foo</innerKey></key>", {key: {innerKey: "string"}})).toBeTruthy();
expect(comparator.compare("xmlContainsKeys", "<key><innerKey>foo</innerKey><innerKey>bar</innerKey></key>", {key: {innerKey: "array"}})).toBeTruthy();
expect(comparator.compare("xmlContainsKeys", "<key1>stringValue</key1><key1>stringValue2</key1><key2>2</key2><key2>3</key2>", {key1: ['string'], key2: ['number']})).toBeTruthy();
});

test('returns false when comparing unexpected objects', () => {
expect(comparator.compare("xmlContainsKeys", "<key>2</key>", {key: "string"})).toBeFalsy();
expect(comparator.compare("xmlContainsKeys", "<key></key><key></key>", {key: "number"})).toBeFalsy();
expect(comparator.compare("xmlContainsKeys", "<key><innerKey>foo</innerKey></key>", {key: "string"})).toBeFalsy();
expect(comparator.compare("xmlContainsKeys", "<key><innerKey>foo</innerKey><innerKey>bar</innerKey></key>", {key: {innerKey: "string"}})).toBeFalsy();
});

test('returns true when comparing real soap response', () => {
expect(comparator.compare("xmlContainsKeys", "<?xml version='1.0' encoding='UTF-8' standalone='no' ?><soapenv:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:soapenv='http://schemas.xmlsoap.org/soapenvelope/' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:common='http://pagopa-api.pagopa.gov.it/xsd/common-types/v1.0.0' xmlns:nfp='http://pagopa-api.pagopa.gov.it/node/nodeForPsp.xsd'><soapenv:Body><nfp:verifyPaymentNoticeRes><outcome>KO</outcome><fault><faultCode>PPT_PAGAMENTO_DUPLICATO</faultCode><faultString>Pagamento in attesa risulta concluso al sistema pagoPA</faultString><id>NodoDeiPagamentiSPC</id><description>Pagamento duplicato</description></fault></nfp:verifyPaymentNoticeRes></soapenv:Body></soapenv:Envelope>",
{"soapenv:Envelope": { "soapenv:Body": { "nfp:verifyPaymentNoticeRes": {outcome: "string"} }}})).toBeTruthy();
})

})


describe('contains tests', () => {
test('returns true when comparing expected objects', () => {
Expand All @@ -96,6 +119,31 @@ describe('contains tests', () => {
})


describe('xmlContains tests', () => {
test('returns true when comparing expected objects', () => {
expect(comparator.compare("xmlContains", "<key>2</key>", {key: 2})).toBeTruthy();
expect(comparator.compare("xmlContains", "<key><innerKey>2</innerKey></key>", {key: {innerKey: 2}})).toBeTruthy();
expect(comparator.compare("xmlContains", "<key><innerKey>2</innerKey></key><key2>foo</key2>", {key: {innerKey: 2}, key2: 'foo'}, {key: {innerKey: 2}})).toBeTruthy();
expect(comparator.compare("xmlContains", "<key>bar</key><key2>foo</key2>", {key: 'bar'})).toBeTruthy();
expect(comparator.compare("xmlContains", "<key>1</key><key>2</key>", {key: [1, 2]})).toBeTruthy();
expect(comparator.compare("xmlContains", "<key><key2>1</key2></key><key><key2>2</key2></key>", {key: [{key2: 1}, {key2: 2}]})).toBeTruthy();
});

test('returns true when comparing real soap response', () => {
expect(comparator.compare("xmlContains", "<?xml version='1.0' encoding='UTF-8' standalone='no' ?><soapenv:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:soapenv='http://schemas.xmlsoap.org/soapenvelope/' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:common='http://pagopa-api.pagopa.gov.it/xsd/common-types/v1.0.0' xmlns:nfp='http://pagopa-api.pagopa.gov.it/node/nodeForPsp.xsd'><soapenv:Body><nfp:verifyPaymentNoticeRes><outcome>KO</outcome><fault><faultCode>PPT_PAGAMENTO_DUPLICATO</faultCode><faultString>Pagamento in attesa risulta concluso al sistema pagoPA</faultString><id>NodoDeiPagamentiSPC</id><description>Pagamento duplicato</description></fault></nfp:verifyPaymentNoticeRes></soapenv:Body></soapenv:Envelope>",
{"soapenv:Envelope": { "soapenv:Body": { "nfp:verifyPaymentNoticeRes": {outcome: "KO"} }}})).toBeTruthy();
})

test('returns false when comparing unexpected objects', () => {
expect(comparator.compare("xmlContains", "<wrongKey>2</wrongKey>", {key: 2})).toBeFalsy();
expect(comparator.compare("xmlContains", "<key><innerKey>2</innerKey></key>", {key: {innerKey: 3}})).toBeFalsy();
//Same key but wrong type
expect(comparator.compare("xmlContains", "<key></key>", {key: 2})).toBeFalsy();
expect(comparator.compare("xmlContains", "<key><key2>1</key2></key><key><key2>2</key2></key>", {key: [{key2: 3}, {key2: 3}]})).toBeFalsy();
});
})



describe('comparator main tests', () => {
test('returns false when strategy not found', () => {
Expand Down

0 comments on commit 14998cf

Please sign in to comment.