iotagent-node-lib 3.4.4 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +4 -0
  2. package/doc/admin.md +1 -13
  3. package/doc/api.md +116 -18
  4. package/doc/devel/architecture.md +0 -12
  5. package/doc/index.md +1 -1
  6. package/doc/roadmap.md +22 -10
  7. package/lib/commonConfig.js +0 -11
  8. package/lib/errors.js +2 -2
  9. package/lib/model/Device.js +2 -1
  10. package/lib/model/Group.js +2 -1
  11. package/lib/model/dbConn.js +22 -11
  12. package/lib/plugins/expressionPlugin.js +0 -5
  13. package/lib/plugins/jexlParser.js +15 -31
  14. package/lib/services/common/genericMiddleware.js +14 -2
  15. package/lib/services/common/iotManagerService.js +2 -1
  16. package/lib/services/devices/deviceRegistryMongoDB.js +3 -1
  17. package/lib/services/devices/deviceService.js +16 -21
  18. package/lib/services/devices/devices-NGSI-LD.js +5 -98
  19. package/lib/services/devices/devices-NGSI-mixed.js +0 -14
  20. package/lib/services/devices/devices-NGSI-v2.js +3 -0
  21. package/lib/services/groups/groupRegistryMemory.js +0 -25
  22. package/lib/services/groups/groupRegistryMongoDB.js +20 -19
  23. package/lib/services/groups/groupService.js +3 -14
  24. package/lib/services/ngsi/entities-NGSI-LD.js +82 -7
  25. package/lib/services/ngsi/entities-NGSI-v2.js +297 -696
  26. package/lib/services/ngsi/ngsiUtils.js +0 -30
  27. package/lib/services/northBound/deviceProvisioningServer.js +6 -3
  28. package/lib/templates/createDevice.json +4 -0
  29. package/lib/templates/createDeviceLax.json +4 -0
  30. package/lib/templates/deviceGroup.json +4 -0
  31. package/lib/templates/updateDevice.json +4 -0
  32. package/lib/templates/updateDeviceLax.json +4 -0
  33. package/package.json +6 -2
  34. package/test/functional/README.md +378 -0
  35. package/test/functional/config-test.js +70 -0
  36. package/test/functional/functional-tests-runner.js +126 -0
  37. package/test/functional/functional-tests.js +241 -0
  38. package/test/functional/testCases.js +2944 -0
  39. package/test/functional/testUtils.js +251 -0
  40. package/test/tools/utils.js +25 -0
  41. package/test/unit/mongodb/mongodb-connectionoptions-test.js +35 -22
  42. package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json +3 -34
  43. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin6.json +8 -1
  44. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin7.json +1 -4
  45. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin8.json +1 -6
  46. package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +67 -87
  47. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +7 -13
  48. package/test/unit/ngsi-ld/lazyAndCommands/merge-patch-test.js +43 -43
  49. package/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js +19 -29
  50. package/test/unit/ngsi-ld/ngsiService/languageProperties-test.js +0 -1
  51. package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +35 -46
  52. package/test/unit/ngsi-ld/plugins/alias-plugin_test.js +8 -9
  53. package/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js +96 -221
  54. package/test/unit/ngsi-ld/provisioning/device-registration_test.js +18 -27
  55. package/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +8 -16
  56. package/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js +0 -13
  57. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin8.json +4 -4
  58. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29b.json +8 -0
  59. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin30.json +1 -1
  60. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +0 -6
  61. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +8 -0
  62. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34b.json +14 -0
  63. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +1 -11
  64. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36b.json +13 -0
  65. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin37.json +8 -0
  66. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +1 -11
  67. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin10b.json +37 -0
  68. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin11.json +0 -4
  69. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +0 -4
  70. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +0 -4
  71. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +4 -0
  72. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json +0 -3
  73. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin5.json +10 -12
  74. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json +0 -4
  75. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json +1 -5
  76. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin8.json +8 -12
  77. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +0 -4
  78. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +0 -8
  79. package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributesMetadata.json +7 -1
  80. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +898 -28
  81. package/test/unit/ngsiv2/ngsiService/active-devices-test.js +0 -4
  82. package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +267 -0
  83. package/test/unit/ngsiv2/plugins/alias-plugin_test.js +19 -21
  84. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +21 -24
  85. package/test/unit/ngsiv2/provisioning/device-group-utils-test.js +1 -21
  86. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +4 -6
  87. package/CHANGES_NEXT_RELEASE +0 -0
  88. package/test/unit/ngsi-ld/ngsiService/autocast-test.js +0 -438
  89. package/test/unit/ngsi-ld/ngsiService/geoproperties-test.js +0 -381
  90. package/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js +0 -311
  91. package/test/unit/ngsiv2/ngsiService/autocast-test.js +0 -325
  92. package/test/unit/ngsiv2/ngsiService/geoproperties-test.js +0 -427
  93. package/test/unit/ngsiv2/plugins/compress-timestamp-plugin_test.js +0 -217
  94. package/test/unit/ngsiv2/plugins/timestamp-processing-plugin_test.js +0 -119
  95. package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +0 -309
