iotagent-node-lib 2.21.0 → 2.24.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.
Files changed (62) hide show
  1. package/.nyc_output/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +1 -0
  2. package/.nyc_output/processinfo/{76bc24ff-5fac-4b5a-997d-de2799342eb0.json → 33364de2-1199-4ec2-b33c-cae063ef8cc4.json} +1 -1
  3. package/.nyc_output/processinfo/index.json +1 -1
  4. package/CHANGES_NEXT_RELEASE +0 -1
  5. package/doc/Contribution.md +3 -3
  6. package/doc/advanced-topics.md +73 -9
  7. package/doc/api.md +7 -5
  8. package/doc/architecture.md +52 -5
  9. package/doc/expressionLanguage.md +18 -3
  10. package/doc/operations.md +8 -5
  11. package/doc/usermanual.md +18 -16
  12. package/docker/Mosquitto/Dockerfile +1 -1
  13. package/lib/errors.js +9 -1
  14. package/lib/model/Group.js +2 -1
  15. package/lib/model/dbConn.js +4 -0
  16. package/lib/plugins/bidirectionalData.js +104 -6
  17. package/lib/plugins/expressionPlugin.js +18 -7
  18. package/lib/plugins/multiEntity.js +42 -29
  19. package/lib/plugins/pluginUtils.js +17 -0
  20. package/lib/request-shim.js +2 -1
  21. package/lib/services/commands/commandService.js +29 -2
  22. package/lib/services/common/iotManagerService.js +2 -1
  23. package/lib/services/devices/deviceService.js +35 -9
  24. package/lib/services/groups/groupRegistryMongoDB.js +13 -12
  25. package/lib/services/ngsi/entities-NGSI-LD.js +7 -0
  26. package/lib/services/ngsi/entities-NGSI-v2.js +70 -11
  27. package/lib/services/ngsi/ngsiService.js +1 -1
  28. package/lib/services/northBound/contextServer-NGSI-LD.js +110 -15
  29. package/lib/services/northBound/contextServer-NGSI-v2.js +8 -3
  30. package/lib/services/northBound/contextServerUtils.js +9 -9
  31. package/lib/services/northBound/deviceProvisioningServer.js +2 -1
  32. package/lib/templates/createDevice.json +1 -2
  33. package/lib/templates/createDeviceLax.json +2 -3
  34. package/lib/templates/updateDevice.json +1 -2
  35. package/package.json +24 -24
  36. package/test/unit/examples/deviceProvisioningRequests/provisionMinimumDevice4.json +14 -0
  37. package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +51 -0
  38. package/test/unit/mongodb/mongoDBUtils.js +2 -2
  39. package/test/unit/mongodb/mongodb-group-registry-test.js +25 -1
  40. package/test/unit/mongodb/mongodb-registry-test.js +51 -3
  41. package/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgentCommands.json +2 -1
  42. package/test/unit/ngsi-ld/examples/contextRequests/updateContextLanguageProperties1.json +15 -0
  43. package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithDatasetId.json +21 -0
  44. package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json +17 -0
  45. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +995 -27
  46. package/test/unit/ngsi-ld/ngsiService/languageProperties-test.js +112 -0
  47. package/test/unit/ngsi-ld/ngsiService/unsupported-endpoints-test.js +111 -0
  48. package/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +221 -0
  49. package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +1 -1
  50. package/test/unit/ngsiv2/examples/contextRequests/createMinimumProvisionedDevice4.json +8 -0
  51. package/test/unit/ngsiv2/examples/contextRequests/updateContextCommandStatus2.json +6 -0
  52. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json +12 -1
  53. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin17.json +27 -0
  54. package/test/unit/ngsiv2/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json +19 -0
  55. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +10 -8
  56. package/test/unit/ngsiv2/lazyAndCommands/command-test.js +106 -0
  57. package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +151 -0
  58. package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +115 -0
  59. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +63 -0
  60. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +60 -0
  61. package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +2 -1
  62. package/.nyc_output/76bc24ff-5fac-4b5a-997d-de2799342eb0.json +0 -1
