From 1fdb7e3cc095dc46b0f41a1267f84b117fe0a678 Mon Sep 17 00:00:00 2001 From: a620381 Date: Thu, 8 Nov 2018 13:38:11 +0100 Subject: [PATCH 01/27] Corrects linting --- .jshintrc | 1 + lib/plugins/attributeAlias.js | 5 +--- lib/plugins/expressionParser.js | 2 ++ lib/plugins/expressionPlugin.js | 4 ---- lib/plugins/multiEntity.js | 18 +++++++------- lib/plugins/pluginUtils.js | 3 +++ lib/services/devices/deviceRegistryMongoDB.js | 4 ++-- lib/services/devices/deviceService.js | 24 ++++++++++++------- lib/services/devices/registrationUtils.js | 3 ++- lib/services/groups/groupService.js | 15 ++++++++---- lib/services/ngsi/ngsiService.js | 17 ++++++++----- .../provisioning/device-group-api-test.js | 2 +- .../provisionDeviceMultientity-test.js | 3 ++- 13 files changed, 60 insertions(+), 41 deletions(-) diff --git a/.jshintrc b/.jshintrc index bf36e3197..517729321 100644 --- a/.jshintrc +++ b/.jshintrc @@ -17,6 +17,7 @@ "node": true, "expr": true, "unused": "vars", + "esversion": 6, "globals": { "describe":true, "it": true, diff --git a/lib/plugins/attributeAlias.js b/lib/plugins/attributeAlias.js index 0073e3a7a..2a90b1099 100644 --- a/lib/plugins/attributeAlias.js +++ b/lib/plugins/attributeAlias.js @@ -27,10 +27,6 @@ var config = require('../commonConfig'), utils = require('./pluginUtils'), - logger = require('logops'), - context = { - op: 'IoTAgentNGSI.attributeAlias' - }, ngsiService = require('../services/ngsi/ngsiService'); function extractSingleMapping(previous, current) { @@ -79,6 +75,7 @@ function applyAlias(mappings) { return function aliasApplier(attribute) { if (mappings.direct[attribute.name]) { if (config.checkNgsi2()) { + /*jshint camelcase: false */ attribute.object_id = attribute.name; // inverse not usefull due to collision } attribute.type = mappings.types[attribute.name]; diff --git a/lib/plugins/expressionParser.js b/lib/plugins/expressionParser.js index 4bc960c4c..faf9771f4 100644 --- a/lib/plugins/expressionParser.js +++ b/lib/plugins/expressionParser.js @@ -175,6 +175,8 @@ function expressionApplier(context, typeInformation) { name: attribute.name, type: attribute.type }; + + /*jshint camelcase: false */ if (config.checkNgsi2() && attribute.object_id) { newAttribute.object_id = attribute.object_id; } diff --git a/lib/plugins/expressionPlugin.js b/lib/plugins/expressionPlugin.js index d726063a8..abff011a6 100644 --- a/lib/plugins/expressionPlugin.js +++ b/lib/plugins/expressionPlugin.js @@ -29,10 +29,6 @@ var _ = require('underscore'), parser = require('./expressionParser'), config = require('../commonConfig'), - logger = require('logops'), - context = { - op: 'IoTAgentNGSI.expressionPlugin' - }, utils = require('./pluginUtils'); function mergeAttributes(attrList1, attrList2) { diff --git a/lib/plugins/multiEntity.js b/lib/plugins/multiEntity.js index 89102f30e..cd657a203 100644 --- a/lib/plugins/multiEntity.js +++ b/lib/plugins/multiEntity.js @@ -30,10 +30,6 @@ var _ = require('underscore'), parser = require('./expressionParser'), config = require('../commonConfig'), - logger = require('logops'), - context = { - op: 'IoTAgentNGSI.MultiEntityPlugin' - }, utils = require('./pluginUtils'), aliasPlugin = require('./attributeAlias'); @@ -158,6 +154,7 @@ function generateNewCEsNgsi2(entity, newEntities, entityTypes, typeInformation, if (entity.hasOwnProperty(att)) { if (_.contains(newEntityAttributeNames, att)) { if (entity[att].multi && entity[att].multi.length > 0) { + // jshint maxdepth:7 if (mappings.inverse[att] && mappings.inverse[att].length > 0) { for (var j in (mappings.inverse[att])) { if (_.contains(newEntityAttributeObjectIds, mappings.inverse[att][j])) { @@ -167,10 +164,12 @@ function generateNewCEsNgsi2(entity, newEntities, entityTypes, typeInformation, } } } - for (var j in entity[att].multi) { - if (entity[att].multi[j].object_id && _.contains(newEntityAttributeObjectIds, entity[att].multi[j].object_id)) { - result[att] = entity[att].multi[j]; - delete entity[att].multi[j].object_id; + // jshint maxdepth:7 + for (var k in entity[att].multi) { + if (entity[att].multi[k].object_id && _.contains(newEntityAttributeObjectIds, + entity[att].multi[k].object_id)) { + result[att] = entity[att].multi[k]; + delete entity[att].multi[k].object_id; } } } else { @@ -189,7 +188,8 @@ function generateNewCEsNgsi2(entity, newEntities, entityTypes, typeInformation, for (var i = 0; i < newEntities.length; i++) { newEntityAttributeNames = _.pluck(multiEntityAttributes.filter(filterByEntityName(newEntities[i])), 'name'); - newEntityAttributeObjectIds = _.pluck(multiEntityAttributes.filter(filterByEntityName(newEntities[i])), 'object_id'); + newEntityAttributeObjectIds = _.pluck(multiEntityAttributes.filter( + filterByEntityName(newEntities[i])), 'object_id'); newEntityAttributes = filterAttributes(); entityName = parser.applyExpression(newEntities[i], ctx, typeInformation); diff --git a/lib/plugins/pluginUtils.js b/lib/plugins/pluginUtils.js index e99ca18e3..52d7c5d73 100644 --- a/lib/plugins/pluginUtils.js +++ b/lib/plugins/pluginUtils.js @@ -39,6 +39,7 @@ function extractAttributesArrayFromNgsi2Entity(entity) { if (i !== 'id' && i !== 'type') { var att = Object.assign({}, entity[i]); if (att.multi) { + // jshint maxdepth:5 for (var j in att.multi) { var matt = Object.assign({}, entity[i].multi[j]); matt.name = i; @@ -68,6 +69,7 @@ function createNgsi2Entity(id, type, attsArray, objectId) { entity.id = id; entity.type = type; for (var i = 0; i < attsArray.length; i++) { + /*jshint camelcase: false */ if (entity[attsArray[i].name] && objectId && attsArray[i].object_id) { // Check if multiple measures with multientity attributes with same name(#635) if (!entity[attsArray[i].name].multi) { @@ -76,6 +78,7 @@ function createNgsi2Entity(id, type, attsArray, objectId) { entity[attsArray[i].name].multi.push({ 'type' : attsArray[i].type, 'value' : attsArray[i].value, + /*jshint camelcase: false */ 'object_id' : attsArray[i].object_id, 'metadata' : attsArray[i].metadata }); diff --git a/lib/services/devices/deviceRegistryMongoDB.js b/lib/services/devices/deviceRegistryMongoDB.js index 2aa05f77b..0ef30bf0d 100644 --- a/lib/services/devices/deviceRegistryMongoDB.js +++ b/lib/services/devices/deviceRegistryMongoDB.js @@ -68,8 +68,8 @@ function storeDevice(newDevice, callback) { } // Ensure protocol is in newDevice - if ( !newDevice['protocol'] && config.getConfig().iotManager && config.getConfig().iotManager.protocol) { - deviceObj['protocol'] = config.getConfig().iotManager.protocol; + if ( !newDevice.protocol && config.getConfig().iotManager && config.getConfig().iotManager.protocol) { + deviceObj.protocol = config.getConfig().iotManager.protocol; } logger.debug(context, 'Storing device with id [%s] and type [%s]', newDevice.id, newDevice.type); diff --git a/lib/services/devices/deviceService.js b/lib/services/devices/deviceService.js index a9a181e41..e01a0bcc6 100644 --- a/lib/services/devices/deviceService.js +++ b/lib/services/devices/deviceService.js @@ -216,6 +216,7 @@ function formatAttributesNgsi2(originalVector, staticAtts) { // (#628) check if attribute has entity_name: // In that case attribute should not be appear in current entity + /*jshint camelcase: false */ if (!originalVector[i].entity_name) { attributeList[originalVector[i].name] = { type: originalVector[i].type, @@ -287,9 +288,10 @@ function createInitialEntityNgsi2(deviceData, newDevice, callback) { jsonConcat(options.json, formatCommandsNgsi2(deviceData.commands)); logger.debug(context, 'deviceData: %j', deviceData); - if ( (('timestamp' in deviceData && deviceData['timestamp'] !== undefined) ? deviceData.timestamp : config.getConfig().timestamp) && - ! utils.isTimestampedNgsi2(options.json)) { - logger.debug(context, 'config.timestamp %s %s', deviceData['timestamp'], config.getConfig().timestamp); + if ( (('timestamp' in deviceData && deviceData.timestamp !== undefined) ? + deviceData.timestamp : config.getConfig().timestamp) && + ! utils.isTimestampedNgsi2(options.json)) { + logger.debug(context, 'config.timestamp %s %s', deviceData.timestamp, config.getConfig().timestamp); options.json[constants.TIMESTAMP_ATTRIBUTE] = { type: constants.TIMESTAMP_TYPE_NGSI2, value: moment() @@ -338,6 +340,7 @@ function createInitialEntityNgsi1(deviceData, newDevice, callback) { for (var i = 0; i < originalVector.length; i++) { // (#628) check if attribute has entity_name: // In that case attribute should not be appear in current entity + /*jshint camelcase: false */ if (!originalVector[i].entity_name) { attributeList.push({ name: originalVector[i].name, @@ -377,8 +380,9 @@ function createInitialEntityNgsi1(deviceData, newDevice, callback) { deviceData.staticAttributes, formatCommands(deviceData.commands)); - if ( (('timestamp' in deviceData && deviceData['timestamp'] !== undefined) ? deviceData.timestamp : config.getConfig().timestamp) && - ! utils.isTimestamped(options.json)) { + if ( (('timestamp' in deviceData && deviceData.timestamp !== undefined) ? + deviceData.timestamp : config.getConfig().timestamp) && + ! utils.isTimestamped(options.json)) { options.json.contextElements[0].attributes.push({ name: constants.TIMESTAMP_ATTRIBUTE, type: constants.TIMESTAMP_TYPE, @@ -429,8 +433,9 @@ function updateEntityNgsi2(deviceData, updatedDevice, callback) { jsonConcat(options.json, formatAttributesNgsi2(deviceData.staticAttributes, true)); jsonConcat(options.json, formatCommandsNgsi2(deviceData.commands)); - if ( (('timestamp' in deviceData && deviceData['timestamp'] !== undefined) ? deviceData.timestamp : config.getConfig().timestamp) && - ! utils.isTimestampedNgsi2(options.json)) { + if ( (('timestamp' in deviceData && deviceData.timestamp !== undefined) ? + deviceData.timestamp : config.getConfig().timestamp) && + ! utils.isTimestampedNgsi2(options.json)) { options.json[constants.TIMESTAMP_ATTRIBUTE] = { type: constants.TIMESTAMP_TYPE_NGSI2, value: moment() @@ -521,7 +526,8 @@ function mergeDeviceWithConfiguration(fields, defaults, deviceData, configuratio if (deviceData[fields[i]] && configuration && configuration[confField]) { deviceData[fields[i]] = mergeArrays(deviceData[fields[i]], configuration[confField]); - } else if (!deviceData[fields[i]] && configuration && confField in configuration && configuration[confField] !== undefined) { + } else if (!deviceData[fields[i]] && configuration && + confField in configuration && configuration[confField] !== undefined) { deviceData[fields[i]] = configuration[confField]; } else if (!deviceData[fields[i]] && (!configuration || !configuration[confField])) { deviceData[fields[i]] = defaults[i]; @@ -1023,7 +1029,7 @@ function findOrCreate(deviceId, group, callback) { newDevice.protocol = config.getConfig().iotManager.protocol; } - if ('timestamp' in group && group['timestamp'] !== undefined) { + if ('timestamp' in group && group.timestamp !== undefined) { newDevice.timestamp = group.timestamp; } diff --git a/lib/services/devices/registrationUtils.js b/lib/services/devices/registrationUtils.js index 6fd3d808b..61f099199 100644 --- a/lib/services/devices/registrationUtils.js +++ b/lib/services/devices/registrationUtils.js @@ -318,7 +318,8 @@ function sendRegistrationsNgsi2(unregister, deviceData, callback) { ).reduce(mergeWithSameName, []); if (options.json.dataProvided.attrs.length === 0) { - logger.debug(context, 'Registration with Context Provider is not needed. Device without lazy atts or commands'); + logger.debug(context, 'Registration with Context Provider is not needed.' + + 'Device without lazy atts or commands'); callback(null, deviceData); } else { logger.debug(context, 'Sending device registrations to Context Broker at [%s]', options.url); diff --git a/lib/services/groups/groupService.js b/lib/services/groups/groupService.js index 181a3c7b6..a892bd6c4 100644 --- a/lib/services/groups/groupService.js +++ b/lib/services/groups/groupService.js @@ -172,6 +172,14 @@ function remove(service, subservice, resource, apikey, device, callback) { callback(null, deviceGroup._id); } + function unregisterDevice(device, cb) { + deviceService.unregister(device.id, service, subservice, function(error) { + if (error) { + cb(error); + } + }); + } + function deleteDevices(device, service, subservice, id, callback) { if(device) { deviceService.listDevices(service, subservice, function (error, devices) { @@ -179,13 +187,12 @@ function remove(service, subservice, resource, apikey, device, callback) { callback(error); } else { if (devices && devices.count > 0){ - for(var device of devices.devices) { - deviceService.unregister(device.id, service, subservice, function(error) { + + async.map(devices.devices, unregisterDevice, function(error) { if (error) { callback(error); - } + } }); - } } } }); diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index b6026488a..96c17d662 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -470,8 +470,9 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca typeInformation, token); - if ( (('timestamp' in typeInformation && typeInformation['timestamp'] !== undefined) ? typeInformation.timestamp : config.getConfig().timestamp) && - ! utils.isTimestampedNgsi2(result)) { + if ( (('timestamp' in typeInformation && typeInformation.timestamp !== undefined) ? + typeInformation.timestamp : config.getConfig().timestamp) && + ! utils.isTimestampedNgsi2(result)) { result = addTimestampNgsi2(result, typeInformation.timezone); } @@ -484,8 +485,9 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca delete result.type; options.json = result; logger.debug(context, 'typeInformation: %j', typeInformation); - if ( (('timestamp' in typeInformation && typeInformation['timestamp'] !== undefined) ? typeInformation.timestamp : config.getConfig().timestamp) && - ! utils.isTimestampedNgsi2(options.json)) { + if ( (('timestamp' in typeInformation && typeInformation.timestamp !== undefined) ? + typeInformation.timestamp : config.getConfig().timestamp) && + ! utils.isTimestampedNgsi2(options.json)) { options.json = addTimestampNgsi2(options.json, typeInformation.timezone); } } @@ -556,7 +558,8 @@ function sendUpdateValueNgsi1(entityName, attributes, typeInformation, token, ca options.json = payload; } - if ( (('timestamp' in typeInformation && typeInformation['timestamp'] !== undefined) ? typeInformation.timestamp : config.getConfig().timestamp) && + if ( (('timestamp' in typeInformation && typeInformation.timestamp !== undefined) ? + typeInformation.timestamp : config.getConfig().timestamp) && ! utils.isTimestamped(options.json)) { options.json = addTimestamp(options.json, typeInformation.timezone); } @@ -723,7 +726,9 @@ function updateTrust(deviceGroup, deviceInformation, trust, response, callback) function executeWithDeviceInformation(operationFunction) { return function(entityName, type, apikey, attributes, deviceInformation, callback) { - logger.debug(context, 'executeWithDeviceInfo entityName %s type %s apikey %s attributes %j deviceInformation %j', entityName, type, apikey, attributes, deviceInformation); + logger.debug(context, + 'executeWithDeviceInfo entityName %s type %s apikey %s attributes %j deviceInformation %j', + entityName, type, apikey, attributes, deviceInformation); config.getGroupRegistry().getType(type, function(error, deviceGroup) { var typeInformation; if (error) { diff --git a/test/unit/provisioning/device-group-api-test.js b/test/unit/provisioning/device-group-api-test.js index 56c274b42..0e7cdc48c 100644 --- a/test/unit/provisioning/device-group-api-test.js +++ b/test/unit/provisioning/device-group-api-test.js @@ -428,7 +428,7 @@ describe('Device Group Configuration API', function() { function test (error, response, body) { response.statusCode.should.equal(404); done(); - }; + } async.series([ async.apply(request, optionsDeleteDevice), diff --git a/test/unit/provisioning/provisionDeviceMultientity-test.js b/test/unit/provisioning/provisionDeviceMultientity-test.js index 8878760a1..a9cf304f0 100644 --- a/test/unit/provisioning/provisionDeviceMultientity-test.js +++ b/test/unit/provisioning/provisionDeviceMultientity-test.js @@ -86,7 +86,8 @@ describe('Device provisioning API: Provision devices', function() { var options = { url: 'http://localhost:' + iotAgentConfig.server.port + '/iot/devices', method: 'POST', - json: utils.readExampleFile('./test/unit/examples/deviceProvisioningRequests/provisionNewDeviceMultientity.json'), + json: utils.readExampleFile('./test/unit/examples/deviceProvisioningRequests/' + + 'provisionNewDeviceMultientity.json'), headers: { 'fiware-service': 'smartGondor', 'fiware-servicepath': '/gardens' From dbff7d393b45c8313751d1d42f6b04b1ed4ac364 Mon Sep 17 00:00:00 2001 From: a620381 Date: Thu, 8 Nov 2018 13:40:48 +0100 Subject: [PATCH 02/27] Includes lint check in travis --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 7ec7b8646..70cf8a644 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,3 +19,6 @@ install: before_install: - npm update -q +before_script: + - npm run lint + From 9eddc2dcd54cccbfa5c63c2bc42a4888dd28e8bb Mon Sep 17 00:00:00 2001 From: a620381 Date: Thu, 8 Nov 2018 13:42:14 +0100 Subject: [PATCH 03/27] Updates CNR --- CHANGES_NEXT_RELEASE | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index b3b7e6335..8fd64d949 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -22,3 +22,4 @@ Fix: updating dependencies due to known vulnerabilities in the previous ones Remove: old unused dependencies (sax, grunt, closure-linter-wrapper) Fix: mosquitto.conf.example file not found by iot/mosquitto Dockerfile (#554) Fix: isDomain is not used anymore for context availability registration (#701) +Fix: corrects linting and includes npm run lint in travis From 749e1751e41ea144efdd10e6ef2f45a4f73a00bd Mon Sep 17 00:00:00 2001 From: a620381 Date: Thu, 8 Nov 2018 15:58:29 +0100 Subject: [PATCH 04/27] Restores deleted code --- lib/plugins/attributeAlias.js | 4 ++++ lib/plugins/expressionPlugin.js | 4 ++++ lib/plugins/multiEntity.js | 4 ++++ package.json | 2 +- 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/plugins/attributeAlias.js b/lib/plugins/attributeAlias.js index 2a90b1099..86b03f597 100644 --- a/lib/plugins/attributeAlias.js +++ b/lib/plugins/attributeAlias.js @@ -27,6 +27,10 @@ var config = require('../commonConfig'), utils = require('./pluginUtils'), + logger = require('logops'), + context = { + op: 'IoTAgentNGSI.attributeAlias' + }, ngsiService = require('../services/ngsi/ngsiService'); function extractSingleMapping(previous, current) { diff --git a/lib/plugins/expressionPlugin.js b/lib/plugins/expressionPlugin.js index abff011a6..d726063a8 100644 --- a/lib/plugins/expressionPlugin.js +++ b/lib/plugins/expressionPlugin.js @@ -29,6 +29,10 @@ var _ = require('underscore'), parser = require('./expressionParser'), config = require('../commonConfig'), + logger = require('logops'), + context = { + op: 'IoTAgentNGSI.expressionPlugin' + }, utils = require('./pluginUtils'); function mergeAttributes(attrList1, attrList2) { diff --git a/lib/plugins/multiEntity.js b/lib/plugins/multiEntity.js index cd657a203..be4cc5981 100644 --- a/lib/plugins/multiEntity.js +++ b/lib/plugins/multiEntity.js @@ -30,6 +30,10 @@ var _ = require('underscore'), parser = require('./expressionParser'), config = require('../commonConfig'), + logger = require('logops'), + context = { + op: 'IoTAgentNGSI.MultiEntityPlugin' + }, utils = require('./pluginUtils'), aliasPlugin = require('./attributeAlias'); diff --git a/package.json b/package.json index 74ad2c883..c0a18641b 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "clean": "rm -rf package-lock.json && rm -rf node_modules && rm -rf coverage", "test": "mocha --recursive 'test/**/*.js' --reporter spec --timeout 3000 --ui bdd --exit", "test:watch": "npm run test -- -w ./lib", - "lint": "jshint lib/ --config .jshintrc && jshint test/ --config test/.jshintrc", + "lint": "jshint lib/ --config .jshintrc && jshint test/ --config test/.jshintrc", "test:coverage": "istanbul cover _mocha -- --recursive 'test/**/*.js' --reporter spec --exit", "watch": "watch 'npm test && npm run lint' ./lib ./test" }, From f467b5aaa51fdb4391d84664ff2129d92599dcba Mon Sep 17 00:00:00 2001 From: a620381 Date: Thu, 8 Nov 2018 16:02:20 +0100 Subject: [PATCH 05/27] Restores deleted code --- lib/plugins/attributeAlias.js | 2 ++ lib/plugins/expressionPlugin.js | 2 ++ lib/plugins/multiEntity.js | 2 ++ 3 files changed, 6 insertions(+) diff --git a/lib/plugins/attributeAlias.js b/lib/plugins/attributeAlias.js index 86b03f597..bfd95893f 100644 --- a/lib/plugins/attributeAlias.js +++ b/lib/plugins/attributeAlias.js @@ -27,7 +27,9 @@ var config = require('../commonConfig'), utils = require('./pluginUtils'), + /*jshint unused:false*/ logger = require('logops'), + /*jshint unused:false*/ context = { op: 'IoTAgentNGSI.attributeAlias' }, diff --git a/lib/plugins/expressionPlugin.js b/lib/plugins/expressionPlugin.js index d726063a8..ae5349f6d 100644 --- a/lib/plugins/expressionPlugin.js +++ b/lib/plugins/expressionPlugin.js @@ -29,7 +29,9 @@ var _ = require('underscore'), parser = require('./expressionParser'), config = require('../commonConfig'), + /*jshint unused:false*/ logger = require('logops'), + /*jshint unused:false*/ context = { op: 'IoTAgentNGSI.expressionPlugin' }, diff --git a/lib/plugins/multiEntity.js b/lib/plugins/multiEntity.js index be4cc5981..7eee9addb 100644 --- a/lib/plugins/multiEntity.js +++ b/lib/plugins/multiEntity.js @@ -30,7 +30,9 @@ var _ = require('underscore'), parser = require('./expressionParser'), config = require('../commonConfig'), + /*jshint unused:false*/ logger = require('logops'), + /*jshint unused:false*/ context = { op: 'IoTAgentNGSI.MultiEntityPlugin' }, From 082030fb26574c2bb4f1992ced8cec24cd8d5e12 Mon Sep 17 00:00:00 2001 From: a620381 Date: Thu, 8 Nov 2018 16:23:09 +0100 Subject: [PATCH 06/27] Address comments of PR #707 --- lib/services/groups/groupService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/groups/groupService.js b/lib/services/groups/groupService.js index a892bd6c4..231ba8b6d 100644 --- a/lib/services/groups/groupService.js +++ b/lib/services/groups/groupService.js @@ -191,7 +191,7 @@ function remove(service, subservice, resource, apikey, device, callback) { async.map(devices.devices, unregisterDevice, function(error) { if (error) { callback(error); - } + } }); } } From 00a9f128e5b616eb08e1f29c96b4ef39dc423773 Mon Sep 17 00:00:00 2001 From: a620381 Date: Fri, 9 Nov 2018 21:24:53 +0100 Subject: [PATCH 07/27] Implements #679 --- CHANGES_NEXT_RELEASE | 1 + lib/errors.js | 7 ++++ lib/services/ngsi/ngsiService.js | 34 +++++++++++---- lib/services/northBound/restUtils.js | 41 +++++++++++++++++++ test/unit/ngsiService/active-devices-test.js | 40 ++++++++++++++++++ .../ngsiv2/ngsiService/active-devices-test.js | 40 ++++++++++++++++++ 6 files changed, 154 insertions(+), 9 deletions(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index b3b7e6335..ec2fe36dd 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -22,3 +22,4 @@ Fix: updating dependencies due to known vulnerabilities in the previous ones Remove: old unused dependencies (sax, grunt, closure-linter-wrapper) Fix: mosquitto.conf.example file not found by iot/mosquitto Dockerfile (#554) Fix: isDomain is not used anymore for context availability registration (#701) +Add: checks ISO8601 timeinstants provided by devices (#679) diff --git a/lib/errors.js b/lib/errors.js index e96a13cde..68c363b2b 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -19,6 +19,8 @@ * * For those usages not covered by the GNU Affero General Public License * please contact with::daniel.moranjimenez@telefonica.com + * + * Modified by: Daniel Calvo - ATOS Research & Innovation */ 'use strict'; @@ -168,5 +170,10 @@ module.exports = { this.name = 'BAD_ANSWER'; this.message = 'Invalid statusCode in operation [' + operation + ']'; this.code = 400; + }, + BadTimestamp: function(payload) { + this.name = 'BAD_TIMESTAMP'; + this.message = 'Invalid ISO8601 timestamp[' + payload + ']'; + this.code = 400; } }; diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index b6026488a..2e96e5676 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -470,9 +470,14 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca typeInformation, token); - if ( (('timestamp' in typeInformation && typeInformation['timestamp'] !== undefined) ? typeInformation.timestamp : config.getConfig().timestamp) && - ! utils.isTimestampedNgsi2(result)) { - result = addTimestampNgsi2(result, typeInformation.timezone); + if ( ('timestamp' in typeInformation && typeInformation['timestamp'] !== undefined) ? typeInformation.timestamp : config.getConfig().timestamp) { + if (!utils.isTimestampedNgsi2(result)) { + options.json = addTimestampNgsi2(result, typeInformation.timezone); + } else if (!utils.IsValidTimestampedNgsi2(result)) { + logger.error(context, 'Invalid timestamp:%s', JSON.stringify(result)); + callback(new errors.BadTimestamp(result)); + return; + } } options.json = { @@ -484,9 +489,14 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca delete result.type; options.json = result; logger.debug(context, 'typeInformation: %j', typeInformation); - if ( (('timestamp' in typeInformation && typeInformation['timestamp'] !== undefined) ? typeInformation.timestamp : config.getConfig().timestamp) && - ! utils.isTimestampedNgsi2(options.json)) { - options.json = addTimestampNgsi2(options.json, typeInformation.timezone); + if ( ('timestamp' in typeInformation && typeInformation['timestamp'] !== undefined) ? typeInformation.timestamp : config.getConfig().timestamp) { + if (!utils.isTimestampedNgsi2(options.json)) { + options.json = addTimestampNgsi2(options.json, typeInformation.timezone); + } else if (!utils.IsValidTimestampedNgsi2(options.json)) { + logger.error(context, 'Invalid timestamp:%s', JSON.stringify(options.json)); + callback(new errors.BadTimestamp(options.json)); + return; + } } } } else { @@ -556,9 +566,15 @@ function sendUpdateValueNgsi1(entityName, attributes, typeInformation, token, ca options.json = payload; } - if ( (('timestamp' in typeInformation && typeInformation['timestamp'] !== undefined) ? typeInformation.timestamp : config.getConfig().timestamp) && - ! utils.isTimestamped(options.json)) { - options.json = addTimestamp(options.json, typeInformation.timezone); + if ( ('timestamp' in typeInformation && typeInformation['timestamp'] !== undefined) ? typeInformation.timestamp : config.getConfig().timestamp) { + if (!utils.isTimestamped(options.json)) { + options.json = addTimestamp(options.json, typeInformation.timezone); + } else if (!utils.IsValidTimestamped(options.json)) { + logger.error(context, 'Invalid timestamp:%s', JSON.stringify(options.json)); + callback(new errors.BadTimestamp(options.json)); + return; + } + } logger.debug(context, 'Updating device value in the Context Broker at [%s]', options.url); diff --git a/lib/services/northBound/restUtils.js b/lib/services/northBound/restUtils.js index 12d690b3c..b862f9c69 100644 --- a/lib/services/northBound/restUtils.js +++ b/lib/services/northBound/restUtils.js @@ -29,6 +29,7 @@ var logger = require('logops'), constants = require('../../constants'), intoTrans = require('../common/domain').intoTrans, revalidator = require('revalidator'), + moment = require('moment'), context = { op: 'IoTAgentNGSI.RestUtils' }, @@ -140,6 +141,44 @@ function checkBody(template) { }; } +function IsValidTimestamped(payload) { + for (var i in payload.contextElements[0].attributes) { + if (payload.contextElements[0].attributes[i].name === constants.TIMESTAMP_ATTRIBUTE && + ! moment(payload.contextElements[0].attributes[i].value, moment.ISO_8601).isValid()) { + return false; + } + } + + return true; +} + +function IsValidTimestampedNgsi2(payload) { + function isValidTimestampedNgsi2Entity(entity) { + for (var i in entity) { + if (entity.hasOwnProperty(i)) { + if (i === constants.TIMESTAMP_ATTRIBUTE && + ! moment(entity[i].value, moment.ISO_8601).isValid()) { + return false; + } + } + } + + return true; + } + + if (payload instanceof Array) { + for (var i = 0; i < payload.length; i++) { + if (!isValidTimestampedNgsi2Entity(payload[i])) { + return false; + } + } + + return true; + } else { + return isValidTimestampedNgsi2Entity(payload); + } +} + function isTimestamped(payload) { for (var i in payload.contextElements[0].attributes) { if (payload.contextElements[0].attributes[i].name === constants.TIMESTAMP_ATTRIBUTE) { @@ -182,4 +221,6 @@ exports.xmlRawBody = intoTrans(context, xmlRawBody); exports.checkRequestAttributes = intoTrans(context, checkRequestAttributes); exports.checkBody = intoTrans(context, checkBody); exports.isTimestamped = isTimestamped; +exports.IsValidTimestamped = IsValidTimestamped; exports.isTimestampedNgsi2 = isTimestampedNgsi2; +exports.IsValidTimestampedNgsi2 = IsValidTimestampedNgsi2; diff --git a/test/unit/ngsiService/active-devices-test.js b/test/unit/ngsiService/active-devices-test.js index 9d963cf90..35c227475 100644 --- a/test/unit/ngsiService/active-devices-test.js +++ b/test/unit/ngsiService/active-devices-test.js @@ -352,6 +352,46 @@ describe('Active attributes test', function() { }); }); + describe('When the IoTA gets a set of values with a TimeInstant which are not in ISO8601 format', function() { + var modifiedValues; + + beforeEach(function(done) { + var time = new Date(1438760101468); // 2015-08-05T07:35:01.468+00:00 + + modifiedValues = [ + { + name: 'state', + type: 'Boolean', + value: 'true' + }, + { + name: 'TimeInstant', + type: 'ISO8601', + value: '2015-12-14T08:06:01 00.46Z' + } + ]; + + nock.cleanAll(); + + iotAgentConfig.timestamp = true; + iotAgentLib.activate(iotAgentConfig, done); + }); + + afterEach(function(done) { + delete iotAgentConfig.timestamp; + done(); + }); + + it('should fail with a 400 BAD_TIMESTAMP error', function(done) { + iotAgentLib.update('light1', 'Light', '', modifiedValues, function(error) { + should.exist(error); + error.code.should.equal(400); + error.name.should.equal('BAD_TIMESTAMP'); + done(); + }); + }); + }); + describe('When the IoTA gets a set of values with a TimeInstant, the timestamp flag is on' + 'and timezone is defined', function() { var modifiedValues; diff --git a/test/unit/ngsiv2/ngsiService/active-devices-test.js b/test/unit/ngsiv2/ngsiService/active-devices-test.js index 2e214bab0..1ffa744ae 100644 --- a/test/unit/ngsiv2/ngsiService/active-devices-test.js +++ b/test/unit/ngsiv2/ngsiService/active-devices-test.js @@ -217,6 +217,46 @@ describe('Active attributes test', function() { }); }); + describe('When the IoTA gets a set of values with a TimeInstant which are not in ISO8601 format', function() { + var modifiedValues; + + beforeEach(function(done) { + var time = new Date(1438760101468); // 2015-08-05T07:35:01.468+00:00 + + modifiedValues = [ + { + name: 'state', + type: 'Boolean', + value: 'true' + }, + { + name: 'TimeInstant', + type: 'ISO8601', + value: '2015-12-14T08:06:01 00.46Z' + } + ]; + + nock.cleanAll(); + + iotAgentConfig.timestamp = true; + iotAgentLib.activate(iotAgentConfig, done); + }); + + afterEach(function(done) { + delete iotAgentConfig.timestamp; + done(); + }); + + it('should fail with a 400 BAD_TIMESTAMP error', function(done) { + iotAgentLib.update('light1', 'Light', '', modifiedValues, function(error) { + should.exist(error); + error.code.should.equal(400); + error.name.should.equal('BAD_TIMESTAMP'); + done(); + }); + }); + }); + describe('When the IoT Agent receives new information, the timestamp flag is on' + 'and timezone is defined', function() { var modifiedValues; From ccfb974104b9aceecac889fa524e016c81f8a6e0 Mon Sep 17 00:00:00 2001 From: a620381 Date: Tue, 13 Nov 2018 09:54:57 +0100 Subject: [PATCH 08/27] Address comments of PR #708 --- CHANGES_NEXT_RELEASE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index ec2fe36dd..384275028 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -22,4 +22,4 @@ Fix: updating dependencies due to known vulnerabilities in the previous ones Remove: old unused dependencies (sax, grunt, closure-linter-wrapper) Fix: mosquitto.conf.example file not found by iot/mosquitto Dockerfile (#554) Fix: isDomain is not used anymore for context availability registration (#701) -Add: checks ISO8601 timeinstants provided by devices (#679) +Fix: checks ISO8601 timeinstants provided by devices (#679) From 1cfb789978af5af81078925d636006848a703c19 Mon Sep 17 00:00:00 2001 From: a620381 Date: Tue, 13 Nov 2018 09:55:56 +0100 Subject: [PATCH 09/27] Address comments of PR #708 --- lib/errors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/errors.js b/lib/errors.js index 68c363b2b..e962c6091 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -173,7 +173,7 @@ module.exports = { }, BadTimestamp: function(payload) { this.name = 'BAD_TIMESTAMP'; - this.message = 'Invalid ISO8601 timestamp[' + payload + ']'; + this.message = 'Invalid ISO8601 timestamp [' + payload + ']'; this.code = 400; } }; From 3d126264cb002fbc5a4c4ce2960c126238efc748 Mon Sep 17 00:00:00 2001 From: a620381 Date: Tue, 13 Nov 2018 10:05:13 +0100 Subject: [PATCH 10/27] Address comments of PR #708 --- lib/services/northBound/restUtils.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/services/northBound/restUtils.js b/lib/services/northBound/restUtils.js index b862f9c69..8dd1e021f 100644 --- a/lib/services/northBound/restUtils.js +++ b/lib/services/northBound/restUtils.js @@ -141,6 +141,12 @@ function checkBody(template) { }; } +/** + * Checks if the timestamp properties of NGSIv1 entities are valid ISO8601 dates. + * + * @param {Object} payload NGSIv1 payload to be analyzed. + * @return {Boolean} true if timestamp attributes are valid ISO8601. false if not. + */ function IsValidTimestamped(payload) { for (var i in payload.contextElements[0].attributes) { if (payload.contextElements[0].attributes[i].name === constants.TIMESTAMP_ATTRIBUTE && @@ -152,6 +158,12 @@ function IsValidTimestamped(payload) { return true; } +/** + * Checks if the timestamp properties of NGSIv2 entities are valid ISO8601 dates. + * + * @param {Object} payload NGSIv2 payload to be analyzed. + * @return {Boolean} true if timestamp attributes are valid ISO8601. false if not. + */ function IsValidTimestampedNgsi2(payload) { function isValidTimestampedNgsi2Entity(entity) { for (var i in entity) { @@ -179,6 +191,12 @@ function IsValidTimestampedNgsi2(payload) { } } +/** + * Checks if timestamp attributes are included in NGSIv1 entities. + * + * @param {Object} payload NGSIv1 payload to be analyzed. + * @return {Boolean} true if timestamp attributes are included. false if not. + */ function isTimestamped(payload) { for (var i in payload.contextElements[0].attributes) { if (payload.contextElements[0].attributes[i].name === constants.TIMESTAMP_ATTRIBUTE) { @@ -189,6 +207,12 @@ function isTimestamped(payload) { return false; } +/** + * Checks if timestamp attributes are included in NGSIv1 entities. + * + * @param {Object} payload NGSIv1 payload to be analyzed. + * @return {Boolean} true if timestamp attributes are included. false if not. + */ function isTimestampedNgsi2(payload) { function isTimestampedNgsi2Entity(entity) { From dc0db77cba9d68d8ef89c0bdc22cf8691b7bf112 Mon Sep 17 00:00:00 2001 From: a620381 Date: Tue, 13 Nov 2018 10:10:00 +0100 Subject: [PATCH 11/27] Address comments of PR #708 --- test/unit/ngsiv2/ngsiService/active-devices-test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/ngsiv2/ngsiService/active-devices-test.js b/test/unit/ngsiv2/ngsiService/active-devices-test.js index 1ffa744ae..3ce44f8b9 100644 --- a/test/unit/ngsiv2/ngsiService/active-devices-test.js +++ b/test/unit/ngsiv2/ngsiService/active-devices-test.js @@ -221,7 +221,6 @@ describe('Active attributes test', function() { var modifiedValues; beforeEach(function(done) { - var time = new Date(1438760101468); // 2015-08-05T07:35:01.468+00:00 modifiedValues = [ { From ae5ab803548af6c228eeec8ade20c5756f60eef5 Mon Sep 17 00:00:00 2001 From: a620381 Date: Tue, 13 Nov 2018 10:15:59 +0100 Subject: [PATCH 12/27] Address comments of PR #708 --- test/unit/ngsiService/active-devices-test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/ngsiService/active-devices-test.js b/test/unit/ngsiService/active-devices-test.js index 35c227475..49c2eb654 100644 --- a/test/unit/ngsiService/active-devices-test.js +++ b/test/unit/ngsiService/active-devices-test.js @@ -356,7 +356,6 @@ describe('Active attributes test', function() { var modifiedValues; beforeEach(function(done) { - var time = new Date(1438760101468); // 2015-08-05T07:35:01.468+00:00 modifiedValues = [ { From 171064daac4c14a3e985453dd040294410ffba2c Mon Sep 17 00:00:00 2001 From: a620381 Date: Tue, 13 Nov 2018 10:19:23 +0100 Subject: [PATCH 13/27] Address comments of PR #708 --- test/unit/ngsiService/active-devices-test.js | 2 +- test/unit/ngsiv2/ngsiService/active-devices-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/ngsiService/active-devices-test.js b/test/unit/ngsiService/active-devices-test.js index 49c2eb654..358f8b2a4 100644 --- a/test/unit/ngsiService/active-devices-test.js +++ b/test/unit/ngsiService/active-devices-test.js @@ -366,7 +366,7 @@ describe('Active attributes test', function() { { name: 'TimeInstant', type: 'ISO8601', - value: '2015-12-14T08:06:01 00.46Z' + value: '2018-10-05T11:03:56 00:00Z' } ]; diff --git a/test/unit/ngsiv2/ngsiService/active-devices-test.js b/test/unit/ngsiv2/ngsiService/active-devices-test.js index 3ce44f8b9..8b7c14af9 100644 --- a/test/unit/ngsiv2/ngsiService/active-devices-test.js +++ b/test/unit/ngsiv2/ngsiService/active-devices-test.js @@ -231,7 +231,7 @@ describe('Active attributes test', function() { { name: 'TimeInstant', type: 'ISO8601', - value: '2015-12-14T08:06:01 00.46Z' + value: '2018-10-05T11:03:56 00:00Z' } ]; From fae3e296805e6c025e216739a6b66a79d5053310 Mon Sep 17 00:00:00 2001 From: a620381 Date: Tue, 13 Nov 2018 11:46:09 +0100 Subject: [PATCH 14/27] Corrects JavaDoc --- lib/services/northBound/restUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/northBound/restUtils.js b/lib/services/northBound/restUtils.js index 8dd1e021f..e17b00979 100644 --- a/lib/services/northBound/restUtils.js +++ b/lib/services/northBound/restUtils.js @@ -208,7 +208,7 @@ function isTimestamped(payload) { } /** - * Checks if timestamp attributes are included in NGSIv1 entities. + * Checks if timestamp attributes are included in NGSIv2 entities. * * @param {Object} payload NGSIv1 payload to be analyzed. * @return {Boolean} true if timestamp attributes are included. false if not. From dd947ccfb612f62cdb9fbdf67f2350a23c67b78e Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 14 Nov 2018 11:37:15 +0100 Subject: [PATCH 15/27] revert filterByObjectId --- CHANGES_NEXT_RELEASE | 1 + lib/plugins/attributeAlias.js | 5 +---- lib/plugins/multiEntity.js | 35 ++++++++++++++++++++++++++++++-- lib/plugins/pluginUtils.js | 7 +++++-- lib/services/ngsi/ngsiService.js | 18 ++++++++++++++++ 5 files changed, 58 insertions(+), 8 deletions(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index b3b7e6335..58b92feb6 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,3 +1,4 @@ +Fix: revert usage of restore filter by attribute object ids Add missed conf env vars about authentication (#704) Add timestamp in device and group provision (#655) Fix: missing support for device=true in the delete service endpoint (see #596) diff --git a/lib/plugins/attributeAlias.js b/lib/plugins/attributeAlias.js index 0073e3a7a..c1af8bee0 100644 --- a/lib/plugins/attributeAlias.js +++ b/lib/plugins/attributeAlias.js @@ -38,10 +38,7 @@ function extractSingleMapping(previous, current) { previous.direct[current.object_id] = current.name; previous.types[current.object_id] = current.type; - if (!previous.inverse[current.name]) { - previous.inverse[current.name] = []; - } - previous.inverse[current.name].push(current.object_id); // collision using multientity + previous.inverse[current.name] = current.object_id; // collision using multientity return previous; } diff --git a/lib/plugins/multiEntity.js b/lib/plugins/multiEntity.js index 89102f30e..65357ff2b 100644 --- a/lib/plugins/multiEntity.js +++ b/lib/plugins/multiEntity.js @@ -184,13 +184,44 @@ function generateNewCEsNgsi2(entity, newEntities, entityTypes, typeInformation, return result; } + function filterByAttributeObjectIds() { + var result = {}; + for (var att in entity) { + if (entity.hasOwnProperty(att)) { + if (_.contains(newEntityAttributeNames, att)) { + if (entity[att].object_id && _.contains(newEntityAttributeObjectIds, entity[att].object_id )){ + result[att] = entity[att]; + delete entity[att].object_id; + } else { + // Check matches in rest of multientity attributes with same name (#635) + if (entity[att].multi) { + for (var j in entity[att].multi) { + if (entity[att].multi[j].object_id && _.contains(newEntityAttributeObjectIds, entity[att].multi[j].object_id)) { + result[att] = entity[att].multi[j]; + delete entity[att].multi[j].object_id; + } + } + delete entity[att].multi; + } else { + if (entity[att].object_id) { + delete entity[att].object_id; // clean object_id + } + } + } + } + } + } + return result; + } + var attsArray = utils.extractAttributesArrayFromNgsi2Entity(entity); ctx = parser.extractContext(attsArray); for (var i = 0; i < newEntities.length; i++) { newEntityAttributeNames = _.pluck(multiEntityAttributes.filter(filterByEntityName(newEntities[i])), 'name'); newEntityAttributeObjectIds = _.pluck(multiEntityAttributes.filter(filterByEntityName(newEntities[i])), 'object_id'); - newEntityAttributes = filterAttributes(); + //newEntityAttributes = filterAttributes(); + newEntityAttributes = filterByAttributeObjectIds(); entityName = parser.applyExpression(newEntities[i], ctx, typeInformation); newEntityAttributes.type = entityTypes[newEntities[i]]; @@ -264,4 +295,4 @@ function updateAttribute(entity, typeInformation, callback) { } } -exports.update = updateAttribute; \ No newline at end of file +exports.update = updateAttribute; diff --git a/lib/plugins/pluginUtils.js b/lib/plugins/pluginUtils.js index e99ca18e3..e53e0d5e2 100644 --- a/lib/plugins/pluginUtils.js +++ b/lib/plugins/pluginUtils.js @@ -63,12 +63,12 @@ function extractAttributesArrayFromNgsi2Entity(entity) { * @param {Object} attsArray The atts array * @return {Object} A NGSIv2 entity */ -function createNgsi2Entity(id, type, attsArray, objectId) { +function createNgsi2Entity(id, type, attsArray, withObjectId) { var entity = {}; entity.id = id; entity.type = type; for (var i = 0; i < attsArray.length; i++) { - if (entity[attsArray[i].name] && objectId && attsArray[i].object_id) { + if (entity[attsArray[i].name] && withObjectId && attsArray[i].object_id) { // Check if multiple measures with multientity attributes with same name(#635) if (!entity[attsArray[i].name].multi) { entity[attsArray[i].name].multi = []; @@ -85,6 +85,9 @@ function createNgsi2Entity(id, type, attsArray, objectId) { 'value' : attsArray[i].value, 'metadata' : attsArray[i].metadata }; + if (withObjectId && attsArray[i].object_id) { + entity[attsArray[i].name].object_id = attsArray[i].object_id; + } } } diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index b6026488a..a6374cd0e 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -494,6 +494,24 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca delete payload.type; options.json = payload; } + // Try to clean object_id from options.json + if (options.json.entities) { + for (var entity = 0; entity < options.json.entities.length; entity++) { + for (var att in options.json.entities[entity]) { + console.log(options.json.entities[entity][att]); + if (options.json.entities[entity][att].object_id) { + delete options.json.entities[entity][att].object_id; + } + } + } + } else { + for (var att in options.json) { + console.log(options.json[att]); + if (options.json[att].object_id) { + delete options.json[att].object_id; + } + } + } logger.debug(context, 'Updating device value in the Context Broker at [%s]', options.url); logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4)); From 8f5b288f4b30f098b556d94c74b393efddbc7609 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 14 Nov 2018 12:49:53 +0100 Subject: [PATCH 16/27] remove --- lib/plugins/multiEntity.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/plugins/multiEntity.js b/lib/plugins/multiEntity.js index 65357ff2b..02ee4d12e 100644 --- a/lib/plugins/multiEntity.js +++ b/lib/plugins/multiEntity.js @@ -202,10 +202,6 @@ function generateNewCEsNgsi2(entity, newEntities, entityTypes, typeInformation, } } delete entity[att].multi; - } else { - if (entity[att].object_id) { - delete entity[att].object_id; // clean object_id - } } } } From adf13637cd292fd5caf1c75b4cafc680bc3f5db5 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 14 Nov 2018 14:26:44 +0100 Subject: [PATCH 17/27] remove console.log --- lib/services/ngsi/ngsiService.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index a6374cd0e..a21f63860 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -498,7 +498,6 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca if (options.json.entities) { for (var entity = 0; entity < options.json.entities.length; entity++) { for (var att in options.json.entities[entity]) { - console.log(options.json.entities[entity][att]); if (options.json.entities[entity][att].object_id) { delete options.json.entities[entity][att].object_id; } @@ -506,7 +505,6 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca } } else { for (var att in options.json) { - console.log(options.json[att]); if (options.json[att].object_id) { delete options.json[att].object_id; } From 8ec2c20f3603c1d948d2076ecfea4cf563e1259a Mon Sep 17 00:00:00 2001 From: a620381 Date: Wed, 14 Nov 2018 21:31:58 +0100 Subject: [PATCH 18/27] Adds unit test --- ...ateContextMultientityTimestampPlugin4.json | 23 ++++++ .../ngsiv2/plugins/multientity-plugin_test.js | 76 ++++++++++++++++++- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json diff --git a/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json b/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json new file mode 100644 index 000000000..82fe577e3 --- /dev/null +++ b/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json @@ -0,0 +1,23 @@ +{ + "actionType": "APPEND", + "entities": [ + { + "id": "Sensor001", + "type": "Sensor", + "vol": { + "type": "number", + "value": "38", + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2018-06-13T13:28:34.611Z" + } + } + }, + "TimeInstant": { + "type": "DateTime", + "value": "2018-06-13T13:28:34.611Z" + } + } + ] +} diff --git a/test/unit/ngsiv2/plugins/multientity-plugin_test.js b/test/unit/ngsiv2/plugins/multientity-plugin_test.js index 963d87e3f..8b1183a38 100644 --- a/test/unit/ngsiv2/plugins/multientity-plugin_test.js +++ b/test/unit/ngsiv2/plugins/multientity-plugin_test.js @@ -137,7 +137,51 @@ var iotAgentLib = require('../../../../lib/fiware-iotagent-lib'), entity_type: 'Higrometer' } ] - } + }, + 'Sensor001': { + commands: [], + type: 'Sensor', + lazy: [], + active: [ + { + type : 'number', + name : 'vol', + object_id : 'cont1', + entity_name : 'SO1', + entity_type : 'WM' + }, + { + type : 'number', + name : 'vol', + object_id : 'cont2', + entity_name : 'SO2', + entity_type : 'WM' + }, + { + type : 'number', + name : 'vol', + object_id : 'cont3', + entity_name : 'SO3', + entity_type : 'WM' + }, + { + type : 'number', + name : 'vol', + object_id : 'cont4', + entity_name : 'SO4', + entity_type : 'WM' + }, + { + type : 'number', + name : 'vol', + object_id : 'cont5', + entity_name : 'SO5', + entity_type : 'WM' + } + ] + + }, + }, service: 'smartGondor', subservice: 'gardens', @@ -336,6 +380,36 @@ describe('Multi-entity plugin', function() { }); }); }); + + describe('When an update comes for a multientity measurement and there are attributes with' + + ' the same name but different alias and mapped to different CB entities', function() { + var values = [ + { + name: 'cont1', + type: 'number', + value: '38' + } + ]; + + beforeEach(function() { + nock.cleanAll(); + + contextBrokerMock = nock('http://192.168.1.1:1026') + .matchHeader('fiware-service', 'smartGondor') + .matchHeader('fiware-servicepath', 'gardens') + .post('/v2/op/update', utils.readExampleFile( + './test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json')) + .reply(204); + }); + + it('should update only the appropriate CB entity', function(done) { + iotAgentLib.update('Sensor', 'Sensor001', '', values, function(error) { + should.not.exist(error); + contextBrokerMock.done(); + done(); + }); + }); + }); }); describe('Multi-entity plugin is executed before timestamp process plugin', function() { From c71c1b861358226024d56336938c3187f9a167d9 Mon Sep 17 00:00:00 2001 From: a620381 Date: Wed, 14 Nov 2018 21:45:51 +0100 Subject: [PATCH 19/27] Corrects test --- .../updateContextMultientityPlugin6.json | 33 +++++++++++++ ...ateContextMultientityTimestampPlugin4.json | 48 +++++++++++-------- .../ngsiv2/plugins/multientity-plugin_test.js | 2 +- 3 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json diff --git a/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json b/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json new file mode 100644 index 000000000..a434f55db --- /dev/null +++ b/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json @@ -0,0 +1,33 @@ +{ + "actionType": "APPEND", + "entities": [ + { + "id": "Sensor", + "type": "Sensor" + }, + { + "vol": { + "type": "number", + "value": "38" + }, + "type": "WM", + "id": "SO1" + }, + { + "type": "WM", + "id": "SO2" + }, + { + "type": "WM", + "id": "SO3" + }, + { + "type": "WM", + "id": "SO4" + }, + { + "type": "WM", + "id": "SO5" + } + ] +} diff --git a/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json b/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json index 82fe577e3..a434f55db 100644 --- a/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +++ b/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json @@ -1,23 +1,33 @@ { "actionType": "APPEND", "entities": [ - { - "id": "Sensor001", - "type": "Sensor", - "vol": { - "type": "number", - "value": "38", - "metadata": { - "TimeInstant": { - "type": "DateTime", - "value": "2018-06-13T13:28:34.611Z" - } - } - }, - "TimeInstant": { - "type": "DateTime", - "value": "2018-06-13T13:28:34.611Z" - } - } - ] + { + "id": "Sensor", + "type": "Sensor" + }, + { + "vol": { + "type": "number", + "value": "38" + }, + "type": "WM", + "id": "SO1" + }, + { + "type": "WM", + "id": "SO2" + }, + { + "type": "WM", + "id": "SO3" + }, + { + "type": "WM", + "id": "SO4" + }, + { + "type": "WM", + "id": "SO5" + } + ] } diff --git a/test/unit/ngsiv2/plugins/multientity-plugin_test.js b/test/unit/ngsiv2/plugins/multientity-plugin_test.js index 8b1183a38..32db86a97 100644 --- a/test/unit/ngsiv2/plugins/multientity-plugin_test.js +++ b/test/unit/ngsiv2/plugins/multientity-plugin_test.js @@ -398,7 +398,7 @@ describe('Multi-entity plugin', function() { .matchHeader('fiware-service', 'smartGondor') .matchHeader('fiware-servicepath', 'gardens') .post('/v2/op/update', utils.readExampleFile( - './test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json')) + './test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json')) .reply(204); }); From 06b1f856d1b0044c94bc2b0811a73b1e5695402a Mon Sep 17 00:00:00 2001 From: a620381 Date: Wed, 14 Nov 2018 21:46:21 +0100 Subject: [PATCH 20/27] Removes test --- ...ateContextMultientityTimestampPlugin4.json | 33 ------------------- 1 file changed, 33 deletions(-) delete mode 100644 test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json diff --git a/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json b/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json deleted file mode 100644 index a434f55db..000000000 --- a/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin4.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "actionType": "APPEND", - "entities": [ - { - "id": "Sensor", - "type": "Sensor" - }, - { - "vol": { - "type": "number", - "value": "38" - }, - "type": "WM", - "id": "SO1" - }, - { - "type": "WM", - "id": "SO2" - }, - { - "type": "WM", - "id": "SO3" - }, - { - "type": "WM", - "id": "SO4" - }, - { - "type": "WM", - "id": "SO5" - } - ] -} From 563d687b2b11004109478e9d3ea1a9fd084d7ded Mon Sep 17 00:00:00 2001 From: a620381 Date: Thu, 15 Nov 2018 08:17:43 +0100 Subject: [PATCH 21/27] Adds esversion 6 to jsintrc within test folder --- test/.jshintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/.jshintrc b/test/.jshintrc index d44254452..2cbeefda0 100644 --- a/test/.jshintrc +++ b/test/.jshintrc @@ -17,6 +17,7 @@ "node": true, "expr": true, "unused": "vars", + "esversion": 6, "globals": { "describe":true, "it": true, From a79ffd8438cadf1fd25a5cc22e3e49ec8170a437 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 15 Nov 2018 09:45:18 +0100 Subject: [PATCH 22/27] add doc --- lib/plugins/multiEntity.js | 1 - lib/plugins/pluginUtils.js | 1 + lib/services/ngsi/ngsiService.js | 4 +++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/plugins/multiEntity.js b/lib/plugins/multiEntity.js index 02ee4d12e..3ba6597b4 100644 --- a/lib/plugins/multiEntity.js +++ b/lib/plugins/multiEntity.js @@ -216,7 +216,6 @@ function generateNewCEsNgsi2(entity, newEntities, entityTypes, typeInformation, for (var i = 0; i < newEntities.length; i++) { newEntityAttributeNames = _.pluck(multiEntityAttributes.filter(filterByEntityName(newEntities[i])), 'name'); newEntityAttributeObjectIds = _.pluck(multiEntityAttributes.filter(filterByEntityName(newEntities[i])), 'object_id'); - //newEntityAttributes = filterAttributes(); newEntityAttributes = filterByAttributeObjectIds(); entityName = parser.applyExpression(newEntities[i], ctx, typeInformation); diff --git a/lib/plugins/pluginUtils.js b/lib/plugins/pluginUtils.js index e53e0d5e2..d1a7e100b 100644 --- a/lib/plugins/pluginUtils.js +++ b/lib/plugins/pluginUtils.js @@ -61,6 +61,7 @@ function extractAttributesArrayFromNgsi2Entity(entity) { * @param {String} id The identifier * @param {String} type The type * @param {Object} attsArray The atts array + * @param {Object} withObjectId The flag to keep object_id * @return {Object} A NGSIv2 entity */ function createNgsi2Entity(id, type, attsArray, withObjectId) { diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index a21f63860..8d3385c3f 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -494,7 +494,9 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca delete payload.type; options.json = payload; } - // Try to clean object_id from options.json + // Purge object_id from entities before sent to CB + // object_id was added by createNgsi2Entity to allow multientity + // with duplicate attribute names. if (options.json.entities) { for (var entity = 0; entity < options.json.entities.length; entity++) { for (var att in options.json.entities[entity]) { From 71570d41d324369eb5aad2020a764f289d17a7bf Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 15 Nov 2018 09:46:46 +0100 Subject: [PATCH 23/27] fix CNR --- CHANGES_NEXT_RELEASE | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 58b92feb6..b3b7e6335 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,4 +1,3 @@ -Fix: revert usage of restore filter by attribute object ids Add missed conf env vars about authentication (#704) Add timestamp in device and group provision (#655) Fix: missing support for device=true in the delete service endpoint (see #596) From 7b3802a142df3911e2e7290e06f99b74983cb926 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 15 Nov 2018 11:52:45 +0100 Subject: [PATCH 24/27] allow multientity with a multimeasure in a attribute with the same name --- lib/plugins/multiEntity.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/plugins/multiEntity.js b/lib/plugins/multiEntity.js index 3ba6597b4..9316b183e 100644 --- a/lib/plugins/multiEntity.js +++ b/lib/plugins/multiEntity.js @@ -201,7 +201,6 @@ function generateNewCEsNgsi2(entity, newEntities, entityTypes, typeInformation, delete entity[att].multi[j].object_id; } } - delete entity[att].multi; } } } From 5ab5bd705d91b300b46bba85b01c2a20b439f990 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 15 Nov 2018 13:23:34 +0100 Subject: [PATCH 25/27] remove multi remainder --- lib/services/ngsi/ngsiService.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index 8d3385c3f..5fc0f873c 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -503,6 +503,9 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca if (options.json.entities[entity][att].object_id) { delete options.json.entities[entity][att].object_id; } + if (options.json.entities[entity][att].multi) { + delete options.json.entities[entity][att].multi; + } } } } else { @@ -510,6 +513,9 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca if (options.json[att].object_id) { delete options.json[att].object_id; } + if (options.json[att].multi) { + delete options.json[att].multi; + } } } From c0b0ecb68cae9ba55d9d648e87ef13639b34677a Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 15 Nov 2018 14:26:14 +0100 Subject: [PATCH 26/27] add test --- .../updateContextMultientityPlugin7.json | 45 +++++++++++++++++ .../ngsiv2/plugins/multientity-plugin_test.js | 48 ++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json diff --git a/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json b/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json new file mode 100644 index 000000000..c1c930d34 --- /dev/null +++ b/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json @@ -0,0 +1,45 @@ +{ + "actionType": "APPEND", + "entities": [ + { + "id": "Sensor", + "type": "Sensor" + }, + { + "vol": { + "type": "number", + "value": "38" + }, + "type": "WM", + "id": "SO1" + }, + { + "vol": { + "type": "number", + "value": "39" + }, + "type": "WM", + "id": "SO2" + }, + { + "vol": { + "type": "number", + "value": "40" + }, + "type": "WM", + "id": "SO3" + }, + { + "type": "WM", + "id": "SO4" + }, + { + "vol": { + "type": "number", + "value": "42" + }, + "type": "WM", + "id": "SO5" + } + ] +} diff --git a/test/unit/ngsiv2/plugins/multientity-plugin_test.js b/test/unit/ngsiv2/plugins/multientity-plugin_test.js index 32db86a97..0a9fef5be 100644 --- a/test/unit/ngsiv2/plugins/multientity-plugin_test.js +++ b/test/unit/ngsiv2/plugins/multientity-plugin_test.js @@ -192,7 +192,7 @@ var iotAgentLib = require('../../../../lib/fiware-iotagent-lib'), describe('Multi-entity plugin', function() { beforeEach(function(done) { - logger.setLevel('FATAL'); + logger.setLevel('DEBUG'); iotAgentLib.activate(iotAgentConfig, function() { iotAgentLib.clearAll(function() { @@ -410,6 +410,52 @@ describe('Multi-entity plugin', function() { }); }); }); + + describe('When an update comes for a multientity multi measurement and there are attributes with' + + ' the same name but different alias and mapped to different CB entities', function() { + var values = [ + { + name: 'cont1', + type: 'number', + value: '38' + }, + { + name: 'cont2', + type: 'number', + value: '39' + }, + { + name: 'cont3', + type: 'number', + value: '40' + }, + { + name: 'cont5', + type: 'number', + value: '42' + } + ]; + + beforeEach(function() { + nock.cleanAll(); + + contextBrokerMock = nock('http://192.168.1.1:1026') + .matchHeader('fiware-service', 'smartGondor') + .matchHeader('fiware-servicepath', 'gardens') + .post('/v2/op/update', utils.readExampleFile( + './test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json')) + .reply(204); + }); + + it('should update only the appropriate CB entity', function(done) { + iotAgentLib.update('Sensor', 'Sensor001', '', values, function(error) { + should.not.exist(error); + contextBrokerMock.done(); + done(); + }); + }); + }); + }); describe('Multi-entity plugin is executed before timestamp process plugin', function() { From 40f61775f4c32d10db9bd5f3a59e83b9ff09c6b0 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 15 Nov 2018 15:39:18 +0100 Subject: [PATCH 27/27] update CNR --- CHANGES_NEXT_RELEASE | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index b3b7e6335..2b47ef97b 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,3 +1,4 @@ +Fix: multientity multimeasure with the same att name Add missed conf env vars about authentication (#704) Add timestamp in device and group provision (#655) Fix: missing support for device=true in the delete service endpoint (see #596)