@@ -89,35 +89,6 @@ function isFloat(value) {
89
89
  return !isNaN(value) && value.toString().indexOf('.') !== -1;
90
90
  }
91
91
 
92
- /**
93
- * It casts attribute values which are reported using JSON parsing
94
- *
95
- * @param {String} payload The payload
96
- * @return {String} New payload where attributes's values are casted to the corresponding JSON values
97
- */
98
- function castJsonNativeAttributes(payload) {
99
- if (!config.getConfig().autocast) {
100
- return payload;
101
- }
102
-
103
- for (const key in payload) {
104
- if (
105
- /* eslint-disable-next-line no-prototype-builtins */
106
- payload.hasOwnProperty(key) &&
107
- payload[key].value &&
108
- typeof payload[key].value === 'string'
109
- ) {
110
- try {
111
- const parsedValue = JSON.parse(payload[key].value);
112
- payload[key].value = parsedValue;
113
- } catch (e) {
114
- // Keep value as is
115
- }
116
- }
117
- }
118
- return payload;
119
- }
120
-
121
92
  /**
122
93
  * Create the request object used to communicate with the Context Broker, adding security and service information.
123
94
  *
@@ -230,7 +201,6 @@ exports.createRequestObject = createRequestObject;
230
201
  exports.applyMiddlewares = applyMiddlewares;
231
202
  exports.getMetaData = getMetaData;
232
203
  exports.getLngLats = getLngLats;
233
- exports.castJsonNativeAttributes = castJsonNativeAttributes;
234
204
  exports.isFloat = isFloat;
235
205
  exports.updateMiddleware = updateMiddleware;
236
206
  exports.queryMiddleware = queryMiddleware;
@@ -63,7 +63,8 @@ const provisioningAPITranslation = {
63
63
  autoprovision: 'autoprovision',
64
64
  explicitAttrs: 'explicitAttrs',
65
65
  ngsiVersion: 'ngsiVersion',
66
- entityNameExp: 'entityNameExp'
66
+ entityNameExp: 'entityNameExp',
67
+ payloadType: 'payloadType'
67
68
  };
68
69
 
69
70
  /**
@@ -141,7 +142,8 @@ function handleProvision(req, res, next) {
141
142
  internalId: null,
142
143
  autoprovision: body.autoprovision,
143
144
  explicitAttrs: body.explicitAttrs,
144
- ngsiVersion: body.ngsiVersion
145
+ ngsiVersion: body.ngsiVersion,
146
+ payloadType: body.payloadType
145
147
  });
146
148
  }
147
149
 
@@ -218,7 +220,8 @@ function toProvisioningAPIFormat(device) {
218
220
  protocol: device.protocol,
219
221
  autoprovision: device.autoprovision,
220
222
  explicitAttrs: device.explicitAttrs,
221
- ngsiVersion: device.ngsiVersion
223
+ ngsiVersion: device.ngsiVersion,
224
+ payloadType: device.payloadType
222
225
  };
223
226
  }
224
227
 
@@ -43,6 +43,10 @@
43
43
  "description": "NGSI Interface for this device",
44
44
  "type": "string"
45
45
  },
46
+ "payloadType": {
47
+ "description": "Payload type allowed for measures for this device",
48
+ "type": "string"
49
+ },
46
50
  "lazy": {
47
51
  "description": "list of lazy attributes of the devices",
48
52
  "type": "array",
@@ -43,6 +43,10 @@
43
43
  "description": "NGSI Interface for this device",
44
44
  "type": "string"
45
45
  },
46
+ "payloadType": {
47
+ "description": "Payload type allowed for measures for this device",
48
+ "type": "string"
49
+ },
46
50
  "lazy": {
47
51
  "description": "list of lazy attributes of the devices",
48
52
  "type": "array",
@@ -41,6 +41,10 @@
41
41
  "description": "NGSI Interface for this group of devices",
42
42
  "type": "string"
43
43
  },
44
+ "payloadType": {
45
+ "description": "Payload type allowed for measures for this group",
46
+ "type": "string"
47
+ },
44
48
  "attributes": {
45
49
  "description": "list of active attributes of the devices",
46
50
  "type": "array"
@@ -210,6 +210,10 @@
210
210
  "ngsiVersion": {
211
211
  "description": "NGSI Interface for this device",
212
212
  "type": "string"
213
+ },
214
+ "payloadType": {
215
+ "description": "Payload type allowed for measures for this device",
216
+ "type": "string"
213
217
  }
214
218
  }
215
219
  }
@@ -165,6 +165,10 @@
165
165
  "ngsiVersion": {
166
166
  "description": "NGSI Interface for this device",
167
167
  "type": "string"
168
+ },
169
+ "payloadType": {
170
+ "description": "Payload type allowed for measures for this device",
171
+ "type": "string"
168
172
  }
169
173
  }
170
174
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "iotagent-node-lib",
3
3
  "license": "AGPL-3.0-only",
4
4
  "description": "IoT Agent library to interface with NGSI Context Broker",
5
- "version": "3.4.4",
5
+ "version": "4.0.1",
6
6
  "homepage": "https://github.com/telefonicaid/iotagent-node-lib",
7
7
  "keywords": [
8
8
  "fiware",
@@ -33,6 +33,7 @@
33
33
  "prettier": "prettier --config .prettierrc.json --write '**/**/**/**/*.js' '**/**/**/*.js' '**/**/*.js' '**/*.js' '*.js'",
34
34
  "prettier:text": "prettier 'README.md' 'doc/*.md' 'doc/**/*.md' --no-config --tab-width 4 --print-width 120 --write --prose-wrap always",