@@ -314,13 +314,52 @@ function sendQueryValueNgsi2(entityName, attributes, typeInformation, token, cal
314
314
  );
315
315
  }
316
316
 
317
+ function extractContextFromPayload(payload) {
318
+ //{b: {value: 3,type: "string"},c: {value: false,type: "string"},d:{value: {g: 45},type: "string"},id: "tamcaysanto",type: "WaterTankMulti"}
319
+ //to
320
+ //{b:3,c:false,d:{g:45}}
321
+
322
+ let ctx = {};
323
+ for (const key in payload) {
324
+ if (key !== 'type' && key !== 'id') {
325
+ ctx[key] = payload[key].value;
326
+ }
327
+ }
328
+ return ctx;
329
+ }
317
330
  /**
318
331
  * Remove id, type and any hidden attrs after processing
319
332
  *
320
333
  * @param {Object} enities Unprocessed entities
321
334
  * @param {Object} typeInformation Configuration information for the device.
322
335
  */
323
- function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
336
+ function removeHiddenAttrsFromMultiEntity(entities, typeInformation, payload) {
337
+ function filterForEntity(entity, explicitAttrsList, typeInformation) {
338
+ let effectiveList = [];
339
+ for (const attr of explicitAttrsList) {
340
+ if (typeof attr === 'string') {
341
+ effectiveList.push(attr);
342
+ } else if (typeof attr === 'object' && attr.object_id) {
343
+ //find objectId in active attributes
344
+ for (const active of typeInformation.active) {
345
+ if (active.object_id === attr.object_id) {
346
+ if (
347
+ active &&
348
+ active.name &&
349
+ active.entity_name &&
350
+ active.entity_name === entity.id
351
+ //if name is an expression it could fail... BUT IT WORKS!
352
+ ) {
353
+ effectiveList.push(active.name);
354
+ }
355
+ continue; //object_id must be unique
356
+ }
357
+ }
358
+ }
359
+ }
360
+ return effectiveList;
361
+ }
362
+
324
363
  let explicitAttrsList;
325
364
  if (typeInformation.explicitAttrs) {
326
365
  explicitAttrsList = [];
@@ -344,15 +383,26 @@ function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
344
383
  } else if (typeof typeInformation.explicitAttrs === 'string') {
345
384
  entities.forEach((entity) => {
346
385
  const attsArray = pluginUtils.extractAttributesArrayFromNgsi2Entity(entity);
347
- const ctx = jexlParser.extractContext(attsArray);
348
- const res = jexlParser.applyExpression(typeInformation.explicitAttrs, ctx, typeInformation);
349
- explicitAttrsList = explicitAttrsList.concat(res);
386
+ const ctx = {
387
+ ...jexlParser.extractContext(attsArray),
388
+ ...extractContextFromPayload(payload)
389
+ }; //maybe overlapping between this two objects.
390
+ let res = null;
391
+ try {
392
+ res = jexlParser.applyExpression(typeInformation.explicitAttrs, ctx, typeInformation);
393
+ } catch (e) {
394
+ // nothing to do: exception is already logged at info level
395
+ }
396
+ explicitAttrsList = res ? explicitAttrsList.concat(res) : explicitAttrsList;
350
397
  });
351
398
  }
352
399
  }
