Skip to content

Commit f5bebc2

Browse files
authored
feat: Added xml compare strategies (#17)
1 parent 7f4f165 commit f5bebc2

File tree

6 files changed

+136
-30
lines changed

6 files changed

+136
-30
lines changed

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ This application relies on a configuration structure stored on the configured ta
2323
| 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 |
2424
| tags | json stringifyied. dictionary of tags to be added to the tracked metrics | yes |
2525
| headers | json stringifyied. dictionary of headers to be sent in the http request | no |
26-
| bodyCompareStrategy | strategy to be used when compating received response body to `expectedBoddy`. Possible values: `contains`, `containsKeys`, `listOfTypes`, `typeOf` | no |
26+
| bodyCompareStrategy | strategy to be used when compating received response body to `expectedBoddy`. Possible values listed in the table below *Detail on compareStrategy* | no |
2727
| expectedBody | json stringifyied. expected body type/content. used in conjunction with `bodyCompareStrategy` | no |
2828

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

3535
**Detail on compareStrategy**
3636

37-
| Method | Functionality | Applied to |
38-
|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|
39-
| 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 |
40-
| 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 |
41-
| 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 |
42-
| typeOf | checks if the response type is as expected. supports all types returned by javascript `typeof` | any |
37+
| Method | Functionality | Applied to |
38+
|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|
39+
| 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 |
40+
| 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 |
41+
| 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 |
42+
| typeOf | checks if the response type is as expected. supports all types returned by javascript `typeof` | any |
43+
| xmlContains | like contains; parses the reponse xml as json and then compares it to the expected | any |
44+
| xmlContainsKeys | like containsKeys; but parses the reponse xml as json and then compares it to the expected | any |
4345

4446

4547

package-lock.json

Lines changed: 37 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "azure-synthetic-monitoring",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "Azure Synthetic monitoring",
55
"main": "./src/functions/synthetic-monitoring.js",
66
"author": "",
@@ -12,7 +12,8 @@
1212
"dependencies": {
1313
"@azure/data-tables": "^13.2.2",
1414
"applicationinsights": "^2.9.1",
15-
"axios": "^1.6.2"
15+
"axios": "^1.7.4",
16+
"fast-xml-parser": "4.0.0"
1617
},
1718
"devDependencies": {
1819
"jest": "^29.7.0"

src/comparator.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const {XMLParser} = require('fast-xml-parser');
2+
13
function compare(strategyName, actual, expected){
24
if(strategyName in strategies){
35
return strategies[strategyName](actual, expected)
@@ -7,6 +9,8 @@ function compare(strategyName, actual, expected){
79
}
810
}
911

12+
13+
1014
const contains = function (actual, expected) {
1115
let result = true;
1216
try {
@@ -109,11 +113,42 @@ const contains = function (actual, expected) {
109113
return check;
110114
}
111115

116+
117+
const xmlContains = function (actual, expected) {
118+
let result = true;
119+
try{
120+
const parser = new XMLParser();
121+
let actualParsed = parser.parse(actual);
122+
console.log(actualParsed)
123+
result = this.contains(actualParsed, expected);
124+
} catch (err) {
125+
console.error(`failed check: ${err}`)
126+
result = false;
127+
}
128+
return result;
129+
}
130+
131+
const xmlContainsKeys = function (actual, expected) {
132+
let result = true;
133+
try{
134+
const parser = new XMLParser();
135+
let actualParsed = parser.parse(actual);
136+
console.debug(actualParsed)
137+
result = this.containsKeys(actualParsed, expected);
138+
} catch (err) {
139+
console.error(`failed check: ${err}`)
140+
result = false;
141+
}
142+
return result;
143+
}
144+
112145
const strategies = {
113146
contains,
114147
containsKeys,
115148
listOfTypes,
116-
typeOf
149+
typeOf,
150+
xmlContains,
151+
xmlContainsKeys
117152
}
118153

119154

tests/comparator.test.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,29 @@ describe('containsKeys tests', () => {
7676

7777
})
7878

79+
describe('xmlContainsKeys tests', () => {
80+
test('returns true when comparing expected objects', () => {
81+
expect(comparator.compare("xmlContainsKeys", "<key>2</key>", {key: "number"})).toBeTruthy();
82+
expect(comparator.compare("xmlContainsKeys", "<key></key><key></key>", {key: "array"})).toBeTruthy();
83+
expect(comparator.compare("xmlContainsKeys", "<key><innerKey>foo</innerKey></key>", {key: {innerKey: "string"}})).toBeTruthy();
84+
expect(comparator.compare("xmlContainsKeys", "<key><innerKey>foo</innerKey><innerKey>bar</innerKey></key>", {key: {innerKey: "array"}})).toBeTruthy();
85+
expect(comparator.compare("xmlContainsKeys", "<key1>stringValue</key1><key1>stringValue2</key1><key2>2</key2><key2>3</key2>", {key1: ['string'], key2: ['number']})).toBeTruthy();
86+
});
87+
88+
test('returns false when comparing unexpected objects', () => {
89+
expect(comparator.compare("xmlContainsKeys", "<key>2</key>", {key: "string"})).toBeFalsy();
90+
expect(comparator.compare("xmlContainsKeys", "<key></key><key></key>", {key: "number"})).toBeFalsy();
91+
expect(comparator.compare("xmlContainsKeys", "<key><innerKey>foo</innerKey></key>", {key: "string"})).toBeFalsy();
92+
expect(comparator.compare("xmlContainsKeys", "<key><innerKey>foo</innerKey><innerKey>bar</innerKey></key>", {key: {innerKey: "string"}})).toBeFalsy();
93+
});
94+
95+
test('returns true when comparing real soap response', () => {
96+
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>",
97+
{"soapenv:Envelope": { "soapenv:Body": { "nfp:verifyPaymentNoticeRes": {outcome: "string"} }}})).toBeTruthy();
98+
})
99+
100+
})
101+
79102

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

98121

122+
describe('xmlContains tests', () => {
123+
test('returns true when comparing expected objects', () => {
124+
expect(comparator.compare("xmlContains", "<key>2</key>", {key: 2})).toBeTruthy();
125+
expect(comparator.compare("xmlContains", "<key><innerKey>2</innerKey></key>", {key: {innerKey: 2}})).toBeTruthy();
126+
expect(comparator.compare("xmlContains", "<key><innerKey>2</innerKey></key><key2>foo</key2>", {key: {innerKey: 2}, key2: 'foo'}, {key: {innerKey: 2}})).toBeTruthy();
127+
expect(comparator.compare("xmlContains", "<key>bar</key><key2>foo</key2>", {key: 'bar'})).toBeTruthy();
128+
expect(comparator.compare("xmlContains", "<key>1</key><key>2</key>", {key: [1, 2]})).toBeTruthy();
129+
expect(comparator.compare("xmlContains", "<key><key2>1</key2></key><key><key2>2</key2></key>", {key: [{key2: 1}, {key2: 2}]})).toBeTruthy();
130+
});
131+
132+
test('returns true when comparing real soap response', () => {
133+
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>",
134+
{"soapenv:Envelope": { "soapenv:Body": { "nfp:verifyPaymentNoticeRes": {outcome: "KO"} }}})).toBeTruthy();
135+
})
136+
137+
test('returns false when comparing unexpected objects', () => {
138+
expect(comparator.compare("xmlContains", "<wrongKey>2</wrongKey>", {key: 2})).toBeFalsy();
139+
expect(comparator.compare("xmlContains", "<key><innerKey>2</innerKey></key>", {key: {innerKey: 3}})).toBeFalsy();
140+
//Same key but wrong type
141+
expect(comparator.compare("xmlContains", "<key></key>", {key: 2})).toBeFalsy();
142+
expect(comparator.compare("xmlContains", "<key><key2>1</key2></key><key><key2>2</key2></key>", {key: [{key2: 3}, {key2: 3}]})).toBeFalsy();
143+
});
144+
})
145+
146+
99147

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

tests/utils.test.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ describe('checkApi tests', () => {
385385

386386

387387
test('enrich context with cert data when response ok and checkCert true', () => {
388+
let expirationDate = datePlusDays(10)
388389
let dummyHttpResponse = {
389390
status : 200,
390391
RESPONSE_TIME: 1234,
@@ -394,7 +395,7 @@ describe('checkApi tests', () => {
394395
res: {
395396
socket: {
396397
getPeerCertificate: function (booleanValue){
397-
return {valid_to: datePlusDays(10)}
398+
return {valid_to: expirationDate}
398399
}
399400
}
400401
}
@@ -411,7 +412,7 @@ describe('checkApi tests', () => {
411412
success:true,
412413
certSuccess:1,
413414
targetExpireInDays:10,
414-
targetExpirationTimestamp:1644534000000,
415+
targetExpirationTimestamp: 1644534000000,
415416
runLocation:"private-cert"
416417
},
417418

0 commit comments

Comments
 (0)