35
35
  "test": "nyc --reporter=text mocha --recursive 'test/**/*.js' --reporter spec --timeout 8000 --ui bdd --exit --color true",
36
+ "test:functional": "nyc --reporter=text mocha --recursive 'test/functional/*.js' --reporter spec --timeout 5000 --ui bdd --exit --color true",
36
37
  "test:expression": "nyc --reporter=text mocha --recursive 'test/unit/expressions/*.js' --reporter spec --timeout 5000 --ui bdd --exit --color true",
37
38
  "test:multientity": "nyc --reporter=text mocha --recursive 'test/unit/ngsiv2/plugins/multientity-plugin_test.js' --reporter spec --timeout 5000 --ui bdd --exit --color true",
38
39
  "test:debug": "mocha --recursive 'test/**/*.js' --reporter spec --inspect-brk --timeout 30000 --ui bdd --exit",
@@ -58,6 +59,9 @@
58
59
  "uuid": "~8.3.2"
59
60
  },
60
61
  "devDependencies": {
62
+ "async-mqtt": "~2.6.3",
63
+ "chai": "~4.3.10",
64
+ "chai-match-pattern": "~1.3.0",
61
65
  "coveralls": "~3.1.1",
62
66
  "eslint": "~8.18.0",
63
67
  "eslint-config-tamia": "~8.0.0",
@@ -65,7 +69,7 @@
65
69
  "husky": "~4.2.5",
66
70
  "lint-staged": "~12.3.8",
67
71
  "mocha": "10.0.0",
68
- "mongodb": "4.17.0",
72
+ "mongodb": "4.17.1",
69
73
  "nock": "13.2.7",
70
74
  "nyc": "~15.1.0",
71
75
  "prettier": "~2.7.1",
@@ -0,0 +1,378 @@
1
+ ## Functional test suite
2
+
3
+ This directory contains the functional test suite for the IoTA Node Lib. This test suite is based on mocha and chai. For
4
+ mocks, we use the nock library. Additionally, it uses some specific functions to ease to implement the test. Helper
5
+ functions are located in the `testUtils.js` file.
6
+
7
+ There are 2 tests files in this directory:
8
+
9
+ - `fuctional-tests.js`: This file contains the test defined in the "classic way". This means, coded in the JS file as
10
+ any other mocha test. It uses the functions defined in the `testUtils.js` file to simplify the tests.
11
+ - `functional-tests-runner.js`: This file contains the test runner that executes the tests defined as JSON in a
12
+ separate file (`testCases.js`) in a "automatic way". This file is loaded by the test suite and the test cases are
13
+ automatically executed.
14
+
15
+ The recommended way is to use `testCases.js` (run by `functional-tests-runner.js`). The `fuctional-tests.js` file is
16
+ provides as basically as an example in the case the "old way" needs to be used (I.E: when the test follow a different
17
+ pattern than the one supported by the test runner).
18
+
19
+ ### Automatic test cases
20
+
21
+ Each test case is defined as a JSON object in the `testCases.js` file. This file is loaded by the test suite and the
22
+ test cases are automatically generated. Each test case is defined as an object with the following elements:
23
+
24
+ - `describeName`: The name of the `DESCRIBE` test case. This will be used to generate the test case name in the mocha. Note this name is prefixed by a pure number (e.g `0010 - Simple group without attributes`) which specifies the group to which the test belong (usually meaning a feature) or by a number preced by the `#` symbol to refer to an issue number (e.g. `#1234 - Bug foobar`).
25
+ test suite.
26
+ - `provision`: The JSON object that will be sent to the IoTA JSON provisioning API. This will be used to create the
27
+ group. It contains the following elements:
28
+ - `url`: The URL of the provisioning API (group)
29
+ - `method`: The HTTP method to use (POST)
30
+ - `json`: The JSON object that defines the group
31
+ - `headers`: The headers to send to the provisioning API. This should contain the `fiware-service` and
32
+ `fiware-servicepath` headers.
33
+ - `skip`: optional. If set to `true`, the test case (`describe`) will be skipped. This is useful to skip test
34
+ cases that are not supported by the agent. It can also have a string value `"lib"`. This will skip the test case
35
+ only if the is executed in the IoTA Node lib repo. This is useful to skip test cases that are not supported by
36
+ the lib (I.E: all tests related to the transport).
37
+ - `should`: The array of test cases to execute. Each test case is defined as an object with the following elements:
38
+ - `transport`: The transport to use to send the measure. This can be `HTTP` or `MQTT`. It uses `HTTP` by default
39
+ or if the `transport` element is not defined. See the "Advanced features" section for more information.
40
+ - `shouldName`: The name of the `IT` test case. This will be used to generate the test case name in the mocha test
41
+ suite.
42
+ - `type`: The type of the test case. This can be `single` or `multientity`. See the "Advanced features" section
43
+ for more information.
44
+ - `measure`: The JSON object that will be sent to the IoTA JSON measure API. This will be used to send the
45
+ measure. It contains the following elements:
46
+ - `url`: The URL of the measure API (group)
47
+ - `method`: The HTTP method to use (POST)
48
+ - `qs`: The query string to send to the measure API. This should contain the `i` and `k` parameters.
49
+ - `json`: The JSON object that defines the measure
50
+ - `expectation`: The JSON object that defines the expectation. This will be used to check that the measure has
51
+ been correctly sent to the Context Broker.
52
+ - `loglevel`: optional. If set to `debug`, the agent will log all the debug messages to the console. This is
53
+ useful to check the messages sent to the Context Broker. See the "Debugging automated tests" section for more
54
+ information.
55
+ - `skip`: optional. If set to `true`, the test case (`it`) will be skipped. Same as the `skip` element in the
56
+ `provision` element.
57
+ - `isRegex`: optional. If set to `true`, then the expectation will be treated as a regular expression. This is
58
+ useful to check that the measure has been correctly sent to the Context Broker when the measure contains a a
59
+ variable parameter like a timestamp. See the "Advanced features" section for more information.
60
+
61
+ #### Example
62
+
63
+ ```javascript
64
+ {
65
+ describeName: 'Basic group provision with attributes',
66
+ provision: {
67
+ url: 'http://localhost:' + config.iota.server.port + '/iot/services',
68
+ method: 'POST',
69
+ json: {
70
+ services: [
71
+ {
72
+ resource: '/iot/json',
73
+ apikey: '123456',
74
+ entity_type: 'TheLightType2',
75
+ cbHost: 'http://192.168.1.1:1026',
76
+ commands: [],
77
+ lazy: [],
78
+ attributes: [
79
+ {
80
+ object_id: 's',
81
+ name: 'status',
82
+ type: 'Boolean'
83
+ },
84
+ {
85
+ object_id: 't',
86
+ name: 'temperature',
87
+ type: 'Number'
88
+ }
89
+ ],
90
+ static_attributes: []
91
+ }
92
+ ]
93
+ },
94
+ headers: {
95
+ 'fiware-service': 'smartgondor',
96
+ 'fiware-servicepath': '/gardens'
97
+ }
98
+ },
99
+ should:[
100
+ {
101
+ shouldName: 'should send its value to the Context Broker',
102
+ config:{
103
+ type: 'single'
104
+ },
105
+ measure: {
106
+ url: 'http://localhost:' + config.http.port + '/iot/json',
107
+ method: 'POST',
108
+ qs: {
109
+ i: 'MQTT_2',
110
+ k: '123456'
111
+ },
112
+ json: {
113
+ s: false,
114
+ t: 10
115
+ }
116
+ },
117
+ expectation: {
118
+ id: 'TheLightType2:MQTT_2',
119
+ type: 'TheLightType2',
120
+ temperature: {
121
+ value: 10,
122
+ type: 'Number'
123
+ },
124
+ status: {
125
+ value: false,
126
+ type: 'Boolean'
127
+ }
128
+ }
129
+ },
130
+ {
131
+ transport: 'MQTT',
132
+ shouldName: 'should send its value to the Context Broker when using MQTT',
133
+ config:{
134
+ type: 'single'
135
+ },
136
+ measure: {
137
+ url: 'http://localhost:' + config.http.port + '/iot/json',
138
+ method: 'POST',
139
+ qs: {
140
+ i: 'MQTT_2',
141
+ k: '123456'
142
+ },
143
+ json: {
144
+ s: false,
145
+ t: 10
146
+ }
147
+ },
148
+ expectation: {
149
+ id: 'TheLightType2:MQTT_2',
150
+ type: 'TheLightType2',
151
+ temperature: {
152
+ value: 10,
153
+ type: 'Number'
154
+ },
155
+ status: {
156
+ value: false,
157
+ type: 'Boolean'
158
+ }
159
+ }
160
+ }
161
+ ]
162
+ }
163
+ ```
164
+
165
+ ### Advanced features
166
+
167
+ #### Multientity
168
+
169
+ This test suite support the multientity feature. To test this feature, you need to set add to the test case the
170
+ parameter `type: 'multientity'`. This will automatically take care of the multientity feature. This means that the suite
171
+ will configure the mock to listen to `/v2/op/update` instead of `/v2/entities?options=upsert`.
172
+
173
+ In particular, it will configure the mock to listen the correct URL. You should define the expectation for the test case
174
+ as a batch operation (see the following example).
175
+
176
+ ```javascript
177
+ {
178
+ "entities": [
179
+ {
180
+ "id": "TheLightType2:MQTT_2",
181
+ "type": "TheLightType2",
182
+ "status": {
183
+ "value": false,
184
+ "type": "Boolean"
185
+ }
186
+ },
187
+ {
188
+ "id": "TheLightType2:MQTT_3",
189
+ "type": "TheLightType2",
190
+ "temperature": {
191
+ "value": 10,
192
+ "type": "Number"
193
+ }
194
+ }
195
+ ],
196
+ "actionType": "append"
197
+ }
198
+ ```
199
+
200
+ #### Multimeasures
201
+
202
+ It is also supported to test cases in which is sent more than one measure. To do so, you need to define the test case
203
+ `expectation` as an array, with one object for each measurement. Then, the suite will recognize the array length and will
204
+ expect the same number of NGSI requests. I.E:
205
+
206
+ ```js
207
+ [
208
+ {
209
+ id: 'TheLightType2:MQTT_2',
210
+ type: 'TheLightType2',
211
+ temperature: {
212
+ value: 10,
213
+ type: 'Number'
214
+ },
215
+ status: {
216
+ value: false,
217
+ type: 'Boolean'
218
+ }
219
+ },
220
+ {
221
+ id: 'TheLightType2:MQTT_2',
222
+ type: 'TheLightType2',
223
+ temperature: {
224
+ value: 20,
225
+ type: 'Number'
226
+ },
227
+ status: {
228
+ value: true,
229
+ type: 'Boolean'
230
+ }
231
+ }
232
+ ];
233
+ ```
234
+
235
+ You also should define the measure as multimeasure. This is done by defining the `measure` JSON element as an array of
236
+ objects. Each object will be a measure that will be sent to the Context Broker in a different request. I.E:
237
+
238
+ ```javascript
239
+ measure: {
240
+ url: 'http://localhost:' + config.http.port + '/iot/json',
241
+ method: 'POST',
242
+ qs: {
243
+ i: 'MQTT_2',
244
+ k: '123456'
245
+ },
246
+ json: [
247
+ {
248
+ s: false,
249
+ t: 10
250
+ },
251
+ {
252
+ s: true,
253
+ t: 20
254
+ }
255
+ ]
256
+ }
257
+ ```
258
+
259
+ #### Transport
260
+
261
+ The test suite supports using the internal node lib function `iotAgentLib.update`, `HTTP` or `MQTT` for measure sending.
262
+ In order to select the specific way to send the measure you should add a `transport` element to each should case having
263
+ the value set to `MQTT`. By doing so, the suite will automatically configure the mock to connect to the MQTT broker and
264
+ send the measure to the correct topic based on the `i` and `k` parameters. It will ignore the `url` and `method`
265
+ parameters present in the measure JSON element. I.E:
266
+
267
+ ```javascript
268
+ should: [
269
+ {
270
+ transport: 'MQTT',
271
+ shouldName: 'should send its value to the Context Broker when using MQTT',
272
+ type: 'single',
273
+ measure: {
274
+ url: 'http://localhost:' + config.http.port + '/iot/json',
275
+ method: 'POST',
276
+ qs: {
277
+ i: 'MQTT_2',
278
+ k: '123456'
279
+ },
280
+ json: {
281
+ s: false,
282
+ t: 10
283
+ }
284
+ },
285
+ expectation: {
286
+ id: 'TheLightType2:MQTT_2',
287
+ type: 'TheLightType2',
288
+ temperature: {
289
+ value: 10,
290
+ type: 'Number'
291
+ },
292
+ status: {
293
+ value: false,
294
+ type: 'Boolean'
295
+ }
296
+ }
297
+ }
298
+ ];
299
+ ```
300
+
301
+ #### No payload reception
302
+
303
+ The test suite also supports the case in which the Context Broker does not receive any payload. This is done by defining
304
+ the expectation as an empty object. I.E:
305
+
306
+ ```javascript
307
+ ...
308
+ expectation: []
309
+ ...
310
+ ```
311
+
312
+ Note that this means the CB *must not* receive any payload. In other words, if the CB would receive any payload, the test will fail.
313
+
314
+ ### Debugging automated tests
315
+
316
+ It is possible to debug the automated tests by using the loglevel parameter set to `debug` for each should case. This
317
+ parameter configures the IoTA log level. By setting it to `debug`, the agent will log all the debug messages to the
318
+ console. This is useful to check the messages sent to the Context Broker.
319
+
320
+ It is also useful to debug the test by adding a breakpoint in the `testUtils.js` (read the comments in the file to know
321
+ where to add the breakpoint). This will allow you to debug just that particular test case stopping the execution in the
322
+ breakpoint.
323
+
324
+ Example of a test case with the loglevel set to `debug`:
325
+
326
+ ```javascript
327
+ should:[
328
+ {
329
+ shouldName: 'should send its value to the Context Broker when using MQTT',
330
+ loglevel: 'debug',
331
+ transport: 'MQTT',
332
+ config:{
333
+ type: 'single'
334
+ },
335
+ measure: {...},
336
+ expectation: {...}
337
+ }
338
+ ]
339
+ ```
340
+
341
+ ### Using expressions in the expectation
342
+
343
+ It is possible to use expressions in the expectation. This is useful to check that the measure has been correctly sent
344
+ to the Context Broker when the measure contains a variable parameter like a timestamp. To do so, you need to set the
345
+ `isRegex` parameter to `true` in the test case. This will tell the test suite that the expectation can contain some
346
+ expressions. The expression support is based on [Chai match pattern plugin](https://github.com/mjhm/chai-match-pattern).
347
+ This plugin relies on [loadash match pattern](https://github.com/mjhm/lodash-match-pattern) to support the expressions.
348
+ For further information about the expression support, check the documentation of the previous links.
349
+
350
+ Even if setting the `isRegex` parameter to `true` make the test pass if the expectation does not contain any expression,
351
+ it is recommended to do not set this parameter to `true` if the expectation does not contain any expression because the
352
+ test result will be less clear if fails (it will show the error message of the expression library instead of the
353
+ expected value).
354
+
355
+ Here, you can find an example of a test case using expressions:
356
+
357
+ ```javascript
358
+ expectation: {
359
+ id: globalEnv.entity_name,
360
+ type: globalEnv.entity_type,
361
+ attr_a: {
362
+ value: 21,
363
+ type: 'Number',
364
+ metadata: {
365
+ TimeInstant: {
366
+ type: 'DateTime',
367
+ value: _.isDateString
368
+ }
369
+ }
370
+ },
371
+ TimeInstant: {
372
+ type: 'DateTime',
373
+ value: _.isDateString
374
+ }
375
+ }
376
+ ```
377
+
378
+ The previous example will check that the `TimeInstant` value and `attr_a.metadata.TimeInstant.value` are valid date.
@@ -0,0 +1,70 @@
1
+ /*
2
+ * Copyright 2023 Telefonica Investigación y Desarrollo, S.A.U
3
+ *
4
+ * This file is part of iotagent-json
5
+ *
6
+ * iotagent-json is free software: you can redistribute it and/or
7
+ * modify it under the terms of the GNU Affero General Public License as
8
+ * published by the Free Software Foundation, either version 3 of the License,
9
+ * or (at your option) any later version.
10
+ *
11
+ * iotagent-json is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
+ * See the GNU Affero General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Affero General Public
17
+ * License along with iotagent-json.
18
+ * If not, seehttp://www.gnu.org/licenses/.
19
+ *
20
+ * For those usages not covered by the GNU Affero General Public License
21
+ * please contact with::[contacto@tid.es]
22
+ *
23
+ * Modified by: Miguel Angel Pedraza
24
+ */
25
+
26
+ /* eslint-disable no-unused-vars */
27
+
28
+ const config = {};
29
+
30
+ config.mqtt = {
31
+ host: 'localhost',
32
+ port: 1883
33
+ };
34
+
35
+ config.http = {
36
+ port: 7896,
37
+ host: 'localhost'
38
+ };
39
+
40
+ config.amqp = {
41
+ port: 5672,
42
+ exchange: 'amq.topic',
43
+ queue: 'iota_queue',
44
+ options: { durable: true }
45
+ };
46
+
47
+ config.iota = {
48
+ logLevel: 'FATAL',
49
+ contextBroker: {
50
+ host: '192.168.1.1',
51
+ port: '1026',
52
+ ngsiVersion: 'v2'
53
+ },
54
+ server: {
55
+ port: 4041,
56
+ host: 'localhost'
57
+ },
58
+ deviceRegistry: {
59
+ type: 'memory'
60
+ },
61
+ service: 'smartgondor',
62
+ subservice: '/gardens',
63
+ providerUrl: 'http://localhost:4041',
64
+ types: {}
65
+ };
66
+
67
+ config.defaultKey = '1234';
68
+ config.defaultTransport = 'MQTT';
69
+
70
+ module.exports = config;