353
400
  if (explicitAttrsList && explicitAttrsList.length >= 0) {
354
401
  entities.forEach((entity) => {
355
- const hidden = _.difference(_.keys(entity), explicitAttrsList);
402
+ //some attrs are object_ids {object_id:oid} and need to be resolved for this entity
403
+ //"explicitAttrs" : "attrA?['attrA',{object_id:'foo'}]:['attrB',{object_id:'bar'}]",
404
+ let efectiveAttrsList = filterForEntity(entity, explicitAttrsList, typeInformation);
405
+ const hidden = _.difference(_.keys(entity), efectiveAttrsList);
356
406
  logger.debug(context, 'removeHiddenAttrsFromMultiEntity %s from entity %s', hidden, entity);
357
407
  hidden.forEach((attr) => {
358
408
  delete entity[attr];
@@ -361,13 +411,14 @@ function removeHiddenAttrsFromMultiEntity(entities, typeInformation) {
361
411
  }
362
412
  return entities;
363
413
  }
414
+
364
415
  /**
365
416
  * Remove id, type and any hidden attrs after processing
366
417
  *
367
418
  * @param {Object} result An Unprocessed entity
368
419
  * @param {Object} typeInformation Configuration information for the device.
369
420
  */
370
- function removeHiddenAttrs(result, typeInformation) {
421
+ function removeHiddenAttrs(result, typeInformation, payload) {
371
422
  delete result.id;
372
423
  delete result.type;
373
424
  let explicitAttrsList;
@@ -388,9 +439,17 @@ function removeHiddenAttrs(result, typeInformation) {
388
439
  }
389
440
  } else if (typeInformation.explicitAttrs && typeof typeInformation.explicitAttrs === 'string') {
390
441
  const attsArray = pluginUtils.extractAttributesArrayFromNgsi2Entity(result);
391
- const ctx = jexlParser.extractContext(attsArray);
392
- const res = jexlParser.applyExpression(typeInformation.explicitAttrs, ctx, typeInformation);
393
- explicitAttrsList = res;
442
+ const ctx = {
443
+ ...jexlParser.extractContext(attsArray),
444
+ ...extractContextFromPayload(payload)
445
+ }; //maybe overlapping between this two objects. Measures not in active attrs.
446
+ let res = null;
447
+ try {
448
+ res = jexlParser.applyExpression(typeInformation.explicitAttrs, ctx, typeInformation);
449
+ } catch (e) {
450
+ // nothing to do: exception is already logged at info level
451
+ }
452
+ explicitAttrsList = res ? res : [];
394
453
  }
395
454
  if (explicitAttrsList && explicitAttrsList.length >= 0) {
396
455
  const hidden = _.difference(_.keys(result), explicitAttrsList);
@@ -481,7 +540,7 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
481
540
  }
482
541
  options.json = {
483
542
  actionType: 'append',
484
- entities: removeHiddenAttrsFromMultiEntity(result, typeInformation)
543
+ entities: removeHiddenAttrsFromMultiEntity(result, typeInformation, payload)
485
544
  };
486
545
  if (config.getConfig().appendMode === true) {
487
546
  options.json.actionType = 'append';
@@ -489,7 +548,7 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
489
548
  options.json.actionType = 'update';
490
549
  }
491
550
  } else {
492
- options.json = removeHiddenAttrs(result, typeInformation);
551
+ options.json = removeHiddenAttrs(result, typeInformation, payload);
493
552
  logger.debug(context, 'typeInformation: %j', typeInformation);
494
553
  if (
495
554
  'timestamp' in typeInformation && typeInformation.timestamp !== undefined
@@ -133,7 +133,7 @@ function executeWithDeviceInformation(operationFunction) {
133
133
  deviceInformation
134
134
  );
135
135
  const currentType = type ? type : deviceInformation.type;
136
- config.getGroupRegistry().getType(currentType, function (error, deviceGroup) {
136
+ config.getGroupRegistry().getTypeSilently(currentType, function (error, deviceGroup) {
137
137
  let typeInformation;
138
138
  const configDeviceInfo = config.getConfig().types[currentType];
139
139
  if (error) {
@@ -42,9 +42,25 @@ const notificationTemplateNgsiLD = require('../../templates/notificationTemplate
42
42
  const contextServerUtils = require('./contextServerUtils');
43
43
  const ngsiLD = require('../ngsi/entities-NGSI-LD');
44
44
 
45
- const updatePaths = ['/ngsi-ld/v1/entities/:entity/attrs/:attr'];
45
+ const overwritePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entities/:entity/attrs/:attr'];
46
+ const updatePaths = ['/ngsi-ld/v1/entities/:entity/attrs', '/ngsi-ld/v1/entities/:entity/attrs/:attr'];
46
47
  const queryPaths = ['/ngsi-ld/v1/entities/:entity'];
47
48
 
49
+ /**
50
+ * Extract metadata attributes from input.
51
+ *
52
+ * @param {Object} obj input object
53
+ */
54
+ function getMetaData(obj) {
55
+ const excludedKeys = ['datasetId', 'value', 'type'];
56
+ const metaData = {};
57
+ _.keys(obj).forEach((key) => {
58
+ if (!excludedKeys.includes(key)) {
59
+ metaData[key] = obj[key];
60
+ }
61
+ });
62
+ return !_.isEmpty(metaData) ? metaData : {};
63
+ }
48
64
  /**
49
65
  * Generate all the update actions corresponding to a update context request using Ngsi2.
50
66
  * Update actions include updates in attributes and execution of commands.
@@ -55,8 +71,11 @@ const queryPaths = ['/ngsi-ld/v1/entities/:entity'];
55
71
  function generateUpdateActionsNgsiLD(req, contextElement, callback) {
56
72
  let entityId;
57
73
  let entityType;
74
+
58
75
  const attribute = req.params.attr;
59
76
  const value = req.body.value;
77
+ const datasetId = req.body.datasetId;
78
+ const incomingAttrs = !req.params.attr ? _.keys(req.body) : [];
60
79
 
61
80
  if (contextElement.id && contextElement.type) {
62
81
  entityId = contextElement.id;
@@ -72,12 +91,49 @@ function generateUpdateActionsNgsiLD(req, contextElement, callback) {
72
91
 
73
92
  if (device.commands) {
74
93
  for (const j in device.commands) {
75
- if (attribute === device.commands[j].name) {
76
- commands.push({
77
- type: device.commands[j].type,
78
- value,
79
- name: attribute
80
- });
94
+ const name = device.commands[j].name;
95
+ if (attribute === name) {
96
+ if (_.isArray(req.body)) {
97
+ req.body[name].forEach((obj) => {
98
+ commands.push({
99
+ type: device.commands[j].type,
100
+ value: obj.value,
101
+ name: name,
102
+ datasetId: obj.datasetId,
103
+ metadata: getMetaData(obj)
104
+ });
105
+ });
106
+ } else {
107
+ commands.push({
108
+ type: device.commands[j].type,
109
+ value,
110
+ name,
111
+ datasetId,
112
+ metadata: getMetaData(req.body)
113
+ });
114
+ }
115
+ found = true;
116
+ } else if (incomingAttrs.includes(name)) {
117
+ if (_.isArray(req.body[name])) {
118
+ req.body[name].forEach((obj) => {
119
+ commands.push({
120
+ type: device.commands[j].type,
121
+ value: obj.value,
122
+ name: name,
123
+ datasetId: obj.datasetId,
124
+ metadata: getMetaData(obj)
125
+ });
126
+ });
127
+ } else {
128
+ const obj = req.body[name];
129
+ commands.push({
130
+ type: device.commands[j].type,
131
+ value: obj.value,
132
+ name: name,
133
+ datasetId: obj.datasetId,
134
+ metadata: getMetaData(obj)
135
+ });
136
+ }
81
137
  found = true;
82
138
  }
83
139
  }
@@ -280,7 +336,7 @@ function handleQueryNgsiLD(req, res, next) {
280
336
 
281
337
  if (device.staticAttributes) {
282
338
  let selectedAttributes = [];
283
- if (attributes === undefined || attributes.length === 0) {
339
+ if (attributes === null || attributes === undefined || attributes.length === 0) {
284
340
  selectedAttributes = device.staticAttributes;
285
341
  } else {
286
342
  selectedAttributes = device.staticAttributes.filter(inAttributes);
@@ -306,8 +362,8 @@ function handleQueryNgsiLD(req, res, next) {
306
362
  const results = device.lazy.map(getName);
307
363
  callback(null, results);
308
364
  } else {
309
- logger.debug(context, "Couldn't find any attributes. Handling with null reference");
310
- callback(null, null);
365
+ logger.debug(context, "Couldn't find any attributes. Handling with empty reference");
366
+ callback(null, []);
311
367
  }
312
368
  }
313
369
 
@@ -462,11 +518,25 @@ function handleNotificationNgsiLD(req, res, next) {
462
518
  /* eslint-disable-next-line no-prototype-builtins */
463
519
  if (dataElement.hasOwnProperty(key)) {
464
520
  if (key !== 'id' && key !== 'type') {
465
- const att = {};
466
- att.type = dataElement[key].type;
467
- att.value = dataElement[key].value;
468
- att.name = key;
469
- atts.push(att);
521
+ if (_.isArray(dataElement[key])) {
522
+ dataElement[key].forEach((obj) => {
523
+ atts.push({
524
+ type: obj.type,
525
+ value: obj.value,
526
+ name: key,
527
+ datasetId: obj.datasetId,
528
+ metadata: getMetaData(obj)
529
+ });
530
+ });
531
+ } else {
532
+ atts.push({
533
+ type: dataElement[key].type,
534
+ value: dataElement[key].value,
535
+ name: key,
536
+ datasetId: dataElement[key].datasetId,
537
+ metadata: getMetaData(dataElement[key])
538
+ });
539
+ }
470
540
  }
471
541
  }
472
542
  }
@@ -553,6 +623,21 @@ function updateErrorHandlingNgsiLD(error, req, res, next) {
553
623
  });
554
624
  }
555
625
 
626
+ /**
627
+ * Load unsupported NGSI-LD entity routes and return proper NGSI-LD not supported responses
628
+ *
629
+ * @param {Object} router Express request router object.
630
+ */
631
+ function loadUnsupportedEndpointsNGSILD(router) {
632
+ const unsupportedEndpoint = function (req, res) {
633
+ return res.status(501).send(new errors.MethodNotSupported(req.method, req.path));
634
+ };
635
+ router.get('/ngsi-ld/v1/entities', unsupportedEndpoint);
636
+ router.post('/ngsi-ld/v1/entities', unsupportedEndpoint);
637
+ router.delete('/ngsi-ld/v1/entities/:entity', unsupportedEndpoint);
638
+ router.delete('/ngsi-ld/v1/entities/:entity/attrs/:attr', unsupportedEndpoint);
639
+ }
640
+
556
641
  /**
557
642
  * Load the routes related to context dispatching (NGSI10 calls).
558
643
  *
@@ -573,6 +658,15 @@ function loadContextRoutesNGSILD(router) {
573
658
  updateErrorHandlingNgsiLD
574
659
  ]);
575
660
  }
661
+
662
+ for (i = 0; i < overwritePaths.length; i++) {
663
+ router.put(overwritePaths[i], [
664
+ middlewares.ensureType,
665
+ middlewares.validateJson(updateContextTemplateNgsiLD),
666
+ handleUpdateNgsiLD,
667
+ updateErrorHandlingNgsiLD
668
+ ]);
669
+ }
576
670
  for (i = 0; i < queryPaths.length; i++) {
577
671
  router.get(queryPaths[i], [handleQueryNgsiLD, queryErrorHandlingNgsiLD]);
578
672
  }
@@ -582,6 +676,7 @@ function loadContextRoutesNGSILD(router) {
582
676
  handleNotificationNgsiLD,
583
677
  queryErrorHandlingNgsiLD
584
678
  ]);
679
+ loadUnsupportedEndpointsNGSILD(router);
585
680
  }
586
681
 
587
682
  exports.loadContextRoutes = loadContextRoutesNGSILD;
@@ -217,7 +217,11 @@ function handleUpdateNgsi2(req, res, next) {
217
217
  }
218
218
  );
219
219
  } else {
220
- logger.error(context, 'Tried to handle an update request before the update handler was stablished.');
220
+ logger.error(
221
+ context,
222
+ 'Tried to handle an update request [%j] before the update handler was stablished.',
223
+ req.body
224
+ );
221
225
 
222
226
  const errorNotFound = new Error({
223
227
  message: 'Update handler not found'
@@ -282,6 +286,7 @@ function handleNotificationNgsi2(req, res, next) {
282
286
  const att = {};
283
287
  att.type = dataElement[key].type;
284
288
  att.value = dataElement[key].value;
289
+ att.metadata = dataElement[key].metadata || {};
285
290
  att.name = key;
286
291
  atts.push(att);
287
292
  }
@@ -381,7 +386,7 @@ function queryErrorHandlingNgsi2(error, req, res, next) {
381
386
  function updateErrorHandlingNgsi2(error, req, res, next) {
382
387
  let code = 500;
383
388
 
384
- logger.debug(context, 'Update NGSIv2 error [%s] handing request: %s', error.name, error.message);
389
+ logger.debug(context, 'Update NGSIv2 error [%j] handing request: %j', error, req.body);
385
390
 
386
391
  if (error.code && String(error.code).match(/^[2345]\d\d$/)) {
387
392
  code = error.code;
@@ -533,7 +538,7 @@ function handleQueryNgsi2(req, res, next) {
533
538
  logger.debug(context, 'There was an error handling the query: %s.', error);
534
539
  next(error);
535
540
  } else {
536
- logger.debug(context, 'Query from [%s] handled successfully.', req.get('host'));
541
+ logger.debug(context, 'Query from [%s] handled successfully. req %s', req.get('host'), req);
537
542
  res.status(200).json(result);
538
543
  }
539
544
  }
@@ -41,10 +41,10 @@ const commands = require('../commands/commandService');
41
41
  * @return {String} The Tenant decribed in the request headers
42
42
  */
43
43
  function getLDTenant(req) {
44
- if (req.headers['NGSILD-Tenant']) {
45
- return req.headers['NGSILD-Tenant'];
46
- } else if (req.headers['fiware-service']) {
47
- return req.headers['fiware-service'];
44
+ if (req.header('NGSILD-Tenant')) {
45
+ return req.header('NGSILD-Tenant');
46
+ } else if (req.header('fiware-service')) {
47
+ return req.header('fiware-service');
48
48
  }
49
49
  return config.getConfig().contextBroker.fallbackTenant;
50
50
  }
@@ -56,10 +56,10 @@ function getLDTenant(req) {
56
56
  * obliged to offer service headers - this is still being defined in the NGSI-LD specifications.
57
57
  */
58
58
  function getLDPath(req) {
59
- if (req.headers['NGSILD-Path']) {
60
- return req.headers['NGSILD-Path'];
61
- } else if (req.headers['fiware-servicepath']) {
62
- return req.headers['fiware-servicepath'];
59
+ if (req.header('NGSILD-Path')) {
60
+ return req.header('NGSILD-path');
61
+ } else if (req.header('fiware-servicepath')) {
62
+ return req.header('fiware-servicepath');
63
63
  }
64
64
  return config.getConfig().contextBroker.fallbackPath;
65
65
  }
@@ -112,7 +112,7 @@ function executeUpdateSideEffects(device, id, type, service, subservice, attribu
112
112
  * @param {Array} attributes List of attributes to update with their types and values.
113
113
  */
114
114
  function pushCommandsToQueue(device, id, type, service, subservice, attributes, callback) {
115
- async.map(attributes, apply(commands.add, service, subservice, device.id), callback);
115
+ async.map(attributes, apply(commands.addCmd, service, subservice, device), callback);
116
116
  }
117
117
 
118
118
  exports.notificationMiddlewares = [];
@@ -63,7 +63,8 @@ const provisioningAPITranslation = {
63
63
  autoprovision: 'autoprovision',
64
64
  explicitAttrs: 'explicitAttrs',
65
65
  expressionLanguage: 'expressionLanguage',
66
- ngsiVersion: 'ngsiVersion'
66
+ ngsiVersion: 'ngsiVersion',
67
+ entityNameExp: 'entityNameExp'
67
68
  };
68
69
 
69
70
  /**
@@ -41,8 +41,7 @@
41
41
  "type": "string"
42
42
  },
43
43
  "explicitAttrs": {
44
- "description": "Flag about only provisioned attributes will be processed to Context Broker",
45
- "type": "boolean"
44
+ "description": "Flag about only provisioned attributes will be processed to Context Broker"
46
45
  },
47
46
  "ngsiVersion": {
48
47
  "description": "NGSI Interface for this device",
@@ -41,8 +41,7 @@
41
41
  "type": "boolean"
42
42
  },
43
43
  "explicitAttrs": {
44
- "description": "Flag about only provisioned attributes will be processed to Context Broker",
45
- "type": "boolean"
44
+ "description": "Flag about only provisioned attributes will be processed to Context Broker"
46
45
  },
47
46
  "ngsiVersion": {
48
47
  "description": "NGSI Interface for this device",
@@ -181,4 +180,4 @@
181
180
  }
182
181
  }
183
182
  }
184
- }
183
+ }
@@ -198,8 +198,7 @@
198
198
  "type": "array"
199
199
  },
200
200
  "explicitAttrs": {
201
- "description": "Flag to decide update of active attributes only",
202
- "type": "Boolean"
201
+ "description": "Flag to decide update of active attributes only"
203
202
  },
204
203
  "ngsiVersion": {
205
204
  "description": "NGSI Interface for this device",
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": "2.21.0",
5
+ "version": "2.24.0",
6
6
  "homepage": "https://github.com/telefonicaid/iotagent-node-lib",
7
7
  "keywords": [
8
8
  "fiware",
@@ -43,41 +43,41 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "async": "2.6.4",
46
- "body-parser": "~1.19.0",
47
- "express": "~4.16.4",
48
- "got": "~11.8.2",
46
+ "body-parser": "~1.20.0",
47
+ "express": "~4.18.1",
48
+ "got": "~11.8.5",
49
49
  "jexl": "2.3.0",
50
50
  "jison": "0.4.18",
51
51
  "logops": "2.1.2",
52
52
  "moment": "~2.29.2",
53
- "moment-timezone": "~0.5.25",
54
- "mongodb": "3.6.12",
55
- "mongoose": "5.7.14",
56
- "query-string": "6.5.0",
53
+ "moment-timezone": "~0.5.34",
54
+ "mongoose": "5.13.14",
55
+ "query-string": "7.1.1",
57
56
  "revalidator": "~0.3.1",
58
- "underscore": "~1.12.1",
59
- "uuid": "~3.3.2"
57
+ "underscore": "~1.13.4",
58
+ "uuid": "~8.3.2"
60
59
  },
61
60
  "devDependencies": {
62
- "coveralls": "~3.1.0",
63
- "eslint": "~7.5.0",
64
- "eslint-config-tamia": "~7.2.5",
65
- "eslint-plugin-prettier": "~3.1.4",
61
+ "coveralls": "~3.1.1",
62
+ "eslint": "~8.18.0",
63
+ "eslint-config-tamia": "~8.0.0",
64
+ "eslint-plugin-prettier": "~4.0.0",
66
65
  "husky": "~4.2.5",
67
- "lint-staged": "~10.2.11",
68
- "prettier": "~2.0.5",
69
- "mocha": "8.0.1",
70
- "nock": "13.0.3",
66
+ "lint-staged": "~12.3.8",
67
+ "mocha": "10.0.0",
68
+ "mongodb": "4.7.0",
69
+ "nock": "13.2.7",
71
70
  "nyc": "~15.1.0",
72
- "remark-cli": "~8.0.1",
73
- "remark-preset-lint-recommended": "~4.0.1",
71
+ "prettier": "~2.7.1",
72
+ "remark-cli": "~10.0.1",
73
+ "remark-preset-lint-recommended": "~6.1.2",
74
74
  "should": "13.2.3",
75
- "sinon": "~9.0.2",
76
- "textlint": "~11.7.6",
75
+ "sinon": "~14.0.0",
76
+ "textlint": "~12.2.1",
77
77
  "textlint-filter-rule-comments": "~1.2.2",
78
78
  "textlint-rule-common-misspellings": "~1.0.1",
79
- "textlint-rule-terminology": "~2.1.4",
80
- "textlint-rule-write-good": "~1.6.2",
79
+ "textlint-rule-terminology": "~3.0.2",
80
+ "textlint-rule-write-good": "~2.0.0",
81
81
  "timekeeper": "2.2.0",
82
82
  "watch": "~1.0.2"
83
83
  },
@@ -0,0 +1,14 @@
1
+ {
2
+ "devices": [
3
+ {
4
+ "device_id": "MicroLight1",
5
+ "protocol": "GENERIC_PROTO",
6
+ "attributes": [
7
+ {
8
+ "name": "attr_name",
9
+ "type": "string"
10
+ }
11
+ ]
12
+ }
13
+ ]
14
+ }
@@ -194,4 +194,55 @@ describe('NGSI-v2 - In memory device registry', function () {
194
194
  });
195
195
  });
196
196
  });
197
+
198
+ describe('When a the registry is queried for device in a particular name and type', function (){
199
+ beforeEach(function (done) {
200
+ contextBrokerMock = nock('http://192.168.1.1:1026')
201
+ .post('/v2/entities?options=upsert')
202
+ .times(10)
203
+ .reply(204);
204
+
205
+ const devices = [];
206
+
207
+ for (let i = 0; i < 10; i++)
208
+ {
209
+ devices.push(
210
+ {
211
+ id: 'id' + i,
212
+ name : 'name' + i,
213
+ type: 'Light' + i,
214
+ internalId: 'internal' + i,
215
+ service: 'smartgondor',
216
+ subservice: 'gardens',
217
+ active: [ {
218
+ id: 'attrId',
219
+ type: 'attrType' + i,
220
+ value: i
221
+ }]
222
+ });
223
+ }
224
+
225
+ async.map(devices, iotAgentLib.register, function (error, results) {
226
+ done();
227
+ });
228
+ });
229
+
230
+ afterEach(function (done) {
231
+ iotAgentLib.clearRegistry(done);
232
+ });
233
+ it('should return the name and type of device', function (done)
234
+ {
235
+ iotAgentLib.getDeviceByNameAndType('name5', 'Light5','smartgondor', 'gardens' ,function(error, device)
236
+ {
237
+ should.not.exist(error);
238
+ should.exist(device);
239
+ should.exist(device.name);
240
+ should.exist(device.type);
241
+ device.name.should.equal('name5');
242
+ device.type.should.equal('Light5');
243
+ Object.keys(device).length.should.equal(11);
244
+ done();
245
+ });
246
+ });
247
+ });
197
248
  });
@@ -29,7 +29,7 @@ const async = require('async');
29
29
  function cleanDb(host, name, callback) {
30
30
  const url = 'mongodb://' + host + ':27017/' + name;
31
31
 
32
- MongoClient.connect(url, { useNewUrlParser: true }, function (err, db) {
32
+ MongoClient.connect(url, function (err, db) {
33
33
  if (db && db.db()) {
34
34
  db.db().dropDatabase(function (err, result) {
35
35
  db.close();
@@ -46,7 +46,7 @@ function cleanDbs(callback) {
46
46
  function populate(host, dbName, entityList, collectionName, callback) {
47
47
  const url = 'mongodb://' + host + ':27017/' + dbName;
48
48
 
49
- MongoClient.connect(url, { useNewUrlParser: true }, function (err, db) {
49
+ MongoClient.connect(url, function (err, db) {
50
50
  if (db) {
51
51
  db.db()
52
52
  .collection(collectionName)