iotagent-node-lib 4.0.1 → 4.2.0
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.
- package/.github/workflows/ci.yml +2 -2
- package/.readthedocs.yml +5 -1
- package/CHANGES_NEXT_RELEASE +0 -0
- package/doc/api.md +30 -8
- package/doc/requirements.txt +2 -2
- package/docker/Mosquitto/Dockerfile +1 -1
- package/docker-compose-dev.yml +1 -1
- package/lib/constants.js +2 -1
- package/lib/fiware-iotagent-lib.js +1 -0
- package/lib/model/Group.js +2 -0
- package/lib/services/common/iotManagerService.js +3 -1
- package/lib/services/devices/deviceRegistryMongoDB.js +1 -0
- package/lib/services/devices/deviceService.js +3 -2
- package/lib/services/devices/devices-NGSI-v2.js +6 -1
- package/lib/services/groups/groupRegistryMemory.js +9 -5
- package/lib/services/groups/groupRegistryMongoDB.js +2 -0
- package/lib/services/ngsi/entities-NGSI-v2.js +6 -1
- package/lib/templates/createDevice.json +4 -0
- package/lib/templates/createDeviceLax.json +4 -0
- package/lib/templates/deviceGroup.json +8 -0
- package/lib/templates/updateDevice.json +4 -0
- package/package.json +1 -1
- package/test/functional/README.md +4 -4
- package/test/functional/functional-tests-runner.js +1 -1
- package/test/functional/testCases.js +61 -0
- package/test/functional/testUtils.js +2 -0
- package/test/unit/ngsiv2/ngsiService/active-devices-test.js +16 -0
- package/test/unit/ngsiv2/provisioning/device-group-api-test.js +8 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -45,7 +45,7 @@ jobs:
|
|
|
45
45
|
runs-on: ubuntu-latest
|
|
46
46
|
services:
|
|
47
47
|
mongodb:
|
|
48
|
-
image: mongo:
|
|
48
|
+
image: mongo:6.0
|
|
49
49
|
ports:
|
|
50
50
|
- 27017:27017
|
|
51
51
|
strategy:
|
|
@@ -72,7 +72,7 @@ jobs:
|
|
|
72
72
|
needs: unit-test
|
|
73
73
|
services:
|
|
74
74
|
mongodb:
|
|
75
|
-
image: mongo:
|
|
75
|
+
image: mongo:6.0
|
|
76
76
|
ports:
|
|
77
77
|
- 27017:27017
|
|
78
78
|
steps:
|
package/.readthedocs.yml
CHANGED
|
File without changes
|
package/doc/api.md
CHANGED
|
@@ -450,7 +450,7 @@ propagated to NGSI interface (note that in this case the value of `explicitAttrs
|
|
|
450
450
|
that looks likes a JSON). This is necessary when same attribute names are used within multiple entities. Only static
|
|
451
451
|
attributes included in that array will be propagated to NGSI interface.
|
|
452
452
|
|
|
453
|
-
Note that in the previous case show above, when selecting the object_id (with `{object_id:'active_id'}`), the attribute
|
|
453
|
+
Note that in the previous case show above, when selecting the object_id (with `{object_id:'active_id'}`), the attribute
|
|
454
454
|
must be defined. In other words, it would not work if the attribute with the corresponding `object_id`, is not defined.
|
|
455
455
|
|
|
456
456
|
Case 5:
|
|
@@ -955,6 +955,28 @@ The IOTA processes the entity attributes looking for a `TimeInstant` attribute.
|
|
|
955
955
|
adds a `TimeInstant` attribute as metadata for every other attribute in the same request. With NGSI-LD, the Standard
|
|
956
956
|
`observedAt` property-of-a-property is used instead.
|
|
957
957
|
|
|
958
|
+
If a `TimeInstant` arrives as measure but not follows [ISO_8601](https://en.wikipedia.org/wiki/ISO_8601) then measure
|
|
959
|
+
is refused.
|
|
960
|
+
|
|
961
|
+
Depending on the `timestamp` configuration and if the measure contains a
|
|
962
|
+
value named `TimeInstant` with a correct value, the IoTA behaviour is described
|
|
963
|
+
in the following table:
|
|
964
|
+
|
|
965
|
+
`timestamp` value | measure contains `TimeInstant` | Behaviour
|
|
966
|
+
-- | -- | --
|
|
967
|
+
true | Yes | TimeInstant and metadata updated with measure value
|
|
968
|
+
true | No | TimeInstant and metadata updated with server timestamp
|
|
969
|
+
false | Yes | TimeInstant and metadata updated with measure value
|
|
970
|
+
false | No | TimeInstant and metadata updated with server timestamp
|
|
971
|
+
Not defined | Yes | TimeInstant and metadata updated with measure value
|
|
972
|
+
Not defined | No | TimeInstant and metadata updated with server timestamp
|
|
973
|
+
|
|
974
|
+
The `timestamp` value used is:
|
|
975
|
+
|
|
976
|
+
* The one defined at device level
|
|
977
|
+
* The one defined at group level (if not defined at device level)
|
|
978
|
+
* The one defined at [IoTA configuration level](admin.md#timestamp) / `IOTA_TIMESTAMP` env var (if not defined at group level or device level)
|
|
979
|
+
|
|
958
980
|
## Overriding global Context Broker host
|
|
959
981
|
|
|
960
982
|
**cbHost**: Context Broker host URL. This option can be used to override the global CB configuration for specific types
|
|
@@ -963,8 +985,7 @@ of devices.
|
|
|
963
985
|
## Multitenancy, FIWARE Service and FIWARE ServicePath
|
|
964
986
|
|
|
965
987
|
Every operation in the API require the `fiware-service` and `fiware-servicepath` to be defined; the operations are
|
|
966
|
-
performed in the scope of those headers.
|
|
967
|
-
this case, the operation applies to all the subservices of the service given by the `fiware-service` header.
|
|
988
|
+
performed in the scope of those headers.
|
|
968
989
|
|
|
969
990
|
## Secured access to the Context Broker
|
|
970
991
|
|
|
@@ -1202,7 +1223,7 @@ Config group is represented by a JSON object with the following fields:
|
|
|
1202
1223
|
| `subservice` | | string | | Subservice of the devices of this type. |
|
|
1203
1224
|
| `resource` | | string | | string representing the Southbound resource that will be used to assign a type to a device (e.g.: pathname in the southbound port). |
|
|
1204
1225
|
| `apikey` | | string | | API Key string. |
|
|
1205
|
-
| `timestamp` | ✓ | bool | | Optional flag about whether or not to add the `TimeInstant` attribute to the device entity created, as well as a `TimeInstant` metadata to each attribute, with the current timestamp. With NGSI-LD, the Standard `observedAt` property-of-a-property is created instead. |
|
|
1226
|
+
| `timestamp` | ✓ | bool | | Optional flag about whether or not to add the `TimeInstant` attribute to the device entity created, as well as a `TimeInstant` metadata to each attribute, with the current server timestamp or provided `TimeInstant` as measure when follows ISO 8601 format (see [timestamp processing](#timestamp-processing) section for aditional detail). With NGSI-LD, the Standard `observedAt` property-of-a-property is created instead. |
|
|
1206
1227
|
| `entity_type` | | string | | name of the Entity `type` to assign to the group. |
|
|
1207
1228
|
| `trust` | ✓ | string | | trust token to use for secured access to the Context Broker for this type of devices (optional; only needed for secured scenarios). |
|
|
1208
1229
|
| `cbHost` | ✓ | string | | Context Broker connection information. This options can be used to override the global ones for specific types of devices. |
|
|
@@ -1217,6 +1238,8 @@ Config group is represented by a JSON object with the following fields:
|
|
|
1217
1238
|
| `defaultEntityNameConjunction` | ✓ | string | | optional string value to set default conjunction string used to compose a default `entity_name` when is not provided at device provisioning time. |
|
|
1218
1239
|
| `autoprovision` | ✓ | bool | ✓? | optional boolean: If `false`, autoprovisioned devices (i.e. devices that are not created with an explicit provision operation but when the first measure arrives) are not allowed in this group. Default (in the case of omitting the field) is `true`. |
|
|
1219
1240
|
| `payloadType` | ✓ | string | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. |
|
|
1241
|
+
| `transport` | ✓ | `string` | | Transport protocol used by the group of devices to send updates, for the IoT Agents with multiple transport protocols. |
|
|
1242
|
+
| `endpoint` | ✓ | `string` | | Endpoint where the group of device is going to receive commands, if any. |
|
|
1220
1243
|
|
|
1221
1244
|
### Config group operations
|
|
1222
1245
|
|
|
@@ -1224,9 +1247,8 @@ The following actions are available under the config group endpoint:
|
|
|
1224
1247
|
|
|
1225
1248
|
#### Retrieve config groups `GET /iot/services`
|
|
1226
1249
|
|
|
1227
|
-
List all the config groups for the given `fiware-service` and `fiware-servicepath`.
|
|
1228
|
-
|
|
1229
|
-
match the `fiware-servicepath` are returned in any other case.
|
|
1250
|
+
List all the config groups for the given `fiware-service` and `fiware-servicepath`. The config groups that match the
|
|
1251
|
+
`fiware-servicepath` are returned in any other case.
|
|
1230
1252
|
|
|
1231
1253
|
_**Request headers**_
|
|
1232
1254
|
|
|
@@ -1425,7 +1447,7 @@ the API resource fields and the same fields in the database model.
|
|
|
1425
1447
|
| `entity_name` | | `string` | | Name of the entity representing the device in the Context Broker |
|
|
1426
1448
|
| `entity_type` | | `string` | | Type of the entity in the Context Broker |
|
|
1427
1449
|
| `timezone` | ✓ | `string` | | Timezone of the device if that has any |
|
|
1428
|
-
| `timestamp` | ✓ | `string` | | Flag about whether or not to add the `TimeInstant` attribute to the device entity created, as well as a `TimeInstant` metadata to each attribute, with the current timestamp. With NGSI-LD, the Standard `observedAt` property-of-a-property is created instead. |
|
|
1450
|
+
| `timestamp` | ✓ | `string` | | Flag about whether or not to add the `TimeInstant` attribute to the device entity created, as well as a `TimeInstant` metadata to each attribute, with the current server timestamp or provided `TimeInstant` as measure when follows ISO 8601 format (see [timestamp processing](#timestamp-processing) section for aditional detail). With NGSI-LD, the Standard `observedAt` property-of-a-property is created instead. |
|
|
1429
1451
|
| `apikey` | ✓ | `string` | | Apikey key string to use instead of group apikey |
|
|
1430
1452
|
| `endpoint` | ✓ | `string` | | Endpoint where the device is going to receive commands, if any. |
|
|
1431
1453
|
| `protocol` | ✓ | `string` | | Pame of the device protocol, for its use with an IoT Manager |
|
package/doc/requirements.txt
CHANGED
package/docker-compose-dev.yml
CHANGED
package/lib/constants.js
CHANGED
|
@@ -61,6 +61,7 @@ module.exports = {
|
|
|
61
61
|
NGSI_LD_TENANT_HEADER: 'NGSILD-Tenant',
|
|
62
62
|
NGSI_LD_PATH_HEADER: 'NGSILD-Path',
|
|
63
63
|
NGSI_LD_NULL: 'urn:ngsi-ld:null',
|
|
64
|
+
MEASURE: 'measure_',
|
|
64
65
|
//FIXME: check Keystone support this in lowercase, then change
|
|
65
66
|
AUTH_HEADER: 'X-Auth-Token',
|
|
66
67
|
X_FORWARDED_FOR_HEADER: 'x-forwarded-for',
|
|
@@ -83,7 +84,7 @@ module.exports = {
|
|
|
83
84
|
MONGO_ALARM: 'MONGO-ALARM',
|
|
84
85
|
ORION_ALARM: 'ORION-ALARM',
|
|
85
86
|
IOTAM_ALARM: 'IOTAM-ALARM',
|
|
86
|
-
|
|
87
|
+
|
|
87
88
|
ATTRIBUTE_DEFAULT,
|
|
88
89
|
DATETIME_DEFAULT,
|
|
89
90
|
|
|
@@ -308,6 +308,7 @@ exports.getDeviceByName = deviceService.getDeviceByName;
|
|
|
308
308
|
exports.getDeviceByNameAndType = deviceService.getDeviceByNameAndType;
|
|
309
309
|
exports.getDevicesByAttribute = deviceService.getDevicesByAttribute;
|
|
310
310
|
exports.mergeDeviceWithConfiguration = deviceService.mergeDeviceWithConfiguration;
|
|
311
|
+
exports.findOrCreate = deviceService.findOrCreate;
|
|
311
312
|
exports.retrieveDevice = deviceService.retrieveDevice;
|
|
312
313
|
exports.getConfiguration = groupConfig.get;
|
|
313
314
|
exports.getConfigurationSilently = groupConfig.getSilently;
|
package/lib/model/Group.js
CHANGED
|
@@ -61,7 +61,9 @@ function register(callback) {
|
|
|
61
61
|
defaultEntityNameConjunction: service.defaultEntityNameConjunction,
|
|
62
62
|
ngsiVersion: service.ngsiVersion,
|
|
63
63
|
entityNameExp: service.entityNameExp,
|
|
64
|
-
payloadType: service.payloadType
|
|
64
|
+
payloadType: service.payloadType,
|
|
65
|
+
endpoint: service.endpoint,
|
|
66
|
+
transport: service.transport
|
|
65
67
|
};
|
|
66
68
|
}
|
|
67
69
|
|
|
@@ -309,6 +309,7 @@ function update(device, callback) {
|
|
|
309
309
|
data.internalAttributes = device.internalAttributes;
|
|
310
310
|
data.commands = device.commands;
|
|
311
311
|
data.endpoint = device.endpoint;
|
|
312
|
+
data.transport = device.transport;
|
|
312
313
|
data.polling = device.polling;
|
|
313
314
|
data.name = device.name;
|
|
314
315
|
data.type = device.type;
|
|
@@ -352,7 +352,7 @@ function registerDevice(deviceObj, callback) {
|
|
|
352
352
|
deviceObj.subservice = deviceData.subservice;
|
|
353
353
|
deviceObj.type = deviceData.type;
|
|
354
354
|
deviceObj.staticAttributes = deviceObj.staticAttributes ? deviceObj.staticAttributes : [];
|
|
355
|
-
deviceObj.commands =
|
|
355
|
+
deviceObj.commands = deviceData.commands ? deviceData.commands : [];
|
|
356
356
|
deviceObj.lazy = deviceObj.lazy ? deviceObj.lazy : [];
|
|
357
357
|
if ('apikey' in deviceData && deviceData.apikey !== undefined) {
|
|
358
358
|
deviceObj.apikey = deviceData.apikey;
|
|
@@ -677,7 +677,7 @@ function retrieveDevice(deviceId, apiKey, callback) {
|
|
|
677
677
|
} else {
|
|
678
678
|
async.waterfall(
|
|
679
679
|
[
|
|
680
|
-
apply(groupService.
|
|
680
|
+
apply(groupService.getSilently, config.getConfig().defaultResource || '', apiKey),
|
|
681
681
|
apply(findOrCreate, deviceId, apiKey),
|
|
682
682
|
apply(
|
|
683
683
|
mergeDeviceWithConfiguration,
|
|
@@ -704,5 +704,6 @@ exports.unregister = intoTrans(context, unregisterDevice);
|
|
|
704
704
|
exports.clearRegistry = intoTrans(context, checkRegistry)(clearRegistry);
|
|
705
705
|
exports.retrieveDevice = intoTrans(context, checkRegistry)(retrieveDevice);
|
|
706
706
|
exports.mergeDeviceWithConfiguration = mergeDeviceWithConfiguration;
|
|
707
|
+
exports.findOrCreate = findOrCreate;
|
|
707
708
|
exports.findConfigurationGroup = findConfigurationGroup;
|
|
708
709
|
exports.init = init;
|
|
@@ -273,7 +273,12 @@ function updateRegisterDeviceNgsi2(deviceObj, entityInfoUpdated, callback) {
|
|
|
273
273
|
if ('payloadType' in newDevice && newDevice.payloadType !== undefined) {
|
|
274
274
|
oldDevice.payloadType = newDevice.payloadType;
|
|
275
275
|
}
|
|
276
|
-
|
|
276
|
+
if ('endpoint' in newDevice && newDevice.endpoint !== undefined) {
|
|
277
|
+
oldDevice.endpoint = newDevice.endpoint;
|
|
278
|
+
}
|
|
279
|
+
if ('transport' in newDevice && newDevice.transport !== undefined) {
|
|
280
|
+
oldDevice.transport = newDevice.transport;
|
|
281
|
+
}
|
|
277
282
|
|
|
278
283
|
callback(null, oldDevice);
|
|
279
284
|
} else {
|
|
@@ -61,7 +61,7 @@ function createGroup(group, callback) {
|
|
|
61
61
|
|
|
62
62
|
logger.debug(
|
|
63
63
|
context,
|
|
64
|
-
'Storing device group for service [%s] and subservice [%s]',
|
|
64
|
+
'Storing device group id %s for service [%s] and subservice [%s]',
|
|
65
65
|
storeGroup._id,
|
|
66
66
|
storeGroup.service,
|
|
67
67
|
storeGroup.subservice
|
|
@@ -144,6 +144,7 @@ function find(service, subservice, callback) {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
if (result.length > 0) {
|
|
147
|
+
logger.debug(context, 'groups found %j', result);
|
|
147
148
|
return callback(null, {
|
|
148
149
|
count: result.length,
|
|
149
150
|
services: result
|
|
@@ -169,7 +170,7 @@ function findBy(fields) {
|
|
|
169
170
|
/* eslint-disable-next-line prefer-rest-params */
|
|
170
171
|
const callback = arguments[i];
|
|
171
172
|
|
|
172
|
-
logger.debug(context, 'Looking for
|
|
173
|
+
logger.debug(context, 'Looking for group with params %j', fields);
|
|
173
174
|
|
|
174
175
|
for (const p in registeredGroups) {
|
|
175
176
|
if (registeredGroups.hasOwnProperty(p)) {
|
|
@@ -189,6 +190,7 @@ function findBy(fields) {
|
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
if (result) {
|
|
193
|
+
logger.debug(context, 'group found %j', result);
|
|
192
194
|
callback(null, result);
|
|
193
195
|
} else {
|
|
194
196
|
callback(new errors.DeviceGroupNotFound('n/a', 'n/a'));
|
|
@@ -211,6 +213,7 @@ function getSingleGroup(resource, apikey, callback) {
|
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
if (result) {
|
|
216
|
+
logger.debug(context, 'single group found %j', result);
|
|
214
217
|
callback(null, result);
|
|
215
218
|
} else {
|
|
216
219
|
callback(new errors.DeviceGroupNotFound(resource, apikey));
|
|
@@ -228,6 +231,7 @@ function getSingleGroupType(type, callback) {
|
|
|
228
231
|
}
|
|
229
232
|
|
|
230
233
|
if (result) {
|
|
234
|
+
logger.debug(context, 'single group type found %j', result);
|
|
231
235
|
callback(null, result);
|
|
232
236
|
} else {
|
|
233
237
|
callback(new errors.DeviceGroupNotFound(type));
|
|
@@ -243,7 +247,7 @@ function update(id, body, callback) {
|
|
|
243
247
|
groupToModify[i] = body[i];
|
|
244
248
|
}
|
|
245
249
|
}
|
|
246
|
-
|
|
250
|
+
logger.debug(context, 'groupd to update %j', groupToModify);
|
|
247
251
|
callback(null, groupToModify);
|
|
248
252
|
} else {
|
|
249
253
|
callback(new errors.DeviceGroupNotFound(id));
|
|
@@ -262,8 +266,8 @@ exports.list = intoTrans(context, listGroups);
|
|
|
262
266
|
exports.init = intoTrans(context, init);
|
|
263
267
|
exports.find = intoTrans(context, find);
|
|
264
268
|
exports.findBy = intoTrans(context, findBy);
|
|
265
|
-
exports.findType = intoTrans(context, findBy(['service', 'subservice', 'type']));
|
|
266
|
-
exports.findTypeSilently = intoTrans(context, findBy(['service', 'subservice', 'type']));
|
|
269
|
+
exports.findType = intoTrans(context, findBy(['service', 'subservice', 'type', 'apikey']));
|
|
270
|
+
exports.findTypeSilently = intoTrans(context, findBy(['service', 'subservice', 'type', 'apikey']));
|
|
267
271
|
exports.findSilently = intoTrans(context, findBy(['service', 'subservice']));
|
|
268
272
|
exports.get = intoTrans(context, getSingleGroup);
|
|
269
273
|
exports.getSilently = intoTrans(context, getSingleGroup);
|
|
@@ -282,6 +282,12 @@ function sendUpdateValueNgsi2(entityName, measures, typeInformation, token, call
|
|
|
282
282
|
callback(new errors.TypeNotFound(null, entityName));
|
|
283
283
|
return;
|
|
284
284
|
}
|
|
285
|
+
//Rename all measures with matches with id and type to measure_id and measure_type
|
|
286
|
+
for (let measure of measures) {
|
|
287
|
+
if (measure.name === 'id' || measure.name === 'type') {
|
|
288
|
+
measure.name = constants.MEASURE + measure.name;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
285
291
|
|
|
286
292
|
//Make a copy of measures in an plain object: plainMeasures
|
|
287
293
|
plainMeasures = reduceAttrToPlainObject(measures);
|
|
@@ -541,7 +547,6 @@ function sendUpdateValueNgsi2(entityName, measures, typeInformation, token, call
|
|
|
541
547
|
//extract attributes
|
|
542
548
|
let isEmpty = true;
|
|
543
549
|
for (let attr of entities[ename][etype]) {
|
|
544
|
-
//Handling id/type measures, skip, hit & explicit (condition)
|
|
545
550
|
if (
|
|
546
551
|
attr.name !== 'id' &&
|
|
547
552
|
attr.name !== 'type' &&
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"description": "Protocol the device is using to communicate with the platform",
|
|
33
33
|
"type": "string"
|
|
34
34
|
},
|
|
35
|
+
"endpoint": {
|
|
36
|
+
"description": "Endpoint for the commands targeting this device",
|
|
37
|
+
"type": "string"
|
|
38
|
+
},
|
|
35
39
|
"transport": {
|
|
36
40
|
"description": "Transport protocol used by the platform to communicate with the device",
|
|
37
41
|
"type": "string"
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"description": "Protocol the device is using to communicate with the platform",
|
|
33
33
|
"type": "string"
|
|
34
34
|
},
|
|
35
|
+
"endpoint": {
|
|
36
|
+
"description": "Endpoint for the commands targeting this device",
|
|
37
|
+
"type": "string"
|
|
38
|
+
},
|
|
35
39
|
"transport": {
|
|
36
40
|
"description": "Transport protocol used by the platform to communicate with the device",
|
|
37
41
|
"type": "string"
|
|
@@ -20,6 +20,14 @@
|
|
|
20
20
|
"type": "string",
|
|
21
21
|
"required": true
|
|
22
22
|
},
|
|
23
|
+
"endpoint": {
|
|
24
|
+
"description": "Endpoint for the commands targeting this group",
|
|
25
|
+
"type": "string"
|
|
26
|
+
},
|
|
27
|
+
"transport": {
|
|
28
|
+
"description": "Transport protocol used by the platform to communicate with the device",
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
23
31
|
"token": {
|
|
24
32
|
"description": "token",
|
|
25
33
|
"type": "string"
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
"description": "Endpoint for the commands targeting this device",
|
|
34
34
|
"type": "string"
|
|
35
35
|
},
|
|
36
|
+
"transport": {
|
|
37
|
+
"description": "Transport protocol used by the platform to communicate with the device",
|
|
38
|
+
"type": "string"
|
|
39
|
+
},
|
|
36
40
|
"lazy": {
|
|
37
41
|
"description": "list of lazy attributes of the devices",
|
|
38
42
|
"type": "array",
|
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": "4.0
|
|
5
|
+
"version": "4.2.0",
|
|
6
6
|
"homepage": "https://github.com/telefonicaid/iotagent-node-lib",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"fiware",
|
|
@@ -30,10 +30,10 @@ test cases are automatically generated. Each test case is defined as an object w
|
|
|
30
30
|
- `json`: The JSON object that defines the group
|
|
31
31
|
- `headers`: The headers to send to the provisioning API. This should contain the `fiware-service` and
|
|
32
32
|
`fiware-servicepath` headers.
|
|
33
|
-
- `skip`: optional.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
the lib (I.E: all tests related to the transport).
|
|
33
|
+
- `skip`: optional. Allow to skip test cases (at `describe` level). It allows diferent values: `false` (default, meaning that the test is not skipped in any circustance),
|
|
34
|
+
`true` (meaning the test is always skipped), `"lib"` (meaning the test has to be skipped when running it in IoTA Node lib repo) and
|
|
35
|
+
`"json"` (meaning the test has to be skipped when running it in IOTA JSON repo). The latter alternatives are useful to skip test cases that are not supported by
|
|
36
|
+
the lib (I.E: all tests related to the transport) or by the IOTA. Combinations (e.g `"lib,json"`) and negation (e.g. `"!lib"`) are also supported.
|
|
37
37
|
- `should`: The array of test cases to execute. Each test case is defined as an object with the following elements:
|
|
38
38
|
- `transport`: The transport to use to send the measure. This can be `HTTP` or `MQTT`. It uses `HTTP` by default
|
|
39
39
|
or if the `transport` element is not defined. See the "Advanced features" section for more information.
|
|
@@ -88,7 +88,7 @@ describe('FUNCTIONAL TESTS AUTO', function () {
|
|
|
88
88
|
|
|
89
89
|
testCase.should.forEach((should) => {
|
|
90
90
|
it(should.shouldName, async function () {
|
|
91
|
-
if (
|
|
91
|
+
if (should.skip && testUtils.checkSkip(should.skip, 'lib')) {
|
|
92
92
|
this.skip();
|
|
93
93
|
}
|
|
94
94
|
// Skip the test if the transport is specified (IoTA Lib does not support any transport)
|
|
@@ -1476,6 +1476,65 @@ const testCases = [
|
|
|
1476
1476
|
}
|
|
1477
1477
|
]
|
|
1478
1478
|
},
|
|
1479
|
+
// 0200 - COMMANDS TESTS
|
|
1480
|
+
{
|
|
1481
|
+
describeName: '0200 - Simple group with commands',
|
|
1482
|
+
provision: {
|
|
1483
|
+
url: 'http://localhost:' + config.iota.server.port + '/iot/services',
|
|
1484
|
+
method: 'POST',
|
|
1485
|
+
json: {
|
|
1486
|
+
services: [
|
|
1487
|
+
{
|
|
1488
|
+
resource: '/iot/json',
|
|
1489
|
+
apikey: globalEnv.apikey,
|
|
1490
|
+
entity_type: globalEnv.entity_type,
|
|
1491
|
+
commands: [
|
|
1492
|
+
{
|
|
1493
|
+
name: 'cmd1',
|
|
1494
|
+
type: 'command'
|
|
1495
|
+
}
|
|
1496
|
+
],
|
|
1497
|
+
endpoint: 'http://myendpoint.com',
|
|
1498
|
+
transport: 'http',
|
|
1499
|
+
lazy: [],
|
|
1500
|
+
attributes: [],
|
|
1501
|
+
static_attributes: []
|
|
1502
|
+
}
|
|
1503
|
+
]
|
|
1504
|
+
},
|
|
1505
|
+
headers: {
|
|
1506
|
+
'fiware-service': globalEnv.service,
|
|
1507
|
+
'fiware-servicepath': globalEnv.servicePath
|
|
1508
|
+
}
|
|
1509
|
+
},
|
|
1510
|
+
should: [
|
|
1511
|
+
{
|
|
1512
|
+
shouldName:
|
|
1513
|
+
'A - WHEN sending not provisioned object_ids (measures) through http IT should store commands into Context Broker',
|
|
1514
|
+
type: 'single',
|
|
1515
|
+
skip: '!lib', // there is not CB registration mock
|
|
1516
|
+
measure: {
|
|
1517
|
+
url: 'http://localhost:' + config.http.port + '/iot/json',
|
|
1518
|
+
method: 'POST',
|
|
1519
|
+
qs: {
|
|
1520
|
+
i: globalEnv.deviceId,
|
|
1521
|
+
k: globalEnv.apikey
|
|
1522
|
+
},
|
|
1523
|
+
json: {
|
|
1524
|
+
b: 10
|
|
1525
|
+
}
|
|
1526
|
+
},
|
|
1527
|
+
expectation: {
|
|
1528
|
+
id: globalEnv.entity_name,
|
|
1529
|
+
type: globalEnv.entity_type,
|
|
1530
|
+
b: {
|
|
1531
|
+
value: 10,
|
|
1532
|
+
type: 'string'
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
]
|
|
1537
|
+
},
|
|
1479
1538
|
// 0300 - STATIC ATTRIBUTES TESTS
|
|
1480
1539
|
{
|
|
1481
1540
|
describeName:
|
|
@@ -2424,6 +2483,7 @@ const testCases = [
|
|
|
2424
2483
|
{
|
|
2425
2484
|
shouldName: 'C - WHEN sending only b IT should store only [{object_id:b}] attrs into Context Broker',
|
|
2426
2485
|
type: 'single',
|
|
2486
|
+
skip: '!lib', // FIXME: https://github.com/telefonicaid/iotagent-json/issues/782
|
|
2427
2487
|
measure: {
|
|
2428
2488
|
url: 'http://localhost:' + config.http.port + '/iot/json',
|
|
2429
2489
|
method: 'POST',
|
|
@@ -2450,6 +2510,7 @@ const testCases = [
|
|
|
2450
2510
|
shouldName:
|
|
2451
2511
|
'D - WHEN no sending any defined case IT should store [static_a,static_b] attrs into Context Broker',
|
|
2452
2512
|
type: 'single',
|
|
2513
|
+
skip: '!lib', // FIXME: https://github.com/telefonicaid/iotagent-json/issues/782
|
|
2453
2514
|
measure: {
|
|
2454
2515
|
url: 'http://localhost:' + config.http.port + '/iot/json',
|
|
2455
2516
|
method: 'POST',
|
|
@@ -139,6 +139,8 @@ function groupToIoTAConfigType(group, service, subservice) {
|
|
|
139
139
|
type.type = group.entity_type;
|
|
140
140
|
} else if (key === 'static_attributes') {
|
|
141
141
|
type.staticAttributes = group.static_attributes;
|
|
142
|
+
} else if (key === 'commands') {
|
|
143
|
+
type.commands = group.commands;
|
|
142
144
|
} else if (key !== 'resource') {
|
|
143
145
|
type[key] = group[key];
|
|
144
146
|
}
|
|
@@ -932,6 +932,14 @@ describe('NGSI-v2 - Active attributes test', function () {
|
|
|
932
932
|
meas: {
|
|
933
933
|
value: 'measIoTA',
|
|
934
934
|
type: 'String'
|
|
935
|
+
},
|
|
936
|
+
measure_id: {
|
|
937
|
+
type: 'text',
|
|
938
|
+
value: 'idIoTA'
|
|
939
|
+
},
|
|
940
|
+
measure_type: {
|
|
941
|
+
type: 'text',
|
|
942
|
+
value: 'typeIoTA'
|
|
935
943
|
}
|
|
936
944
|
})
|
|
937
945
|
.reply(204);
|
|
@@ -1026,6 +1034,14 @@ describe('NGSI-v2 - Active attributes test', function () {
|
|
|
1026
1034
|
meas: {
|
|
1027
1035
|
value: 'measIoTA',
|
|
1028
1036
|
type: 'String'
|
|
1037
|
+
},
|
|
1038
|
+
measure_id: {
|
|
1039
|
+
value: 'idIoTA',
|
|
1040
|
+
type: 'text'
|
|
1041
|
+
},
|
|
1042
|
+
measure_type: {
|
|
1043
|
+
value: 'typeIoTA',
|
|
1044
|
+
type: 'text'
|
|
1029
1045
|
}
|
|
1030
1046
|
})
|
|
1031
1047
|
.reply(204);
|
|
@@ -61,6 +61,8 @@ const optionsCreation = {
|
|
|
61
61
|
entity_type: 'SensorMachine',
|
|
62
62
|
trust: '8970A9078A803H3BL98PINEQRW8342HBAMS',
|
|
63
63
|
cbHost: 'http://unexistentHost:1026',
|
|
64
|
+
transport: 'HTTP',
|
|
65
|
+
endpoint: 'http://myendpoint.com',
|
|
64
66
|
commands: [
|
|
65
67
|
{
|
|
66
68
|
name: 'wheel1',
|
|
@@ -136,6 +138,8 @@ const optionsUpdate = {
|
|
|
136
138
|
json: {
|
|
137
139
|
trust: '8970A9078A803H3BL98PINEQRW8342HBAMS',
|
|
138
140
|
cbHost: 'http://anotherUnexistentHost:1026',
|
|
141
|
+
transport: 'MQTT',
|
|
142
|
+
endpoint: 'http://yourendpoint.com',
|
|
139
143
|
commands: [
|
|
140
144
|
{
|
|
141
145
|
name: 'wheel1',
|
|
@@ -217,6 +221,8 @@ describe('NGSI-v2 - Device Group Configuration API', function () {
|
|
|
217
221
|
request(optionsList, function (error, response, body) {
|
|
218
222
|
body.count.should.equal(1);
|
|
219
223
|
body.services[0].apikey.should.equal('801230BJKL23Y9090DSFL123HJK09H324HV8732');
|
|
224
|
+
body.services[0].transport.should.equal('HTTP');
|
|
225
|
+
body.services[0].endpoint.should.equal('http://myendpoint.com');
|
|
220
226
|
done();
|
|
221
227
|
});
|
|
222
228
|
});
|
|
@@ -664,6 +670,8 @@ describe('NGSI-v2 - Device Group Configuration API', function () {
|
|
|
664
670
|
) {
|
|
665
671
|
body.services[i].cbHost.should.equal('http://anotherUnexistentHost:1026');
|
|
666
672
|
body.services[i].static_attributes.length.should.equal(1);
|
|
673
|
+
body.services[i].endpoint = 'http://yourendpoint.com';
|
|
674
|
+
body.services[i].transport = 'MQTT';
|
|
667
675
|
found = true;
|
|
668
676
|
}
|
|
669
677
|
}
|