diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 09ee4432f..2c045064a 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -2,6 +2,7 @@ Refresh Documentation Add NGSIv2 metadata support to device provisioned attributes Fix: Error message when sending measures with unknown/undefined attribute Add Null check within executeWithSecurity() to avoid crash (#829) +NGSI-LD Command support (#848) Basic NGSI-LD active measures support (#841) Add GeoJSON and DateTime, unitCode and observedAt NGSI-LD support (#843) - The NGSI v2 `TimeInstant` element has been mapped onto the NGSI-LD `observedAt` property diff --git a/doc/installationguide.md b/doc/installationguide.md index 005caf5fa..e150105eb 100644 --- a/doc/installationguide.md +++ b/doc/installationguide.md @@ -226,6 +226,10 @@ used for the same purpose. For instance: the IoTAgent runs in a single thread. For more details about multi-core functionality, please refer to the [Cluster](https://nodejs.org/api/cluster.html) module in Node.js and [this section](howto.md#iot-agent-in-multi-thread-mode) of the library documentation. +- **fallbackTenant** - For Linked Data Context Brokers which do not support multi-tenancy, this provides an alternative mechanism for suppling the `NGSILD-Tenant` header. + Note that for backwards compatibility with NGSI v2, the `fiware-service` header is already used as alternative if the `NGSILD-Tenant` header is not supplied. +- **fallbackPath** - For Linked Data Context Brokers which do not support a service path, this provides an alternative mechanism for suppling the `NGSILD-Path` header. + Note that for backwards compatibility with NGSI v2, the `fiware-service-path` header is already used as alternative if the `NGSILD-Path` header is not supplied. ### Configuration using environment variables @@ -282,3 +286,5 @@ overrides. | IOTA_AUTOCAST | `autocast` | | IOTA_MULTI_CORE | `multiCore` | | IOTA_JSON_LD_CONTEXT | `jsonLdContext` | +| IOTA_FALLBACK_TENANT | `fallbackTenant` | +| IOTA_FALLBACK_PATH | `fallbackPath` | diff --git a/lib/commonConfig.js b/lib/commonConfig.js index b5848b1c1..8864d8e99 100644 --- a/lib/commonConfig.js +++ b/lib/commonConfig.js @@ -95,7 +95,9 @@ function processEnvironmentVariables() { 'IOTA_POLLING_EXPIRATION', 'IOTA_POLLING_DAEMON_FREQ', 'IOTA_MULTI_CORE', - 'IOTA_JSON_LD_CONTEXT' + 'IOTA_JSON_LD_CONTEXT', + 'IOTA_FALLBACK_TENANT', + 'IOTA_FALLBACK_PATH' ], iotamVariables = [ 'IOTA_IOTAM_URL', @@ -157,6 +159,11 @@ function processEnvironmentVariables() { config.contextBroker.jsonLdContext = process.env.IOTA_JSON_LD_CONTEXT; } + config.contextBroker.fallbackTenant = process.env.IOTA_FALLBACK_TENANT || + config.contextBroker.service || 'iotagent'; + config.contextBroker.fallbackPath = process.env.IOTA_FALLBACK_PATH || + config.contextBroker.subservice || '/'; + // North Port Configuration (ensuring the configuration sub-object exists before start using it) if (config.server === undefined) { config.server = {}; diff --git a/lib/constants.js b/lib/constants.js index 43e9574bf..fd274a8e5 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -54,6 +54,8 @@ module.exports = { TIMESTAMP_TYPE_NGSI2: 'DateTime', SERVICE_HEADER: 'fiware-service', SUBSERVICE_HEADER: 'fiware-servicepath', + NGSI_LD_TENANT_HEADER: 'NGSILD-Tenant', + NGSI_LD_PATH_HEADER: 'NGSILD-Path', //FIXME: check Keystone support this in lowercase, then change AUTH_HEADER: 'X-Auth-Token', diff --git a/lib/fiware-iotagent-lib.js b/lib/fiware-iotagent-lib.js index c315a8a8b..2dcc9ab01 100644 --- a/lib/fiware-iotagent-lib.js +++ b/lib/fiware-iotagent-lib.js @@ -29,6 +29,7 @@ var async = require('async'), intoTrans = require('./services/common/domain').intoTrans, middlewares = require('./services/common/genericMiddleware'), db = require('./model/dbConn'), + ngsiService = require('./services/ngsi/ngsiService'), subscriptions = require('./services/ngsi/subscriptionService'), statsRegistry = require('./services/stats/statsRegistry'), domainUtils = require('./services/common/domain'), @@ -164,6 +165,10 @@ function doActivate(newConfig, callback) { config.setRegistry(registry); config.setGroupRegistry(groupRegistry); config.setCommandRegistry(commandRegistry); + deviceService.init(); + subscriptions.init(); + contextServer.init(); + ngsiService.init(); commands.start(); diff --git a/lib/services/devices/deviceService.js b/lib/services/devices/deviceService.js index ee2adeba0..0cfdd7236 100644 --- a/lib/services/devices/deviceService.js +++ b/lib/services/devices/deviceService.js @@ -38,10 +38,22 @@ var async = require('async'), _ = require('underscore'), context = { op: 'IoTAgentNGSI.DeviceService' - }, - NGSIv1 = require('./devices-NGSI-v1'), - NGSIv2 = require('./devices-NGSI-v2'), - NGSILD = require('./devices-NGSI-LD'); + }; + +let deviceHandler; + +/** + * Loads the correct device handler based on the current config. + */ +function init(){ + if (config.checkNgsiLD()) { + deviceHandler = require('./devices-NGSI-LD'); + } else if (config.checkNgsi2()) { + deviceHandler = require('./devices-NGSI-v2'); + } else { + deviceHandler = require('./devices-NGSI-v1'); + } +} /** * Creates the initial entity representing the device in the Context Broker. This is important mainly to allow the @@ -51,13 +63,7 @@ var async = require('async'), * @param {Object} newDevice Device object that will be stored in the database. */ function createInitialEntity(deviceData, newDevice, callback) { - if (config.checkNgsiLD()) { - NGSILD.createInitialEntity(deviceData, newDevice, callback); - } else if (config.checkNgsi2()) { - NGSIv2.createInitialEntity(deviceData, newDevice, callback); - } else { - NGSIv1.createInitialEntity(deviceData, newDevice, callback); - } + deviceHandler.createInitialEntity(deviceData, newDevice, callback); } /** @@ -348,13 +354,7 @@ function unregisterDevice(id, service, subservice, callback) { } function updateRegisterDevice(deviceObj, callback) { - if (config.checkNgsiLD()) { - NGSILD.updateRegisterDevice(deviceObj, callback); - } else if (config.checkNgsi2()) { - NGSIv2.updateRegisterDevice(deviceObj, callback); - } else { - NGSIv1.updateRegisterDevice(deviceObj, callback); - } + deviceHandler.updateRegisterDevice(deviceObj, callback); } /** @@ -553,3 +553,4 @@ exports.clearRegistry = intoTrans(context, checkRegistry)(clearRegistry); exports.retrieveDevice = intoTrans(context, checkRegistry)(retrieveDevice); exports.mergeDeviceWithConfiguration = mergeDeviceWithConfiguration; exports.findConfigurationGroup = findConfigurationGroup; +exports.init = init; diff --git a/lib/services/devices/devices-NGSI-LD.js b/lib/services/devices/devices-NGSI-LD.js index b66b4c0a7..1c656d52c 100644 --- a/lib/services/devices/devices-NGSI-LD.js +++ b/lib/services/devices/devices-NGSI-LD.js @@ -78,7 +78,7 @@ function createInitialEntityHandlerNgsiLD(deviceData, newDevice, callback) { alarms.raise(constants.ORION_ALARM, error); callback(error); - } else if (response && response.statusCode === 200) { + } else if (response && response.statusCode === 204 ) { alarms.release(constants.ORION_ALARM); logger.debug(context, 'Initial entity created successfully.'); callback(null, newDevice); @@ -120,7 +120,7 @@ function updateEntityHandlerNgsiLD(deviceData, updatedDevice, callback) { alarms.raise(constants.ORION_ALARM, error); callback(error); - } else if (response && response.statusCode === 200) { + } else if (response && response.statusCode === 204) { alarms.release(constants.ORION_ALARM); logger.debug(context, 'Entity updated successfully.'); callback(null, updatedDevice); @@ -170,7 +170,6 @@ function createInitialEntityNgsiLD(deviceData, newDevice, callback) { } json = ngsiLD.formatAsNGSILD(json); - delete json['@context']; var options = { url: config.getConfig().contextBroker.url + '/ngsi-ld/v1/entityOperations/upsert/', @@ -178,11 +177,10 @@ function createInitialEntityNgsiLD(deviceData, newDevice, callback) { json: [json], headers: { 'fiware-service': deviceData.service, - 'Content-Type': 'application/ld+json', - Link: - '<' + - config.getConfig().contextBroker.jsonLdContext + - '>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"' + 'fiware-servicepath': deviceData.subservice, + 'NGSILD-Tenant': deviceData.service, + 'NGSILD-Path': deviceData.subservice, + 'Content-Type': 'application/ld+json' } }; @@ -212,11 +210,10 @@ function updateEntityNgsiLD(deviceData, updatedDevice, callback) { json: {}, headers: { 'fiware-service': deviceData.service, - 'Content-Type': 'application/ld+json', - Link: - '<' + - config.getConfig().contextBroker.jsonLdContext + - '>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"' + 'fiware-servicepath': deviceData.subservice, + 'NGSILD-Tenant': deviceData.service, + 'NGSILD-Path': deviceData.subservice, + 'Content-Type': 'application/ld+json' } }; diff --git a/lib/services/devices/registrationUtils.js b/lib/services/devices/registrationUtils.js index 0ff3c041f..41913dbe1 100644 --- a/lib/services/devices/registrationUtils.js +++ b/lib/services/devices/registrationUtils.js @@ -305,7 +305,9 @@ function sendUnregistrationsNgsiLD(deviceData, callback) { json: true, headers: { 'fiware-service': deviceData.service, - 'fiware-servicepath': deviceData.subservice + 'fiware-servicepath': deviceData.subservice, + 'NGSILD-Tenant': deviceData.service, + 'NGSILD-Path': deviceData.subservice, } }; if (deviceData.cbHost && deviceData.cbHost.indexOf('://') !== -1) { @@ -441,21 +443,17 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) { } var properties = []; - var additionalContext = { - 'ngsi-ld': 'https://uri.etsi.org/ngsi-ld/default-context/' - }; var lazy = deviceData.lazy || []; var commands = deviceData.commands || []; lazy.forEach((element) => { properties.push(element.name); - additionalContext[element.name] = 'ngsi-ld:' + element.name; }); commands.forEach((element) => { properties.push(element.name); - additionalContext[element.name] = 'ngsi-ld:' + element.name; }); + if (properties.length === 0) { logger.debug( context, @@ -472,10 +470,6 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) { cbHost = 'http://' + deviceData.cbHost; } - var contexts = [additionalContext]; - if (config.getConfig().contextBroker.jsonLdContext) { - contexts.push(config.getConfig().contextBroker.jsonLdContext); - } var id = String(deviceData.name); id = id.startsWith(NGSI_LD_URN) ? id : NGSI_LD_URN + deviceData.type + ':' + id; @@ -492,11 +486,13 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) { } ], endpoint: config.getConfig().providerUrl, - '@context': contexts + '@context': config.getConfig().contextBroker.jsonLdContext }, headers: { 'fiware-service': deviceData.service, 'fiware-servicepath': deviceData.subservice, + 'NGSILD-Tenant': deviceData.service, + 'NGSILD-Path': deviceData.subservice, 'Content-Type': 'application/ld+json' } }; diff --git a/lib/services/ngsi/entities-NGSI-LD.js b/lib/services/ngsi/entities-NGSI-LD.js index d6f9b1d63..642a436ae 100644 --- a/lib/services/ngsi/entities-NGSI-LD.js +++ b/lib/services/ngsi/entities-NGSI-LD.js @@ -265,6 +265,8 @@ function formatAsNGSILD(json) { */ function generateNGSILDOperationHandler(operationName, entityName, typeInformation, token, options, callback) { return function(error, response, body) { + var bodyAsString = body ? JSON.stringify(body, null, 4) : ''; + if (error) { logger.error(context, 'Error found executing ' + operationName + ' action in Context Broker: %s', error); @@ -278,7 +280,8 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati ); callback(new errors.BadRequest(body.orionError.details)); - } else if (response && operationName === 'update' && response.statusCode === 200) { + } else if (response && operationName === 'update' && + (response.statusCode === 200 ||response.statusCode === 204)) { logger.debug(context, 'Received the following response from the CB: Value updated successfully\n'); alarms.release(constants.ORION_ALARM); callback(null, body); @@ -286,7 +289,7 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati logger.debug( context, 'Received the following response from the CB:\n\n%s\n\n', - JSON.stringify(body, null, 4) + bodyAsString ); logger.debug(context, 'Value queried successfully'); alarms.release(constants.ORION_ALARM); @@ -295,7 +298,7 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati logger.debug( context, 'Received the following response from the CB:\n\n%s\n\n', - JSON.stringify(body, null, 4) + bodyAsString ); logger.error( @@ -319,7 +322,7 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati logger.debug( context, 'Received the following response from the CB:\n\n%s\n\n', - JSON.stringify(body, null, 4) + bodyAsString ); logger.error(context, 'Operation ' + operationName + ' error connecting to the Context Broker: %j', body); @@ -344,6 +347,46 @@ function generateNGSILDOperationHandler(operationName, entityName, typeInformati }; } +/** + * Makes a query to the Device's entity in the context broker using NGSI-LD, with the list + * of attributes given by the 'attributes' array. + * + * @param {String} entityName Name of the entity to query. + * @param {Array} attributes Attribute array containing the names of the attributes to query. + * @param {Object} typeInformation Configuration information for the device. + * @param {String} token User token to identify against the PEP Proxies (optional). + */ +function sendQueryValueNgsiLD(entityName, attributes, typeInformation, token, callback) { + var url = '/ngsi-ld/v1/entities/urn:ngsi-ld:' + typeInformation.type + ':' + entityName; + + if (attributes && attributes.length > 0) { + url = url + '?attrs=' + attributes.join(','); + } + + var options = NGSIUtils.createRequestObject(url, typeInformation, token); + options.method = 'GET'; + options.json = true; + + if (!typeInformation || !typeInformation.type) { + callback(new errors.TypeNotFound(null, entityName)); + return; + } + + logger.debug(context, 'Querying values of the device 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)); + + request( + options, + generateNGSILDOperationHandler('query', entityName, typeInformation, token, options, function(error, result) { + if (error) { + callback(error); + } else { + NGSIUtils.applyMiddlewares(NGSIUtils.queryMiddleware, result, typeInformation, callback); + } + }) + ); +} + /** * Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array. * This array should comply to the NGSI-LD's attribute format. @@ -505,3 +548,4 @@ function sendUpdateValueNgsiLD(entityName, attributes, typeInformation, token, c exports.formatAsNGSILD = formatAsNGSILD; exports.sendUpdateValue = sendUpdateValueNgsiLD; +exports.sendQueryValue = sendQueryValueNgsiLD; diff --git a/lib/services/ngsi/ngsiService.js b/lib/services/ngsi/ngsiService.js index 80b4f0cc3..13f5bc0ff 100644 --- a/lib/services/ngsi/ngsiService.js +++ b/lib/services/ngsi/ngsiService.js @@ -34,14 +34,27 @@ var async = require('async'), constants = require('../../constants'), logger = require('logops'), ngsiUtils = require('./ngsiUtils'), - ngsiv1 = require('./entities-NGSI-v1'), - ngsiv2 = require('./entities-NGSI-v2'), - ngsiLD = require('./entities-NGSI-LD'), _ = require('underscore'), context = { op: 'IoTAgentNGSI.NGSIService' }; + +var entityHandler; + +/** + * Loads the correct ngsiService handler based on the current config. + */ +function init(){ + if (config.checkNgsiLD()) { + entityHandler = require('./entities-NGSI-LD'); + } else if (config.checkNgsi2()) { + entityHandler = require('./entities-NGSI-v2'); + } else { + entityHandler = require('./entities-NGSI-v1'); + } +} + /** * Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array. This * array should comply to the NGSI's attribute format. @@ -52,13 +65,7 @@ var async = require('async'), * @param {String} token User token to identify against the PEP Proxies (optional). */ function sendUpdateValue(entityName, attributes, typeInformation, token, callback) { - if (config.checkNgsiLD()) { - ngsiLD.sendUpdateValue(entityName, attributes, typeInformation, token, callback); - } else if (config.checkNgsi2()) { - ngsiv2.sendUpdateValue(entityName, attributes, typeInformation, token, callback); - } else { - ngsiv1.sendUpdateValue(entityName, attributes, typeInformation, token, callback); - } + entityHandler.sendUpdateValue(entityName, attributes, typeInformation, token, callback); } /** @@ -71,13 +78,7 @@ function sendUpdateValue(entityName, attributes, typeInformation, token, callbac * @param {String} token User token to identify against the PEP Proxies (optional). */ function sendQueryValue(entityName, attributes, typeInformation, token, callback) { - if (config.checkNgsiLD()) { - ngsiLD.sendQueryValue(entityName, attributes, typeInformation, token, callback); - } else if (config.checkNgsi2()) { - ngsiv2.sendQueryValue(entityName, attributes, typeInformation, token, callback); - } else { - ngsiv1.sendQueryValue(entityName, attributes, typeInformation, token, callback); - } + entityHandler.sendQueryValue(entityName, attributes, typeInformation, token, callback); } /** @@ -280,3 +281,4 @@ exports.addQueryMiddleware = intoTrans(context, addQueryMiddleware); exports.resetMiddlewares = intoTrans(context, resetMiddlewares); exports.setCommandResult = intoTrans(context, setCommandResult); exports.updateTrust = updateTrust; +exports.init = init; diff --git a/lib/services/ngsi/ngsiUtils.js b/lib/services/ngsi/ngsiUtils.js index 9d5bc0047..402300674 100644 --- a/lib/services/ngsi/ngsiUtils.js +++ b/lib/services/ngsi/ngsiUtils.js @@ -100,10 +100,7 @@ function createRequestObject(url, typeInformation, token) { 'fiware-servicepath': config.getConfig().subservice }; - if (config.checkNgsiLD()) { - headers['Content-Type'] = 'application/ld+json'; - delete headers['fiware-servicepath']; - } + if (config.getConfig().authentication && config.getConfig().authentication.enabled) { headers[config.getConfig().authentication.header] = token; @@ -127,6 +124,12 @@ function createRequestObject(url, typeInformation, token) { } } + if (config.checkNgsiLD()) { + headers['Content-Type'] = 'application/ld+json'; + headers['NGSILD-Tenant'] = headers['fiware-service']; + headers['NGSILD-Path'] = headers['fiware-servicepath']; + } + options = { url: cbHost + url, method: 'POST', diff --git a/lib/services/ngsi/subscriptionService.js b/lib/services/ngsi/subscriptionService.js index 8cceaf02a..f8f09b884 100644 --- a/lib/services/ngsi/subscriptionService.js +++ b/lib/services/ngsi/subscriptionService.js @@ -30,10 +30,23 @@ var intoTrans = require('../common/domain').intoTrans, context = { op: 'IoTAgentNGSI.SubscriptionService' }, - config = require('../../commonConfig'), - ngsiv1 = require('./subscription-NGSI-v1'), - ngsiv2 = require('./subscription-NGSI-v2'), - ngsiLD = require('./subscription-NGSI-LD'); + config = require('../../commonConfig'); + +var subscriptionHandler; + + +/** + * Loads the correct subscription handler based on the current config. + */ +function init(){ + if (config.checkNgsiLD()) { + subscriptionHandler = require('./subscription-NGSI-LD'); + } else if (config.checkNgsi2()) { + subscriptionHandler = require('./subscription-NGSI-v2'); + } else { + subscriptionHandler = require('./subscription-NGSI-v1'); + } +} /** * Makes a subscription for the given device's entity, triggered by the given attributes. @@ -45,13 +58,7 @@ var intoTrans = require('../common/domain').intoTrans, * @param {Object} content Array with the names of the attributes to retrieve in the notification. */ function subscribe(device, triggers, content, callback) { - if (config.checkNgsiLD()) { - ngsiLD.subscribe(device, triggers, content, callback); - } else if (config.checkNgsi2()) { - ngsiv2.subscribe(device, triggers, content, callback); - } else { - ngsiv1.subscribe(device, triggers, content, callback); - } + subscriptionHandler.subscribe(device, triggers, content, callback); } /** @@ -61,14 +68,9 @@ function subscribe(device, triggers, content, callback) { * @param {String} id ID of the subscription to remove. */ function unsubscribe(device, id, callback) { - if (config.checkNgsiLD()) { - ngsiLD.unsubscribe(device, id, callback); - } else if (config.checkNgsi2()) { - ngsiv2.unsubscribe(device, id, callback); - } else { - ngsiv1.unsubscribe(device, id, callback); - } + subscriptionHandler.unsubscribe(device, id, callback); } exports.subscribe = intoTrans(context, subscribe); exports.unsubscribe = intoTrans(context, unsubscribe); +exports.init = init; diff --git a/lib/services/northBound/contextServer-NGSI-LD.js b/lib/services/northBound/contextServer-NGSI-LD.js new file mode 100644 index 000000000..7273f09c2 --- /dev/null +++ b/lib/services/northBound/contextServer-NGSI-LD.js @@ -0,0 +1,584 @@ +/* + * Copyright 2020 Telefonica Investigación y Desarrollo, S.A.U + * + * This file is part of fiware-iotagent-lib + * + * fiware-iotagent-lib is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * fiware-iotagent-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with fiware-iotagent-lib. + * If not, see http://www.gnu.org/licenses/. + * + * For those usages not covered by the GNU Affero General Public License + * please contact with::daniel.moranjimenez@telefonica.com + * + * Modified by: Jason Fox - FIWARE Foundation + */ +'use strict'; + +var async = require('async'), + apply = async.apply, + logger = require('logops'), + errors = require('../../errors'), + deviceService = require('../devices/deviceService'), + middlewares = require('../common/genericMiddleware'), + _ = require('underscore'), + context = { + op: 'IoTAgentNGSI.ContextServer-LD' + }, + updateContextTemplateNgsiLD = require('../../templates/updateContextNgsiLD.json'), + notificationTemplateNgsiLD = require('../../templates/notificationTemplateNgsiLD.json'), + contextServerUtils = require('./contextServerUtils'); + +const updatePaths = ['/ngsi-ld/v1/entities/:entity/attrs/:attr']; +const queryPaths = ['/ngsi-ld/v1/entities/:entity']; + +/** + * Generate all the update actions corresponding to a update context request using Ngsi2. + * Update actions include updates in attributes and execution of commands. + * + * @param {Object} req Update request to generate Actions from + * @param {Object} contextElement Context Element whose actions will be extracted. + */ +function generateUpdateActionsNgsiLD(req, contextElement, callback) { + var entityId; + var entityType; + var attribute = req.params.attr; + var value = req.body.value; + + if (contextElement.id && contextElement.type) { + entityId = contextElement.id; + entityType = contextElement.type; + } else if (req.params.entity) { + entityId = req.params.entity; + } + + function splitUpdates(device, callback) { + var attributes = [], + commands = [], + found; + + if (device.commands) { + for (var j in device.commands) { + if (attribute === device.commands[j].name) { + commands.push({ + type: device.commands[j].type, + value, + name: attribute + }); + found = true; + } + } + } + + if (attribute && !found) { + attributes.push({ + type: 'Property', + value, + name: attribute + }); + } + callback(null, attributes, commands, device); + } + + function createActionsArray(attributes, commands, device, callback) { + var updateActions = []; + + if (!entityType) { + entityType = device.type; + } + + if (contextServerUtils.updateHandler) { + updateActions.push( + async.apply( + contextServerUtils.updateHandler, + entityId, + entityType, + contextServerUtils.getLDTenant(req), + contextServerUtils.getLDPath(req), + attributes + ) + ); + } + + if (contextServerUtils.commandHandler) { + if (device.polling) { + updateActions.push( + async.apply( + contextServerUtils.pushCommandsToQueue, + device, + entityId, + entityType, + contextServerUtils.getLDTenant(req), + contextServerUtils.getLDPath(req), + attributes + ) + ); + } else { + updateActions.push( + async.apply( + contextServerUtils.commandHandler, + entityId, + entityType, + contextServerUtils.getLDTenant(req), + contextServerUtils.getLDPath(req), + commands + ) + ); + } + } + + updateActions.push( + async.apply( + contextServerUtils.executeUpdateSideEffects, + device, + entityId, + entityType, + contextServerUtils.getLDTenant(req), + contextServerUtils.getLDPath(req), + attributes + ) + ); + + callback(null, updateActions); + } + + deviceService.getDeviceByName(entityId, + contextServerUtils.getLDTenant(req), + contextServerUtils.getLDPath(req), function( + error, + deviceObj + ) { + if (error) { + callback(error); + } else { + async.waterfall( + [ + apply(deviceService.findConfigurationGroup, deviceObj), + apply( + deviceService.mergeDeviceWithConfiguration, + ['lazy', 'internalAttributes', 'active', 'staticAttributes', 'commands', 'subscriptions'], + [null, null, [], [], [], [], []], + deviceObj + ), + splitUpdates, + createActionsArray + ], + callback + ); + } + }); +} + +/** Express middleware to manage incoming update requests using NGSI-LD. + * + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function handleUpdateNgsiLD(req, res, next) { + function reduceActions(actions, callback) { + callback(null, _.flatten(actions)); + } + + if (contextServerUtils.updateHandler || contextServerUtils.commandHandler) { + logger.debug(context, 'Handling LD update from [%s]', req.get('host')); + if (req.body) { + logger.debug(context, JSON.stringify(req.body , null, 4)); + } + + async.waterfall( + [apply(async.map, req.body, apply(generateUpdateActionsNgsiLD, req)), reduceActions, async.series], + function(error, result) { + if (error) { + logger.debug(context, 'There was an error handling the update action: %s.', error); + //console.error(JSON.stringify(error)); + next(error); + } else { + logger.debug(context, 'Update action from [%s] handled successfully.', req.get('host')); + res.status(204).json(); + } + } + ); + } else { + logger.error(context, 'Tried to handle an update request before the update handler was established.'); + + var errorNotFound = new Error({ + message: 'Update handler not found' + }); + next(errorNotFound); + } +} + +/** + * Handle queries coming to the IoT Agent via de Context Provider API (as a consequence of a query to a passive + * attribute redirected by the Context Broker). + * + * @param {String} id Entity name of the selected entity in the query. + * @param {String} type Type of the entity. + * @param {String} service Service the device belongs to. + * @param {String} subservice Division inside the service. + * @param {Array} attributes List of attributes to read. + */ +function defaultQueryHandlerNgsiLD(id, type, service, subservice, attributes, callback) { + var contextElement = { + type: type, + id: id + }; + + deviceService.getDeviceByName(id, service, subservice, function(error, ngsiDevice) { + if (error) { + callback(error); + } else { + for (var i = 0; i < attributes.length; i++) { + var lazyAttribute = _.findWhere(ngsiDevice.lazy, { name: attributes[i] }), + command = _.findWhere(ngsiDevice.commands, { name: attributes[i] }), + attributeType; + + if (command) { + attributeType = command.type; + } else if (lazyAttribute) { + attributeType = lazyAttribute.type; + } else { + attributeType = 'string'; + } + + contextElement[attributes[i]] = { + type: attributeType, + value: '' + }; + } + + callback(null, contextElement); + } + }); +} + +/** + * Express middleware to manage incoming query context requests using NGSI-LD. + * + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function handleQueryNgsiLD(req, res, next) { + function getName(element) { + return element.name; + } + + function addStaticAttributes(attributes, device, contextElement, callback) { + function inAttributes(item) { + return item.name && attributes.indexOf(item.name) >= 0; + } + + if (device.staticAttributes) { + var selectedAttributes = []; + if (attributes === undefined || attributes.length === 0) { + selectedAttributes = device.staticAttributes; + } else { + selectedAttributes = device.staticAttributes.filter(inAttributes); + } + + for (var att in selectedAttributes) { + contextElement[selectedAttributes[att].name] = { + type: selectedAttributes[att].type, + value: selectedAttributes[att].value + }; + } + } + + callback(null, contextElement); + } + + function completeAttributes(attributes, device, callback) { + if (attributes && attributes.length !== 0) { + logger.debug(context, 'Handling received set of attributes: %j', attributes); + callback(null, attributes); + } else if (device.lazy) { + logger.debug(context, 'Handling stored set of attributes: %j', attributes); + var results = device.lazy.map(getName); + callback(null, results); + } else { + logger.debug(context, 'Couldn\'t find any attributes. Handling with null reference'); + callback(null, null); + } + } + + function finishQueryForDevice(attributes, contextEntity, actualHandler, device, callback) { + var contextId = contextEntity.id; + var contextType = contextEntity.type; + if (!contextId) { + contextId = device.id; + } + + if (!contextType) { + contextType = device.type; + } + + deviceService.findConfigurationGroup(device, function(error, group) { + var executeCompleteAttributes = apply(completeAttributes, attributes, group), + executeQueryHandler = apply( + actualHandler, + contextId, + contextType, + contextServerUtils.getLDTenant(req), + contextServerUtils.getLDPath(req) + ), + executeAddStaticAttributes = apply(addStaticAttributes, attributes, group); + + async.waterfall([executeCompleteAttributes, executeQueryHandler, executeAddStaticAttributes], callback); + }); + } + + function createQueryRequest(attributes, contextEntity, callback) { + var actualHandler; + var getFunction; + + if (contextServerUtils.queryHandler) { + actualHandler = contextServerUtils.queryHandler; + } else { + actualHandler = defaultQueryHandlerNgsiLD; + } + + if (contextEntity.id) { + getFunction = apply( + deviceService.getDeviceByName, + contextEntity.id, + contextServerUtils.getLDTenant(req), + contextServerUtils.getLDPath(req) + ); + } else { + getFunction = apply( + deviceService.listDevicesWithType, + contextEntity.type, + contextServerUtils.getLDTenant(req), + contextServerUtils.getLDPath(req), + null, + null + ); + } + + getFunction(function handleFindDevice(error, innerDevice) { + let deviceList = []; + if (!innerDevice) { + return callback(new errors.DeviceNotFound(contextEntity.id)); + } + + if (innerDevice.count) { + if (innerDevice.count === 0) { + return callback(null, []); + } else { + deviceList = innerDevice.devices; + } + } else { + deviceList = [innerDevice]; + } + + async.map(deviceList, async.apply(finishQueryForDevice, attributes, contextEntity, actualHandler), function( + error, + results + ) { + if (error) { + callback(error); + } else if (innerDevice.count) { + callback(null, results); + } else if (Array.isArray(results) && results.length > 0) { + callback(null, results); + } else { + callback(null, results); + } + }); + }); + } + + function handleQueryContextRequests(error, result) { + if (error) { + logger.debug(context, 'There was an error handling the query: %s.', error); + next(error); + } else { + logger.debug(context, 'Query from [%s] handled successfully.', req.get('host')); + res.status(200).json(result); + } + } + + logger.debug(context, 'Handling query from [%s]', req.get('host')); + if (req.body) { + logger.debug(context, JSON.stringify(req.body , null, 4)); + } + + const nss = req.params.entity.replace('urn:ngsi-ld:', ''); + const contextEntity = { + id: req.params.entity, + type: nss.substring(0, nss.indexOf(':')) + + }; + + createQueryRequest( + req.query.attrs ? req.query.attrs.split(',') : null, + contextEntity, handleQueryContextRequests); +} + +/** + * Error handler for NGSI-LD context query requests. + * + * @param {Object} error Incoming error + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function queryErrorHandlingNgsiLD(error, req, res, next) { + var code = 500; + + logger.debug(context, 'Query NGSI-LD error [%s] handling request: %s', error.name, error.message); + + if (error.code && String(error.code).match(/^[2345]\d\d$/)) { + code = error.code; + } + + res.status(code).json({ + error: error.name, + description: error.message.replace(/[<>\"\'=;\(\)]/g, '') + }); +} + +/** + * Express middleware to manage incoming notification requests using NGSI-LD. + * + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ + +function handleNotificationNgsiLD(req, res, next) { + function extractInformation(dataElement, callback) { + var atts = []; + for (var key in dataElement) { + if (dataElement.hasOwnProperty(key)) { + if (key !== 'id' && key !== 'type') { + var att = {}; + att.type = dataElement[key].type; + att.value = dataElement[key].value; + att.name = key; + atts.push(att); + } + } + } + deviceService.getDeviceByName( + dataElement.id, + contextServerUtils.getLDTenant(req), + contextServerUtils.getLDPath(req), + function(error, device) { + if (error) { + callback(error); + } else { + callback(null, device, atts); + } + } + ); + } + + function applyNotificationMiddlewares(device, values, callback) { + if (contextServerUtils.notificationMiddlewares.length > 0) { + var firstMiddleware = contextServerUtils.notificationMiddlewares.slice(0, 1)[0], + rest = contextServerUtils.notificationMiddlewares.slice(1), + startMiddleware = apply(firstMiddleware, device, values), + composedMiddlewares = [startMiddleware].concat(rest); + + async.waterfall(composedMiddlewares, callback); + } else { + callback(null, device, values); + } + } + + function createNotificationHandler(contextResponse, callback) { + async.waterfall( + [ + apply(extractInformation, contextResponse), + applyNotificationMiddlewares, + contextServerUtils.notificationHandler + ], + callback + ); + } + + function handleNotificationRequests(error) { + if (error) { + logger.error(context, 'Error found when processing notification: %j', error); + next(error); + } else { + res.status(200).json({}); + } + } + + if (contextServerUtils.notificationHandler) { + logger.debug(context, 'Handling notification from [%s]', req.get('host')); + async.map(req.body.data, createNotificationHandler, handleNotificationRequests); + } else { + var errorNotFound = new Error({ + message: 'Notification handler not found' + }); + + logger.error(context, 'Tried to handle a notification before notification handler was established.'); + + next(errorNotFound); + } +} + +/** + * Error handler for NGSI-LD update requests. + * + * @param {Object} error Incoming error + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function updateErrorHandlingNgsiLD(error, req, res, next) { + var code = 500; + + logger.debug(context, 'Update NGSI-LD error [%s] handing request: %s', error.name, error.message); + + if (error.code && String(error.code).match(/^[2345]\d\d$/)) { + code = error.code; + } + + res.status(code).json({ + error: error.name, + description: error.message.replace(/[<>\"\'=;\(\)]/g, '') + }); +} + +/** + * Load the routes related to context dispatching (NGSI10 calls). + * + * @param {Object} router Express request router object. + */ +function loadContextRoutesNGSILD(router) { + // In a more evolved implementation, more endpoints could be added to queryPathsNgsi2 + // according to http://fiware.github.io/specifications/ngsiv2/stable. + + var i; + + logger.info(context, 'Loading NGSI-LD Context server routes'); + for (i = 0; i < updatePaths.length; i++) { + router.patch(updatePaths[i], [ + middlewares.ensureType, + middlewares.validateJson(updateContextTemplateNgsiLD), + handleUpdateNgsiLD, + updateErrorHandlingNgsiLD + ]); + } + for (i = 0; i < queryPaths.length; i++) { + router.get(queryPaths[i], [handleQueryNgsiLD, queryErrorHandlingNgsiLD]); + } + router.post('/notify', [ + middlewares.ensureType, + middlewares.validateJson(notificationTemplateNgsiLD), + handleNotificationNgsiLD, + queryErrorHandlingNgsiLD + ]); +} + +exports.loadContextRoutes = loadContextRoutesNGSILD; diff --git a/lib/services/northBound/contextServer-NGSI-v1.js b/lib/services/northBound/contextServer-NGSI-v1.js new file mode 100644 index 000000000..b13b0a98d --- /dev/null +++ b/lib/services/northBound/contextServer-NGSI-v1.js @@ -0,0 +1,524 @@ +/* + * Copyright 2020 Telefonica Investigación y Desarrollo, S.A.U + * + * This file is part of fiware-iotagent-lib + * + * fiware-iotagent-lib is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * fiware-iotagent-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with fiware-iotagent-lib. + * If not, see http://www.gnu.org/licenses/. + * + * 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 + * Modified by: Jason Fox - FIWARE Foundation + */ +'use strict'; + +var async = require('async'), + apply = async.apply, + logger = require('logops'), + errors = require('../../errors'), + deviceService = require('../devices/deviceService'), + middlewares = require('../common/genericMiddleware'), + _ = require('underscore'), + context = { + op: 'IoTAgentNGSI.ContextServer-v1' + }, + updateContextTemplateNgsi1 = require('../../templates/updateContextNgsi1.json'), + queryContextTemplate = require('../../templates/queryContext.json'), + notificationTemplateNgsi1 = require('../../templates/notificationTemplateNgsi1.json'), + contextServerUtils = require('./contextServerUtils'); + +const updatePaths = ['/v1/updateContext', '/NGSI10/updateContext', '//updateContext']; +const queryPaths = ['/v1/queryContext', '/NGSI10/queryContext', '//queryContext']; +/** + * Generate all the update actions corresponding to a update context request using Ngsi1. + * Update actions include updates in attributes and execution of commands. This action will + * be called once per Context Element in the request. + * + * @param {Object} req Update request to generate Actions from + * @param {Object} contextElement Context Element whose actions will be extracted. + */ +function generateUpdateActionsNgsi1(req, contextElement, callback) { + function splitUpdates(device, callback) { + var attributes = [], + commands = [], + found; + + if (device.commands) { + attributeLoop: for (var i in contextElement.attributes) { + for (var j in device.commands) { + if (contextElement.attributes[i].name === device.commands[j].name) { + commands.push(contextElement.attributes[i]); + found = true; + continue attributeLoop; + } + } + + attributes.push(contextElement.attributes[i]); + } + } else { + attributes = contextElement.attributes; + } + + callback(null, attributes, commands, device); + } + + function createActionsArray(attributes, commands, device, callback) { + var updateActions = []; + + if (contextServerUtils.updateHandler) { + updateActions.push( + async.apply( + contextServerUtils.updateHandler, + contextElement.id, + contextElement.type, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + attributes + ) + ); + } + + if (contextServerUtils.commandHandler) { + if (device.polling) { + updateActions.push( + async.apply( + contextServerUtils.pushCommandsToQueue, + device, + contextElement.id, + contextElement.type, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + contextElement.attributes + ) + ); + } else { + updateActions.push( + async.apply( + contextServerUtils.commandHandler, + contextElement.id, + contextElement.type, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + commands + ) + ); + } + } + + updateActions.push( + async.apply( + contextServerUtils.executeUpdateSideEffects, + device, + contextElement.id, + contextElement.type, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + contextElement.attributes + ) + ); + + callback(null, updateActions); + } + + deviceService.getDeviceByName( + contextElement.id, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + function(error, deviceObj) { + if (error) { + callback(error); + } else { + async.waterfall( + [ + apply(deviceService.findConfigurationGroup, deviceObj), + apply( + deviceService.mergeDeviceWithConfiguration, + ['lazy', 'internalAttributes', 'active', 'staticAttributes', 'commands', 'subscriptions'], + [null, null, [], [], [], [], []], + deviceObj + ), + splitUpdates, + createActionsArray + ], + callback + ); + } + } + ); +} + +/** + * Express middleware to manage incoming UpdateContext requests using NGSIv1. + * As NGSI10 requests can affect multiple entities, for each one of them a call + * to the user update handler function is made. + */ +function handleUpdateNgsi1(req, res, next) { + function reduceActions(actions, callback) { + callback(null, _.flatten(actions)); + } + + if (contextServerUtils.updateHandler || contextServerUtils.commandHandler) { + logger.debug(context, 'Handling v1 update from [%s]', req.get('host')); + if (req.body) { + logger.debug(context, JSON.stringify(req.body , null, 4)); + } + + async.waterfall( + [ + apply(async.map, req.body.contextElements, apply(generateUpdateActionsNgsi1, req)), + reduceActions, + async.series + ], + function(error, result) { + if (error) { + logger.debug(context, 'There was an error handling the update action: %s.', error); + + next(error); + } else { + logger.debug(context, 'Update action from [%s] handled successfully.', req.get('host')); + res.status(200).json(contextServerUtils.createUpdateResponse(req, res, result)); + } + } + ); + } else { + logger.error(context, 'Tried to handle an update request before the update handler was stablished.'); + + var errorNotFound = new Error({ + message: 'Update handler not found' + }); + next(errorNotFound); + } +} + +/** + * Handle queries coming to the IoT Agent via de Context Provider API (as a consequence of a query to a passive + * attribute redirected by the Context Broker). + * + * @param {String} id Entity name of the selected entity in the query. + * @param {String} type Type of the entity. + * @param {String} service Service the device belongs to. + * @param {String} subservice Division inside the service. + * @param {Array} attributes List of attributes to read. + */ +function defaultQueryHandlerNgsi1(id, type, service, subservice, attributes, callback) { + var contextElement = { + type: type, + isPattern: false, + id: id, + attributes: [] + }; + + deviceService.getDeviceByName(id, service, subservice, function(error, ngsiDevice) { + if (error) { + callback(error); + } else { + for (var i = 0; i < attributes.length; i++) { + var lazyAttribute = _.findWhere(ngsiDevice.lazy, { name: attributes[i] }), + command = _.findWhere(ngsiDevice.commands, { name: attributes[i] }), + attributeType; + + if (command) { + attributeType = command.type; + } else if (lazyAttribute) { + attributeType = lazyAttribute.type; + } else { + attributeType = 'string'; + } + + contextElement.attributes.push({ + name: attributes[i], + type: attributeType, + value: '' + }); + } + + callback(null, contextElement); + } + }); +} + +/** + * Express middleware to manage incoming QueryContext requests using NGSIv1. + * As NGSI10 requests can affect multiple entities, for each one of them a call + * to the user query handler function is made. + */ +function handleQueryNgsi1(req, res, next) { + function getName(element) { + return element.name; + } + + function addStaticAttributes(attributes, device, contextElement, callback) { + function inAttributes(item) { + return item.name && attributes.indexOf(item.name) >= 0; + } + + if (device.staticAttributes) { + var selectedAttributes = device.staticAttributes.filter(inAttributes); + + if (selectedAttributes.length > 0) { + if (contextElement.attributes) { + contextElement.attributes = contextElement.attributes.concat(selectedAttributes); + } else { + contextElement.attributes = selectedAttributes; + } + } + } + + callback(null, contextElement); + } + + function completeAttributes(attributes, device, callback) { + if (attributes && attributes.length !== 0) { + logger.debug(context, 'Handling received set of attributes: %j', attributes); + callback(null, attributes); + } else if (device.lazy) { + logger.debug(context, 'Handling stored set of attributes: %j', attributes); + callback(null, device.lazy.map(getName)); + } else { + logger.debug(context, 'Couldn\'t find any attributes. Handling with null reference'); + callback(null, null); + } + } + + function createQueryRequests(attributes, contextEntity, callback) { + var actualHandler; + + if (contextServerUtils.queryHandler) { + actualHandler = contextServerUtils.queryHandler; + } else { + actualHandler = defaultQueryHandlerNgsi1; + } + + async.waterfall( + [ + apply( + deviceService.getDeviceByName, + contextEntity.id, + req.headers['fiware-service'], + req.headers['fiware-servicepath'] + ), + deviceService.findConfigurationGroup + ], + function handleFindDevice(error, device) { + var executeCompleteAttributes = apply(completeAttributes, attributes, device), + executeQueryHandler = apply( + actualHandler, + contextEntity.id, + contextEntity.type, + req.headers['fiware-service'], + req.headers['fiware-servicepath'] + ), + executeAddStaticAttributes = apply(addStaticAttributes, attributes, device); + + callback( + error, + apply(async.waterfall, [executeCompleteAttributes, executeQueryHandler, executeAddStaticAttributes]) + ); + } + ); + } + + function handleQueryContextRequests(error, result) { + if (error) { + logger.debug(context, 'There was an error handling the query: %s.', error); + next(error); + } else { + logger.debug(context, 'Query from [%s] handled successfully.', req.get('host')); + res.status(200).json(contextServerUtils.createQueryResponse(req, res, result)); + } + } + + logger.debug(context, 'Handling query from [%s]', req.get('host')); + if (req.body) { + logger.debug(context, JSON.stringify(req.body , null, 4)); + } + + async.waterfall( + [apply(async.map, req.body.entities, apply(createQueryRequests, req.body.attributes)), async.series], + handleQueryContextRequests + ); +} + +/** + * Express middleware to manage incoming notification requests using NGSIv1. + * + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function handleNotificationNgsi1(req, res, next) { + function checkStatus(statusCode, callback) { + if (statusCode.code && statusCode.code === '200') { + callback(); + } else { + callback(new errors.NotificationError(statusCode.code)); + } + } + + function extractInformation(contextResponse, callback) { + deviceService.getDeviceByName( + contextResponse.contextElement.id, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + function(error, device) { + if (error) { + callback(error); + } else { + callback(null, device, contextResponse.contextElement.attributes); + } + } + ); + } + + function applyNotificationMiddlewares(device, values, callback) { + if (contextServerUtils.notificationMiddlewares.length > 0) { + var firstMiddleware = contextServerUtils.notificationMiddlewares.slice(0, 1)[0], + rest = contextServerUtils.notificationMiddlewares.slice(1), + startMiddleware = apply(firstMiddleware, device, values), + composedMiddlewares = [startMiddleware].concat(rest); + + async.waterfall(composedMiddlewares, callback); + } else { + callback(null, device, values); + } + } + + function createNotificationHandler(contextResponse, callback) { + async.waterfall( + [ + apply(checkStatus, contextResponse.statusCode), + apply(extractInformation, contextResponse), + applyNotificationMiddlewares, + contextServerUtils.notificationHandler + ], + callback + ); + } + + function handleNotificationRequests(error) { + if (error) { + logger.error(context, 'Error found when processing notification: %j', error); + next(error); + } else { + res.status(200).json({}); + } + } + + if (contextServerUtils.notificationHandler) { + logger.debug(context, 'Handling notification from [%s]', req.get('host')); + + async.map(req.body.contextResponses, createNotificationHandler, handleNotificationRequests); + } else { + var errorNotFound = new Error({ + message: 'Notification handler not found' + }); + + logger.error(context, 'Tried to handle a notification before notification handler was established.'); + + next(errorNotFound); + } +} + +/** + * Error handler for NGSIv1 context query requests. + * + * @param {Object} error Incoming error + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function queryErrorHandlingNgsi1(error, req, res, next) { + var code = 500; + + logger.debug(context, 'Query NGSIv1 error [%s] handling request: %s', error.name, error.message); + + if (error.code && String(error.code).match(/^[2345]\d\d$/)) { + code = error.code; + } + + res.status(code).json({ + errorCode: { + code: code, + reasonPhrase: error.name, + details: error.message.replace(/[<>\"\'=;\(\)]/g, '') + } + }); +} + +/** + * Error handler for NGSIv1 update requests. + * + * @param {Object} error Incoming error + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function updateErrorHandlingNgsi1(error, req, res, next) { + var code = 500; + + logger.debug(context, 'Update NGSIv1 error [%s] handing request: %s', error.name, error.message); + + if (error.code && String(error.code).match(/^[2345]\d\d$/)) { + code = error.code; + } + + res.status(code).json({ + contextResponses: [ + { + contextElement: req.body, + statusCode: { + code: code, + reasonPhrase: error.name, + details: error.message.replace(/[<>\"\'=;\(\)]/g, '') + } + } + ] + }); +} + +/** + * Load the routes related to context dispatching (NGSI10 calls). + * + * @param {Object} router Express request router object. + */ +function loadContextRoutesNGSIv1(router) { + // In a more evolved implementation, more endpoints could be added to queryPathsNgsi2 + // according to http://fiware.github.io/specifications/ngsiv2/stable. + + var i; + logger.info(context, 'Loading NGSI-v1 Context server routes'); + for (i = 0; i < updatePaths.length; i++) { + router.post(updatePaths[i], [ + middlewares.ensureType, + middlewares.validateJson(updateContextTemplateNgsi1), + handleUpdateNgsi1, + updateErrorHandlingNgsi1 + ]); + } + for (i = 0; i < queryPaths.length; i++) { + router.post(queryPaths[i], [ + middlewares.ensureType, + middlewares.validateJson(queryContextTemplate), + handleQueryNgsi1, + queryErrorHandlingNgsi1 + ]); + } + router.post('/notify', [ + middlewares.ensureType, + middlewares.validateJson(notificationTemplateNgsi1), + handleNotificationNgsi1, + queryErrorHandlingNgsi1 + ]); +} + +exports.loadContextRoutes = loadContextRoutesNGSIv1; diff --git a/lib/services/northBound/contextServer-NGSI-v2.js b/lib/services/northBound/contextServer-NGSI-v2.js new file mode 100644 index 000000000..b9006fe46 --- /dev/null +++ b/lib/services/northBound/contextServer-NGSI-v2.js @@ -0,0 +1,592 @@ +/* + * Copyright 2020 Telefonica Investigación y Desarrollo, S.A.U + * + * This file is part of fiware-iotagent-lib + * + * fiware-iotagent-lib is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * fiware-iotagent-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with fiware-iotagent-lib. + * If not, see http://www.gnu.org/licenses/. + * + * 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 + * Modified by: Jason Fox - FIWARE Foundation + */ +'use strict'; + +var async = require('async'), + apply = async.apply, + logger = require('logops'), + errors = require('../../errors'), + deviceService = require('../devices/deviceService'), + middlewares = require('../common/genericMiddleware'), + _ = require('underscore'), + context = { + op: 'IoTAgentNGSI.ContextServer-v2' + }, + updateContextTemplateNgsi2 = require('../../templates/updateContextNgsi2.json'), + notificationTemplateNgsi2 = require('../../templates/notificationTemplateNgsi2.json'), + contextServerUtils = require('./contextServerUtils'); + +const updatePaths = ['/v2/op/update', '//op/update']; +const queryPaths = ['/v2/op/query', '//op/query']; +/** + * Generate all the update actions corresponding to a update context request using Ngsi2. + * Update actions include updates in attributes and execution of commands. + * + * @param {Object} req Update request to generate Actions from + * @param {Object} contextElement Context Element whose actions will be extracted. + */ +function generateUpdateActionsNgsi2(req, contextElement, callback) { + var entityId; + var entityType; + + if (contextElement.id && contextElement.type) { + entityId = contextElement.id; + entityType = contextElement.type; + } else if (req.params.entity) { + entityId = req.params.entity; + } + + function splitUpdates(device, callback) { + var attributes = [], + commands = [], + found, + newAtt, + i; + + if (device.commands) { + attributeLoop: for (i in contextElement) { + for (var j in device.commands) { + if (i === device.commands[j].name) { + newAtt = {}; + newAtt[i] = contextElement[i]; + newAtt[i].name = i; + commands.push(newAtt[i]); + found = true; + continue attributeLoop; + } + } + } + } + + for (i in contextElement) { + if (i !== 'type' && i !== 'id') { + newAtt = {}; + newAtt = contextElement[i]; + newAtt.name = i; + attributes.push(newAtt); + } + } + + callback(null, attributes, commands, device); + } + + function createActionsArray(attributes, commands, device, callback) { + var updateActions = []; + + if (!entityType) { + entityType = device.type; + } + + if (contextServerUtils.updateHandler) { + updateActions.push( + async.apply( + contextServerUtils.updateHandler, + entityId, + entityType, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + attributes + ) + ); + } + + if (contextServerUtils.commandHandler) { + if (device.polling) { + updateActions.push( + async.apply( + contextServerUtils.pushCommandsToQueue, + device, + entityId, + entityType, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + attributes + ) + ); + } else { + updateActions.push( + async.apply( + contextServerUtils.commandHandler, + entityId, + entityType, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + commands + ) + ); + } + } + + updateActions.push( + async.apply( + contextServerUtils.executeUpdateSideEffects, + device, + entityId, + entityType, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + attributes + ) + ); + + callback(null, updateActions); + } + + deviceService.getDeviceByName(entityId, req.headers['fiware-service'], req.headers['fiware-servicepath'], function( + error, + deviceObj + ) { + if (error) { + callback(error); + } else { + async.waterfall( + [ + apply(deviceService.findConfigurationGroup, deviceObj), + apply( + deviceService.mergeDeviceWithConfiguration, + ['lazy', 'internalAttributes', 'active', 'staticAttributes', 'commands', 'subscriptions'], + [null, null, [], [], [], [], []], + deviceObj + ), + splitUpdates, + createActionsArray + ], + callback + ); + } + }); +} + +/** Express middleware to manage incoming update requests using NGSIv2. + * + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function handleUpdateNgsi2(req, res, next) { + function reduceActions(actions, callback) { + callback(null, _.flatten(actions)); + } + + if (contextServerUtils.updateHandler || contextServerUtils.commandHandler) { + logger.debug(context, 'Handling v2 update from [%s]', req.get('host')); + if (req.body) { + logger.debug(context, JSON.stringify(req.body , null, 4)); + } + + async.waterfall( + [apply(async.map, req.body.entities, apply(generateUpdateActionsNgsi2, req)), reduceActions, async.series], + function(error, result) { + if (error) { + logger.debug(context, 'There was an error handling the update action: %s.', error); + + next(error); + } else { + logger.debug(context, 'Update action from [%s] handled successfully.', req.get('host')); + res.status(204).json(); + } + } + ); + } else { + logger.error(context, 'Tried to handle an update request before the update handler was stablished.'); + + var errorNotFound = new Error({ + message: 'Update handler not found' + }); + next(errorNotFound); + } +} + +/** + * Handle queries coming to the IoT Agent via de Context Provider API (as a consequence of a query to a passive + * attribute redirected by the Context Broker). + * + * @param {String} id Entity name of the selected entity in the query. + * @param {String} type Type of the entity. + * @param {String} service Service the device belongs to. + * @param {String} subservice Division inside the service. + * @param {Array} attributes List of attributes to read. + */ +function defaultQueryHandlerNgsi2(id, type, service, subservice, attributes, callback) { + var contextElement = { + type: type, + id: id + }; + + deviceService.getDeviceByName(id, service, subservice, function(error, ngsiDevice) { + if (error) { + callback(error); + } else { + for (var i = 0; i < attributes.length; i++) { + var lazyAttribute = _.findWhere(ngsiDevice.lazy, { name: attributes[i] }), + command = _.findWhere(ngsiDevice.commands, { name: attributes[i] }), + attributeType; + + if (command) { + attributeType = command.type; + } else if (lazyAttribute) { + attributeType = lazyAttribute.type; + } else { + attributeType = 'string'; + } + + contextElement[attributes[i]] = { + type: attributeType, + value: '' + }; + } + + callback(null, contextElement); + } + }); +} + +/** + * Express middleware to manage incoming query context requests using NGSIv2. + * + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function handleNotificationNgsi2(req, res, next) { + function extractInformation(dataElement, callback) { + var atts = []; + for (var key in dataElement) { + if (dataElement.hasOwnProperty(key)) { + if (key !== 'id' && key !== 'type') { + var att = {}; + att.type = dataElement[key].type; + att.value = dataElement[key].value; + att.name = key; + atts.push(att); + } + } + } + deviceService.getDeviceByName( + dataElement.id, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + function(error, device) { + if (error) { + callback(error); + } else { + callback(null, device, atts); + } + } + ); + } + + function applyNotificationMiddlewares(device, values, callback) { + if (contextServerUtils.notificationMiddlewares.length > 0) { + var firstMiddleware = contextServerUtils.notificationMiddlewares.slice(0, 1)[0], + rest = contextServerUtils.notificationMiddlewares.slice(1), + startMiddleware = apply(firstMiddleware, device, values), + composedMiddlewares = [startMiddleware].concat(rest); + + async.waterfall(composedMiddlewares, callback); + } else { + callback(null, device, values); + } + } + + function createNotificationHandler(contextResponse, callback) { + async.waterfall( + [ + apply(extractInformation, contextResponse), + applyNotificationMiddlewares, + contextServerUtils.notificationHandler + ], + callback + ); + } + + function handleNotificationRequests(error) { + if (error) { + logger.error(context, 'Error found when processing notification: %j', error); + next(error); + } else { + res.status(200).json({}); + } + } + + if (contextServerUtils.notificationHandler) { + logger.debug(context, 'Handling notification from [%s]', req.get('host')); + async.map(req.body.data, createNotificationHandler, handleNotificationRequests); + } else { + var errorNotFound = new Error({ + message: 'Notification handler not found' + }); + + logger.error(context, 'Tried to handle a notification before notification handler was established.'); + + next(errorNotFound); + } +} + +/** + * Error handler for NGSIv2 context query requests. + * + * @param {Object} error Incoming error + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function queryErrorHandlingNgsi2(error, req, res, next) { + var code = 500; + + logger.debug(context, 'Query NGSIv2 error [%s] handling request: %s', error.name, error.message); + + if (error.code && String(error.code).match(/^[2345]\d\d$/)) { + code = error.code; + } + + res.status(code).json({ + error: error.name, + description: error.message.replace(/[<>\"\'=;\(\)]/g, '') + }); +} + +/** + * Error handler for NGSIv2 update requests. + * + * @param {Object} error Incoming error + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + */ +function updateErrorHandlingNgsi2(error, req, res, next) { + var code = 500; + + logger.debug(context, 'Update NGSIv2 error [%s] handing request: %s', error.name, error.message); + + if (error.code && String(error.code).match(/^[2345]\d\d$/)) { + code = error.code; + } + + res.status(code).json({ + error: error.name, + description: error.message.replace(/[<>\"\'=;\(\)]/g, '') + }); +} + +/** + * Express middleware to manage incoming query context requests using NGSIv2. + */ +function handleQueryNgsi2(req, res, next) { + function getName(element) { + return element.name; + } + + function addStaticAttributes(attributes, device, contextElement, callback) { + function inAttributes(item) { + return item.name && attributes.indexOf(item.name) >= 0; + } + + if (device.staticAttributes) { + var selectedAttributes = []; + if (attributes === undefined || attributes.length === 0) { + selectedAttributes = device.staticAttributes; + } else { + selectedAttributes = device.staticAttributes.filter(inAttributes); + } + + for (var att in selectedAttributes) { + contextElement[selectedAttributes[att].name] = { + type: selectedAttributes[att].type, + value: selectedAttributes[att].value + }; + } + } + + callback(null, contextElement); + } + + function completeAttributes(attributes, device, callback) { + if (attributes && attributes.length !== 0) { + logger.debug(context, 'Handling received set of attributes: %j', attributes); + callback(null, attributes); + } else if (device.lazy) { + logger.debug(context, 'Handling stored set of attributes: %j', attributes); + var results = device.lazy.map(getName); + callback(null, results); + } else { + logger.debug(context, 'Couldn\'t find any attributes. Handling with null reference'); + callback(null, null); + } + } + + function finishQueryForDevice(attributes, contextEntity, actualHandler, device, callback) { + var contextId = contextEntity.id; + var contextType = contextEntity.type; + if (!contextId) { + contextId = device.id; + } + + if (!contextType) { + contextType = device.type; + } + + deviceService.findConfigurationGroup(device, function(error, group) { + var executeCompleteAttributes = apply(completeAttributes, attributes, group), + executeQueryHandler = apply( + actualHandler, + contextId, + contextType, + req.headers['fiware-service'], + req.headers['fiware-servicepath'] + ), + executeAddStaticAttributes = apply(addStaticAttributes, attributes, group); + + async.waterfall([executeCompleteAttributes, executeQueryHandler, executeAddStaticAttributes], callback); + }); + } + + function createQueryRequest(attributes, contextEntity, callback) { + var actualHandler; + var getFunction; + + if (contextServerUtils.queryHandler) { + actualHandler = contextServerUtils.queryHandler; + } else { + actualHandler = defaultQueryHandlerNgsi2; + } + + if (contextEntity.id) { + getFunction = apply( + deviceService.getDeviceByName, + contextEntity.id, + req.headers['fiware-service'], + req.headers['fiware-servicepath'] + ); + } else { + getFunction = apply( + deviceService.listDevicesWithType, + contextEntity.type, + req.headers['fiware-service'], + req.headers['fiware-servicepath'], + null, + null + ); + } + + getFunction(function handleFindDevice(error, innerDevice) { + let deviceList = []; + if (!innerDevice) { + return callback(new errors.DeviceNotFound(contextEntity.id)); + } + + if (innerDevice.count) { + if (innerDevice.count === 0) { + return callback(null, []); + } else { + deviceList = innerDevice.devices; + } + } else { + deviceList = [innerDevice]; + } + + async.map(deviceList, async.apply(finishQueryForDevice, attributes, contextEntity, actualHandler), function( + error, + results + ) { + if (error) { + callback(error); + } else if (innerDevice.count) { + callback(null, results); + } else if (Array.isArray(results) && results.length > 0) { + callback(null, results); + } else { + callback(null, results); + } + }); + }); + } + + function handleQueryContextRequests(error, result) { + if (error) { + logger.debug(context, 'There was an error handling the query: %s.', error); + next(error); + } else { + logger.debug(context, 'Query from [%s] handled successfully.', req.get('host')); + res.status(200).json(result); + } + } + + logger.debug(context, 'Handling query from [%s]', req.get('host')); + if (req.body) { + logger.debug(context, JSON.stringify(req.body , null, 4)); + } + var contextEntity = {}; + + // At the present moment, IOTA supports query request with one entity and without patterns. This is aligned + // with the utilization cases in combination with ContextBroker. Other cases are returned as error + if (req.body.entities.length !== 1) { + logger.warn( + 'queries with entities number different to 1 are not supported (%d found)', + req.body.entities.length + ); + handleQueryContextRequests({ code: 400, name: 'BadRequest', message: 'more than one entity in query' }); + return; + } + if (req.body.entities[0].idPattern) { + logger.warn('queries with idPattern are not supported'); + handleQueryContextRequests({ code: 400, name: 'BadRequest', message: 'idPattern usage in query' }); + return; + } + + contextEntity.id = req.body.entities[0].id; + contextEntity.type = req.body.entities[0].type; + var queryAtts = req.body.attrs; + createQueryRequest(queryAtts, contextEntity, handleQueryContextRequests); +} + +/** + * Load the routes related to context dispatching (NGSI10 calls). + * + * @param {Object} router Express request router object. + */ +function loadContextRoutesNGSIv2(router) { + // In a more evolved implementation, more endpoints could be added to queryPathsNgsi2 + // according to http://fiware.github.io/specifications/ngsiv2/stable. + + var i; + logger.info(context, 'Loading NGSI-v2 Context server routes'); + for (i = 0; i < updatePaths.length; i++) { + router.post(updatePaths[i], [ + middlewares.ensureType, + middlewares.validateJson(updateContextTemplateNgsi2), + handleUpdateNgsi2, + updateErrorHandlingNgsi2 + ]); + } + for (i = 0; i < queryPaths.length; i++) { + router.post(queryPaths[i], [handleQueryNgsi2, queryErrorHandlingNgsi2]); + } + router.post('/notify', [ + middlewares.ensureType, + middlewares.validateJson(notificationTemplateNgsi2), + handleNotificationNgsi2, + queryErrorHandlingNgsi2 + ]); +} + +exports.loadContextRoutes = loadContextRoutesNGSIv2; diff --git a/lib/services/northBound/contextServer.js b/lib/services/northBound/contextServer.js index d8a89ae57..9a560c3d1 100644 --- a/lib/services/northBound/contextServer.js +++ b/lib/services/northBound/contextServer.js @@ -1,5 +1,5 @@ /* - * Copyright 2014 Telefonica Investigación y Desarrollo, S.A.U + * Copyright 2020 Telefonica Investigación y Desarrollo, S.A.U * * This file is part of fiware-iotagent-lib * @@ -21,1337 +21,30 @@ * please contact with::daniel.moranjimenez@telefonica.com * * Modified by: Daniel Calvo - ATOS Research & Innovation + * Modified by: Jason Fox - FIWARE Foundation */ 'use strict'; -var async = require('async'), - apply = async.apply, - logger = require('logops'), - constants = require('../../constants'), - errors = require('../../errors'), - ngsi = require('../ngsi/ngsiService'), - intoTrans = require('../common/domain').intoTrans, - deviceService = require('../devices/deviceService'), - commands = require('../commands/commandService'), - middlewares = require('../common/genericMiddleware'), - _ = require('underscore'), +var intoTrans = require('../common/domain').intoTrans, config = require('../../commonConfig'), context = { op: 'IoTAgentNGSI.ContextServer' }, - updateContextTemplateNgsi1 = require('../../templates/updateContextNgsi1.json'), - updateContextTemplateNgsi2 = require('../../templates/updateContextNgsi2.json'), - updateContextTemplateNgsiLD = require('../../templates/updateContextNgsiLD.json'), - queryContextTemplate = require('../../templates/queryContext.json'), - notificationTemplateNgsi1 = require('../../templates/notificationTemplateNgsi1.json'), - notificationTemplateNgsi2 = require('../../templates/notificationTemplateNgsi2.json'), - notificationTemplateNgsiLD = require('../../templates/notificationTemplateNgsiLD.json'), - notificationMiddlewares = [], - updateHandler, - commandHandler, - queryHandler, - notificationHandler; + contextServerUtils = require('./contextServerUtils'); -/** - * Create the response for an UpdateContext operation, based on the results of the individual updates. The signature - * retains the results object for homogeinity with the createQuery* version. - * - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - * @param {Object} results Ignored for this function. TODO: to be removed in later versions. - * @return {{contextResponses: Array}} - */ -function createUpdateResponse(req, res, results) { - var result = { - contextResponses: [] - }; - - for (var i = 0; i < req.body.contextElements.length; i++) { - var contextResponse = { - contextElement: { - attributes: req.body.contextElements[i].attributes, - id: req.body.contextElements[i].id, - isPattern: false, - type: req.body.contextElements[i].type - }, - statusCode: { - code: 200, - reasonPhrase: 'OK' - } - }; - - for (var j = 0; j < contextResponse.contextElement.attributes.length; j++) { - contextResponse.contextElement.attributes[i].value = ''; - } - - result.contextResponses.push(contextResponse); - } - - logger.debug(context, 'Generated update response: %j', result); - - return result; -} - -/** - * Create the response for a queryContext operation based on the individual results gathered from the query handlers. - * The returned response is in the NGSI Response format. - * - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - * @param {Object} results Individual Context Element results from the query handlers. - * @return {{contextResponses: Array}} - */ -function createQueryResponse(req, res, results) { - var result = { - contextResponses: [] - }; - - for (var i = 0; i < results.length; i++) { - var contextResponse = { - contextElement: results[i], - statusCode: { - code: 200, - reasonPhrase: 'OK' - } - }; - - contextResponse.contextElement.isPattern = false; - - result.contextResponses.push(contextResponse); - } - - logger.debug(context, 'Generated query response: %j', result); - - return result; -} - -/** - * Retrieve the Device that corresponds to a Context Update, and execute the update side effects - * if there were any (e.g.: creation of attributes related to comands). - * - * @param {String} device Object that contains all the information about the device. - * @param {String} id Entity ID of the device to find. - * @param {String} type Type of the device to find. - * @param {String} service Service of the device. - * @param {String} subservice Subservice of the device. - * @param {Array} attributes List of attributes to update with their types and values. - */ -function executeUpdateSideEffects(device, id, type, service, subservice, attributes, callback) { - var sideEffects = []; - - if (device.commands) { - for (var i = 0; i < device.commands.length; i++) { - for (var j = 0; j < attributes.length; j++) { - if (device.commands[i].name === attributes[j].name) { - var newAttributes = [ - { - name: device.commands[i].name + '_status', - type: constants.COMMAND_STATUS, - value: 'PENDING' - } - ]; - - sideEffects.push( - apply(ngsi.update, - device.name, - device.resource, - device.apikey, - newAttributes, - device - ) - ); - } - } - } - } - - async.series(sideEffects, callback); -} - -/** - * Extract all the commands from the attributes section and add them to the Commands Queue. - * - * @param {String} device Object that contains all the information about the device. - * @param {String} id Entity ID of the device to find. - * @param {String} type Type of the device to find. - * @param {String} service Service of the device. - * @param {String} subservice Subservice of the device. - * @param {Array} attributes List of attributes to update with their types and values. - */ -function pushCommandsToQueue(device, id, type, service, subservice, attributes, callback) { - async.map(attributes, apply(commands.add, service, subservice, device.id), callback); -} - -/** - * Generate all the update actions corresponding to a update context request using Ngsi1. - * Update actions include updates in attributes and execution of commands. This action will - * be called once per Context Element in the request. - * - * @param {Object} req Update request to generate Actions from - * @param {Object} contextElement Context Element whose actions will be extracted. - */ -function generateUpdateActionsNgsi1(req, contextElement, callback) { - function splitUpdates(device, callback) { - var attributes = [], - commands = [], - found; - - if (device.commands) { - attributeLoop: for (var i in contextElement.attributes) { - for (var j in device.commands) { - if (contextElement.attributes[i].name === device.commands[j].name) { - commands.push(contextElement.attributes[i]); - found = true; - continue attributeLoop; - } - } - - attributes.push(contextElement.attributes[i]); - } - - } else { - attributes = contextElement.attributes; - } - - callback(null, attributes, commands, device); - } - - function createActionsArray(attributes, commands, device, callback) { - var updateActions = []; - - if (updateHandler) { - updateActions.push( - async.apply( - updateHandler, - contextElement.id, - contextElement.type, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - attributes) - ); - } - - if (commandHandler) { - if (device.polling) { - updateActions.push( - async.apply( - pushCommandsToQueue, - device, - contextElement.id, - contextElement.type, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - contextElement.attributes) - ); - } else { - updateActions.push( - async.apply( - commandHandler, - contextElement.id, - contextElement.type, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - commands) - ); - } - } - - updateActions.push( - async.apply( - executeUpdateSideEffects, - device, - contextElement.id, - contextElement.type, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - contextElement.attributes) - ); - - callback(null, updateActions); - } - - deviceService.getDeviceByName(contextElement.id, req.headers['fiware-service'], req.headers['fiware-servicepath'], - function(error, deviceObj) { - if (error) { - callback(error); - } else { - async.waterfall([ - apply(deviceService.findConfigurationGroup, deviceObj), - apply(deviceService.mergeDeviceWithConfiguration, - [ - 'lazy', - 'internalAttributes', - 'active', - 'staticAttributes', - 'commands', - 'subscriptions' - ], - [null, null, [], [], [], [], []], - deviceObj - ), - splitUpdates, - createActionsArray - ], callback); - } - }); -} - -/** - * Generate all the update actions corresponding to a update context request using Ngsi2. - * Update actions include updates in attributes and execution of commands. - * - * @param {Object} req Update request to generate Actions from - * @param {Object} contextElement Context Element whose actions will be extracted. - */ -function generateUpdateActionsNgsi2(req, contextElement, callback) { - var entityId; - var entityType; - - if (contextElement.id && contextElement.type) { - entityId = contextElement.id; - entityType = contextElement.type; - }else if (req.params.entity) { - entityId = req.params.entity; - } - - function splitUpdates(device, callback) { - var attributes = [], - commands = [], - found, - newAtt, - i; - - if (device.commands) { - attributeLoop: for (i in contextElement) { - for (var j in device.commands) { - - if (i === device.commands[j].name) { - newAtt = {}; - newAtt[i] = contextElement[i]; - newAtt[i].name = i; - commands.push(newAtt[i]); - found = true; - continue attributeLoop; - } - } - } - - } - - for (i in contextElement) { - if (i !== 'type' && i !== 'id') { - newAtt = {}; - newAtt = contextElement[i]; - newAtt.name = i; - attributes.push(newAtt); - } - } - - callback(null, attributes, commands, device); - } - - function createActionsArray(attributes, commands, device, callback) { - var updateActions = []; - - if(!entityType) { - entityType = device.type; - } - - if (updateHandler) { - updateActions.push( - async.apply( - updateHandler, - entityId, - entityType, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - attributes) - ); - } - - if (commandHandler) { - if (device.polling) { - updateActions.push( - async.apply( - pushCommandsToQueue, - device, - entityId, - entityType, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - attributes) - ); - } else { - updateActions.push( - async.apply( - commandHandler, - entityId, - entityType, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - commands) - ); - } - } - - updateActions.push( - async.apply( - executeUpdateSideEffects, - device, - entityId, - entityType, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - attributes) - ); - - callback(null, updateActions); - } - - deviceService.getDeviceByName(entityId, req.headers['fiware-service'], req.headers['fiware-servicepath'], - function(error, deviceObj) { - if (error) { - callback(error); - } else { - async.waterfall([ - apply(deviceService.findConfigurationGroup, deviceObj), - apply(deviceService.mergeDeviceWithConfiguration, - [ - 'lazy', - 'internalAttributes', - 'active', - 'staticAttributes', - 'commands', - 'subscriptions' - ], - [null, null, [], [], [], [], []], - deviceObj - ), - splitUpdates, - createActionsArray - ], callback); - } - }); -} - -/** - * Express middleware to manage incoming update requests using NGSI-LD. - * - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function handleUpdateNgsiLD(req, res, next) { - - function reduceActions(actions, callback) { - callback(null, _.flatten(actions)); - } - - if (updateHandler || commandHandler) { - logger.debug(context, 'Handling LD update from [%s]', req.get('host')); - logger.debug(context, req.body); - - async.waterfall([ - apply(async.map, req.body.entities, apply(generateUpdateActionsNgsi2, req)), - reduceActions, - async.series - ], function(error, result) { - if (error) { - logger.debug(context, 'There was an error handling the update action: %s.', error); - - next(error); - } else { - logger.debug(context, 'Update action from [%s] handled successfully.', req.get('host')); - res.status(204).json(); - } - }); - } else { - logger.error(context, 'Tried to handle an update request before the update handler was stablished.'); - - var errorNotFound = new Error({ - message: 'Update handler not found' - }); - next(errorNotFound); - } -} +var contextServerHandler; -/** - * Express middleware to manage incoming update requests using NGSIv2 - * - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function handleUpdateNgsi2(req, res, next) { - function reduceActions(actions, callback) { - callback(null, _.flatten(actions)); - } - - if (updateHandler || commandHandler) { - logger.debug(context, 'Handling v2 update from [%s]', req.get('host')); - logger.debug(context, req.body); - - async.waterfall([ - apply(async.map, req.body.entities, apply(generateUpdateActionsNgsi2, req)), - reduceActions, - async.series - ], function(error, result) { - if (error) { - logger.debug(context, 'There was an error handling the update action: %s.', error); - - next(error); - } else { - logger.debug(context, 'Update action from [%s] handled successfully.', req.get('host')); - res.status(204).json(); - } - }); - } else { - logger.error(context, 'Tried to handle an update request before the update handler was stablished.'); - - var errorNotFound = new Error({ - message: 'Update handler not found' - }); - next(errorNotFound); - } -} - -/** - * Express middleware to manage incoming UpdateContext requests using NGSIv1. - * As NGSI10 requests can affect multiple entities, for each one of them a call - * to the user update handler function is made. - */ -function handleUpdateNgsi1(req, res, next) { - - function reduceActions(actions, callback) { - callback(null, _.flatten(actions)); - } - - if (updateHandler || commandHandler) { - logger.debug(context, 'Handling v1 update from [%s]', req.get('host')); - logger.debug(context, req.body); - - async.waterfall([ - apply(async.map, req.body.contextElements, apply(generateUpdateActionsNgsi1, req)), - reduceActions, - async.series - ], function(error, result) { - if (error) { - logger.debug(context, 'There was an error handling the update action: %s.', error); - - next(error); - } else { - logger.debug(context, 'Update action from [%s] handled successfully.', req.get('host')); - res.status(200).json(createUpdateResponse(req, res, result)); - } - }); - } else { - logger.error(context, 'Tried to handle an update request before the update handler was stablished.'); - - var errorNotFound = new Error({ - message: 'Update handler not found' - }); - next(errorNotFound); - } -} - -/** - * Handle queries coming to the IoT Agent via de Context Provider API (as a consequence of a query to a passive - * attribute redirected by the Context Broker). - * - * @param {String} id Entity name of the selected entity in the query. - * @param {String} type Type of the entity. - * @param {String} service Service the device belongs to. - * @param {String} subservice Division inside the service. - * @param {Array} attributes List of attributes to read. - */ -function defaultQueryHandlerNgsi1(id, type, service, subservice, attributes, callback) { - var contextElement = { - type: type, - isPattern: false, - id: id, - attributes: [] - }; - - deviceService.getDeviceByName(id, service, subservice, function(error, ngsiDevice) { - if (error) { - callback(error); - } else { - for (var i = 0; i < attributes.length; i++) { - var lazyAttribute = _.findWhere(ngsiDevice.lazy, { name: attributes[i] }), - command = _.findWhere(ngsiDevice.commands, { name: attributes[i] }), - attributeType; - - if (command) { - attributeType = command.type; - } else if (lazyAttribute) { - attributeType = lazyAttribute.type; - } else { - attributeType = 'string'; - } - - contextElement.attributes.push({ - name: attributes[i], - type: attributeType, - value: '' - }); - } - - callback(null, contextElement); - } - }); -} - -/** - * Handle queries coming to the IoT Agent via de Context Provider API (as a consequence of a query to a passive - * attribute redirected by the Context Broker). - * - * @param {String} id Entity name of the selected entity in the query. - * @param {String} type Type of the entity. - * @param {String} service Service the device belongs to. - * @param {String} subservice Division inside the service. - * @param {Array} attributes List of attributes to read. +/** + * Loads the correct context server handler based on the current config. */ -function defaultQueryHandlerNgsi2(id, type, service, subservice, attributes, callback) { - var contextElement = { - type: type, - id: id - }; - - deviceService.getDeviceByName(id, service, subservice, function(error, ngsiDevice) { - if (error) { - callback(error); - } else { - for (var i = 0; i < attributes.length; i++) { - var lazyAttribute = _.findWhere(ngsiDevice.lazy, { name: attributes[i] }), - command = _.findWhere(ngsiDevice.commands, { name: attributes[i] }), - attributeType; - - if (command) { - attributeType = command.type; - } else if (lazyAttribute) { - attributeType = lazyAttribute.type; - } else { - attributeType = 'string'; - } - - contextElement[attributes[i]] = { - type: attributeType, - value: '' - }; - } - - callback(null, contextElement); - } - }); -} - -/** - * Express middleware to manage incoming QueryContext requests using NGSIv1. - * As NGSI10 requests can affect multiple entities, for each one of them a call - * to the user query handler function is made. - */ -function handleQueryNgsi1(req, res, next) { - function getName(element) { - return element.name; - } - - function addStaticAttributes(attributes, device, contextElement, callback) { - - function inAttributes(item) { - return item.name && attributes.indexOf(item.name) >= 0; - } - - if (device.staticAttributes) { - var selectedAttributes = device.staticAttributes.filter(inAttributes); - - if (selectedAttributes.length > 0) { - if (contextElement.attributes) { - contextElement.attributes = contextElement.attributes.concat(selectedAttributes); - } else { - contextElement.attributes = selectedAttributes; - } - } - } - - callback(null, contextElement); - } - - function completeAttributes(attributes, device, callback) { - if (attributes && attributes.length !== 0) { - logger.debug(context, 'Handling received set of attributes: %j', attributes); - callback(null, attributes); - } else if (device.lazy) { - logger.debug(context, 'Handling stored set of attributes: %j', attributes); - callback(null, device.lazy.map(getName)); - } else { - logger.debug(context, 'Couldn\'t find any attributes. Handling with null reference'); - callback(null, null); - } - } - - function createQueryRequests(attributes, contextEntity, callback) { - var actualHandler; - - if (queryHandler) { - actualHandler = queryHandler; - } else { - actualHandler = defaultQueryHandlerNgsi1; - } - - async.waterfall([ - apply( - deviceService.getDeviceByName, - contextEntity.id, - req.headers['fiware-service'], - req.headers['fiware-servicepath']), - deviceService.findConfigurationGroup - ], function handleFindDevice(error, device) { - var executeCompleteAttributes = apply( - completeAttributes, - attributes, - device - ), - executeQueryHandler = apply( - actualHandler, - contextEntity.id, - contextEntity.type, - req.headers['fiware-service'], - req.headers['fiware-servicepath'] - ), - executeAddStaticAttributes = apply( - addStaticAttributes, - attributes, - device - ); - - callback(error, apply(async.waterfall, [ - executeCompleteAttributes, - executeQueryHandler, - executeAddStaticAttributes - ])); - }); - - } - - function handleQueryContextRequests(error, result) { - if (error) { - logger.debug(context, 'There was an error handling the query: %s.', error); - next(error); - } else { - logger.debug(context, 'Query from [%s] handled successfully.', req.get('host')); - res.status(200).json(createQueryResponse(req, res, result)); - } - } - - logger.debug(context, 'Handling query from [%s]', req.get('host')); - - async.waterfall([ - apply(async.map, req.body.entities, apply(createQueryRequests, req.body.attributes)), - async.series - ], handleQueryContextRequests); -} - -/** - * Express middleware to manage incoming query context requests using NGSI-LD. - * - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function handleQueryNgsiLD(req, res, next) { - function getName(element) { - return element.name; - } - - function addStaticAttributes(attributes, device, contextElement, callback) { - - function inAttributes(item) { - return item.name && attributes.indexOf(item.name) >= 0; - } - - if (device.staticAttributes) { - - var selectedAttributes = []; - if (attributes === undefined || attributes.length === 0) { - selectedAttributes = device.staticAttributes; - } - else { - selectedAttributes = device.staticAttributes.filter(inAttributes); - } - - for (var att in selectedAttributes) { - contextElement[selectedAttributes[att].name] = { - 'type' : selectedAttributes[att].type, - 'value' : selectedAttributes[att].value - }; - } - } - - callback(null, contextElement); - } - - function completeAttributes(attributes, device, callback) { - if (attributes && attributes.length !== 0) { - logger.debug(context, 'Handling received set of attributes: %j', attributes); - callback(null, attributes); - } else if (device.lazy) { - logger.debug(context, 'Handling stored set of attributes: %j', attributes); - var results = device.lazy.map(getName); - callback(null, results); - } else { - logger.debug(context, 'Couldn\'t find any attributes. Handling with null reference'); - callback(null, null); - } - } - - function finishQueryForDevice(attributes, contextEntity, actualHandler, device, callback) { - var contextId = contextEntity.id; - var contextType = contextEntity.type; - if(!contextId) { - contextId = device.id; - } - - if(!contextType) { - contextType = device.type; - } - - deviceService.findConfigurationGroup(device, function(error, group) { - var executeCompleteAttributes = apply( - completeAttributes, - attributes, - group - ), - executeQueryHandler = apply( - actualHandler, - contextId, - contextType, - req.headers['fiware-service'], - req.headers['fiware-servicepath'] - ), - executeAddStaticAttributes = apply( - addStaticAttributes, - attributes, - group - ); - - async.waterfall([ - executeCompleteAttributes, - executeQueryHandler, - executeAddStaticAttributes - ], callback); - }); - } - - function createQueryRequest(attributes, contextEntity, callback) { - var actualHandler; - var getFunction; - - if (queryHandler) { - actualHandler = queryHandler; - } else { - actualHandler = defaultQueryHandlerNgsi2; - } - - if (contextEntity.id) { - getFunction = apply( - deviceService.getDeviceByName, - contextEntity.id, - req.headers['fiware-service'], - req.headers['fiware-servicepath']); - } else { - getFunction = apply( - deviceService.listDevicesWithType, - contextEntity.type, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - null, - null); - } - - getFunction(function handleFindDevice(error, innerDevice) { - let deviceList = []; - if (!innerDevice) { - return callback(new errors.DeviceNotFound(contextEntity.id)); - } - - if(innerDevice.count) { - if (innerDevice.count === 0) { - return callback(null, []); - } else { - deviceList = innerDevice.devices; - } - } else { - deviceList = [innerDevice]; - } - - async.map(deviceList, async.apply( - finishQueryForDevice, attributes, contextEntity, actualHandler), function (error, results) { - if (error) { - callback(error); - } - else if(innerDevice.count) { - callback(null,results); - } else if(Array.isArray(results) && results.length > 0){ - callback(null, results); - } else { - callback(null, results); - } - }); - }); - - } - - function handleQueryContextRequests(error, result) { - if (error) { - logger.debug(context, 'There was an error handling the query: %s.', error); - next(error); - } else { - logger.debug(context, 'Query from [%s] handled successfully.', req.get('host')); - res.status(200).json(result); - } - } - - logger.debug(context, 'Handling query from [%s]', req.get('host')); - var contextEntity = {}; - - // At the present moment, IOTA supports query request with one entity and without patterns. This is aligned - // with the utilization cases in combination with ContextBroker. Other cases are returned as error - if (req.body.entities.length !== 1) - { - logger.warn('queries with entities number different to 1 are not supported (%d found)', - req.body.entities.length); - handleQueryContextRequests({code: 400, name: 'BadRequest', message: 'more than one entity in query'}); - return; - } - if (req.body.entities[0].idPattern) - { - logger.warn('queries with idPattern are not supported'); - handleQueryContextRequests({code: 400, name: 'BadRequest', message: 'idPattern usage in query'}); - return; - } - - contextEntity.id = req.body.entities[0].id; - contextEntity.type = req.body.entities[0].type; - var queryAtts = req.body.attrs; - createQueryRequest(queryAtts, contextEntity, handleQueryContextRequests); - -} - -/** - * Express middleware to manage incoming query context requests using NGSI-LD. - * - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function handleQueryNgsi2(req, res, next) { - function getName(element) { - return element.name; - } - - function addStaticAttributes(attributes, device, contextElement, callback) { - - function inAttributes(item) { - return item.name && attributes.indexOf(item.name) >= 0; - } - - if (device.staticAttributes) { - - var selectedAttributes = []; - if (attributes === undefined || attributes.length === 0) { - selectedAttributes = device.staticAttributes; - } - else { - selectedAttributes = device.staticAttributes.filter(inAttributes); - } - - for (var att in selectedAttributes) { - contextElement[selectedAttributes[att].name] = { - 'type' : selectedAttributes[att].type, - 'value' : selectedAttributes[att].value - }; - } - } - - callback(null, contextElement); - } - - function completeAttributes(attributes, device, callback) { - if (attributes && attributes.length !== 0) { - logger.debug(context, 'Handling received set of attributes: %j', attributes); - callback(null, attributes); - } else if (device.lazy) { - logger.debug(context, 'Handling stored set of attributes: %j', attributes); - var results = device.lazy.map(getName); - callback(null, results); - } else { - logger.debug(context, 'Couldn\'t find any attributes. Handling with null reference'); - callback(null, null); - } - } - - function finishQueryForDevice(attributes, contextEntity, actualHandler, device, callback) { - var contextId = contextEntity.id; - var contextType = contextEntity.type; - if(!contextId) { - contextId = device.id; - } - - if(!contextType) { - contextType = device.type; - } - - deviceService.findConfigurationGroup(device, function(error, group) { - var executeCompleteAttributes = apply( - completeAttributes, - attributes, - group - ), - executeQueryHandler = apply( - actualHandler, - contextId, - contextType, - req.headers['fiware-service'], - req.headers['fiware-servicepath'] - ), - executeAddStaticAttributes = apply( - addStaticAttributes, - attributes, - group - ); - - async.waterfall([ - executeCompleteAttributes, - executeQueryHandler, - executeAddStaticAttributes - ], callback); - }); - } - - function createQueryRequest(attributes, contextEntity, callback) { - var actualHandler; - var getFunction; - - if (queryHandler) { - actualHandler = queryHandler; - } else { - actualHandler = defaultQueryHandlerNgsi2; - } - - if (contextEntity.id) { - getFunction = apply( - deviceService.getDeviceByName, - contextEntity.id, - req.headers['fiware-service'], - req.headers['fiware-servicepath']); - } else { - getFunction = apply( - deviceService.listDevicesWithType, - contextEntity.type, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - null, - null); - } - - getFunction(function handleFindDevice(error, innerDevice) { - let deviceList = []; - if (!innerDevice) { - return callback(new errors.DeviceNotFound(contextEntity.id)); - } - - if(innerDevice.count) { - if (innerDevice.count === 0) { - return callback(null, []); - } else { - deviceList = innerDevice.devices; - } - } else { - deviceList = [innerDevice]; - } - - async.map(deviceList, async.apply( - finishQueryForDevice, attributes, contextEntity, actualHandler), function (error, results) { - if (error) { - callback(error); - } - else if(innerDevice.count) { - callback(null,results); - } else if(Array.isArray(results) && results.length > 0){ - callback(null, results); - } else { - callback(null, results); - } - }); - }); - - } - - function handleQueryContextRequests(error, result) { - if (error) { - logger.debug(context, 'There was an error handling the query: %s.', error); - next(error); - } else { - logger.debug(context, 'Query from [%s] handled successfully.', req.get('host')); - res.status(200).json(result); - } - } - - logger.debug(context, 'Handling query from [%s]', req.get('host')); - var contextEntity = {}; - - // At the present moment, IOTA supports query request with one entity and without patterns. This is aligned - // with the utilization cases in combination with ContextBroker. Other cases are returned as error - if (req.body.entities.length !== 1) - { - logger.warn('queries with entities number different to 1 are not supported (%d found)', - req.body.entities.length); - handleQueryContextRequests({code: 400, name: 'BadRequest', message: 'more than one entity in query'}); - return; - } - if (req.body.entities[0].idPattern) - { - logger.warn('queries with idPattern are not supported'); - handleQueryContextRequests({code: 400, name: 'BadRequest', message: 'idPattern usage in query'}); - return; - } - - contextEntity.id = req.body.entities[0].id; - contextEntity.type = req.body.entities[0].type; - var queryAtts = req.body.attrs; - createQueryRequest(queryAtts, contextEntity, handleQueryContextRequests); - -} - -/** - * Express middleware to manage incoming notification requests using NGSIv1. - * - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function handleNotificationNgsi1(req, res, next) { - - function checkStatus(statusCode, callback) { - if (statusCode.code && statusCode.code === '200') { - callback(); - } else { - callback(new errors.NotificationError(statusCode.code)); - } - } - - function extractInformation(contextResponse, callback) { - deviceService.getDeviceByName( - contextResponse.contextElement.id, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - function(error, device) { - if (error) { - callback(error); - } else { - callback(null, device, contextResponse.contextElement.attributes); - } - }); - } - - function applyNotificationMiddlewares(device, values, callback) { - if (notificationMiddlewares.length > 0) { - var firstMiddleware = notificationMiddlewares.slice(0, 1)[0], - rest = notificationMiddlewares.slice(1), - startMiddleware = apply(firstMiddleware, device, values), - composedMiddlewares = [startMiddleware].concat(rest); - - async.waterfall(composedMiddlewares, callback); - } else { - callback(null, device, values); - } - } - - function createNotificationHandler(contextResponse, callback) { - async.waterfall([ - apply(checkStatus, contextResponse.statusCode), - apply(extractInformation, contextResponse), - applyNotificationMiddlewares, - notificationHandler - ], callback); - } - - function handleNotificationRequests(error) { - if (error) { - logger.error(context, 'Error found when processing notification: %j', error); - next(error); - } else { - res.status(200).json({}); - } - } - - if (notificationHandler) { - logger.debug(context, 'Handling notification from [%s]', req.get('host')); - - async.map(req.body.contextResponses, createNotificationHandler, handleNotificationRequests); - - } else { - var errorNotFound = new Error({ - message: 'Notification handler not found' - }); - - logger.error(context, 'Tried to handle a notification before notification handler was established.'); - - next(errorNotFound); - } -} - -/** - * Express middleware to manage incoming notification requests using NGSI-LD. - * - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function handleNotificationNgsiLD(req, res, next) { - function extractInformation(dataElement, callback) { - var atts = []; - for (var key in dataElement) { - if (dataElement.hasOwnProperty(key)) { - if (key !== 'id' && key !== 'type') { - var att = {}; - att.type = dataElement[key].type; - att.value = dataElement[key].value; - att.name = key; - atts.push(att); - } - } - } - deviceService.getDeviceByName( - dataElement.id, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - function(error, device) { - if (error) { - callback(error); - } else { - callback(null, device, atts); - } - }); - } - - function applyNotificationMiddlewares(device, values, callback) { - if (notificationMiddlewares.length > 0) { - var firstMiddleware = notificationMiddlewares.slice(0, 1)[0], - rest = notificationMiddlewares.slice(1), - startMiddleware = apply(firstMiddleware, device, values), - composedMiddlewares = [startMiddleware].concat(rest); - - async.waterfall(composedMiddlewares, callback); - } else { - callback(null, device, values); - } - } - - function createNotificationHandler(contextResponse, callback) { - async.waterfall([ - apply(extractInformation, contextResponse), - applyNotificationMiddlewares, - notificationHandler - ], callback); - } - - function handleNotificationRequests(error) { - if (error) { - logger.error(context, 'Error found when processing notification: %j', error); - next(error); - } else { - res.status(200).json({}); - } - } - - if (notificationHandler) { - logger.debug(context, 'Handling notification from [%s]', req.get('host')); - async.map(req.body.data, createNotificationHandler, handleNotificationRequests); - - } else { - var errorNotFound = new Error({ - message: 'Notification handler not found' - }); - - logger.error(context, 'Tried to handle a notification before notification handler was established.'); - - next(errorNotFound); - } - -} - -/** - * Express middleware to manage incoming notification requests using NGSIv2. - * - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function handleNotificationNgsi2(req, res, next) { - function extractInformation(dataElement, callback) { - var atts = []; - for (var key in dataElement) { - if (dataElement.hasOwnProperty(key)) { - if (key !== 'id' && key !== 'type') { - var att = {}; - att.type = dataElement[key].type; - att.value = dataElement[key].value; - att.name = key; - atts.push(att); - } - } - } - deviceService.getDeviceByName( - dataElement.id, - req.headers['fiware-service'], - req.headers['fiware-servicepath'], - function(error, device) { - if (error) { - callback(error); - } else { - callback(null, device, atts); - } - }); - } - - function applyNotificationMiddlewares(device, values, callback) { - if (notificationMiddlewares.length > 0) { - var firstMiddleware = notificationMiddlewares.slice(0, 1)[0], - rest = notificationMiddlewares.slice(1), - startMiddleware = apply(firstMiddleware, device, values), - composedMiddlewares = [startMiddleware].concat(rest); - - async.waterfall(composedMiddlewares, callback); - } else { - callback(null, device, values); - } - } - - function createNotificationHandler(contextResponse, callback) { - async.waterfall([ - apply(extractInformation, contextResponse), - applyNotificationMiddlewares, - notificationHandler - ], callback); - } - - function handleNotificationRequests(error) { - if (error) { - logger.error(context, 'Error found when processing notification: %j', error); - next(error); - } else { - res.status(200).json({}); - } - } - - if (notificationHandler) { - logger.debug(context, 'Handling notification from [%s]', req.get('host')); - async.map(req.body.data, createNotificationHandler, handleNotificationRequests); - +function init(){ + if (config.checkNgsiLD()) { + contextServerHandler = require('./contextServer-NGSI-LD'); + } else if (config.checkNgsi2()) { + contextServerHandler = require('./contextServer-NGSI-v2'); } else { - var errorNotFound = new Error({ - message: 'Notification handler not found' - }); - - logger.error(context, 'Tried to handle a notification before notification handler was established.'); - - next(errorNotFound); + contextServerHandler = require('./contextServer-NGSI-v1'); } - } /** @@ -1365,7 +58,7 @@ function handleNotificationNgsi2(req, res, next) { * @param {Function} newHandler User handler for update requests */ function setUpdateHandler(newHandler) { - updateHandler = newHandler; + contextServerUtils.updateHandler = newHandler; } /** @@ -1379,7 +72,7 @@ function setUpdateHandler(newHandler) { * @param {Function} newHandler User handler for update requests */ function setCommandHandler(newHandler) { - commandHandler = newHandler; + contextServerUtils.commandHandler = newHandler; } /** @@ -1393,7 +86,7 @@ function setCommandHandler(newHandler) { * @param {Function} newHandler User handler for query requests */ function setQueryHandler(newHandler) { - queryHandler = newHandler; + contextServerUtils.queryHandler = newHandler; } /** @@ -1407,152 +100,7 @@ function setQueryHandler(newHandler) { * */ function setNotificationHandler(newHandler) { - notificationHandler = newHandler; -} - -/** - * Error handler for NGSIv1 context query requests. - * - * @param {Object} error Incoming error - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function queryErrorHandlingNgsi1(error, req, res, next) { - var code = 500; - - logger.debug(context, 'Query NGSIv1 error [%s] handling request: %s', error.name, error.message); - - if (error.code && String(error.code).match(/^[2345]\d\d$/)) { - code = error.code; - } - - res.status(code).json({ - errorCode: { - code: code, - reasonPhrase: error.name, - details: error.message.replace(/[<>\"\'=;\(\)]/g, '') - } - }); -} - -/** - * Error handler for NGSIv2 context query requests. - * - * @param {Object} error Incoming error - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function queryErrorHandlingNgsi2(error, req, res, next) { - var code = 500; - - logger.debug(context, 'Query NGSIv2 error [%s] handling request: %s', error.name, error.message); - - if (error.code && String(error.code).match(/^[2345]\d\d$/)) { - code = error.code; - } - - res.status(code).json({ - error: error.name, - description: error.message.replace(/[<>\"\'=;\(\)]/g, '') - }); -} - -/** - * Error handler for NGSI-LD context query requests. - * - * @param {Object} error Incoming error - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function queryErrorHandlingNgsiLD(error, req, res, next) { - var code = 500; - - logger.debug(context, 'Query NGSI-LD error [%s] handling request: %s', error.name, error.message); - - if (error.code && String(error.code).match(/^[2345]\d\d$/)) { - code = error.code; - } - - res.status(code).json({ - error: error.name, - description: error.message.replace(/[<>\"\'=;\(\)]/g, '') - }); -} - -/** - * Error handler for NGSIv1 update requests. - * - * @param {Object} error Incoming error - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function updateErrorHandlingNgsi1(error, req, res, next) { - var code = 500; - - logger.debug(context, 'Update NGSIv1 error [%s] handing request: %s', error.name, error.message); - - if (error.code && String(error.code).match(/^[2345]\d\d$/)) { - code = error.code; - } - - res.status(code).json( - { - contextResponses: [ - { - contextElement: req.body, - statusCode: { - code: code, - reasonPhrase: error.name, - details: error.message.replace(/[<>\"\'=;\(\)]/g, '') - } - } - ] - } - ); -} - -/** - * Error handler for NGSIv2 update requests. - * - * @param {Object} error Incoming error - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function updateErrorHandlingNgsi2(error, req, res, next) { - var code = 500; - - logger.debug(context, 'Update NGSIv2 error [%s] handing request: %s', error.name, error.message); - - if (error.code && String(error.code).match(/^[2345]\d\d$/)) { - code = error.code; - } - - res.status(code).json({ - error: error.name, - description: error.message.replace(/[<>\"\'=;\(\)]/g, '') - }); -} - -/** - * Error handler for NGSI-LD update requests. - * - * @param {Object} error Incoming error - * @param {Object} req Request that was handled in first place. - * @param {Object} res Response that will be sent. - */ -function updateErrorHandlingNgsiLD(error, req, res, next) { - var code = 500; - - logger.debug(context, 'Update NGSI-LD error [%s] handing request: %s', error.name, error.message); - - if (error.code && String(error.code).match(/^[2345]\d\d$/)) { - code = error.code; - } - - res.status(code).json({ - error: error.name, - description: error.message.replace(/[<>\"\'=;\(\)]/g, '') - }); + contextServerUtils.notificationHandler = newHandler; } /** @@ -1561,121 +109,26 @@ function updateErrorHandlingNgsiLD(error, req, res, next) { * @param {Object} router Express request router object. */ function loadContextRoutes(router) { - //TODO: remove '//' paths when the appropriate patch comes to Orion - var updateMiddlewaresNgsi1 = [ - middlewares.ensureType, - middlewares.validateJson(updateContextTemplateNgsi1), - handleUpdateNgsi1, - updateErrorHandlingNgsi1 - ], - updateMiddlewaresNgsi2 = [ - middlewares.ensureType, - middlewares.validateJson(updateContextTemplateNgsi2), - handleUpdateNgsi2, - updateErrorHandlingNgsi2 - ], - updateMiddlewaresNgsiLD = [ - middlewares.ensureType, - middlewares.validateJson(updateContextTemplateNgsiLD), - handleUpdateNgsiLD, - updateErrorHandlingNgsiLD - ], - queryMiddlewaresNgsi1 = [ - middlewares.ensureType, - middlewares.validateJson(queryContextTemplate), - handleQueryNgsi1, - queryErrorHandlingNgsi1 - ], - queryMiddlewaresNgsi2 = [ - handleQueryNgsi2, - queryErrorHandlingNgsi2 - ], - queryMiddlewaresNgsiLD = [ - handleQueryNgsiLD, - queryErrorHandlingNgsiLD - ], - updatePathsNgsi1 = [ - '/v1/updateContext', - '/NGSI10/updateContext', - '//updateContext' - ], - updatePathsNgsi2 = [ - '/v2/op/update', - '//op/update' - ], - updatePathsNgsiLD = [ - '/ngsi-ld/v1/entities/:id/attrs/:attr' - ], - queryPathsNgsi1 = [ - '/v1/queryContext', - '/NGSI10/queryContext', - '//queryContext' - ], - queryPathsNgsi2 = [ - '/v2/op/query', - '//op/query' - ], - queryPathsNgsiLD = [ - '/ngsi-ld/v1/entities/:id' - ]; - // In a more evolved implementation, more endpoints could be added to queryPathsNgsi2 - // according to http://fiware.github.io/specifications/ngsiv2/stable. - - var i; - if (config.checkNgsiLD()) { - logger.info(context, 'Loading NGSI-LD Context server routes'); - for (i = 0; i < updatePathsNgsiLD.length; i++) { - router.patch(updatePathsNgsiLD[i], updateMiddlewaresNgsiLD); - } - for (i = 0; i < queryPathsNgsiLD.length; i++) { - router.get(queryPathsNgsiLD[i], queryMiddlewaresNgsiLD); - } - router.post('/notify', [ - middlewares.ensureType, - middlewares.validateJson(notificationTemplateNgsiLD), - handleNotificationNgsiLD, - queryErrorHandlingNgsiLD - ]); - } else if (config.checkNgsi2()) { - logger.info(context, 'Loading NGSI-v2 Context server routes'); - for (i = 0; i < updatePathsNgsi2.length; i++) { - router.post(updatePathsNgsi2[i], updateMiddlewaresNgsi2); - } - for (i = 0; i < queryPathsNgsi2.length; i++) { - router.post(queryPathsNgsi2[i], queryMiddlewaresNgsi2); - } - router.post('/notify', [ - middlewares.ensureType, - middlewares.validateJson(notificationTemplateNgsi2), - handleNotificationNgsi2, - queryErrorHandlingNgsi2 - ]); - } else { - logger.info(context, 'Loading NGSI-v1 Context server routes'); - for (i = 0; i < updatePathsNgsi1.length; i++) { - router.post(updatePathsNgsi1[i], updateMiddlewaresNgsi1); - } - for (i = 0; i < queryPathsNgsi1.length; i++) { - router.post(queryPathsNgsi1[i], queryMiddlewaresNgsi1); - } - router.post('/notify', [ - middlewares.ensureType, - middlewares.validateJson(notificationTemplateNgsi1), - handleNotificationNgsi1, - queryErrorHandlingNgsi1 - ]); - } + contextServerHandler.loadContextRoutes(router); } +/** Adds a new Express middleware to the notifications stack + * + * @param {Object} newMiddleware The middleware to be added + */ function addNotificationMiddleware(newMiddleware) { - notificationMiddlewares.push(newMiddleware); + contextServerUtils.notificationMiddlewares.push(newMiddleware); } +/** Cleans up - removes all middlewares + * + * @param {Function} callback Optional callback to return when complete. + */ function clear(callback) { - notificationMiddlewares = []; - notificationHandler = null; - commandHandler = null; - updateHandler = null; + contextServerUtils.notificationMiddlewares = []; + contextServerUtils.notificationHandler = null; + contextServerUtils.commandHandler = null; + contextServerUtils.updateHandler = null; if (callback) { callback(); @@ -1689,3 +142,4 @@ exports.setCommandHandler = intoTrans(context, setCommandHandler); exports.setNotificationHandler = intoTrans(context, setNotificationHandler); exports.addNotificationMiddleware = intoTrans(context, addNotificationMiddleware); exports.setQueryHandler = intoTrans(context, setQueryHandler); +exports.init = init; diff --git a/lib/services/northBound/contextServerUtils.js b/lib/services/northBound/contextServerUtils.js new file mode 100644 index 000000000..d711cd7ce --- /dev/null +++ b/lib/services/northBound/contextServerUtils.js @@ -0,0 +1,209 @@ +/* + * Copyright 2020 Telefonica Investigación y Desarrollo, S.A.U + * + * This file is part of fiware-iotagent-lib + * + * fiware-iotagent-lib is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * fiware-iotagent-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with fiware-iotagent-lib. + * If not, see http://www.gnu.org/licenses/. + * + * 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 + * Modified by: Jason Fox - FIWARE Foundation + */ + + var async = require('async'), + apply = async.apply, + logger = require('logops'), + constants = require('../../constants'), + config = require('../../commonConfig'), + ngsi = require('../ngsi/ngsiService'), + commands = require('../commands/commandService'), + context = { + op: 'IoTAgentNGSI.ContextServerUtils' + }; + + +/** + * Returns the Current Tenant defined for the NGSI-LD Broker. Tenant is based on the request + * Headers - default to using the new NGSILD-Tenant header, fallback to the v2 fiware-service header + * and finally see if the config holds a defined tenant. Not all brokers are currently + * obliged to offer service headers - this is still being defined in the NGSI-LD specifications. + * + * @param {Object} req Request that was handled in first place. + * @return {String} The Tenant decribed in the request headers + */ +function getLDTenant(req){ + if (req.headers['NGSILD-Tenant']){ + return req.headers['NGSILD-Tenant']; + } else if (req.headers['fiware-service']){ + return req.headers['fiware-service']; + } else { + return config.getConfig().contextBroker.fallbackTenant; + } +} + +/** + * Returns the Current Path defined for the NGSI-LD Broker. Tenant is based on the request + * Headers - default to using the new NGSILD Path header, fallback to the v2 fiware-servicepath header + * see if the config holds a defined servicepath and finally try slashs. Not all brokers are currently + * obliged to offer service headers - this is still being defined in the NGSI-LD specifications. + */ +function getLDPath(req) { + if (req.headers['NGSILD-Path']){ + return req.headers['NGSILD-Path']; + } else if (req.headers['fiware-servicepath']){ + return req.headers['fiware-servicepath']; + } else { + return config.getConfig().contextBroker.fallbackPath; + } +} + + +/** + * Create the response for an UpdateContext operation, based on the results of the individual updates. The signature + * retains the results object for homogeinity with the createQuery* version. + * + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + * @param {Object} results Ignored for this function. TODO: to be removed in later versions. + * @return {{contextResponses: Array}} + */ +function createUpdateResponse(req, res, results) { + var result = { + contextResponses: [] + }; + + for (var i = 0; i < req.body.contextElements.length; i++) { + var contextResponse = { + contextElement: { + attributes: req.body.contextElements[i].attributes, + id: req.body.contextElements[i].id, + isPattern: false, + type: req.body.contextElements[i].type + }, + statusCode: { + code: 200, + reasonPhrase: 'OK' + } + }; + + for (var j = 0; j < contextResponse.contextElement.attributes.length; j++) { + contextResponse.contextElement.attributes[i].value = ''; + } + + result.contextResponses.push(contextResponse); + } + + logger.debug(context, 'Generated update response: %j', result); + + return result; +} + +/** + * Create the response for a queryContext operation based on the individual results gathered from the query handlers. + * The returned response is in the NGSI Response format. + * + * @param {Object} req Request that was handled in first place. + * @param {Object} res Response that will be sent. + * @param {Object} results Individual Context Element results from the query handlers. + * @return {{contextResponses: Array}} + */ +function createQueryResponse(req, res, results) { + var result = { + contextResponses: [] + }; + + for (var i = 0; i < results.length; i++) { + var contextResponse = { + contextElement: results[i], + statusCode: { + code: 200, + reasonPhrase: 'OK' + } + }; + + contextResponse.contextElement.isPattern = false; + + result.contextResponses.push(contextResponse); + } + + logger.debug(context, 'Generated query response: %j', result); + + return result; +} + +/** + * Retrieve the Device that corresponds to a Context Update, and execute the update side effects + * if there were any (e.g.: creation of attributes related to comands). + * + * @param {String} device Object that contains all the information about the device. + * @param {String} id Entity ID of the device to find. + * @param {String} type Type of the device to find. + * @param {String} service Service of the device. + * @param {String} subservice Subservice of the device. + * @param {Array} attributes List of attributes to update with their types and values. + */ +function executeUpdateSideEffects(device, id, type, service, subservice, attributes, callback) { + var sideEffects = []; + + if (device.commands) { + for (var i = 0; i < device.commands.length; i++) { + for (var j = 0; j < attributes.length; j++) { + if (device.commands[i].name === attributes[j].name) { + var newAttributes = [ + { + name: device.commands[i].name + '_status', + type: constants.COMMAND_STATUS, + value: 'PENDING' + } + ]; + + sideEffects.push( + apply(ngsi.update, device.name, device.resource, device.apikey, newAttributes, device) + ); + } + } + } + } + + async.series(sideEffects, callback); +} + +/** + * Extract all the commands from the attributes section and add them to the Commands Queue. + * + * @param {String} device Object that contains all the information about the device. + * @param {String} id Entity ID of the device to find. + * @param {String} type Type of the device to find. + * @param {String} service Service of the device. + * @param {String} subservice Subservice of the device. + * @param {Array} attributes List of attributes to update with their types and values. + */ +function pushCommandsToQueue(device, id, type, service, subservice, attributes, callback) { + async.map(attributes, apply(commands.add, service, subservice, device.id), callback); +} + +exports.notificationMiddlewares = []; +exports.updateHandler = null; +exports.commandHandler = null; +exports.queryHandler = null; +exports.notificationHandler = null; +exports.createUpdateResponse = createUpdateResponse; +exports.createQueryResponse = createQueryResponse; +exports.executeUpdateSideEffects = executeUpdateSideEffects; +exports.pushCommandsToQueue = pushCommandsToQueue; +exports.getLDTenant = getLDTenant; +exports.getLDPath = getLDPath; diff --git a/lib/services/northBound/northboundServer.js b/lib/services/northBound/northboundServer.js index 477c7b80b..2a80aea59 100644 --- a/lib/services/northBound/northboundServer.js +++ b/lib/services/northBound/northboundServer.js @@ -127,3 +127,4 @@ exports.addNotificationMiddleware = contextServer.addNotificationMiddleware; exports.clear = clear; exports.start = intoTrans(context, start); exports.stop = intoTrans(context, stop); +exports.init = contextServer.init; diff --git a/test/tools/utils.js b/test/tools/utils.js index 05bce316e..db6c74ac5 100644 --- a/test/tools/utils.js +++ b/test/tools/utils.js @@ -37,10 +37,10 @@ function readExampleFile(name, raw) { console.error(JSON.stringify(e)); } -// if(!raw){ -// console.error(name); -// console.error(JSON.stringify(JSON.parse(text), null, 4)); -// } + //if(!raw){ + // console.error(name); + // console.error(JSON.stringify(JSON.parse(text), null, 4)); + //} return raw ? text : JSON.parse(text); } diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent1.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent1.json index 3a2937d1e..7999397dd 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent1.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent1.json @@ -1,11 +1,5 @@ { - "@context": [ - { - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/default-context/", - "temperature": "ngsi-ld:temperature" - }, - "http://context.json-ld" - ], + "@context": "http://context.json-ld", "endpoint": "http://smartGondor.com", "information": [ { diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent2.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent2.json index 523cf12b5..b7709fe07 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent2.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent2.json @@ -1,18 +1,18 @@ { - "dataProvided": { - "attrs": [ - "moving" - ], - "entities": [ - { - "id": "urn:ngsi-ld:Motion:motion1", - "type": "Motion" - } - ] - }, - "provider": { - "http": { - "url": "http://smartGondor.com" + "type": "ContextSourceRegistration", + "information": [ + { + "entities": [ + { + "type": "Motion", + "id": "urn:ngsi-ld:Motion:motion1" } + ], + "properties": [ + "moving" + ] } -} + ], + "endpoint": "http://smartGondor.com", + "@context": "http://context.json-ld" +} \ No newline at end of file diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent4.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent4.json index 90f2356bd..4e7ce815c 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent4.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent4.json @@ -1,18 +1,18 @@ { - "dataProvided": { - "attrs": [ - "moving" - ], - "entities": [ - { - "id": "urn:ngsi-ld:RobotPre:TestRobotPre", - "type": "RobotPre" - } - ] - }, - "provider": { - "http": { - "url": "http://smartGondor.com" + "type": "ContextSourceRegistration", + "information": [ + { + "entities": [ + { + "type": "RobotPre", + "id": "urn:ngsi-ld:RobotPre:TestRobotPre" } + ], + "properties": [ + "moving" + ] } -} + ], + "endpoint": "http://smartGondor.com", + "@context": "http://context.json-ld" +} \ No newline at end of file diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgentCommands.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgentCommands.json index a80dae214..ea38afcc8 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgentCommands.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgentCommands.json @@ -1,11 +1,5 @@ { - "@context": [ - { - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/default-context/", - "position": "ngsi-ld:position" - }, - "http://context.json-ld" - ], + "@context": "http://context.json-ld", "endpoint": "http://smartGondor.com", "information": [ { diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice.json index ef0766346..3da2eeb1c 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice.json @@ -1,12 +1,5 @@ { - "@context": [ - { - "commandAttr": "ngsi-ld:commandAttr", - "luminance": "ngsi-ld:luminance", - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/default-context/" - }, - "http://context.json-ld" - ], + "@context": "http://context.json-ld", "endpoint": "http://smartGondor.com", "information": [ { diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice2.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice2.json index 90e48c617..560a277bf 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice2.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice2.json @@ -1,11 +1,5 @@ { - "@context": [ - { - "luminance": "ngsi-ld:luminance", - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/default-context/" - }, - "http://context.json-ld" - ], + "@context": "http://context.json-ld", "endpoint": "http://smartGondor.com", "information": [ { diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup.json index 1b4a5153b..a0498a348 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup.json @@ -1,14 +1,5 @@ { - "@context": [ - { - "commandAttr": "ngsi-ld:commandAttr", - "luminance": "ngsi-ld:luminance", - "luminescence": "ngsi-ld:luminescence", - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/default-context/", - "wheel1": "ngsi-ld:wheel1" - }, - "http://context.json-ld" - ], + "@context": "http://context.json-ld", "endpoint": "http://smartGondor.com", "information": [ { diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup2.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup2.json index 6d58df652..93bc42c11 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup2.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup2.json @@ -1,14 +1,5 @@ { - "@context": [ - { - "commandAttr": "ngsi-ld:commandAttr", - "luminance": "ngsi-ld:luminance", - "luminescence": "ngsi-ld:luminescence", - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/default-context/", - "wheel1": "ngsi-ld:wheel1" - }, - "http://context.json-ld" - ], + "@context": "http://context.json-ld", "endpoint": "http://smartGondor.com", "information": [ { diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup3.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup3.json index 3a2937d1e..7999397dd 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup3.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDeviceWithGroup3.json @@ -1,11 +1,5 @@ { - "@context": [ - { - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/default-context/", - "temperature": "ngsi-ld:temperature" - }, - "http://context.json-ld" - ], + "@context": "http://context.json-ld", "endpoint": "http://smartGondor.com", "information": [ { diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateCommands1.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateCommands1.json index fab1fd197..ef7e60fd5 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateCommands1.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateCommands1.json @@ -14,11 +14,5 @@ } ], "endpoint":"http://smartGondor.com", - "@context":[ - { - "ngsi-ld":"https://uri.etsi.org/ngsi-ld/default-context/", - "move":"ngsi-ld:move" - }, - "http://context.json-ld" - ] + "@context": "http://context.json-ld" } \ No newline at end of file diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent1.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent1.json index b196c8ccd..4c582b5d5 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent1.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent1.json @@ -1,11 +1,5 @@ { - "@context": [ - { - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/default-context/", - "pressure": "ngsi-ld:pressure" - }, - "http://context.json-ld" - ], + "@context": "http://context.json-ld", "endpoint": "http://smartGondor.com", "information": [ { diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent2.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent2.json index 25098f4a8..fd00528d0 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent2.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent2.json @@ -1,12 +1,5 @@ { - "@context": [ - { - "commandAttr": "ngsi-ld:commandAttr", - "luminance": "ngsi-ld:luminance", - "ngsi-ld": "https://uri.etsi.org/ngsi-ld/default-context/" - }, - "http://context.json-ld" - ], + "@context": "http://context.json-ld", "endpoint": "http://smartGondor.com", "information": [ { diff --git a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent3.json b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent3.json index 45783c24c..b32135616 100644 --- a/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent3.json +++ b/test/unit/ngsi-ld/examples/contextAvailabilityRequests/updateIoTAgent3.json @@ -1,4 +1,5 @@ { + "@context": "http://context.json-ld", "dataProvided": { "attrs": [ "luminance" diff --git a/test/unit/ngsi-ld/examples/contextRequests/createAutoprovisionDevice.json b/test/unit/ngsi-ld/examples/contextRequests/createAutoprovisionDevice.json index 392250474..3def79e9d 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createAutoprovisionDevice.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createAutoprovisionDevice.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "id": "urn:ngsi-ld:sensor:eii01201aaa", "type": "sensor" } diff --git a/test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json b/test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json index 272b702df..f32c1f5e7 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "id": "urn:ngsi-ld:TheLightType:TheFirstLight", "location": { "type": "GeoProperty", diff --git a/test/unit/ngsi-ld/examples/contextRequests/createDatetimeProvisionedDevice.json b/test/unit/ngsi-ld/examples/contextRequests/createDatetimeProvisionedDevice.json index 6d499f71a..911249cab 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createDatetimeProvisionedDevice.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createDatetimeProvisionedDevice.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "id": "urn:ngsi-ld:MicroLights:FirstMicroLight", "timestamp": { "type": "Property", diff --git a/test/unit/ngsi-ld/examples/contextRequests/createGeopointProvisionedDevice.json b/test/unit/ngsi-ld/examples/contextRequests/createGeopointProvisionedDevice.json index 065005d6e..f06bc4831 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createGeopointProvisionedDevice.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createGeopointProvisionedDevice.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "id": "urn:ngsi-ld:MicroLights:FirstMicroLight", "location": { "type": "GeoProperty", diff --git a/test/unit/ngsi-ld/examples/contextRequests/createMinimumProvisionedDevice.json b/test/unit/ngsi-ld/examples/contextRequests/createMinimumProvisionedDevice.json index d523da266..376c3f0c7 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createMinimumProvisionedDevice.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createMinimumProvisionedDevice.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "attr_name": { "type": "Property", "value": " " diff --git a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDevice.json b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDevice.json index 6a5fcf0f2..8f6dab919 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDevice.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDevice.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "attr_name": { "type": "Property", "value": " " diff --git a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceMultientity.json b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceMultientity.json index 6a5fcf0f2..8f6dab919 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceMultientity.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceMultientity.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "attr_name": { "type": "Property", "value": " " diff --git a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic.json b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic.json index a795b5cfa..dc380d561 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "attr_name": { "type": "Property", "value": " " diff --git a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json index 7450b4618..9ed0cf6ea 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "attr_name": { "type": "Property", "value": " " diff --git a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic3.json b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic3.json index 7bbe4c05e..8e73199c8 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic3.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic3.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "dimming": { "type": "Property", "value": { diff --git a/test/unit/ngsi-ld/examples/contextRequests/createTimeInstantMinimumDevice.json b/test/unit/ngsi-ld/examples/contextRequests/createTimeInstantMinimumDevice.json index d523da266..376c3f0c7 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createTimeInstantMinimumDevice.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createTimeInstantMinimumDevice.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "attr_name": { "type": "Property", "value": " " diff --git a/test/unit/ngsi-ld/examples/contextRequests/createTimeinstantDevice.json b/test/unit/ngsi-ld/examples/contextRequests/createTimeinstantDevice.json index 2652fc93c..62df2066a 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/createTimeinstantDevice.json +++ b/test/unit/ngsi-ld/examples/contextRequests/createTimeinstantDevice.json @@ -1,5 +1,6 @@ [ { + "@context": "http://context.json-ld", "id": "urn:ngsi-ld:sensor:eii01201ttt", "type": "sensor" } diff --git a/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandError.json b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandError.json index 7dc987272..5504bd98e 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandError.json +++ b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandError.json @@ -1,10 +1,21 @@ -{ +[ + { + "@context": "http://context.json-ld", + "position_status": { + "type": "Property", + "value": { + "@type": "commandStatus", + "@value": "ERROR" + } + }, "position_info": { - "type": "commandResult", - "value": "Stalled" + "type": "Property", + "value": { + "@type": "commandResult", + "@value": "Stalled" + } }, - "position_status": { - "type": "commandStatus", - "value": "ERROR" - } -} + "id": "urn:ngsi-ld:Robot:r2d2", + "type": "Robot" + } +] \ No newline at end of file diff --git a/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandExpired.json b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandExpired.json index 3af9b884c..7dab289fb 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandExpired.json +++ b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandExpired.json @@ -1,10 +1,21 @@ -{ - "position_info": { - "type": "commandResult", - "value": "EXPIRED" - }, - "position_status": { - "type": "commandStatus", - "value": "ERROR" - } -} +[ + { + "@context":"http://context.json-ld", + "position_status": { + "type":"Property", + "value": { + "@type":"commandStatus", + "@value":"ERROR" + } + }, + "position_info": { + "type":"Property", + "value": { + "@type":"commandResult", + "@value":"EXPIRED" + } + }, + "id":"urn:ngsi-ld:Robot:r2d2", + "type":"Robot" + } +] diff --git a/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandFinish.json b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandFinish.json index 01c7b8d1a..66bef5c77 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandFinish.json +++ b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandFinish.json @@ -1,10 +1,21 @@ -{ - "position_info": { - "type": "commandResult", - "value": "[72, 368, 1]" - }, - "position_status": { - "type": "commandStatus", - "value": "FINISHED" - } -} +[ + { + "@context":"http://context.json-ld", + "position_status": { + "type":"Property", + "value": { + "@type":"commandStatus", + "@value":"FINISHED" + } + }, + "position_info": { + "type":"Property", + "value": { + "@type":"commandResult", + "@value":"[72, 368, 1]" + } + }, + "id":"urn:ngsi-ld:Robot:r2d2", + "type":"Robot" + } +] diff --git a/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus.json b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus.json index 9f0c4c859..a98d26784 100644 --- a/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus.json +++ b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus.json @@ -1,6 +1,14 @@ -{ - "position_status": { - "type": "commandStatus", - "value": "PENDING" - } -} +[ + { + "@context":"http://context.json-ld", + "position_status": { + "type":"Property", + "value": { + "@type":"commandStatus", + "@value":"PENDING" + } + }, + "id":"urn:ngsi-ld:Robot:r2d2", + "type":"Robot" + } +] diff --git a/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus1.json b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus1.json new file mode 100644 index 000000000..e74217af2 --- /dev/null +++ b/test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus1.json @@ -0,0 +1,21 @@ +[ + { + "@context": "http://context.json-ld", + "id": "urn:ngsi-ld:Robot:r2d2", + "type": "Robot", + "position_status": { + "type": "Property", + "value": { + "@type": "commandStatus", + "@value": "UNKNOWN" + } + }, + "position_info": { + "type": "Property", + "value": { + "@type": "commandResult", + "@value": " " + } + } + } +] \ No newline at end of file diff --git a/test/unit/ngsi-ld/expressions/expressionBasedTransformations-test.js b/test/unit/ngsi-ld/expressions/expressionBasedTransformations-test.js index f26e3a7df..7d48645bf 100644 --- a/test/unit/ngsi-ld/expressions/expressionBasedTransformations-test.js +++ b/test/unit/ngsi-ld/expressions/expressionBasedTransformations-test.js @@ -258,7 +258,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin2.json' ) ) - .reply(200); + .reply(204); }); it('should calculate them and add them to the payload', function(done) { @@ -297,7 +297,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin4.json' ) ) - .reply(200); + .reply(204); }); it('should calculate it and add it to the payload', function(done) { @@ -330,7 +330,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin11.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -363,7 +363,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin1.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -396,7 +396,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin18.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -430,7 +430,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin3.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -464,7 +464,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin8.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -498,7 +498,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin19.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -532,7 +532,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin5.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -566,7 +566,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin16.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -600,7 +600,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin17.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -634,7 +634,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin9.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -668,7 +668,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin10.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -701,7 +701,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin15.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -734,7 +734,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin6.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -768,7 +768,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin7.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -800,7 +800,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin12.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -832,7 +832,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin13.json' ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { @@ -872,7 +872,7 @@ describe('NGSI-LD - Expression-based transformations plugin', function() { ) ) - .reply(200); + .reply(204); }); it('should apply the expression before sending the values', function(done) { diff --git a/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js b/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js index a2335726f..25e89562d 100644 --- a/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +++ b/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js @@ -129,7 +129,7 @@ describe('NGSI-LD - Secured access to the Context Broker with OAuth2 provider', '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContext1.json') ) - .reply(200, {}); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -201,7 +201,7 @@ describe('NGSI-LD - Secured access to the Context Broker with OAuth2 provider', '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContext1.json') ) - .reply(200, {}); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -231,7 +231,7 @@ describe('NGSI-LD - Secured access to the Context Broker with OAuth2 provider', contextBrokerMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') .matchHeader('Authorization', 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ3cHdWclJ3') - .get('/ngsi-ld/v1/entities/light1/attrs?attrs=state,dimming&type=Light') + .get('/ngsi-ld/v1/entities/urn:ngsi-ld:Light:light1?attrs=state,dimming') .reply( 200, utils.readExampleFile('./test/unit/ngsi-ld/examples/contextResponses/queryContext1Success.json') @@ -240,7 +240,7 @@ describe('NGSI-LD - Secured access to the Context Broker with OAuth2 provider', iotAgentLib.activate(iotAgentConfig, done); }); - xit('should send the Auth Token along with the information query', function(done) { + it('should send the Auth Token along with the information query', function(done) { iotAgentLib.query('light1', 'Light', '', attributes, function(error) { should.not.exist(error); contextBrokerMock.done(); @@ -294,7 +294,7 @@ describe('NGSI-LD - Secured access to the Context Broker with OAuth2 provider', 'contextRequests/createProvisionedDeviceWithGroupAndStatic3.json' ) ) - .reply(200, {}); + .reply(204); contextBrokerMock .post( @@ -394,7 +394,7 @@ describe('NGSI-LD - Secured access to the Context Broker with OAuth2 provider (F '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContext1.json') ) - .reply(200, {}); + .reply(204); iotAgentConfig.authentication.tokenPath = '/oauth2/token'; iotAgentLib.activate(iotAgentConfig, done); @@ -436,7 +436,7 @@ describe('NGSI-LD - Secured access to the Context Broker with OAuth2 provider (F contextBrokerMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') .matchHeader('Authorization', 'Bearer c1b752e377680acd1349a3ed59db855a1db07605') - .get('/ngsi-ld/v1/entities/light1/attrs?attrs=state,dimming&type=Light') + .get('/ngsi-ld/v1/entities/urn:ngsi-ld:Light:light1?attrs=state,dimming') .reply( 200, utils.readExampleFile('./test/unit/ngsi-ld/examples/contextResponses/queryContext1Success.json') @@ -445,7 +445,7 @@ describe('NGSI-LD - Secured access to the Context Broker with OAuth2 provider (F iotAgentLib.activate(iotAgentConfig, done); }); - xit('should send the Auth Token along with the information query', function(done) { + it('should send the Auth Token along with the information query', function(done) { iotAgentLib.query('light1', 'Light', '', attributes, function(error) { should.not.exist(error); contextBrokerMock.done(); @@ -619,7 +619,7 @@ describe( './test/unit/ngsi-ld/examples/contextRequests/updateContext3WithStatic.json' ) ) - .reply(200, {}); + .reply(204); contextBrokerMock2 = nock('http://unexistentHost:1026') .matchHeader('fiware-service', 'TestService') @@ -630,7 +630,7 @@ describe( './test/unit/ngsi-ld/examples/contextRequests/updateContext3WithStatic.json' ) ) - .reply(200, {}); + .reply(204); iotAgentConfig.authentication.tokenPath = '/oauth2/token'; iotAgentLib.activate(iotAgentConfig, function() { @@ -748,7 +748,7 @@ describe( 'contextRequests/createProvisionedDeviceWithGroupAndStatic2.json' ) ) - .reply(200, {}); + .reply(204); contextBrokerMock3 = nock('http://unexistentHost:1026') .matchHeader('fiware-service', 'TestService') @@ -757,7 +757,7 @@ describe( '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContext5.json') ) - .reply(200, {}); + .reply(204); iotAgentConfig.authentication.tokenPath = '/oauth2/token'; iotAgentLib.activate(iotAgentConfig, function() { @@ -837,7 +837,7 @@ describe( './test/unit/ngsi-ld/examples/contextRequests/updateContext3WithStatic.json' ) ) - .reply(200, {}); + .reply(204); iotAgentConfig.authentication.tokenPath = '/oauth2/token'; iotAgentLib.activate(iotAgentConfig, function() { diff --git a/test/unit/ngsi-ld/general/deviceService-test.js b/test/unit/ngsi-ld/general/deviceService-test.js index de90b46f8..13e1260bb 100644 --- a/test/unit/ngsi-ld/general/deviceService-test.js +++ b/test/unit/ngsi-ld/general/deviceService-test.js @@ -192,7 +192,7 @@ describe('NGSI-LD - Device Service: utils', function() { contextBrokerMock = nock('http://unexistenthost:1026') .matchHeader('fiware-service', 'TestService') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); async.series([request.bind(request, groupCreation), request.bind(request, deviceCreation)], function( error, @@ -221,7 +221,7 @@ describe('NGSI-LD - Device Service: utils', function() { contextBrokerMock = nock('http://unexistenthost:1026') .matchHeader('fiware-service', 'TestService') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); async.series([request.bind(request, groupCreation)], function(error, results) { done(); diff --git a/test/unit/ngsi-ld/general/https-support-test.js b/test/unit/ngsi-ld/general/https-support-test.js index e191f97c8..b21cea7c3 100644 --- a/test/unit/ngsi-ld/general/https-support-test.js +++ b/test/unit/ngsi-ld/general/https-support-test.js @@ -37,7 +37,8 @@ const iotAgentConfig = { logLevel: 'FATAL', contextBroker: { url: 'https://192.168.1.1:1026', - ngsiVersion: 'ld' + ngsiVersion: 'ld', + jsonLdContext: 'http://context.json-ld' }, server: { port: 4041 @@ -177,10 +178,11 @@ describe('NGSI-LD - HTTPS support tests', function() { .post( '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile( - './test/unit/ngsi-ld/examples/' + 'contextRequests/createMinimumProvisionedDevice.json' + './test/unit/ngsi-ld/examples/' + + 'contextRequests/createMinimumProvisionedDevice.json' ) ) - .reply(200); + .reply(204); contextBrokerMock = nock('https://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') @@ -232,7 +234,7 @@ describe('NGSI-LD - HTTPS support tests', function() { contextBrokerMock = nock('https://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); contextBrokerMock = nock('https://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') diff --git a/test/unit/ngsi-ld/lazyAndCommands/active-devices-attribute-update-test.js b/test/unit/ngsi-ld/lazyAndCommands/active-devices-attribute-update-test.js index 3171240be..c215bc027 100644 --- a/test/unit/ngsi-ld/lazyAndCommands/active-devices-attribute-update-test.js +++ b/test/unit/ngsi-ld/lazyAndCommands/active-devices-attribute-update-test.js @@ -77,7 +77,7 @@ describe('NGSI-LD - Update attribute functionalities', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -95,26 +95,18 @@ describe('NGSI-LD - Update attribute functionalities', function() { }); }); - xdescribe('When a attribute update arrives to the IoT Agent as Context Provider', function() { + describe('When a attribute update arrives to the IoT Agent as Context Provider', function() { const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/update', - method: 'POST', - json: { - actionType: 'update', - entities: [ - { - id: 'Light:somelight', - type: 'Light', - pressure: { - type: 'Hgmm', - value: 200 - } - } - ] + url: 'http://localhost:' + iotAgentConfig.server.port + + '/ngsi-ld/v1/entities/urn:ngsi-ld:Light:somelight/attrs/pressure', + method: 'PATCH', + json: { + type: 'Hgmm', + value: 200 }, headers: { 'fiware-service': 'smartGondor', - 'fiware-servicepath': 'gardens' + 'content-type': 'application/ld+json' } }; diff --git a/test/unit/ngsi-ld/lazyAndCommands/command-test.js b/test/unit/ngsi-ld/lazyAndCommands/command-test.js index fbaebf071..54a0b4d07 100644 --- a/test/unit/ngsi-ld/lazyAndCommands/command-test.js +++ b/test/unit/ngsi-ld/lazyAndCommands/command-test.js @@ -107,7 +107,7 @@ const device3 = { service: 'smartGondor' }; -xdescribe('NGSI-LD - Command functionalities', function() { +describe('NGSI-LD - Command functionalities', function() { beforeEach(function(done) { const time = new Date(1438760101468); // 2015-08-05T07:35:01.468+00:00 timekeeper.freeze(time); @@ -126,7 +126,7 @@ xdescribe('NGSI-LD - Command functionalities', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -168,12 +168,12 @@ xdescribe('NGSI-LD - Command functionalities', function() { }, headers: { 'fiware-service': 'smartGondor', - 'content-type': 'application/json' + 'content-type': 'application/ld+json' } }; beforeEach(function(done) { - logger.setLevel('FATAL'); + logger.setLevel('ERROR'); iotAgentLib.register(device3, function(error) { done(); }); @@ -181,12 +181,12 @@ xdescribe('NGSI-LD - Command functionalities', function() { it('should call the client handler', function(done) { let handlerCalled = false; - + iotAgentLib.setCommandHandler(function(id, type, service, subservice, attributes, callback) { - id.should.equal(device3.type + ':' + device3.id); + id.should.equal('urn:ngsi-ld:' + device3.type + ':' + device3.id); type.should.equal(device3.type); attributes[0].name.should.equal('position'); - attributes[0].value.should.equal('[28, -104, 23]'); + JSON.stringify(attributes[0].value).should.equal('[28,-104,23]'); handlerCalled = true; callback(null, { id, @@ -228,13 +228,9 @@ xdescribe('NGSI-LD - Command functionalities', function() { }); }); it('should create the attribute with the "_status" prefix in the Context Broker', function(done) { - const service = false; - + let serviceReceived = false; iotAgentLib.setCommandHandler(function(id, type, service, subservice, attributes, callback) { - console.error(service); - console.error(subservice); - - service === 'smartGondor'; + serviceReceived = (service === 'smartGondor'); callback(null, { id, type, @@ -249,7 +245,7 @@ xdescribe('NGSI-LD - Command functionalities', function() { }); request(options, function(error, response, body) { - service.should.equal(true); + serviceReceived.should.equal(true); done(); }); }); @@ -259,7 +255,7 @@ xdescribe('NGSI-LD - Command functionalities', function() { statusAttributeMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') .post( - '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs?type=Robot', + '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile( './test/unit/ngsi-ld/examples/contextRequests/updateContextCommandFinish.json' ) @@ -284,7 +280,7 @@ xdescribe('NGSI-LD - Command functionalities', function() { statusAttributeMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') .post( - '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs?type=Robot', + '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextCommandError.json') ) .reply(204); diff --git a/test/unit/ngsi-ld/lazyAndCommands/lazy-devices-test.js b/test/unit/ngsi-ld/lazyAndCommands/lazy-devices-test.js index 64e0e56c0..ac300d1a7 100644 --- a/test/unit/ngsi-ld/lazyAndCommands/lazy-devices-test.js +++ b/test/unit/ngsi-ld/lazyAndCommands/lazy-devices-test.js @@ -164,22 +164,14 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { }); }); - xdescribe('When the IoT Agent receives an update on the device data in JSON format', function() { + describe('When the IoT Agent receives an update on the device data in JSON format', function() { const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/update', - method: 'POST', + url: 'http://localhost:' + iotAgentConfig.server.port + + '/ngsi-ld/v1/entities/urn:ngsi-ld:Light:light1/attrs/dimming', + method: 'PATCH', json: { - actionType: 'update', - entities: [ - { - id: 'Light:light1', - type: 'Light', - dimming: { - type: 'Percentage', - value: 12 - } - } - ] + type: 'Percentage', + value: 12 }, headers: { 'fiware-service': 'smartGondor', @@ -203,14 +195,14 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); async.series([apply(iotAgentLib.activate, iotAgentConfig), apply(iotAgentLib.register, device1)], done); }); it('should call the device handler with the received data', function(done) { iotAgentLib.setDataUpdateHandler(function(id, type, service, subservice, attributes, callback) { - id.should.equal(device1.type + ':' + device1.id); + id.should.equal( 'urn:ngsi-ld:' + device1.type + ':' + device1.id); type.should.equal(device1.type); attributes[0].value.should.equal(12); callback(null); @@ -228,22 +220,15 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { it('should call the device handler for each of the contexts'); }); - xdescribe('When a context query arrives to the IoT Agent', function() { + describe('When a context query arrives to the IoT Agent', function() { const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/query', - method: 'POST', + url: 'http://localhost:' + iotAgentConfig.server.port + + '/ngsi-ld/v1/entities/urn:ngsi-ld:Light:light1?attrs=dimming', + method: 'GET', json: true, headers: { 'fiware-service': 'smartGondor', 'fiware-servicepath': 'gardens' - }, - body: { - entities: [ - { - id: 'Light:light1' - } - ], - attrs: ['dimming'] } }; const sensorData = [ @@ -273,7 +258,7 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); async.series([apply(iotAgentLib.activate, iotAgentConfig), apply(iotAgentLib.register, device1)], done); }); @@ -283,8 +268,13 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { './test/unit/ngsi-ld/examples/contextProviderResponses/queryInformationResponse.json' ); + + iotAgentLib.setDataUpdateHandler(function(id, type, service, subservice, attributes, callback){ + callback(null); + }); + iotAgentLib.setDataQueryHandler(function(id, type, service, subservice, attributes, callback) { - id.should.equal(device1.type + ':' + device1.id); + id.should.equal('urn:ngsi-ld:' + device1.type + ':' + device1.id); type.should.equal(device1.type); attributes[0].should.equal('dimming'); callback(null, sensorData[0]); @@ -298,22 +288,15 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { }); }); - xdescribe('When a context query arrives to the IoT Agent and no handler is set', function() { + describe('When a context query arrives to the IoT Agent and no handler is set', function() { const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/query', - method: 'POST', + url: 'http://localhost:' + iotAgentConfig.server.port + + '/ngsi-ld/v1/entities/urn:ngsi-ld:Light:light1?attrs=dimming', + method: 'GET', json: true, headers: { 'fiware-service': 'smartGondor', 'fiware-servicepath': 'gardens' - }, - body: { - entities: [ - { - id: 'Light:light1' - } - ], - attrs: ['dimming'] } }; @@ -333,7 +316,7 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); async.series([apply(iotAgentLib.activate, iotAgentConfig), apply(iotAgentLib.register, device1)], function( error @@ -359,21 +342,15 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { }); }); - xdescribe('When a query arrives to the IoT Agent without any attributes', function() { + describe('When a query arrives to the IoT Agent without any attributes', function() { const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/query', - method: 'POST', + url: 'http://localhost:' + iotAgentConfig.server.port + + '/ngsi-ld/v1/entities/urn:ngsi-ld:Light:light1', + method: 'GET', json: true, headers: { 'fiware-service': 'smartGondor', 'fiware-servicepath': 'gardens' - }, - body: { - entities: [ - { - id: 'Light:light1' - } - ] } }; const sensorData = [ @@ -403,7 +380,7 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); async.series([apply(iotAgentLib.activate, iotAgentConfig), apply(iotAgentLib.register, device1)], done); }); @@ -429,22 +406,15 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { }); }); - xdescribe('When a context query arrives to the IoT Agent for a type with static attributes', function() { + describe('When a context query arrives to the IoT Agent for a type with static attributes', function() { const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/query', - method: 'POST', + url: 'http://localhost:' + iotAgentConfig.server.port + + '/ngsi-ld/v1/entities/urn:ngsi-ld:Motion:motion1?attrs=moving,location', + method: 'GET', json: true, headers: { 'fiware-service': 'smartGondor', 'fiware-servicepath': 'gardens' - }, - body: { - entities: [ - { - id: 'Motion:motion1' - } - ], - attrs: ['moving', 'location'] } }; const sensorData = [ @@ -474,7 +444,7 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); async.series([apply(iotAgentLib.activate, iotAgentConfig), apply(iotAgentLib.register, device2)], done); }); @@ -485,7 +455,7 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { ); iotAgentLib.setDataQueryHandler(function(id, type, service, subservice, attributes, callback) { - id.should.equal('Motion:motion1'); + id.should.equal('urn:ngsi-ld:Motion:motion1'); type.should.equal('Motion'); attributes[0].should.equal('moving'); attributes[1].should.equal('location'); @@ -500,246 +470,16 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { }); }); - xdescribe( - 'When the IoT Agent receives an update on the device data in JSON format for a type with' + - 'internalAttributes', - function() { - const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/update', - method: 'POST', - json: { - actionType: 'update', - entities: [ - { - id: 'RobotPre:TestRobotPre', - type: 'RobotPre', - moving: { - type: 'Boolean', - value: true - } - } - ] - }, - headers: { - 'fiware-service': 'smartGondor', - 'fiware-servicepath': 'gardens' - } - }; - - beforeEach(function(done) { - nock.cleanAll(); - - contextBrokerMock = nock('http://192.168.1.1:1026') - .matchHeader('fiware-service', 'smartGondor') - .post( - '/ngsi-ld/v1/csourceRegistrations/', - utils.readExampleFile( - './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent4.json' - ) - ) - .reply(201, null, { Location: '/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d' }); - - contextBrokerMock - .matchHeader('fiware-service', 'smartGondor') - .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); - - async.series([apply(iotAgentLib.activate, iotAgentConfig), apply(iotAgentLib.register, device3)], done); - }); - - it('should call the device handler with the received data', function(done) { - iotAgentLib.setDataUpdateHandler(function(id, type, service, subservice, attributes, callback) { - id.should.equal(device3.type + ':' + device3.id); - type.should.equal(device3.type); - attributes[0].value.should.equal(true); - callback(null); - }); - - request(options, function(error, response, body) { - should.not.exist(error); - response.statusCode.should.equal(204); - done(); - }); - }); - } - ); - - xdescribe('When a context query arrives to the IoT Agent and id and type query params are not present', function() { + + describe('When a query arrives to the IoT Agent with id, type and attributes', function() { const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/query', - method: 'POST', + url: 'http://localhost:' + iotAgentConfig.server.port + + '/ngsi-ld/v1/entities/urn:ngsi-ld:Light:light1?attrs=temperature', + method: 'GET', json: true, headers: { 'fiware-service': 'smartGondor', 'fiware-servicepath': 'gardens' - }, - body: { - entities: [ - { - idPattern: '.*' - } - ] - } - }; - - beforeEach(function(done) { - nock.cleanAll(); - - contextBrokerMock = nock('http://192.168.1.1:1026') - .matchHeader('fiware-service', 'smartGondor') - .post( - '/ngsi-ld/v1/csourceRegistrations/', - utils.readExampleFile( - './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent1.json' - ) - ) - .reply(201, null, { Location: '/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d' }); - - contextBrokerMock - .matchHeader('fiware-service', 'smartGondor') - .post( - '/ngsi-ld/v1/csourceRegistrations/', - utils.readExampleFile( - './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent2.json' - ) - ) - .reply(201, null, { Location: '/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d' }); - - contextBrokerMock - .matchHeader('fiware-service', 'smartGondor') - .post( - '/ngsi-ld/v1/csourceRegistrations/', - utils.readExampleFile( - './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent4.json' - ) - ) - .reply(201, null, { Location: '/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d' }); - - contextBrokerMock - .matchHeader('fiware-service', 'smartGondor') - .post('/ngsi-ld/v1/entityOperations/upsert/') - .times(3) - .reply(204); - - async.series( - [ - apply(iotAgentLib.activate, iotAgentConfig), - apply(iotAgentLib.register, device1), - apply(iotAgentLib.register, device2), - apply(iotAgentLib.register, device3) - ], - done - ); - }); - - it('should return error as idPattern is not supported', function(done) { - request(options, function(error, response, body) { - should.not.exist(error); - response.statusCode.should.equal(400); - body.error.should.equal('BadRequest'); - body.description.should.equal('idPattern usage in query'); - done(); - }); - }); - }); - - xdescribe('When a context query arrives to the IoT Agent and id query param is not present', function() { - const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/query', - method: 'POST', - json: true, - headers: { - 'fiware-service': 'smartGondor', - 'fiware-servicepath': 'gardens' - }, - body: { - entities: [ - { - idPattern: '.*', - type: 'Light' - } - ] - } - }; - - beforeEach(function(done) { - nock.cleanAll(); - - contextBrokerMock = nock('http://192.168.1.1:1026') - .matchHeader('fiware-service', 'smartGondor') - .post( - '/ngsi-ld/v1/csourceRegistrations/', - utils.readExampleFile( - './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent1.json' - ) - ) - .reply(201, null, { Location: '/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d' }); - - contextBrokerMock - .matchHeader('fiware-service', 'smartGondor') - .post( - '/ngsi-ld/v1/csourceRegistrations/', - utils.readExampleFile( - './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent2.json' - ) - ) - .reply(201, null, { Location: '/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d' }); - - contextBrokerMock - .matchHeader('fiware-service', 'smartGondor') - .post( - '/ngsi-ld/v1/csourceRegistrations/', - utils.readExampleFile( - './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent4.json' - ) - ) - .reply(201, null, { Location: '/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d' }); - - contextBrokerMock - .matchHeader('fiware-service', 'smartGondor') - .post('/ngsi-ld/v1/entityOperations/upsert/') - .times(3) - .reply(204); - - async.series( - [ - apply(iotAgentLib.activate, iotAgentConfig), - apply(iotAgentLib.register, device1), - apply(iotAgentLib.register, device2), - apply(iotAgentLib.register, device3) - ], - done - ); - }); - - it('should return error as idPattern is not supported', function(done) { - request(options, function(error, response, body) { - should.not.exist(error); - response.statusCode.should.equal(400); - body.error.should.equal('BadRequest'); - body.description.should.equal('idPattern usage in query'); - done(); - }); - }); - }); - - xdescribe('When a query arrives to the IoT Agent with id, type and attributes', function() { - const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/query', - method: 'POST', - json: true, - headers: { - 'fiware-service': 'smartGondor', - 'fiware-servicepath': 'gardens' - }, - body: { - entities: [ - { - id: 'Light:light1', - type: 'Light' - } - ], - attrs: ['temperature'] } }; const sensorData = [ @@ -769,7 +509,7 @@ describe('NGSI-LD - IoT Agent Lazy Devices', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); async.series([apply(iotAgentLib.activate, iotAgentConfig), apply(iotAgentLib.register, device1)], done); }); diff --git a/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js b/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js index 84d0d2f60..65c6a0b42 100644 --- a/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js +++ b/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js @@ -131,10 +131,6 @@ describe('NGSI-LD - Polling commands', function() { .post('/ngsi-ld/v1/csourceRegistrations/') .reply(201, null, { Location: '/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d' }); - contextBrokerMock - .matchHeader('fiware-service', 'smartGondor') - .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); iotAgentLib.activate(iotAgentConfig, done); }); @@ -153,22 +149,14 @@ describe('NGSI-LD - Polling commands', function() { }); }); - xdescribe('When a command update arrives to the IoT Agent for a device with polling', function() { + describe('When a command update arrives to the IoT Agent for a device with polling', function() { const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/update', - method: 'POST', + url: 'http://localhost:' + iotAgentConfig.server.port + + '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs/position', + method: 'PATCH', json: { - actionType: 'update', - entities: [ - { - id: 'Robot:r2d2', - type: 'Robot', - position: { - type: 'Array', - value: '[28, -104, 23]' - } - } - ] + type: 'Property', + value: [28, -104, 23] }, headers: { 'fiware-service': 'smartGondor', @@ -179,11 +167,10 @@ describe('NGSI-LD - Polling commands', function() { beforeEach(function(done) { statusAttributeMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') - .post( - '/ngsi-ld/v1/entities/Robot:r2d2/attrs?type=Robot', + '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile( - './test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus.json' + './test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus1.json' ) ) .reply(204); @@ -228,7 +215,7 @@ describe('NGSI-LD - Polling commands', function() { done(); }); }); - it('should store the commands in the queue', function(done) { + xit('should store the commands in the queue', function(done) { iotAgentLib.setCommandHandler(function(id, type, service, subservice, attributes, callback) { callback(null); }); @@ -246,25 +233,18 @@ describe('NGSI-LD - Polling commands', function() { }); }); - xdescribe('When a command arrives with multiple values in the value field', function() { + describe('When a command arrives with multiple values in the value field', function() { const options = { - url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/update', - method: 'POST', + url: 'http://localhost:' + iotAgentConfig.server.port + + '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs/position', + method: 'PATCH', json: { - actionType: 'update', - entities: [ - { - id: 'Robot:r2d2', - type: 'Robot', - position: { - type: 'Array', - value: { - attr1: 12, - attr2: 24 - } - } + '@type': 'Array', + '@value': { + attr1: 12, + attr2: 24 } - ] + }, headers: { 'fiware-service': 'smartGondor', @@ -277,9 +257,9 @@ describe('NGSI-LD - Polling commands', function() { .matchHeader('fiware-service', 'smartGondor') .post( - '/ngsi-ld/v1/entities/Robot:r2d2/attrs?type=Robot', + '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile( - './test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus.json' + './test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus1.json' ) ) .reply(204); @@ -304,7 +284,7 @@ describe('NGSI-LD - Polling commands', function() { }); }); - xdescribe('When a polling command expires', function() { + describe('When a polling command expires', function() { const options = { url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/update', method: 'POST', @@ -332,7 +312,7 @@ describe('NGSI-LD - Polling commands', function() { .matchHeader('fiware-service', 'smartGondor') .post( - '/ngsi-ld/v1/entities/Robot:r2d2/attrs?type=Robot', + '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile( './test/unit/ngsi-ld/examples/contextRequests/updateContextCommandStatus.json' ) @@ -343,9 +323,9 @@ describe('NGSI-LD - Polling commands', function() { .matchHeader('fiware-service', 'smartGondor') .post( - '/ngsi-ld/v1/entities/Robot:r2d2/attrs?type=Robot', + '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile( - './test/unit//ngsiv2/examples/contextRequests/updateContextCommandExpired.json' + './test/unit/ngsi-ld/examples/contextRequests/updateContextCommandExpired.json' ) ) .reply(204); @@ -371,7 +351,7 @@ describe('NGSI-LD - Polling commands', function() { }); }); - it('should mark it as ERROR in the Context Broker', function(done) { + xit('should mark it as ERROR in the Context Broker', function(done) { iotAgentLib.setCommandHandler(function(id, type, service, subservice, attributes, callback) { callback(null); }); diff --git a/test/unit/ngsi-ld/ngsiService/active-devices-test.js b/test/unit/ngsi-ld/ngsiService/active-devices-test.js index a29cf65b2..d2f306166 100644 --- a/test/unit/ngsi-ld/ngsiService/active-devices-test.js +++ b/test/unit/ngsi-ld/ngsiService/active-devices-test.js @@ -176,7 +176,7 @@ describe('NGSI-LD - Active attributes test', function() { utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContext.json') ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -220,7 +220,7 @@ describe('NGSI-LD - Active attributes test', function() { utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextTimestamp.json') ) - .reply(200); + .reply(204); iotAgentConfig.timestamp = true; iotAgentLib.activate(iotAgentConfig, done); @@ -315,7 +315,7 @@ describe('NGSI-LD - Active attributes test', function() { ) ) - .reply(200); + .reply(204); iotAgentConfig.timestamp = true; iotAgentLib.activate(iotAgentConfig, done); @@ -372,7 +372,7 @@ describe('NGSI-LD - Active attributes test', function() { ) ) - .reply(200); + .reply(204); iotAgentConfig.timestamp = true; iotAgentConfig.types.Light.timezone = 'America/Los_Angeles'; @@ -429,7 +429,7 @@ describe('NGSI-LD - Active attributes test', function() { ) ) - .reply(200); + .reply(204); iotAgentConfig.timestamp = true; iotAgentLib.activate(iotAgentConfig, done); @@ -485,7 +485,7 @@ describe('NGSI-LD - Active attributes test', function() { ) ) - .reply(200); + .reply(204); iotAgentConfig.timestamp = true; iotAgentConfig.types.Light.timezone = 'America/Los_Angeles'; @@ -632,7 +632,7 @@ describe('NGSI-LD - Active attributes test', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContext2.json') ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -666,7 +666,7 @@ describe('NGSI-LD - Active attributes test', function() { './test/unit/ngsi-ld/examples/' + 'contextRequests/updateContextStaticAttributes.json' ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -704,7 +704,7 @@ describe('NGSI-LD - Active attributes test', function() { ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); diff --git a/test/unit/ngsi-ld/ngsiService/autocast-test.js b/test/unit/ngsi-ld/ngsiService/autocast-test.js index d1ad47e65..3d479edcd 100644 --- a/test/unit/ngsi-ld/ngsiService/autocast-test.js +++ b/test/unit/ngsi-ld/ngsiService/autocast-test.js @@ -113,7 +113,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -151,7 +151,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -189,7 +189,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -227,7 +227,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -261,7 +261,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast5.json') ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -294,7 +294,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast6.json') ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -327,7 +327,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast7.json') ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -360,7 +360,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast8.json') ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -393,7 +393,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast9.json') ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -426,7 +426,7 @@ describe('NGSI-LD - JSON native types autocast test', function() { utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAutocast10.json') ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); diff --git a/test/unit/ngsi-ld/ngsiService/geoproperties-test.js b/test/unit/ngsi-ld/ngsiService/geoproperties-test.js index 471005881..66b8f5e74 100644 --- a/test/unit/ngsi-ld/ngsiService/geoproperties-test.js +++ b/test/unit/ngsi-ld/ngsiService/geoproperties-test.js @@ -89,7 +89,7 @@ describe('NGSI-LD - Geo-JSON types autocast test', function() { './test/unit/ngsi-ld/examples/contextRequests/' + 'updateContextGeoproperties1.json' ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -126,7 +126,7 @@ describe('NGSI-LD - Geo-JSON types autocast test', function() { './test/unit/ngsi-ld/examples/contextRequests/' + 'updateContextGeoproperties1.json' ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -164,7 +164,7 @@ describe('NGSI-LD - Geo-JSON types autocast test', function() { './test/unit/ngsi-ld/examples/contextRequests/' + 'updateContextGeoproperties2.json' ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -202,7 +202,7 @@ describe('NGSI-LD - Geo-JSON types autocast test', function() { './test/unit/ngsi-ld/examples/contextRequests/' + 'updateContextGeoproperties2.json' ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -237,7 +237,7 @@ describe('NGSI-LD - Geo-JSON types autocast test', function() { './test/unit/ngsi-ld/examples/contextRequests/' + 'updateContextGeoproperties3.json' ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -274,7 +274,7 @@ describe('NGSI-LD - Geo-JSON types autocast test', function() { './test/unit/ngsi-ld/examples/contextRequests/' + 'updateContextGeoproperties4.json' ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); @@ -312,7 +312,7 @@ describe('NGSI-LD - Geo-JSON types autocast test', function() { './test/unit/ngsi-ld/examples/contextRequests/' + 'updateContextGeoproperties4.json' ) ) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); diff --git a/test/unit/ngsi-ld/ngsiService/staticAttributes-test.js b/test/unit/ngsi-ld/ngsiService/staticAttributes-test.js index 646c14cd4..1c420916d 100644 --- a/test/unit/ngsi-ld/ngsiService/staticAttributes-test.js +++ b/test/unit/ngsi-ld/ngsiService/staticAttributes-test.js @@ -111,7 +111,7 @@ describe('NGSI-LD - Static attributes test', function() { .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') .times(4) - .reply(200) + .reply(204) .post('/ngsi-ld/v1/entityOperations/upsert/', function(body) { // Since the TimeInstant plugin is in use, // Each property should contain observedAt @@ -124,7 +124,7 @@ describe('NGSI-LD - Static attributes test', function() { } return count === Object.keys(body).length - 1; }) - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, done); }); diff --git a/test/unit/ngsi-ld/ngsiService/subscriptions-test.js b/test/unit/ngsi-ld/ngsiService/subscriptions-test.js index 8e9d99b51..0b246eaff 100644 --- a/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +++ b/test/unit/ngsi-ld/ngsiService/subscriptions-test.js @@ -69,7 +69,7 @@ describe('NGSI-LD - Subscription tests', function() { './test/unit/ngsi-ld/examples/' + 'contextRequests/createMinimumProvisionedDevice.json' ) ) - .reply(200); + .reply(204); contextBrokerMock .matchHeader('fiware-service', 'smartGondor') diff --git a/test/unit/ngsi-ld/plugins/alias-plugin_test.js b/test/unit/ngsi-ld/plugins/alias-plugin_test.js index 6badf0ff5..6d099d15a 100644 --- a/test/unit/ngsi-ld/plugins/alias-plugin_test.js +++ b/test/unit/ngsi-ld/plugins/alias-plugin_test.js @@ -151,7 +151,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin1.json') ) - .reply(200); + .reply(204); }); it( @@ -183,7 +183,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin2.json') ) - .reply(200); + .reply(204); }); it( @@ -215,7 +215,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin3.json') ) - .reply(200); + .reply(204); }); it('should rename the attributes as expected by the mappings', function(done) { @@ -245,7 +245,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin3.json') ) - .reply(200); + .reply(204); }); it( @@ -278,7 +278,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin4.json') ) - .reply(200); + .reply(204); }); it( @@ -311,7 +311,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin5.json') ) - .reply(200); + .reply(204); }); it( @@ -344,7 +344,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin6.json') ) - .reply(200); + .reply(204); }); it( @@ -377,7 +377,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin7.json') ) - .reply(200); + .reply(204); }); it( @@ -410,7 +410,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin8.json') ) - .reply(200); + .reply(204); }); it( @@ -443,7 +443,7 @@ describe('NGSI-LD - Attribute alias plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin9.json') ) - .reply(200); + .reply(204); }); it( diff --git a/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js b/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js index 8235bca22..1d97c0417 100644 --- a/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +++ b/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js @@ -98,7 +98,7 @@ describe('NGSI-LD - Bidirectional data plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json') ) - .reply(200); + .reply(204); }); it('should subscribe to the modification of the combined attribute with all the variables', function(done) { @@ -137,7 +137,7 @@ describe('NGSI-LD - Bidirectional data plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json') ) - .reply(200); + .reply(204); contextBrokerMock .matchHeader('fiware-service', 'smartGondor') @@ -187,7 +187,7 @@ describe('NGSI-LD - Bidirectional data plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json') ) - .reply(200); + .reply(204); }); afterEach(function() { @@ -300,7 +300,7 @@ describe('NGSI-LD - Bidirectional data plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json') ) - .reply(200); + .reply(204); }); it('should subscribe to the modification of the combined attribute with all the variables', function(done) { request(provisionGroup, function(error, response, body) { @@ -363,7 +363,7 @@ describe('NGSI-LD - Bidirectional data plugin', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json') ) - .reply(200); + .reply(204); }); afterEach(function() { @@ -458,7 +458,7 @@ describe('NGSI-LD - Bidirectional data plugin and CB is defined using environmen '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json') ) - .reply(200); + .reply(204); }); it('should subscribe to the modification of the combined attribute with all the variables', function(done) { diff --git a/test/unit/ngsi-ld/plugins/compress-timestamp-plugin_test.js b/test/unit/ngsi-ld/plugins/compress-timestamp-plugin_test.js index 960f42b17..624b80105 100644 --- a/test/unit/ngsi-ld/plugins/compress-timestamp-plugin_test.js +++ b/test/unit/ngsi-ld/plugins/compress-timestamp-plugin_test.js @@ -160,7 +160,7 @@ describe('NGSI-LD - Timestamp compression plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextCompressTimestamp1.json' ) ) - .reply(200); + .reply(204); }); it('should return an entity with all its timestamps expanded to have separators', function(done) { @@ -203,7 +203,7 @@ describe('NGSI-LD - Timestamp compression plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextCompressTimestamp2.json' ) ) - .reply(200); + .reply(204); }); it('should return an entity with all its timestamps expanded to have separators', function(done) { @@ -223,7 +223,7 @@ describe('NGSI-LD - Timestamp compression plugin', function() { contextBrokerMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') - .get('/ngsi-ld/v1/entities/light1/attrs?attrs=state,TheTargetValue&type=Light') + .get('/ngsi-ld/v1/entities/urn:ngsi-ld:Light:light1?attrs=state,TheTargetValue') .reply( 200, utils.readExampleFile( @@ -232,7 +232,7 @@ describe('NGSI-LD - Timestamp compression plugin', function() { ); }); - xit('should return an entity with all its timestamps without separators (basic format)', function(done) { + it('should return an entity with all its timestamps without separators (basic format)', function(done) { iotAgentLib.query('light1', 'Light', '', values, function(error, response) { should.not.exist(error); should.exist(response); diff --git a/test/unit/ngsi-ld/plugins/event-plugin_test.js b/test/unit/ngsi-ld/plugins/event-plugin_test.js index 1d1c7d296..22eda210b 100644 --- a/test/unit/ngsi-ld/plugins/event-plugin_test.js +++ b/test/unit/ngsi-ld/plugins/event-plugin_test.js @@ -102,7 +102,7 @@ describe('NGSI-LD - Event plugin', function() { const dateRegex = /\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d.\d{3}Z/; return body[0].activation.value['@value'].match(dateRegex); }) - .reply(200); + .reply(204); }); it('should return an entity with all its timestamps expanded to have separators', function(done) { diff --git a/test/unit/ngsi-ld/plugins/multientity-plugin_test.js b/test/unit/ngsi-ld/plugins/multientity-plugin_test.js index 2710189e3..2fd4c9cd2 100644 --- a/test/unit/ngsi-ld/plugins/multientity-plugin_test.js +++ b/test/unit/ngsi-ld/plugins/multientity-plugin_test.js @@ -265,7 +265,7 @@ describe('NGSI-LD - Multi-entity plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin1.json' ) ) - .reply(200); + .reply(204); }); it('should send two context elements, one for each entity', function(done) { @@ -297,7 +297,7 @@ describe('NGSI-LD - Multi-entity plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin4.json' ) ) - .reply(200); + .reply(204); }); it('should send context elements', function(done) { @@ -334,7 +334,7 @@ describe('NGSI-LD - Multi-entity plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin5.json' ) ) - .reply(200); + .reply(204); }); it('should send context elements', function(done) { @@ -372,7 +372,7 @@ describe('NGSI-LD - Multi-entity plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin8.json' ) ) - .reply(200); + .reply(204); }); it('should send context elements', function(done) { @@ -414,7 +414,7 @@ describe('NGSI-LD - Multi-entity plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin3.json' ) ) - .reply(200); + .reply(204); }); it('should send the update value to the resulting value of the expression', function(done) { @@ -451,7 +451,7 @@ describe('NGSI-LD - Multi-entity plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin2.json' ) ) - .reply(200); + .reply(204); }); it('should use the device type as a default value', function(done) { @@ -486,7 +486,7 @@ describe('NGSI-LD - Multi-entity plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin6.json' ) ) - .reply(200); + .reply(204); }); it('should update only the appropriate CB entity', function(done) { @@ -537,7 +537,7 @@ describe('NGSI-LD - Multi-entity plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextMultientityPlugin7.json' ) ) - .reply(200); + .reply(204); }); it('should update only the appropriate CB entity', function(done) { @@ -626,7 +626,7 @@ describe('NGSI-LD - Multi-entity plugin is executed before timestamp process plu } return false; }) - .reply(200); + .reply(204); iotAgentLib.update('ws4', 'WeatherStation', '', values, function(error) { should.not.exist(error); @@ -658,7 +658,7 @@ describe('NGSI-LD - Multi-entity plugin is executed before timestamp process plu } return false; }) - .reply(200); + .reply(204); iotAgentLib.update('ws4', 'WeatherStation', '', singleValue, function(error) { should.not.exist(error); @@ -677,7 +677,7 @@ describe('NGSI-LD - Multi-entity plugin is executed before timestamp process plu '/contextRequests/updateContextMultientityTimestampPlugin3.json' ) ) - .reply(200); + .reply(204); const tsValue = [ { @@ -736,7 +736,7 @@ describe('NGSI-LD - Multi-entity plugin is executed for a command update for a r './test/unit/ngsi-ld/examples' + '/contextRequests/updateContextMultientityTimestampPlugin4.json' ) ) - .reply(200); + .reply(204); const commands = [ { diff --git a/test/unit/ngsi-ld/plugins/timestamp-processing-plugin_test.js b/test/unit/ngsi-ld/plugins/timestamp-processing-plugin_test.js index a6fb6488a..9852100c4 100644 --- a/test/unit/ngsi-ld/plugins/timestamp-processing-plugin_test.js +++ b/test/unit/ngsi-ld/plugins/timestamp-processing-plugin_test.js @@ -104,7 +104,7 @@ describe('NGSI-LD - Timestamp processing plugin', function() { './test/unit/ngsi-ld/examples/contextRequests/updateContextProcessTimestamp.json' ) ) - .reply(200); + .reply(204); }); it('should return an entity with all its timestamps expanded to have separators', function(done) { diff --git a/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js b/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js index da3b2ef67..0ab46664a 100644 --- a/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js +++ b/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js @@ -68,7 +68,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); iotAgentLib.clearAll(done); }); @@ -99,7 +99,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createProvisionedDevice.json') ) - .reply(200); + .reply(204); }); const options = { @@ -245,7 +245,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createTimeinstantDevice.json') ) - .reply(200); + .reply(204); done(); }); @@ -288,7 +288,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createTimeinstantDevice.json') ) - .reply(200); + .reply(204); done(); }); @@ -333,7 +333,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { './test/unit/ngsi-ld/examples/' + 'contextRequests/createAutoprovisionDevice.json' ) ) - .reply(200); + .reply(204); done(); }); @@ -381,7 +381,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { './test/unit/ngsi-ld/examples/' + 'contextRequests/createTimeInstantMinimumDevice.json' ) ) - .reply(200); + .reply(204); done(); }); @@ -416,7 +416,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { './test/unit/ngsi-ld/examples/' + 'contextRequests/createMinimumProvisionedDevice.json' ) ) - .reply(200); + .reply(204); done(); }); @@ -474,7 +474,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { './test/unit/ngsi-ld/examples/contextRequests/createGeopointProvisionedDevice.json' ) ) - .reply(200); + .reply(204); done(); }); @@ -508,7 +508,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { './test/unit/ngsi-ld/examples/contextRequests/createDatetimeProvisionedDevice.json' ) ) - .reply(200); + .reply(204); done(); }); @@ -550,7 +550,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { './test/unit/ngsi-ld/examples/' + 'contextRequests/createMinimumProvisionedDevice.json' ) ) - .reply(200); + .reply(204); contextBrokerMock .post( @@ -559,7 +559,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { './test/unit/ngsi-ld/examples/' + 'contextRequests/createMinimumProvisionedDevice.json' ) ) - .reply(200); + .reply(204); done(); }); @@ -719,7 +719,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); done(); }); diff --git a/test/unit/ngsi-ld/provisioning/device-registration_test.js b/test/unit/ngsi-ld/provisioning/device-registration_test.js index 2f2a0e9af..078c59f4f 100644 --- a/test/unit/ngsi-ld/provisioning/device-registration_test.js +++ b/test/unit/ngsi-ld/provisioning/device-registration_test.js @@ -112,7 +112,7 @@ describe('NGSI-LD - IoT Agent Device Registration', function() { contextBrokerMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); const nockBody = utils.readExampleFile( './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerIoTAgent1.json' @@ -209,7 +209,7 @@ describe('NGSI-LD - IoT Agent Device Registration', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, function(error) { iotAgentLib.clearAll(done); @@ -269,7 +269,7 @@ describe('NGSI-LD - IoT Agent Device Registration', function() { // This mock does not check the payload since the aim of the test is not to verify // device provisioning functionality. Appropriate verification is done in tests under // provisioning folder - contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(200); + contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(204); contextBrokerMock .post('/ngsi-ld/v1/csourceRegistrations/') @@ -278,7 +278,7 @@ describe('NGSI-LD - IoT Agent Device Registration', function() { // This mock does not check the payload since the aim of the test is not to verify // device provisioning functionality. Appropriate verification is done in tests under // provisioning folder - contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(200); + contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(204); contextBrokerMock .delete('/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d') @@ -315,7 +315,7 @@ describe('NGSI-LD - IoT Agent Device Registration', function() { // This mock does not check the payload since the aim of the test is not to verify // device provisioning functionality. Appropriate verification is done in tests under // provisioning folder - contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(200); + contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(204); contextBrokerMock = nock('http://192.168.1.1:1026') .post('/ngsi-ld/v1/csourceRegistrations/') @@ -324,7 +324,7 @@ describe('NGSI-LD - IoT Agent Device Registration', function() { // This mock does not check the payload since the aim of the test is not to verify // device provisioning functionality. Appropriate verification is done in tests under // provisioning folder - contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(200); + contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(204); contextBrokerMock.delete('/ngsi-ld/v1/csourceRegistrations/6319a7f5254b05844116584d').reply(500); diff --git a/test/unit/ngsi-ld/provisioning/device-update-registration_test.js b/test/unit/ngsi-ld/provisioning/device-update-registration_test.js index e1bc9a818..9124e92f9 100644 --- a/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +++ b/test/unit/ngsi-ld/provisioning/device-update-registration_test.js @@ -150,7 +150,7 @@ describe('NGSI-LD - IoT Agent Device Update Registration', function() { contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); iotAgentLib.activate(iotAgentConfig, function(error) { iotAgentLib.register(device1, function(error) { @@ -176,7 +176,7 @@ describe('NGSI-LD - IoT Agent Device Update Registration', function() { './test/unit/ngsi-ld/examples/contextRequests/updateProvisionActiveAttributes1.json' ) ) - .reply(200); + .reply(204); contextBrokerMock .matchHeader('fiware-service', 'smartGondor') @@ -219,7 +219,7 @@ describe('NGSI-LD - IoT Agent Device Update Registration', function() { '/ngsi-ld/v1/entityOperations/upsert/', utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/updateProvisionCommands1.json') ) - .reply(200); + .reply(204); contextBrokerMock .matchHeader('fiware-service', 'smartGondor') diff --git a/test/unit/ngsi-ld/provisioning/listProvisionedDevices-test.js b/test/unit/ngsi-ld/provisioning/listProvisionedDevices-test.js index 58181dc0a..cb508ebff 100644 --- a/test/unit/ngsi-ld/provisioning/listProvisionedDevices-test.js +++ b/test/unit/ngsi-ld/provisioning/listProvisionedDevices-test.js @@ -95,7 +95,7 @@ describe('NGSI-LD - Device provisioning API: List provisioned devices', function // This mock does not check the payload since the aim of the test is not to verify // device provisioning functionality. Appropriate verification is done in tests under // provisioning folder - contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(200); + contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(204); contextBrokerMock .post('/ngsi-ld/v1/csourceRegistrations/') @@ -104,7 +104,7 @@ describe('NGSI-LD - Device provisioning API: List provisioned devices', function // This mock does not check the payload since the aim of the test is not to verify // device provisioning functionality. Appropriate verification is done in tests under // provisioning folder - contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(200); + contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(204); contextBrokerMock .post('/ngsi-ld/v1/csourceRegistrations/') @@ -113,7 +113,7 @@ describe('NGSI-LD - Device provisioning API: List provisioned devices', function // This mock does not check the payload since the aim of the test is not to verify // device provisioning functionality. Appropriate verification is done in tests under // provisioning folder - contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(200); + contextBrokerMock.post('/ngsi-ld/v1/entityOperations/upsert/').reply(204); async.series( [ @@ -324,7 +324,7 @@ describe('NGSI-LD - Device provisioning API: List provisioned devices', function contextBrokerMock .post('/ngsi-ld/v1/entityOperations/upsert/') .times(10) - .reply(200); + .reply(204); iotAgentLib.clearAll(function() { async.times(10, createDeviceRequest, function(error, results) { diff --git a/test/unit/ngsi-ld/provisioning/provisionDeviceMultientity-test.js b/test/unit/ngsi-ld/provisioning/provisionDeviceMultientity-test.js index 5df9bacd6..519e8f4aa 100644 --- a/test/unit/ngsi-ld/provisioning/provisionDeviceMultientity-test.js +++ b/test/unit/ngsi-ld/provisioning/provisionDeviceMultientity-test.js @@ -85,7 +85,7 @@ describe('NGSI-LD - Device provisioning API: Provision devices', function() { './test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceMultientity.json' ) ) - .reply(200); + .reply(204); }); const options = { diff --git a/test/unit/ngsi-ld/provisioning/removeProvisionedDevice-test.js b/test/unit/ngsi-ld/provisioning/removeProvisionedDevice-test.js index 37991dfae..e9e966eaa 100644 --- a/test/unit/ngsi-ld/provisioning/removeProvisionedDevice-test.js +++ b/test/unit/ngsi-ld/provisioning/removeProvisionedDevice-test.js @@ -95,7 +95,7 @@ describe('NGSI-LD - Device provisioning API: Remove provisioned devices', functi contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); const nockBody2 = utils.readExampleFile( './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice2.json' @@ -111,7 +111,7 @@ describe('NGSI-LD - Device provisioning API: Remove provisioned devices', functi contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); contextBrokerMock .matchHeader('fiware-service', 'smartGondor') @@ -124,7 +124,7 @@ describe('NGSI-LD - Device provisioning API: Remove provisioned devices', functi contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); async.series( [ diff --git a/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js b/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js index 5b0de4209..f14a2ddbc 100644 --- a/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js +++ b/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js @@ -134,7 +134,7 @@ describe('NGSI-LD - Provisioning API: Single service mode', function() { contextBrokerMock .matchHeader('fiware-service', 'TestService') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); request(groupCreation, function(error) { request(deviceCreation, function(error, response, body) { @@ -187,7 +187,7 @@ describe('NGSI-LD - Provisioning API: Single service mode', function() { contextBrokerMock .matchHeader('fiware-service', 'TestService') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); contextBrokerMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'AlternateService') @@ -200,7 +200,7 @@ describe('NGSI-LD - Provisioning API: Single service mode', function() { contextBrokerMock .matchHeader('fiware-service', 'AlternateService') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); request(groupCreation, function(error) { request(deviceCreation, function(error, response, body) { @@ -244,7 +244,7 @@ describe('NGSI-LD - Provisioning API: Single service mode', function() { contextBrokerMock .matchHeader('fiware-service', 'TestService') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); oldType = deviceCreation.json.devices[0].entity_type; delete deviceCreation.json.devices[0].entity_type; @@ -289,7 +289,7 @@ describe('NGSI-LD - Provisioning API: Single service mode', function() { './test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic.json' ) ) - .reply(200); + .reply(204); request(groupCreation, done); }); diff --git a/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js b/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js index 1290dd080..68dde7d38 100644 --- a/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js +++ b/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js @@ -93,7 +93,7 @@ describe('NGSI-LD - Device provisioning API: Update provisioned devices', functi contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); const nockBody2 = utils.readExampleFile( './test/unit/ngsi-ld/examples/contextAvailabilityRequests/registerProvisionedDevice2.json' @@ -110,7 +110,7 @@ describe('NGSI-LD - Device provisioning API: Update provisioned devices', functi contextBrokerMock .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); // FIXME: When https://github.com/telefonicaid/fiware-orion/issues/3007 is merged into master branch, // this function should use the new API. This is just a temporary solution which implies deleting the @@ -195,7 +195,7 @@ describe('NGSI-LD - Device provisioning API: Update provisioned devices', functi .reply(201, null, { Location: '/ngsi-ld/v1/csourceRegistrations/4419a7f52546658441165849' }); }); - it('should return a 200 OK and no errors', function(done) { + it('should return a 204 OK and no errors', function(done) { request(optionsUpdate, function(error, response, body) { should.not.exist(error); response.statusCode.should.equal(204); @@ -318,7 +318,7 @@ describe('NGSI-LD - Device provisioning API: Update provisioned devices', functi contextBrokerMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); contextBrokerMock .matchHeader('fiware-service', 'smartGondor') @@ -328,7 +328,7 @@ describe('NGSI-LD - Device provisioning API: Update provisioned devices', functi './test/unit/ngsi-ld/examples/contextRequests/updateProvisionMinimumDevice.json' ) ) - .reply(200); + .reply(204); async.series([iotAgentLib.clearAll, async.apply(request, provisioning3Options)], done); }); @@ -393,7 +393,7 @@ describe('NGSI-LD - Device provisioning API: Update provisioned devices', functi contextBrokerMock = nock('http://192.168.1.1:1026') .matchHeader('fiware-service', 'smartGondor') .post('/ngsi-ld/v1/entityOperations/upsert/') - .reply(200); + .reply(204); contextBrokerMock .matchHeader('fiware-service', 'smartGondor') @@ -403,7 +403,7 @@ describe('NGSI-LD - Device provisioning API: Update provisioned devices', functi './test/unit/ngsi-ld/examples/contextRequests/updateProvisionDeviceStatic.json' ) ) - .reply(200); + .reply(204); async.series([iotAgentLib.clearAll, async.apply(request, provisioning3Options)], done); });