iotagent-node-lib 2.23.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +6 -7
- package/.nyc_output/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +1 -0
- package/.nyc_output/processinfo/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -1
- package/CHANGES_NEXT_RELEASE +1 -2
- package/doc/advanced-topics.md +78 -3
- package/doc/apiary/iotagent.apib +5 -5
- package/doc/architecture.md +52 -5
- package/doc/deprecated.md +10 -7
- package/doc/expressionLanguage.md +46 -35
- package/doc/getting-started.md +1 -1
- package/doc/usermanual.md +18 -16
- package/examples/TTOpen-service.json +1 -1
- package/lib/errors.js +9 -1
- package/lib/fiware-iotagent-lib.js +2 -1
- package/lib/jexlTranformsMap.js +12 -1
- package/lib/plugins/bidirectionalData.js +104 -6
- package/lib/plugins/expressionPlugin.js +10 -0
- package/lib/plugins/jexlParser.js +2 -2
- package/lib/plugins/pluginUtils.js +2 -1
- package/lib/request-shim.js +2 -1
- package/lib/services/devices/deviceService.js +53 -21
- package/lib/services/devices/devices-NGSI-v2.js +3 -1
- package/lib/services/ngsi/entities-NGSI-v2.js +14 -4
- package/lib/services/northBound/contextServer-NGSI-LD.js +96 -20
- package/lib/services/northBound/contextServer-NGSI-v2.js +1 -0
- package/lib/services/northBound/restUtils.js +3 -5
- package/lib/templates/deviceGroup.json +1 -1
- package/package.json +2 -2
- package/test/unit/examples/deviceProvisioningRequests/provisionNewDeviceEmpty.json +43 -0
- package/test/unit/examples/mongoCollections/configurations.json +3 -3
- package/test/unit/expressions/jexlExpression-test.js +29 -8
- package/test/unit/general/deviceService-test.js +31 -29
- package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +62 -10
- package/test/unit/mongodb/mongodb-group-registry-test.js +24 -0
- package/test/unit/mongodb/mongodb-registry-test.js +68 -10
- package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin30.json +11 -0
- package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithDatasetId.json +21 -0
- package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json +17 -0
- package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +18 -4
- package/test/unit/ngsi-ld/general/deviceService-test.js +31 -29
- package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +656 -2
- package/test/unit/ngsi-ld/ngsiService/unsupported-endpoints-test.js +111 -0
- package/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +221 -0
- package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +0 -3
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityJexlExpressionPlugin1.json +22 -0
- package/test/unit/ngsiv2/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json +19 -0
- package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +21 -6
- package/test/unit/ngsiv2/general/deviceService-test.js +25 -23
- package/test/unit/ngsiv2/lazyAndCommands/command-test.js +106 -0
- package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +115 -0
- package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +58 -0
- package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +25 -6
- package/.nyc_output/6e3d7795-bf8c-4a50-bd2f-f8221f27aeae.json +0 -1
- package/.nyc_output/processinfo/6e3d7795-bf8c-4a50-bd2f-f8221f27aeae.json +0 -1
- package/config +0 -0
- package/docker/Mosquitto/Dockerfile.debian +0 -38
- package/docker/Mosquitto/Dockerfile.debian~ +0 -23
- package/lib/plugins/multiEntity.js_avg2 +0 -343
- package/test/unit/ngsiv2/plugins/multientity-plugin_test.js_avg2 +0 -1224
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Telefonica Investigación y Desarrollo, S.A.U
|
|
3
|
+
*
|
|
4
|
+
* This file is part of fiware-iotagent-lib
|
|
5
|
+
*
|
|
6
|
+
* fiware-iotagent-lib is free software: you can redistribute it and/or
|
|
7
|
+
* modify it under the terms of the GNU Affero General Public License as
|
|
8
|
+
* published by the Free Software Foundation, either version 3 of the License,
|
|
9
|
+
* or (at your option) any later version.
|
|
10
|
+
*
|
|
11
|
+
* fiware-iotagent-lib is distributed in the hope that it will be useful,
|
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
14
|
+
* See the GNU Affero General Public License for more details.
|
|
15
|
+
*
|
|
16
|
+
* You should have received a copy of the GNU Affero General Public
|
|
17
|
+
* License along with fiware-iotagent-lib.
|
|
18
|
+
* If not, see http://www.gnu.org/licenses/.
|
|
19
|
+
*
|
|
20
|
+
* For those usages not covered by the GNU Affero General Public License
|
|
21
|
+
* please contact with::daniel.moranjimenez@telefonica.com
|
|
22
|
+
*
|
|
23
|
+
* Modified by: Jason Fox - FIWARE Foundation
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/* eslint-disable no-unused-vars */
|
|
27
|
+
|
|
28
|
+
const iotAgentLib = require('../../../../lib/fiware-iotagent-lib');
|
|
29
|
+
const utils = require('../../../tools/utils');
|
|
30
|
+
const request = utils.request;
|
|
31
|
+
const should = require('should');
|
|
32
|
+
|
|
33
|
+
let contextBrokerMock;
|
|
34
|
+
const iotAgentConfig = {
|
|
35
|
+
contextBroker: {
|
|
36
|
+
host: '192.168.1.1',
|
|
37
|
+
port: '1026',
|
|
38
|
+
ngsiVersion: 'ld',
|
|
39
|
+
jsonLdContext: 'http://context.json-ld'
|
|
40
|
+
},
|
|
41
|
+
server: {
|
|
42
|
+
port: 4041
|
|
43
|
+
},
|
|
44
|
+
types: {},
|
|
45
|
+
service: 'smartgondor',
|
|
46
|
+
subservice: 'gardens',
|
|
47
|
+
providerUrl: 'http://smartgondor.com'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
describe('NGSI-LD - Unsupported Endpoints', function () {
|
|
51
|
+
beforeEach(function (done) {
|
|
52
|
+
iotAgentLib.activate(iotAgentConfig, function () {
|
|
53
|
+
iotAgentLib.clearAll(function () {
|
|
54
|
+
done();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
afterEach(function (done) {
|
|
60
|
+
iotAgentLib.clearAll(function () {
|
|
61
|
+
iotAgentLib.deactivate(done);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('When accessing an Unsupported Endpoint', function () {
|
|
66
|
+
it('GET /entities should return a valid NSGI-LD error message', function (done) {
|
|
67
|
+
const options = {
|
|
68
|
+
url: 'http://localhost:' + iotAgentConfig.server.port + '/ngsi-ld/v1/entities',
|
|
69
|
+
method: 'GET'
|
|
70
|
+
};
|
|
71
|
+
request(options, function (error, response, body) {
|
|
72
|
+
response.statusCode.should.equal(501);
|
|
73
|
+
done();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
it('POST /entities should return a valid NSGI-LD error message', function (done) {
|
|
77
|
+
const options = {
|
|
78
|
+
url: 'http://localhost:' + iotAgentConfig.server.port + '/ngsi-ld/v1/entities',
|
|
79
|
+
method: 'POST',
|
|
80
|
+
json: {}
|
|
81
|
+
};
|
|
82
|
+
request(options, function (error, response, body) {
|
|
83
|
+
response.statusCode.should.equal(501);
|
|
84
|
+
done();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
it('DELETE /entities/<entity-id> should return a valid NSGI-LD error message', function (done) {
|
|
88
|
+
const options = {
|
|
89
|
+
url: 'http://localhost:' + iotAgentConfig.server.port + '/ngsi-ld/v1/entities/urn:ngsi-ld:entity',
|
|
90
|
+
method: 'DELETE'
|
|
91
|
+
};
|
|
92
|
+
request(options, function (error, response, body) {
|
|
93
|
+
response.statusCode.should.equal(501);
|
|
94
|
+
done();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
it('DELETE /entities/<entity-id>/attrs/<attr-name> should return a valid NSGI-LD error message', function (done) {
|
|
98
|
+
const options = {
|
|
99
|
+
url:
|
|
100
|
+
'http://localhost:' +
|
|
101
|
+
iotAgentConfig.server.port +
|
|
102
|
+
'/ngsi-ld/v1/entities/urn:ngsi-ld:entity/attrs/att',
|
|
103
|
+
method: 'DELETE'
|
|
104
|
+
};
|
|
105
|
+
request(options, function (error, response, body) {
|
|
106
|
+
response.statusCode.should.equal(501);
|
|
107
|
+
done();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -264,6 +264,227 @@ describe('NGSI-LD - Bidirectional data plugin', function () {
|
|
|
264
264
|
});
|
|
265
265
|
});
|
|
266
266
|
|
|
267
|
+
describe('When a notification with metadata arrives for a bidirectional attribute', function () {
|
|
268
|
+
const notificationOptions = {
|
|
269
|
+
url: 'http://localhost:' + iotAgentConfig.server.port + '/notify',
|
|
270
|
+
method: 'POST',
|
|
271
|
+
json: utils.readExampleFile(
|
|
272
|
+
'./test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json'
|
|
273
|
+
),
|
|
274
|
+
headers: {
|
|
275
|
+
'fiware-service': 'smartgondor',
|
|
276
|
+
'fiware-servicepath': '/gardens'
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
let executedHandler = false;
|
|
280
|
+
|
|
281
|
+
beforeEach(function () {
|
|
282
|
+
contextBrokerMock
|
|
283
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
284
|
+
.post(
|
|
285
|
+
'/ngsi-ld/v1/subscriptions/',
|
|
286
|
+
utils.readExampleFile(
|
|
287
|
+
'./test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalSubscriptionRequest.json'
|
|
288
|
+
)
|
|
289
|
+
)
|
|
290
|
+
.reply(201, null, { Location: '/ngsi-ld/v1/subscriptions/51c0ac9ed714fb3b37d7d5a8' });
|
|
291
|
+
|
|
292
|
+
contextBrokerMock
|
|
293
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
294
|
+
.post(
|
|
295
|
+
'/ngsi-ld/v1/entityOperations/upsert/',
|
|
296
|
+
utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json')
|
|
297
|
+
)
|
|
298
|
+
.reply(204);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
afterEach(function () {
|
|
302
|
+
iotAgentLib.setNotificationHandler();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('should execute the original handler', function (done) {
|
|
306
|
+
function mockedHandler(device, notification, callback) {
|
|
307
|
+
notification[0].name.should.equal('location');
|
|
308
|
+
notification[0].value.should.equal('12.4, -9.6');
|
|
309
|
+
notification[0].metadata.qos.value.should.equal(1);
|
|
310
|
+
executedHandler = true;
|
|
311
|
+
callback();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
iotAgentLib.setNotificationHandler(mockedHandler);
|
|
315
|
+
|
|
316
|
+
request(options, function (error, response, body) {
|
|
317
|
+
request(notificationOptions, function (error, response, body) {
|
|
318
|
+
executedHandler.should.equal(true);
|
|
319
|
+
contextBrokerMock.done();
|
|
320
|
+
done();
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('should return a 200 OK', function (done) {
|
|
326
|
+
function mockedHandler(device, notification, callback) {
|
|
327
|
+
executedHandler = true;
|
|
328
|
+
callback();
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
iotAgentLib.setNotificationHandler(mockedHandler);
|
|
332
|
+
|
|
333
|
+
request(options, function (error, response, body) {
|
|
334
|
+
request(notificationOptions, function (error, response, body) {
|
|
335
|
+
response.statusCode.should.equal(200);
|
|
336
|
+
contextBrokerMock.done();
|
|
337
|
+
done();
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it('should return the transformed values', function (done) {
|
|
343
|
+
let transformedHandler = false;
|
|
344
|
+
|
|
345
|
+
function mockedHandler(device, values, callback) {
|
|
346
|
+
let latitudeFound = false;
|
|
347
|
+
let longitudeFound = false;
|
|
348
|
+
|
|
349
|
+
for (let i = 0; i < values.length; i++) {
|
|
350
|
+
if (values[i].name === 'latitude' && values[i].type === 'string' && values[i].value === '-9.6') {
|
|
351
|
+
latitudeFound = true;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (values[i].name === 'longitude' && values[i].type === 'string' && values[i].value === '12.4') {
|
|
355
|
+
longitudeFound = true;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
transformedHandler = values.length >= 2 && longitudeFound && latitudeFound;
|
|
360
|
+
callback();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
iotAgentLib.setNotificationHandler(mockedHandler);
|
|
364
|
+
|
|
365
|
+
request(options, function (error, response, body) {
|
|
366
|
+
request(notificationOptions, function (error, response, body) {
|
|
367
|
+
contextBrokerMock.done();
|
|
368
|
+
transformedHandler.should.equal(true);
|
|
369
|
+
done();
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
describe('When a sequential notification with datasetId arrives for a bidirectional attribute', function () {
|
|
376
|
+
const notificationOptions = {
|
|
377
|
+
url: 'http://localhost:' + iotAgentConfig.server.port + '/notify',
|
|
378
|
+
method: 'POST',
|
|
379
|
+
json: utils.readExampleFile(
|
|
380
|
+
'./test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithDatasetId.json'
|
|
381
|
+
),
|
|
382
|
+
headers: {
|
|
383
|
+
'fiware-service': 'smartgondor',
|
|
384
|
+
'fiware-servicepath': '/gardens'
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
let executedHandler = false;
|
|
388
|
+
|
|
389
|
+
beforeEach(function () {
|
|
390
|
+
contextBrokerMock
|
|
391
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
392
|
+
.post(
|
|
393
|
+
'/ngsi-ld/v1/subscriptions/',
|
|
394
|
+
utils.readExampleFile(
|
|
395
|
+
'./test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalSubscriptionRequest.json'
|
|
396
|
+
)
|
|
397
|
+
)
|
|
398
|
+
.reply(201, null, { Location: '/ngsi-ld/v1/subscriptions/51c0ac9ed714fb3b37d7d5a8' });
|
|
399
|
+
|
|
400
|
+
contextBrokerMock
|
|
401
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
402
|
+
.post(
|
|
403
|
+
'/ngsi-ld/v1/entityOperations/upsert/',
|
|
404
|
+
utils.readExampleFile('./test/unit/ngsi-ld/examples/contextRequests/createBidirectionalDevice.json')
|
|
405
|
+
)
|
|
406
|
+
.reply(204);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
afterEach(function () {
|
|
410
|
+
iotAgentLib.setNotificationHandler();
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('should execute the original handler', function (done) {
|
|
414
|
+
function mockedHandler(device, notification, callback) {
|
|
415
|
+
notification[0].name.should.equal('location');
|
|
416
|
+
notification[0].value.should.equal('12.4, -9.6');
|
|
417
|
+
notification[0].datasetId.should.equal('urn:ngsi-ld:Property:do-this');
|
|
418
|
+
|
|
419
|
+
notification[1].name.should.equal('location');
|
|
420
|
+
notification[1].value.should.equal('6, 10');
|
|
421
|
+
notification[1].datasetId.should.equal('urn:ngsi-ld:Property:then-do-this');
|
|
422
|
+
|
|
423
|
+
executedHandler = true;
|
|
424
|
+
callback();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
iotAgentLib.setNotificationHandler(mockedHandler);
|
|
428
|
+
|
|
429
|
+
request(options, function (error, response, body) {
|
|
430
|
+
request(notificationOptions, function (error, response, body) {
|
|
431
|
+
executedHandler.should.equal(true);
|
|
432
|
+
contextBrokerMock.done();
|
|
433
|
+
done();
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
it('should return a 200 OK', function (done) {
|
|
439
|
+
function mockedHandler(device, notification, callback) {
|
|
440
|
+
executedHandler = true;
|
|
441
|
+
callback();
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
iotAgentLib.setNotificationHandler(mockedHandler);
|
|
445
|
+
|
|
446
|
+
request(options, function (error, response, body) {
|
|
447
|
+
request(notificationOptions, function (error, response, body) {
|
|
448
|
+
response.statusCode.should.equal(200);
|
|
449
|
+
contextBrokerMock.done();
|
|
450
|
+
done();
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it('should return the transformed values', function (done) {
|
|
456
|
+
let transformedHandler = false;
|
|
457
|
+
|
|
458
|
+
function mockedHandler(device, values, callback) {
|
|
459
|
+
let latitudeFound = false;
|
|
460
|
+
let longitudeFound = false;
|
|
461
|
+
|
|
462
|
+
for (let i = 0; i < values.length; i++) {
|
|
463
|
+
if (values[i].name === 'latitude' && values[i].type === 'string' && values[i].value === '-9.6') {
|
|
464
|
+
latitudeFound = true;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (values[i].name === 'longitude' && values[i].type === 'string' && values[i].value === '12.4') {
|
|
468
|
+
longitudeFound = true;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
transformedHandler = values.length >= 2 && longitudeFound && latitudeFound;
|
|
473
|
+
callback();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
iotAgentLib.setNotificationHandler(mockedHandler);
|
|
477
|
+
|
|
478
|
+
request(options, function (error, response, body) {
|
|
479
|
+
request(notificationOptions, function (error, response, body) {
|
|
480
|
+
contextBrokerMock.done();
|
|
481
|
+
transformedHandler.should.equal(true);
|
|
482
|
+
done();
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
|
|
267
488
|
describe('When a new Group provisioning request arrives with bidirectional attributes', function () {
|
|
268
489
|
const provisionGroup = {
|
|
269
490
|
url: 'http://localhost:' + iotAgentConfig.server.port + '/iot/services',
|
|
@@ -65,7 +65,6 @@ const optionsCreationDefault = {
|
|
|
65
65
|
services: [
|
|
66
66
|
{
|
|
67
67
|
apikey: 'default-test',
|
|
68
|
-
cbroker: 'http://orion:1026',
|
|
69
68
|
entity_type: 'Device',
|
|
70
69
|
resource: '/iot/default',
|
|
71
70
|
attributes: [
|
|
@@ -90,7 +89,6 @@ const optionsCreationV2 = {
|
|
|
90
89
|
services: [
|
|
91
90
|
{
|
|
92
91
|
apikey: 'v2-test',
|
|
93
|
-
cbroker: 'http://orion:1026',
|
|
94
92
|
ngsiVersion: 'v2',
|
|
95
93
|
entity_type: 'Device',
|
|
96
94
|
resource: '/iot/v2',
|
|
@@ -117,7 +115,6 @@ const optionsCreationLD = {
|
|
|
117
115
|
services: [
|
|
118
116
|
{
|
|
119
117
|
apikey: 'ld-test',
|
|
120
|
-
cbroker: 'http://orion:1026',
|
|
121
118
|
entity_type: 'Device',
|
|
122
119
|
ngsiVersion: 'ld',
|
|
123
120
|
resource: '/iot/ld',
|
package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityJexlExpressionPlugin1.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"actionType":"update",
|
|
3
|
+
"entities":[
|
|
4
|
+
{
|
|
5
|
+
"id":"lightPseudo:id",
|
|
6
|
+
"type":"Light",
|
|
7
|
+
"pressure":{
|
|
8
|
+
"type":"Number",
|
|
9
|
+
"value":60
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id":"Ligth:mymulti",
|
|
14
|
+
"type":"myType",
|
|
15
|
+
"pressure":{
|
|
16
|
+
"type":"Number",
|
|
17
|
+
"value":90
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
package/test/unit/ngsiv2/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"subscriptionId": "51c0ac9ed714fb3b37d7d5a8",
|
|
3
|
+
"data": [
|
|
4
|
+
{
|
|
5
|
+
"location": {
|
|
6
|
+
"type": "geo:point",
|
|
7
|
+
"value": "12.4, -9.6",
|
|
8
|
+
"metadata": {
|
|
9
|
+
"qos": {
|
|
10
|
+
"type": "Number",
|
|
11
|
+
"value": 1
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"type": "TheLightType",
|
|
16
|
+
"id": "TheFirstLight"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -437,16 +437,31 @@ describe('Java expression language (JEXL) based transformations plugin', functio
|
|
|
437
437
|
const values = [
|
|
438
438
|
{
|
|
439
439
|
name: 'p',
|
|
440
|
-
type: '
|
|
441
|
-
value:
|
|
440
|
+
type: 'Number',
|
|
441
|
+
value: 1040
|
|
442
442
|
}
|
|
443
443
|
];
|
|
444
444
|
|
|
445
|
-
|
|
445
|
+
beforeEach(function () {
|
|
446
|
+
nock.cleanAll();
|
|
447
|
+
|
|
448
|
+
contextBrokerMock = nock('http://192.168.1.1:1026')
|
|
449
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
450
|
+
.matchHeader('fiware-servicepath', 'gardens')
|
|
451
|
+
.patch(
|
|
452
|
+
'/v2/entities/light1/attrs',
|
|
453
|
+
utils.readExampleFile(
|
|
454
|
+
'./test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin30.json'
|
|
455
|
+
)
|
|
456
|
+
)
|
|
457
|
+
.query({ type: 'Light' })
|
|
458
|
+
.reply(204);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
it('should ignore the expression and send the values', function (done) {
|
|
446
462
|
iotAgentLib.update('light1', 'LightError', '', values, function (error) {
|
|
447
|
-
should.exist(error);
|
|
448
|
-
|
|
449
|
-
error.code.should.equal(400);
|
|
463
|
+
should.not.exist(error);
|
|
464
|
+
contextBrokerMock.done();
|
|
450
465
|
done();
|
|
451
466
|
});
|
|
452
467
|
});
|
|
@@ -137,7 +137,7 @@ const groupCreation = {
|
|
|
137
137
|
apikey: '801230BJKL23Y9090DSFL123HJK09H324HV8732',
|
|
138
138
|
entity_type: 'TheLightType',
|
|
139
139
|
trust: '8970A9078A803H3BL98PINEQRW8342HBAMS',
|
|
140
|
-
cbHost: 'http://
|
|
140
|
+
cbHost: 'http://192.168.1.1:1026',
|
|
141
141
|
commands: [],
|
|
142
142
|
lazy: [],
|
|
143
143
|
attributes: [
|
|
@@ -187,7 +187,7 @@ describe('NGSI-v2 - Device Service: utils', function () {
|
|
|
187
187
|
// This mock does not check the payload since the aim of the test is not to verify
|
|
188
188
|
// device provisioning functionality. Appropriate verification is done in tests under
|
|
189
189
|
// provisioning folder
|
|
190
|
-
contextBrokerMock = nock('http://
|
|
190
|
+
contextBrokerMock = nock('http://192.168.1.1:1026')
|
|
191
191
|
.matchHeader('fiware-service', 'testservice')
|
|
192
192
|
.matchHeader('fiware-servicepath', '/testingPath')
|
|
193
193
|
.post('/v2/entities?options=upsert')
|
|
@@ -217,7 +217,7 @@ describe('NGSI-v2 - Device Service: utils', function () {
|
|
|
217
217
|
// This mock does not check the payload since the aim of the test is not to verify
|
|
218
218
|
// device provisioning functionality. Appropriate verification is done in tests under
|
|
219
219
|
// provisioning folder
|
|
220
|
-
contextBrokerMock = nock('http://
|
|
220
|
+
contextBrokerMock = nock('http://192.168.1.1:1026')
|
|
221
221
|
.matchHeader('fiware-service', 'testservice')
|
|
222
222
|
.matchHeader('fiware-servicepath', '/testingPath')
|
|
223
223
|
.post('/v2/entities?options=upsert')
|
|
@@ -229,32 +229,34 @@ describe('NGSI-v2 - Device Service: utils', function () {
|
|
|
229
229
|
});
|
|
230
230
|
|
|
231
231
|
it('should register the device and return it', function (done) {
|
|
232
|
-
iotAgentLib.retrieveDevice(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
232
|
+
iotAgentLib.retrieveDevice(
|
|
233
|
+
'UNEXISTENT_DEV',
|
|
234
|
+
'801230BJKL23Y9090DSFL123HJK09H324HV8732',
|
|
235
|
+
function (error, device) {
|
|
236
|
+
should.not.exist(error);
|
|
237
|
+
should.exist(device);
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
239
|
+
device.id.should.equal('UNEXISTENT_DEV');
|
|
240
|
+
should.exist(device.protocol);
|
|
241
|
+
device.protocol.should.equal('MQTT_UL');
|
|
242
|
+
done();
|
|
243
|
+
}
|
|
244
|
+
);
|
|
244
245
|
});
|
|
245
246
|
});
|
|
246
247
|
|
|
247
248
|
describe('When an unexisting device tries to be retrieved for an unexisting APIKey', function () {
|
|
248
249
|
it('should raise an error', function (done) {
|
|
249
|
-
iotAgentLib.retrieveDevice(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
250
|
+
iotAgentLib.retrieveDevice(
|
|
251
|
+
'UNEXISTENT_DEV_AND_GROUP',
|
|
252
|
+
'H2332Y909DSF3H346yh20JK092',
|
|
253
|
+
function (error, device) {
|
|
254
|
+
should.exist(error);
|
|
255
|
+
error.name.should.equal('DEVICE_GROUP_NOT_FOUND');
|
|
256
|
+
should.not.exist(device);
|
|
257
|
+
done();
|
|
258
|
+
}
|
|
259
|
+
);
|
|
258
260
|
});
|
|
259
261
|
});
|
|
260
262
|
});
|
|
@@ -311,4 +311,110 @@ describe('NGSI-v2 - Command functionalities', function () {
|
|
|
311
311
|
});
|
|
312
312
|
});
|
|
313
313
|
});
|
|
314
|
+
|
|
315
|
+
describe('When a command update with metadata arrives to the IoT Agent as Context Provider', function () {
|
|
316
|
+
const options = {
|
|
317
|
+
url: 'http://localhost:' + iotAgentConfig.server.port + '/v2/op/update',
|
|
318
|
+
method: 'POST',
|
|
319
|
+
json: {
|
|
320
|
+
actionType: 'update',
|
|
321
|
+
entities: [
|
|
322
|
+
{
|
|
323
|
+
id: 'Robot:r2d2',
|
|
324
|
+
type: 'Robot',
|
|
325
|
+
position: {
|
|
326
|
+
type: 'Array',
|
|
327
|
+
value: '[28, -104, 23]',
|
|
328
|
+
metadata: {
|
|
329
|
+
qos: 1
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
headers: {
|
|
336
|
+
'fiware-service': 'smartgondor',
|
|
337
|
+
'fiware-servicepath': 'gardens'
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
beforeEach(function (done) {
|
|
342
|
+
iotAgentLib.register(device3, function (error) {
|
|
343
|
+
done();
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('should call the client handler once including metadata', function (done) {
|
|
348
|
+
let handlerCalled = 0;
|
|
349
|
+
|
|
350
|
+
iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
|
|
351
|
+
id.should.equal(device3.type + ':' + device3.id);
|
|
352
|
+
type.should.equal(device3.type);
|
|
353
|
+
attributes[0].name.should.equal('position');
|
|
354
|
+
attributes[0].value.should.equal('[28, -104, 23]');
|
|
355
|
+
attributes[0].metadata.qos.should.equal(1);
|
|
356
|
+
handlerCalled++;
|
|
357
|
+
callback(null, {
|
|
358
|
+
id,
|
|
359
|
+
type,
|
|
360
|
+
attributes: [
|
|
361
|
+
{
|
|
362
|
+
name: 'position',
|
|
363
|
+
type: 'Array',
|
|
364
|
+
value: '[28, -104, 23]'
|
|
365
|
+
}
|
|
366
|
+
]
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
request(options, function (error, response, body) {
|
|
371
|
+
should.not.exist(error);
|
|
372
|
+
handlerCalled.should.equal(1);
|
|
373
|
+
done();
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
|
|
377
|
+
iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
|
|
378
|
+
callback(null, {
|
|
379
|
+
id,
|
|
380
|
+
type,
|
|
381
|
+
attributes: [
|
|
382
|
+
{
|
|
383
|
+
name: 'position',
|
|
384
|
+
type: 'Array',
|
|
385
|
+
value: '[28, -104, 23]'
|
|
386
|
+
}
|
|
387
|
+
]
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
request(options, function (error, response, body) {
|
|
392
|
+
should.not.exist(error);
|
|
393
|
+
done();
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
|
|
397
|
+
let serviceAndSubservice = false;
|
|
398
|
+
|
|
399
|
+
iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
|
|
400
|
+
serviceAndSubservice = service === 'smartgondor' && subservice === 'gardens';
|
|
401
|
+
callback(null, {
|
|
402
|
+
id,
|
|
403
|
+
type,
|
|
404
|
+
attributes: [
|
|
405
|
+
{
|
|
406
|
+
name: 'position',
|
|
407
|
+
type: 'Array',
|
|
408
|
+
value: '[28, -104, 23]'
|
|
409
|
+
}
|
|
410
|
+
]
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
request(options, function (error, response, body) {
|
|
415
|
+
serviceAndSubservice.should.equal(true);
|
|
416
|
+
done();
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
});
|
|
314
420
|
});
|