From cf43a214ffed15129d70db988ce045117cf4e8ab Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 20 Oct 2023 11:06:55 +0200 Subject: [PATCH 01/12] add new route to receive ngsiv2 payload measure --- lib/bindings/HTTPBinding.js | 55 +++++++++++++++++++++++++++++++++++++ lib/constants.js | 1 + 2 files changed, 56 insertions(+) diff --git a/lib/bindings/HTTPBinding.js b/lib/bindings/HTTPBinding.js index d907a238a..37c4e2dfd 100644 --- a/lib/bindings/HTTPBinding.js +++ b/lib/bindings/HTTPBinding.js @@ -376,6 +376,53 @@ function handleIncomingMeasure(req, res, next) { iotaUtils.retrieveDevice(req.deviceId, req.apiKey, transport, processDeviceMeasure); } +function handleIncomingNGSIv2Measure(req, res, next) { + function sendHandler(error) { + if (error) { + next(error); + config + .getLogger() + .error( + context, + 'MEASURES-002: Could not send the ngsiv2 measure to the Context Broker due to an error: %j', + error + ); + } else { + config + .getLogger() + .info( + context, + 'NGSIV2 measures for device %s with apiKey %s successfully sent', + req.deviceId, + req.apiKey + ); + + finishSouthBoundTransaction(next); + } + } + + function processNGSIv2MeasureWithDevice(device) { + iotAgentLib.sendNgsiv2Measure(device.name, device.type, '', req.jsonPayload, device, sendHandler); + } + + function processNGSIv2Measure(error, device) { + if (error) { + next(error); + } else { + const localContext = _.clone(context); + req.device = device; + localContext.service = device.service; + localContext.subservice = device.subservice; + intoTrans(localContext, processNGSIv2MeasureWithDevice)(device); + } + } + + context = fillService(context, { service: 'n/a', subservice: 'n/a' }); + config.getLogger().debug(context, 'Processing HTTP NGSIv2 measure'); + + iotaUtils.retrieveDevice(req.deviceId, req.apiKey, transport, processNGSIv2Measure); +} + function isCommand(req, res, next) { if ( req.path === @@ -633,6 +680,14 @@ function start(callback) { returnCommands ); + httpBindingServer.router.post( + config.getConfig().iota.defaultResource || constants.HTTP_NGSIV2_MEASURE_PATH, + bodyParser.json({ strict: false }), // accept anything JSON.parse accepts + checkMandatoryParams(true), + parseDataMultipleMeasure, + handleIncomingNgsiv2Measure + ); + httpBindingServer.router.post( (config.getConfig().iota.defaultResource || constants.HTTP_MEASURE_PATH) + '/' + diff --git a/lib/constants.js b/lib/constants.js index f82a67d56..fa946293b 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -35,6 +35,7 @@ module.exports = { HTTP_MEASURE_PATH: '/iot/d', HTTP_CONFIGURATION_PATH: '/configuration', HTTP_COMMANDS_PATH: '/commands', + HTTP_NGSIV2_MEASURE_PATH: '/iot/ngsiv2', TIMESTAMP_ATTRIBUTE: 'TimeInstant', TIMESTAMP_TYPE_NGSI2: 'DateTime', From 038597b4be3f2acf15e46b4898a1aae6e6a42705 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 20 Oct 2023 11:22:38 +0200 Subject: [PATCH 02/12] fix name --- lib/bindings/HTTPBinding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bindings/HTTPBinding.js b/lib/bindings/HTTPBinding.js index 37c4e2dfd..d69330998 100644 --- a/lib/bindings/HTTPBinding.js +++ b/lib/bindings/HTTPBinding.js @@ -376,7 +376,7 @@ function handleIncomingMeasure(req, res, next) { iotaUtils.retrieveDevice(req.deviceId, req.apiKey, transport, processDeviceMeasure); } -function handleIncomingNGSIv2Measure(req, res, next) { +function handleIncomingNgsiv2Measure(req, res, next) { function sendHandler(error) { if (error) { next(error); From d68b5cc808191803a7ec222120a8aa563c1a0578 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 20 Oct 2023 12:00:59 +0200 Subject: [PATCH 03/12] fix route --- lib/bindings/HTTPBinding.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bindings/HTTPBinding.js b/lib/bindings/HTTPBinding.js index d69330998..163368261 100644 --- a/lib/bindings/HTTPBinding.js +++ b/lib/bindings/HTTPBinding.js @@ -681,9 +681,9 @@ function start(callback) { ); httpBindingServer.router.post( - config.getConfig().iota.defaultResource || constants.HTTP_NGSIV2_MEASURE_PATH, + constants.HTTP_NGSIV2_MEASURE_PATH, bodyParser.json({ strict: false }), // accept anything JSON.parse accepts - checkMandatoryParams(true), + checkMandatoryParams(false), parseDataMultipleMeasure, handleIncomingNgsiv2Measure ); From de727ecd6923b2aef6a68f4b523337e09d080923 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 20 Oct 2023 12:31:50 +0200 Subject: [PATCH 04/12] add missed return status --- lib/bindings/HTTPBinding.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/bindings/HTTPBinding.js b/lib/bindings/HTTPBinding.js index 163368261..21537006b 100644 --- a/lib/bindings/HTTPBinding.js +++ b/lib/bindings/HTTPBinding.js @@ -684,8 +684,9 @@ function start(callback) { constants.HTTP_NGSIV2_MEASURE_PATH, bodyParser.json({ strict: false }), // accept anything JSON.parse accepts checkMandatoryParams(false), - parseDataMultipleMeasure, - handleIncomingNgsiv2Measure + parseData, + handleIncomingNgsiv2Measure, + returnCommands ); httpBindingServer.router.post( From 73911ebafd1a5a327ed8041e4bcb8d017c503ed0 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 27 Oct 2023 12:07:51 +0200 Subject: [PATCH 05/12] add test --- .../ngsiv2/HTTP_receive_measures-test3.js | 87 +++++++++++++++++++ .../contextRequests/ngsiv2entities.json | 54 ++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 test/unit/ngsiv2/contextRequests/ngsiv2entities.json diff --git a/test/unit/ngsiv2/HTTP_receive_measures-test3.js b/test/unit/ngsiv2/HTTP_receive_measures-test3.js index 98b7efc86..5462e8759 100644 --- a/test/unit/ngsiv2/HTTP_receive_measures-test3.js +++ b/test/unit/ngsiv2/HTTP_receive_measures-test3.js @@ -305,6 +305,93 @@ describe('HTTP: Measure reception ', function () { }); }); + describe('When a POST single JSON measure with NGSIv2 format arrives for the HTTP binding', function () { + const optionsMeasure = { + url: 'http://localhost:' + config.http.port + '/iot/ngsiv2/', + method: 'POST', + json: [ + { + id: 'urn:ngsi-ld:Streetlight:Streetlight-Mylightpoint-2', + type: 'Streetlight', + name: { + type: 'Text', + value: 'MyLightPoint-test1' + }, + description: { + type: 'Text', + value: 'testdescription' + }, + status: { + type: 'Text', + value: 'connected' + }, + dateServiceStarted: { + type: 'DateTime', + value: '2020-06-04T09: 55: 02' + }, + locationComment: { + type: 'Text', + value: 'Test1' + }, + location: { + type: 'geo:json', + value: { + coordinates: [-87.88429, 41.99499], + type: 'Point' + } + }, + address: { + type: 'Text', + value: { + streetAddress: 'MyStreet' + } + }, + isRemotelyManaged: { + type: 'Integer', + value: 1 + }, + installationDate: { + type: 'DateTime', + value: '2022-04-17T02: 30: 04' + } + } + ], + headers: { + 'fiware-service': 'smartgondor', + 'fiware-servicepath': '/gardens' + }, + qs: { + i: 'MQTT_2', + k: '1234' + } + }; + + beforeEach(function () { + contextBrokerMock + .matchHeader('fiware-service', 'smartgondor') + .matchHeader('fiware-servicepath', '/gardens') + .post( + '/v2/entities?options=upsert', + utils.readExampleFile('./test/unit/ngsiv2/contextRequests/ngsiv2entities.json') + ) + .reply(204); + }); + it('should return a 200 OK with no error', function (done) { + request(optionsMeasure, function (error, result, body) { + should.not.exist(error); + result.statusCode.should.equal(200); + done(); + }); + }); + + it('should send its value to the Context Broker', function (done) { + request(optionsMeasure, function (error, result, body) { + contextBrokerMock.done(); + done(); + }); + }); + }); + describe('When a POST single Text measure arrives for the HTTP binding', function () { const optionsMeasure = { url: 'http://localhost:' + config.http.port + '/iot/json/attrs/humidity', diff --git a/test/unit/ngsiv2/contextRequests/ngsiv2entities.json b/test/unit/ngsiv2/contextRequests/ngsiv2entities.json new file mode 100644 index 000000000..66b017b57 --- /dev/null +++ b/test/unit/ngsiv2/contextRequests/ngsiv2entities.json @@ -0,0 +1,54 @@ +{ + actionType: 'append', + entities: [ + { + "id": "urn:ngsi-ld:Streetlight:Streetlight-Mylightpoint-2", + "type": "Streetlight", + "name": { + "type": "Text", + "value": "MyLightPoint-test1" + }, + "description": { + "type": "Text", + "value": "testdescription" + }, + "status": { + "type": "Text", + "value": "connected" + }, + "dateServiceStarted": { + "type": "DateTime", + "value": "2020-06-04T09: 55: 02" + }, + "locationComment": { + "type": "Text", + "value": "Test1" + }, + "location": { + "type": "geo:json", + "value": { + "coordinates": [ + -87.88429, + 41.99499 + ], + "type": "Point" + } + }, + "address": { + "type": "Text", + "value": { + "streetAddress": "MyStreet" + } + }, + "isRemotelyManaged": { + "type": "Integer", + "value": 1 + }, + "installationDate": { + "type": "DateTime", + "value": "2022-04-17T02: 30: 04" + } + } + ] + + From 5127352750757d7a6bdba65c577c9ac3178615c8 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 27 Oct 2023 12:27:49 +0200 Subject: [PATCH 06/12] use temp branch of iota-node-lib --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e60a6386e..ce13b4e2e 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "body-parser": "1.20.0", "dateformat": "3.0.3", "express": "4.18.1", - "iotagent-node-lib": "https://github.com/telefonicaid/iotagent-node-lib.git#master", + "iotagent-node-lib": "https://github.com/telefonicaid/iotagent-node-lib.git#task/allow_ngsiv2_as_measure", "logops": "2.1.2", "mqtt": "4.3.7", "sinon": "~6.1.0", From 9f50363a488b9caa17eecc2cd108526a26319a15 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Fri, 27 Oct 2023 13:10:44 +0200 Subject: [PATCH 07/12] update test --- .../ngsiv2/HTTP_receive_measures-test3.js | 102 +++++++++--------- .../contextRequests/ngsiv2entities.json | 6 +- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/test/unit/ngsiv2/HTTP_receive_measures-test3.js b/test/unit/ngsiv2/HTTP_receive_measures-test3.js index 5462e8759..bb1e97c4b 100644 --- a/test/unit/ngsiv2/HTTP_receive_measures-test3.js +++ b/test/unit/ngsiv2/HTTP_receive_measures-test3.js @@ -138,7 +138,7 @@ describe('HTTP: Measure reception ', function () { }); }); - describe('When a POST single JSON measure with NGSIv2 format arrives for the HTTP binding', function () { + describe('When a POST single JSON measure for an attribute with NGSIv2 format arrives for the HTTP binding', function () { const optionsMeasure = { url: 'http://localhost:' + config.http.port + '/iot/json/', method: 'POST', @@ -228,7 +228,7 @@ describe('HTTP: Measure reception ', function () { }); }); - describe('When a POST single JSON measure with NGSILD format arrives for the HTTP binding', function () { + describe('When a POST single JSON measure for an attribute with NGSILD format arrives for the HTTP binding', function () { const optionsMeasure = { url: 'http://localhost:' + config.http.port + '/iot/json/', method: 'POST', @@ -305,57 +305,55 @@ describe('HTTP: Measure reception ', function () { }); }); - describe('When a POST single JSON measure with NGSIv2 format arrives for the HTTP binding', function () { + describe('When a POST with a NGSIv2 measure arrives for the HTTP binding', function () { const optionsMeasure = { - url: 'http://localhost:' + config.http.port + '/iot/ngsiv2/', + url: 'http://localhost:' + config.http.port + '/iot/ngsiv2', method: 'POST', - json: [ - { - id: 'urn:ngsi-ld:Streetlight:Streetlight-Mylightpoint-2', - type: 'Streetlight', - name: { - type: 'Text', - value: 'MyLightPoint-test1' - }, - description: { - type: 'Text', - value: 'testdescription' - }, - status: { - type: 'Text', - value: 'connected' - }, - dateServiceStarted: { - type: 'DateTime', - value: '2020-06-04T09: 55: 02' - }, - locationComment: { - type: 'Text', - value: 'Test1' - }, - location: { - type: 'geo:json', - value: { - coordinates: [-87.88429, 41.99499], - type: 'Point' - } - }, - address: { - type: 'Text', - value: { - streetAddress: 'MyStreet' - } - }, - isRemotelyManaged: { - type: 'Integer', - value: 1 - }, - installationDate: { - type: 'DateTime', - value: '2022-04-17T02: 30: 04' + json: { + id: 'urn:ngsi-ld:Streetlight:Streetlight-Mylightpoint-2', + type: 'Streetlight', + name: { + type: 'Text', + value: 'MyLightPoint-test1' + }, + description: { + type: 'Text', + value: 'testdescription' + }, + status: { + type: 'Text', + value: 'connected' + }, + dateServiceStarted: { + type: 'DateTime', + value: '2020-06-04T09: 55: 02' + }, + locationComment: { + type: 'Text', + value: 'Test1' + }, + location: { + type: 'geo:json', + value: { + coordinates: [-87.88429, 41.99499], + type: 'Point' + } + }, + address: { + type: 'Text', + value: { + streetAddress: 'MyStreet' } + }, + isRemotelyManaged: { + type: 'Integer', + value: 1 + }, + installationDate: { + type: 'DateTime', + value: '2022-04-17T02: 30: 04' } - ], + }, headers: { 'fiware-service': 'smartgondor', 'fiware-servicepath': '/gardens' @@ -370,14 +368,12 @@ describe('HTTP: Measure reception ', function () { contextBrokerMock .matchHeader('fiware-service', 'smartgondor') .matchHeader('fiware-servicepath', '/gardens') - .post( - '/v2/entities?options=upsert', - utils.readExampleFile('./test/unit/ngsiv2/contextRequests/ngsiv2entities.json') - ) + .post('/v2/op/update', utils.readExampleFile('./test/unit/ngsiv2/contextRequests/ngsiv2entities.json')) .reply(204); }); it('should return a 200 OK with no error', function (done) { request(optionsMeasure, function (error, result, body) { + //console.log(error); should.not.exist(error); result.statusCode.should.equal(200); done(); diff --git a/test/unit/ngsiv2/contextRequests/ngsiv2entities.json b/test/unit/ngsiv2/contextRequests/ngsiv2entities.json index 66b017b57..4ef8b2d46 100644 --- a/test/unit/ngsiv2/contextRequests/ngsiv2entities.json +++ b/test/unit/ngsiv2/contextRequests/ngsiv2entities.json @@ -1,6 +1,6 @@ { - actionType: 'append', - entities: [ + "actionType": "append", + "entities": [ { "id": "urn:ngsi-ld:Streetlight:Streetlight-Mylightpoint-2", "type": "Streetlight", @@ -50,5 +50,5 @@ } } ] - +} From 44d618c6788e7c1f3f2797f793a1c2dec6ec9627 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 30 Oct 2023 15:21:32 +0100 Subject: [PATCH 08/12] do not create device when ngsiv2 measure is provided --- lib/bindings/HTTPBinding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bindings/HTTPBinding.js b/lib/bindings/HTTPBinding.js index faac259c8..0e86edbe5 100644 --- a/lib/bindings/HTTPBinding.js +++ b/lib/bindings/HTTPBinding.js @@ -420,7 +420,7 @@ function handleIncomingNgsiv2Measure(req, res, next) { context = fillService(context, { service: 'n/a', subservice: 'n/a' }); config.getLogger().debug(context, 'Processing HTTP NGSIv2 measure'); - iotaUtils.retrieveDevice(req.deviceId, req.apiKey, transport, processNGSIv2Measure); + processNGSIv2Measure(null, { id: req.deviceId, apikey: req.apiKey }); } function isCommand(req, res, next) { From 8b656eb86ea571ae27455cd58260013084694739 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 30 Oct 2023 16:01:13 +0100 Subject: [PATCH 09/12] fix group --- lib/bindings/HTTPBinding.js | 6 +++++- test/unit/ngsiv2/HTTP_receive_measures-test3.js | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/bindings/HTTPBinding.js b/lib/bindings/HTTPBinding.js index 0e86edbe5..28c045ead 100644 --- a/lib/bindings/HTTPBinding.js +++ b/lib/bindings/HTTPBinding.js @@ -420,7 +420,11 @@ function handleIncomingNgsiv2Measure(req, res, next) { context = fillService(context, { service: 'n/a', subservice: 'n/a' }); config.getLogger().debug(context, 'Processing HTTP NGSIv2 measure'); - processNGSIv2Measure(null, { id: req.deviceId, apikey: req.apiKey }); + iotAgentLib.getConfigurationSilently( + config.getConfig().iota.defaultResource || '', + req.apiKey, + processNGSIv2Measure + ); } function isCommand(req, res, next) { diff --git a/test/unit/ngsiv2/HTTP_receive_measures-test3.js b/test/unit/ngsiv2/HTTP_receive_measures-test3.js index bb1e97c4b..1518aa8eb 100644 --- a/test/unit/ngsiv2/HTTP_receive_measures-test3.js +++ b/test/unit/ngsiv2/HTTP_receive_measures-test3.js @@ -360,7 +360,7 @@ describe('HTTP: Measure reception ', function () { }, qs: { i: 'MQTT_2', - k: '1234' + k: 'KL223HHV8732SFL1' } }; @@ -370,6 +370,10 @@ describe('HTTP: Measure reception ', function () { .matchHeader('fiware-servicepath', '/gardens') .post('/v2/op/update', utils.readExampleFile('./test/unit/ngsiv2/contextRequests/ngsiv2entities.json')) .reply(204); + + request(groupCreation, function (error, response, body) { + done(); + }); }); it('should return a 200 OK with no error', function (done) { request(optionsMeasure, function (error, result, body) { From bc06f518cdb18246c9c938b1ec4d6779d504f2d0 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 30 Oct 2023 16:08:40 +0100 Subject: [PATCH 10/12] add missed done --- test/unit/ngsiv2/HTTP_receive_measures-test3.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit/ngsiv2/HTTP_receive_measures-test3.js b/test/unit/ngsiv2/HTTP_receive_measures-test3.js index 1518aa8eb..82ff8e014 100644 --- a/test/unit/ngsiv2/HTTP_receive_measures-test3.js +++ b/test/unit/ngsiv2/HTTP_receive_measures-test3.js @@ -364,7 +364,7 @@ describe('HTTP: Measure reception ', function () { } }; - beforeEach(function () { + beforeEach(function (done) { contextBrokerMock .matchHeader('fiware-service', 'smartgondor') .matchHeader('fiware-servicepath', '/gardens') @@ -377,7 +377,6 @@ describe('HTTP: Measure reception ', function () { }); it('should return a 200 OK with no error', function (done) { request(optionsMeasure, function (error, result, body) { - //console.log(error); should.not.exist(error); result.statusCode.should.equal(200); done(); From fabdd0fe0bee900094661bc481444b8f49978843 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Mon, 30 Oct 2023 16:26:05 +0100 Subject: [PATCH 11/12] fix test --- lib/bindings/HTTPBinding.js | 6 +----- test/unit/ngsiv2/HTTP_receive_measures-test3.js | 5 +++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/bindings/HTTPBinding.js b/lib/bindings/HTTPBinding.js index 28c045ead..0b8a663fa 100644 --- a/lib/bindings/HTTPBinding.js +++ b/lib/bindings/HTTPBinding.js @@ -420,11 +420,7 @@ function handleIncomingNgsiv2Measure(req, res, next) { context = fillService(context, { service: 'n/a', subservice: 'n/a' }); config.getLogger().debug(context, 'Processing HTTP NGSIv2 measure'); - iotAgentLib.getConfigurationSilently( - config.getConfig().iota.defaultResource || '', - req.apiKey, - processNGSIv2Measure - ); + iotAgentLib.getConfiguration(config.getConfig().iota.defaultResource || '', req.apiKey, processNGSIv2Measure); } function isCommand(req, res, next) { diff --git a/test/unit/ngsiv2/HTTP_receive_measures-test3.js b/test/unit/ngsiv2/HTTP_receive_measures-test3.js index 82ff8e014..95e9dd37a 100644 --- a/test/unit/ngsiv2/HTTP_receive_measures-test3.js +++ b/test/unit/ngsiv2/HTTP_receive_measures-test3.js @@ -43,8 +43,9 @@ const groupCreation = { resource: '/iot/json', apikey: 'KL223HHV8732SFL1', entity_type: 'TheLightType', - trust: '8970A9078A803H3BL98PINEQRW8342HBAMS', - cbHost: 'http://unexistentHost:1026', + service: 'smartgondor', + subservice: 'gardens', + cbHost: 'http://192.168.1.1:1026', commands: [], lazy: [], attributes: [ From 36d2b029df36d5d91579356fa5222c76cee46f81 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Thu, 2 Nov 2023 10:23:53 +0100 Subject: [PATCH 12/12] Update CNR --- CHANGES_NEXT_RELEASE | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index aa28dd515..5d91d22e0 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,3 +1,4 @@ +- Add: endpoit to send ngsiv2 measure to Context Broker - Fix: binary data representation when sending data through HTTP & MQTT (#690) - Fix: ensure service and subservice from device in logs about error proccesing message - Remove: legacy code about unused parsedMessageError flag