iotagent-node-lib 3.1.0 → 3.2.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/CHANGES_NEXT_RELEASE +0 -2
- package/config.js +5 -5
- package/doc/api.md +1540 -298
- package/doc/deprecated.md +3 -1
- package/doc/development.md +120 -0
- package/doc/installationguide.md +3 -6
- package/lib/commonConfig.js +7 -10
- package/lib/fiware-iotagent-lib.js +0 -10
- package/lib/jexlTranformsMap.js +2 -1
- package/lib/plugins/bidirectionalData.js +8 -26
- package/lib/plugins/expressionPlugin.js +8 -40
- package/lib/plugins/jexlParser.js +28 -0
- package/lib/services/commands/commandService.js +1 -1
- package/lib/services/devices/deviceService.js +2 -1
- package/lib/services/ngsi/entities-NGSI-LD.js +13 -57
- package/lib/services/ngsi/entities-NGSI-v2.js +145 -108
- package/lib/services/northBound/deviceProvisioningServer.js +17 -14
- package/lib/templates/createDevice.json +5 -2
- package/lib/templates/createDeviceLax.json +7 -5
- package/lib/templates/updateDevice.json +5 -2
- package/lib/templates/updateDeviceLax.json +3 -5
- package/package.json +1 -1
- package/test/unit/examples/deviceProvisioningRequests/provisionBidirectionalDevice.json +5 -5
- package/test/unit/examples/deviceProvisioningRequests/provisionMinimumDevice4.json +1 -0
- package/test/unit/examples/groupProvisioningRequests/bidirectionalGroup.json +4 -4
- package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +0 -2
- package/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +8 -8
- package/test/unit/ngsi-ld/plugins/custom-plugin_test.js +152 -0
- package/test/unit/ngsi-ld/plugins/multientity-plugin_test.js +1 -1
- package/test/unit/ngsiv2/examples/contextRequests/createMinimumProvisionedDevice4.json +5 -1
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin31.json +0 -8
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +20 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin40.json +42 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +32 -0
- package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +37 -0
- package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +228 -6
- package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +1 -2
- package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +6 -6
- package/test/unit/ngsiv2/plugins/custom-plugin_test.js +151 -0
- package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +85 -12
- package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +11 -3
- package/doc/advanced-topics.md +0 -626
- package/doc/expressionLanguage.md +0 -762
- package/lib/plugins/expressionParser.js +0 -205
- package/test/unit/expressions/expression-test.js +0 -197
- package/test/unit/ngsi-ld/expressions/expressionBasedTransformations-test.js +0 -882
- package/test/unit/ngsiv2/expressions/expressionBasedTransformations-test.js +0 -951
- package/test/unit/ngsiv2/expressions/expressionCombinedTransformations-test.js +0 -296
|
@@ -39,7 +39,6 @@ const iotAgentConfig = {
|
|
|
39
39
|
port: '1026',
|
|
40
40
|
ngsiVersion: 'v2'
|
|
41
41
|
},
|
|
42
|
-
defaultExpressionLanguage: 'jexl',
|
|
43
42
|
server: {
|
|
44
43
|
port: 4041,
|
|
45
44
|
host: 'localhost'
|
|
@@ -126,7 +125,7 @@ const iotAgentConfig = {
|
|
|
126
125
|
{
|
|
127
126
|
name: 'weather',
|
|
128
127
|
type: 'Summary',
|
|
129
|
-
expression: '"Humidity " + (humidity / 2) + " and pressure " + (
|
|
128
|
+
expression: '"Humidity " + (humidity / 2) + " and pressure " + (p * 20)'
|
|
130
129
|
},
|
|
131
130
|
{
|
|
132
131
|
object_id: 'a',
|
|
@@ -250,6 +249,24 @@ const iotAgentConfig = {
|
|
|
250
249
|
],
|
|
251
250
|
explicitAttrs: true
|
|
252
251
|
},
|
|
252
|
+
GPS2b: {
|
|
253
|
+
commands: [],
|
|
254
|
+
type: 'GPS',
|
|
255
|
+
lazy: [],
|
|
256
|
+
active: [
|
|
257
|
+
{
|
|
258
|
+
name: 'location',
|
|
259
|
+
type: 'geo:json',
|
|
260
|
+
expression: "{coordinates: [lon,lat], type: 'Point'}"
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: 'temperature',
|
|
264
|
+
type: 'Number',
|
|
265
|
+
expression: 't * 10'
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
explicitAttrs: true
|
|
269
|
+
},
|
|
253
270
|
GPS3: {
|
|
254
271
|
commands: [],
|
|
255
272
|
type: 'GPS',
|
|
@@ -321,8 +338,31 @@ const iotAgentConfig = {
|
|
|
321
338
|
}
|
|
322
339
|
],
|
|
323
340
|
explicitAttrs: "theLocation ? ['mylocation'] : []"
|
|
324
|
-
|
|
325
|
-
|
|
341
|
+
},
|
|
342
|
+
GPS5b: {
|
|
343
|
+
commands: [],
|
|
344
|
+
type: 'GPS',
|
|
345
|
+
lazy: [],
|
|
346
|
+
static: [
|
|
347
|
+
{
|
|
348
|
+
name: 'lat',
|
|
349
|
+
type: 'string',
|
|
350
|
+
value: '52'
|
|
351
|
+
}
|
|
352
|
+
],
|
|
353
|
+
active: [
|
|
354
|
+
{
|
|
355
|
+
name: 'price',
|
|
356
|
+
type: 'number'
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
object_id: 'theLocation',
|
|
360
|
+
name: 'mylocation',
|
|
361
|
+
type: 'geo:json',
|
|
362
|
+
expression: "{coordinates: [lon,lat], type: 'Point'}"
|
|
363
|
+
}
|
|
364
|
+
],
|
|
365
|
+
explicitAttrs: "theLocation ? [{object_id: 'theLocation'}] : []"
|
|
326
366
|
},
|
|
327
367
|
GPS6: {
|
|
328
368
|
commands: [],
|
|
@@ -388,7 +428,6 @@ const iotAgentConfigTS = {
|
|
|
388
428
|
port: '1026',
|
|
389
429
|
ngsiVersion: 'v2'
|
|
390
430
|
},
|
|
391
|
-
defaultExpressionLanguage: 'jexl',
|
|
392
431
|
server: {
|
|
393
432
|
port: 4041,
|
|
394
433
|
host: 'localhost'
|
|
@@ -406,6 +445,57 @@ const iotAgentConfigTS = {
|
|
|
406
445
|
}
|
|
407
446
|
],
|
|
408
447
|
explicitAttrs: true
|
|
448
|
+
},
|
|
449
|
+
WaterTank: {
|
|
450
|
+
commands: [],
|
|
451
|
+
type: 'WaterTank',
|
|
452
|
+
lazy: [],
|
|
453
|
+
active: [
|
|
454
|
+
{
|
|
455
|
+
object_id: 'cnt2',
|
|
456
|
+
name: 'contA',
|
|
457
|
+
type: 'Number'
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
object_id: 'cnt3',
|
|
461
|
+
name: 'contB',
|
|
462
|
+
type: 'Number'
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
object_id: 'false2',
|
|
466
|
+
name: 'waterLeavingTanks',
|
|
467
|
+
type: 'Number',
|
|
468
|
+
expression: 'cnt2*0.1',
|
|
469
|
+
entity_name: 'PA_A_0001',
|
|
470
|
+
entity_type: 'WaterTank'
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
object_id: 'false3',
|
|
474
|
+
name: 'waterLeavingTanks',
|
|
475
|
+
type: 'Number',
|
|
476
|
+
expression: 'cnt3*0.1',
|
|
477
|
+
entity_name: 'PA_B_0001',
|
|
478
|
+
entity_type: 'WaterTank'
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
object_id: 'foostatus2',
|
|
482
|
+
name: 'status',
|
|
483
|
+
type: 'Text',
|
|
484
|
+
expression: 'status',
|
|
485
|
+
entity_name: 'PA_A_0001',
|
|
486
|
+
entity_type: 'WaterTank'
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
object_id: 'foostatus3',
|
|
490
|
+
name: 'status',
|
|
491
|
+
type: 'Text',
|
|
492
|
+
expression: 'status',
|
|
493
|
+
entity_name: 'PA_B_0001',
|
|
494
|
+
entity_type: 'WaterTank'
|
|
495
|
+
}
|
|
496
|
+
],
|
|
497
|
+
explicitAttrs:
|
|
498
|
+
"contA&&contB?['TimeInstant','contA',{object_id:'false2'},'contB',{object_id:'false3'},'status']:contA?['TimeInstant','contA',{object_id:'false2'},{object_id:'foostatus2'}]:contB?['TimeInstant','contB',{object_id:'false3'},{object_id:'foostatus3'}]:[]"
|
|
409
499
|
}
|
|
410
500
|
},
|
|
411
501
|
timestamp: true,
|
|
@@ -1080,7 +1170,7 @@ describe('Java expression language (JEXL) based transformations plugin', functio
|
|
|
1080
1170
|
.patch(
|
|
1081
1171
|
'/v2/entities/gps1/attrs',
|
|
1082
1172
|
utils.readExampleFile(
|
|
1083
|
-
'./test/unit/ngsiv2/examples/contextRequests/
|
|
1173
|
+
'./test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json'
|
|
1084
1174
|
)
|
|
1085
1175
|
)
|
|
1086
1176
|
.query({ type: 'GPS' })
|
|
@@ -1096,6 +1186,56 @@ describe('Java expression language (JEXL) based transformations plugin', functio
|
|
|
1096
1186
|
});
|
|
1097
1187
|
});
|
|
1098
1188
|
|
|
1189
|
+
describe('When there is an extra measure sent by the device to be removed', function () {
|
|
1190
|
+
// Case: Expression which results is sent as a new attribute
|
|
1191
|
+
const values = [
|
|
1192
|
+
{
|
|
1193
|
+
name: 'lat',
|
|
1194
|
+
type: 'Number',
|
|
1195
|
+
value: 52
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
name: 'lon',
|
|
1199
|
+
type: 'Number',
|
|
1200
|
+
value: 13
|
|
1201
|
+
},
|
|
1202
|
+
{
|
|
1203
|
+
name: 'another',
|
|
1204
|
+
type: 'Number',
|
|
1205
|
+
value: 99
|
|
1206
|
+
},
|
|
1207
|
+
{
|
|
1208
|
+
name: 'TimeInstant',
|
|
1209
|
+
type: 'DateTime',
|
|
1210
|
+
value: '2015-08-05T07:35:01.468+00:00'
|
|
1211
|
+
}
|
|
1212
|
+
];
|
|
1213
|
+
|
|
1214
|
+
beforeEach(function () {
|
|
1215
|
+
nock.cleanAll();
|
|
1216
|
+
|
|
1217
|
+
contextBrokerMock = nock('http://192.168.1.1:1026')
|
|
1218
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
1219
|
+
.matchHeader('fiware-servicepath', 'gardens')
|
|
1220
|
+
.patch(
|
|
1221
|
+
'/v2/entities/gps1/attrs',
|
|
1222
|
+
utils.readExampleFile(
|
|
1223
|
+
'./test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json'
|
|
1224
|
+
)
|
|
1225
|
+
)
|
|
1226
|
+
.query({ type: 'GPS' })
|
|
1227
|
+
.reply(204);
|
|
1228
|
+
});
|
|
1229
|
+
|
|
1230
|
+
it('should calculate them and remove non-explicitAttrs from the payload', function (done) {
|
|
1231
|
+
iotAgentLib.update('gps1', 'GPS2b', '', values, function (error) {
|
|
1232
|
+
should.not.exist(error);
|
|
1233
|
+
contextBrokerMock.done();
|
|
1234
|
+
done();
|
|
1235
|
+
});
|
|
1236
|
+
});
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1099
1239
|
describe('When there is an extra TimeInstant sent by the device to be removed by string', function () {
|
|
1100
1240
|
// Case: Expression which results is sent as a new attribute
|
|
1101
1241
|
const values = [
|
|
@@ -1236,6 +1376,46 @@ describe('Java expression language (JEXL) based transformations plugin', functio
|
|
|
1236
1376
|
});
|
|
1237
1377
|
});
|
|
1238
1378
|
|
|
1379
|
+
describe('When there is an extra TimeInstant sent by the device to be removed by jexl expression with context defined with object_id', function () {
|
|
1380
|
+
// Case: Expression which results is sent as a new attribute
|
|
1381
|
+
const values = [
|
|
1382
|
+
{
|
|
1383
|
+
name: 'lon',
|
|
1384
|
+
type: 'Number',
|
|
1385
|
+
value: 13
|
|
1386
|
+
},
|
|
1387
|
+
{
|
|
1388
|
+
name: 'TimeInstant',
|
|
1389
|
+
type: 'DateTime',
|
|
1390
|
+
value: '2015-08-05T07:35:01.468+00:00'
|
|
1391
|
+
}
|
|
1392
|
+
];
|
|
1393
|
+
|
|
1394
|
+
beforeEach(function () {
|
|
1395
|
+
nock.cleanAll();
|
|
1396
|
+
|
|
1397
|
+
contextBrokerMock = nock('http://192.168.1.1:1026')
|
|
1398
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
1399
|
+
.matchHeader('fiware-servicepath', 'gardens')
|
|
1400
|
+
.patch(
|
|
1401
|
+
'/v2/entities/gps1/attrs',
|
|
1402
|
+
utils.readExampleFile(
|
|
1403
|
+
'./test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json'
|
|
1404
|
+
)
|
|
1405
|
+
)
|
|
1406
|
+
.query({ type: 'GPS' })
|
|
1407
|
+
.reply(204);
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1410
|
+
it('should calculate them and remove non-explicitAttrs by jexl expression with context from the payload ', function (done) {
|
|
1411
|
+
iotAgentLib.update('gps1', 'GPS5b', '', values, function (error) {
|
|
1412
|
+
should.not.exist(error);
|
|
1413
|
+
contextBrokerMock.done();
|
|
1414
|
+
done();
|
|
1415
|
+
});
|
|
1416
|
+
});
|
|
1417
|
+
});
|
|
1418
|
+
|
|
1239
1419
|
describe('When there is an extra TimeInstant sent by the device to be removedb jexl expression using static attrs', function () {
|
|
1240
1420
|
// Case: Expression which results is sent as a new attribute
|
|
1241
1421
|
const values = [
|
|
@@ -1378,4 +1558,46 @@ describe('Java expression language (JEXL) based transformations plugin - Timesta
|
|
|
1378
1558
|
});
|
|
1379
1559
|
});
|
|
1380
1560
|
});
|
|
1561
|
+
|
|
1562
|
+
describe('When explicitAttrs is a jexl expression in a multientity case', function () {
|
|
1563
|
+
// Case: Expression which results is sent as a new attribute
|
|
1564
|
+
const values = [
|
|
1565
|
+
{
|
|
1566
|
+
name: 'cnt3',
|
|
1567
|
+
type: 'Number',
|
|
1568
|
+
value: '31450.000'
|
|
1569
|
+
}
|
|
1570
|
+
];
|
|
1571
|
+
|
|
1572
|
+
beforeEach(function () {
|
|
1573
|
+
const time = new Date(1438760101468); // 2015-08-05T07:35:01.468+00:00
|
|
1574
|
+
|
|
1575
|
+
timekeeper.freeze(time);
|
|
1576
|
+
nock.cleanAll();
|
|
1577
|
+
|
|
1578
|
+
contextBrokerMock = nock('http://192.168.1.1:1026')
|
|
1579
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
1580
|
+
.matchHeader('fiware-servicepath', 'gardens')
|
|
1581
|
+
.post(
|
|
1582
|
+
'/v2/op/update',
|
|
1583
|
+
utils.readExampleFile(
|
|
1584
|
+
'./test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin40.json'
|
|
1585
|
+
)
|
|
1586
|
+
)
|
|
1587
|
+
.reply(204);
|
|
1588
|
+
});
|
|
1589
|
+
|
|
1590
|
+
afterEach(function (done) {
|
|
1591
|
+
timekeeper.reset();
|
|
1592
|
+
done();
|
|
1593
|
+
});
|
|
1594
|
+
|
|
1595
|
+
it('should calculate them and not remove the timestamp from the payload', function (done) {
|
|
1596
|
+
iotAgentLib.update('water1', 'WaterTank', '', values, function (error) {
|
|
1597
|
+
should.not.exist(error);
|
|
1598
|
+
contextBrokerMock.done();
|
|
1599
|
+
done();
|
|
1600
|
+
});
|
|
1601
|
+
});
|
|
1602
|
+
});
|
|
1381
1603
|
});
|
|
@@ -246,11 +246,11 @@ describe('NGSI-v2 - Bidirectional data plugin', function () {
|
|
|
246
246
|
let longitudeFound = false;
|
|
247
247
|
|
|
248
248
|
for (let i = 0; i < values.length; i++) {
|
|
249
|
-
if (values[i].name === 'latitude' && values[i].type === '
|
|
249
|
+
if (values[i].name === 'latitude' && values[i].type === 'Number' && values[i].value === -9.6) {
|
|
250
250
|
latitudeFound = true;
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
if (values[i].name === 'longitude' && values[i].type === '
|
|
253
|
+
if (values[i].name === 'longitude' && values[i].type === 'Number' && values[i].value === 12.4) {
|
|
254
254
|
longitudeFound = true;
|
|
255
255
|
}
|
|
256
256
|
}
|
|
@@ -357,11 +357,11 @@ describe('NGSI-v2 - Bidirectional data plugin', function () {
|
|
|
357
357
|
let longitudeFound = false;
|
|
358
358
|
|
|
359
359
|
for (let i = 0; i < values.length; i++) {
|
|
360
|
-
if (values[i].name === 'latitude' && values[i].type === '
|
|
360
|
+
if (values[i].name === 'latitude' && values[i].type === 'Number' && values[i].value === -9.6) {
|
|
361
361
|
latitudeFound = true;
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
-
if (values[i].name === 'longitude' && values[i].type === '
|
|
364
|
+
if (values[i].name === 'longitude' && values[i].type === 'Number' && values[i].value === 12.4) {
|
|
365
365
|
longitudeFound = true;
|
|
366
366
|
}
|
|
367
367
|
}
|
|
@@ -503,11 +503,11 @@ describe('NGSI-v2 - Bidirectional data plugin', function () {
|
|
|
503
503
|
let longitudeFound = false;
|
|
504
504
|
|
|
505
505
|
for (let i = 0; i < values.length; i++) {
|
|
506
|
-
if (values[i].name === 'latitude' && values[i].type === '
|
|
506
|
+
if (values[i].name === 'latitude' && values[i].type === 'Number' && values[i].value === -9.6) {
|
|
507
507
|
latitudeFound = true;
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
-
if (values[i].name === 'longitude' && values[i].type === '
|
|
510
|
+
if (values[i].name === 'longitude' && values[i].type === 'Number' && values[i].value === 12.4) {
|
|
511
511
|
longitudeFound = true;
|
|
512
512
|
}
|
|
513
513
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2015 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: Daniel Calvo - ATOS Research & Innovation
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const iotAgentLib = require('../../../../lib/fiware-iotagent-lib');
|
|
27
|
+
const should = require('should');
|
|
28
|
+
const logger = require('logops');
|
|
29
|
+
const nock = require('nock');
|
|
30
|
+
let contextBrokerMock;
|
|
31
|
+
const iotAgentConfig = {
|
|
32
|
+
contextBroker: {
|
|
33
|
+
host: '192.168.1.1',
|
|
34
|
+
port: '1026',
|
|
35
|
+
ngsiVersion: 'v2'
|
|
36
|
+
},
|
|
37
|
+
server: {
|
|
38
|
+
port: 4041
|
|
39
|
+
},
|
|
40
|
+
types: {
|
|
41
|
+
Light: {
|
|
42
|
+
commands: [],
|
|
43
|
+
type: 'Light',
|
|
44
|
+
lazy: [
|
|
45
|
+
{
|
|
46
|
+
name: 'temperature',
|
|
47
|
+
type: 'centigrades'
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
active: [
|
|
51
|
+
{
|
|
52
|
+
name: 'pressure',
|
|
53
|
+
type: 'Hgmm'
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
service: 'smartgondor',
|
|
59
|
+
subservice: 'gardens',
|
|
60
|
+
providerUrl: 'http://smartgondor.com'
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
describe('NGSI-v2 - Custom plugin', function () {
|
|
64
|
+
let updateInvoked = false;
|
|
65
|
+
let queryInvoked = false;
|
|
66
|
+
|
|
67
|
+
function updatePlugin(entity, typeInformation, callback) {
|
|
68
|
+
updateInvoked = true;
|
|
69
|
+
return callback(null, entity, typeInformation);
|
|
70
|
+
}
|
|
71
|
+
function queryPlugin(entity, typeInformation, callback) {
|
|
72
|
+
queryInvoked = true;
|
|
73
|
+
return callback(null, entity, typeInformation);
|
|
74
|
+
}
|
|
75
|
+
beforeEach(function (done) {
|
|
76
|
+
logger.setLevel('FATAL');
|
|
77
|
+
|
|
78
|
+
iotAgentLib.activate(iotAgentConfig, function () {
|
|
79
|
+
iotAgentLib.clearAll(function () {
|
|
80
|
+
iotAgentLib.addUpdateMiddleware(updatePlugin);
|
|
81
|
+
iotAgentLib.addQueryMiddleware(queryPlugin);
|
|
82
|
+
done();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
afterEach(function (done) {
|
|
88
|
+
iotAgentLib.clearAll(function () {
|
|
89
|
+
iotAgentLib.deactivate(done);
|
|
90
|
+
updateInvoked = false;
|
|
91
|
+
queryInvoked = false;
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('When an update occurs', function () {
|
|
95
|
+
const values = [
|
|
96
|
+
{
|
|
97
|
+
name: 'state',
|
|
98
|
+
type: 'Boolean',
|
|
99
|
+
value: 'true'
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'dimming',
|
|
103
|
+
type: 'Number',
|
|
104
|
+
value: 23
|
|
105
|
+
}
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
beforeEach(function () {
|
|
109
|
+
nock.cleanAll();
|
|
110
|
+
|
|
111
|
+
contextBrokerMock = nock('http://192.168.1.1:1026')
|
|
112
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
113
|
+
.matchHeader('fiware-servicepath', 'gardens')
|
|
114
|
+
.patch('/v2/entities/light1/attrs')
|
|
115
|
+
.query({ type: 'Light' })
|
|
116
|
+
.reply(204);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should invoke the plugin', function (done) {
|
|
120
|
+
iotAgentLib.update('light1', 'Light', '', values, function (error) {
|
|
121
|
+
should.not.exist(error);
|
|
122
|
+
contextBrokerMock.done();
|
|
123
|
+
updateInvoked.should.equal(true);
|
|
124
|
+
done();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe('When an query occurs', function () {
|
|
129
|
+
beforeEach(function () {
|
|
130
|
+
nock.cleanAll();
|
|
131
|
+
|
|
132
|
+
contextBrokerMock = nock('http://192.168.1.1:1026')
|
|
133
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
134
|
+
.matchHeader('fiware-servicepath', 'gardens')
|
|
135
|
+
.get('/v2/entities/light1/attrs')
|
|
136
|
+
.query({ type: 'Light', attrs: 'state,dimming' })
|
|
137
|
+
.reply(200, { state: 'good', dimming: '23' });
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should invoke the plugin', function (done) {
|
|
141
|
+
const attributes = ['state', 'dimming'];
|
|
142
|
+
iotAgentLib.query('light1', 'Light', '', attributes, function (error) {
|
|
143
|
+
should.not.exist(error);
|
|
144
|
+
contextBrokerMock.done();
|
|
145
|
+
should.not.exist(error);
|
|
146
|
+
queryInvoked.should.equal(true);
|
|
147
|
+
done();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
@@ -102,7 +102,7 @@ const iotAgentConfig = {
|
|
|
102
102
|
object_id: 'h',
|
|
103
103
|
name: 'humidity',
|
|
104
104
|
type: 'Percentage',
|
|
105
|
-
entity_name: 'Station Number
|
|
105
|
+
entity_name: '"Station Number "+sn*10'
|
|
106
106
|
}
|
|
107
107
|
]
|
|
108
108
|
},
|
|
@@ -115,13 +115,13 @@ const iotAgentConfig = {
|
|
|
115
115
|
object_id: 'p',
|
|
116
116
|
name: 'pressure',
|
|
117
117
|
type: 'Hgmm',
|
|
118
|
-
entity_name: 'Station Number
|
|
118
|
+
entity_name: '"Station Number "+sn*10'
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
object_id: 'h',
|
|
122
122
|
name: 'humidity',
|
|
123
123
|
type: 'Percentage',
|
|
124
|
-
entity_name: 'Station Number
|
|
124
|
+
entity_name: '"Station Number "+sn*10'
|
|
125
125
|
}
|
|
126
126
|
]
|
|
127
127
|
},
|
|
@@ -197,21 +197,21 @@ const iotAgentConfig = {
|
|
|
197
197
|
{
|
|
198
198
|
object_id: 'v1',
|
|
199
199
|
name: 'vol',
|
|
200
|
-
expression: '
|
|
200
|
+
expression: 'v1*100',
|
|
201
201
|
type: 'Number',
|
|
202
202
|
entity_name: 'WeatherStation1'
|
|
203
203
|
},
|
|
204
204
|
{
|
|
205
205
|
object_id: 'v2',
|
|
206
206
|
name: 'vol',
|
|
207
|
-
expression: '
|
|
207
|
+
expression: 'v2*100',
|
|
208
208
|
type: 'Number',
|
|
209
209
|
entity_name: 'WeatherStation2'
|
|
210
210
|
},
|
|
211
211
|
{
|
|
212
212
|
object_id: 'v',
|
|
213
213
|
name: 'vol',
|
|
214
|
-
expression: '
|
|
214
|
+
expression: 'v*100',
|
|
215
215
|
type: 'Number'
|
|
216
216
|
}
|
|
217
217
|
]
|
|
@@ -244,7 +244,6 @@ const iotAgentConfig = {
|
|
|
244
244
|
WeatherStation8Jexl: {
|
|
245
245
|
commands: [],
|
|
246
246
|
type: 'WeatherStation',
|
|
247
|
-
expressionLanguage: 'jexl',
|
|
248
247
|
lazy: [],
|
|
249
248
|
active: [
|
|
250
249
|
{
|
|
@@ -272,7 +271,6 @@ const iotAgentConfig = {
|
|
|
272
271
|
WeatherStation9Jexl: {
|
|
273
272
|
commands: [],
|
|
274
273
|
type: 'WeatherStation',
|
|
275
|
-
expressionLanguage: 'jexl',
|
|
276
274
|
lazy: [],
|
|
277
275
|
static: [
|
|
278
276
|
{
|
|
@@ -364,7 +362,6 @@ const iotAgentConfig = {
|
|
|
364
362
|
WrongStation: {
|
|
365
363
|
commands: [],
|
|
366
364
|
type: 'WrongStation',
|
|
367
|
-
expressionLanguage: 'jexl',
|
|
368
365
|
lazy: [],
|
|
369
366
|
active: [
|
|
370
367
|
{
|
|
@@ -456,7 +453,6 @@ const iotAgentConfig = {
|
|
|
456
453
|
SharedIds3: {
|
|
457
454
|
commands: [],
|
|
458
455
|
type: 'ShareStation',
|
|
459
|
-
expressionLanguage: 'jexl',
|
|
460
456
|
lazy: [],
|
|
461
457
|
active: [
|
|
462
458
|
{
|
|
@@ -510,6 +506,42 @@ const iotAgentConfig = {
|
|
|
510
506
|
],
|
|
511
507
|
explicitAttrs: true
|
|
512
508
|
},
|
|
509
|
+
GPS1: {
|
|
510
|
+
commands: [],
|
|
511
|
+
expressionLanguage: 'jexl',
|
|
512
|
+
type: 'GPS',
|
|
513
|
+
lazy: [],
|
|
514
|
+
active: [
|
|
515
|
+
{
|
|
516
|
+
name: 'explicit',
|
|
517
|
+
type: 'number',
|
|
518
|
+
object_id: 'z'
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
name: 'expectedAtt',
|
|
522
|
+
type: 'number',
|
|
523
|
+
expression: 'z+1'
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
name: 'nonexpectedAtt',
|
|
527
|
+
type: 'number',
|
|
528
|
+
expression: 'w+1'
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
name: 'explicit',
|
|
532
|
+
type: 'number',
|
|
533
|
+
entity_name: 'SO5',
|
|
534
|
+
object_id: 'x'
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
name: 'explicit',
|
|
538
|
+
type: 'number',
|
|
539
|
+
entity_name: 'SO6',
|
|
540
|
+
object_id: 'y'
|
|
541
|
+
}
|
|
542
|
+
],
|
|
543
|
+
explicitAttrs: true
|
|
544
|
+
},
|
|
513
545
|
GPS2: {
|
|
514
546
|
commands: [],
|
|
515
547
|
type: 'GPS',
|
|
@@ -559,8 +591,7 @@ const iotAgentConfig = {
|
|
|
559
591
|
name: 'pressure',
|
|
560
592
|
type: 'Number'
|
|
561
593
|
}
|
|
562
|
-
]
|
|
563
|
-
expressionLanguage: 'jexl'
|
|
594
|
+
]
|
|
564
595
|
}
|
|
565
596
|
},
|
|
566
597
|
service: 'smartgondor',
|
|
@@ -1244,6 +1275,48 @@ describe('NGSI-v2 - Multi-entity plugin', function () {
|
|
|
1244
1275
|
});
|
|
1245
1276
|
});
|
|
1246
1277
|
|
|
1278
|
+
describe('When an update comes for a multientity measurement explicitAttrs for several entities', function () {
|
|
1279
|
+
const values = [
|
|
1280
|
+
{
|
|
1281
|
+
name: 'x',
|
|
1282
|
+
type: 'Number',
|
|
1283
|
+
value: 52
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
name: 'y',
|
|
1287
|
+
type: 'Number',
|
|
1288
|
+
value: 13
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
name: 'z',
|
|
1292
|
+
type: 'Number',
|
|
1293
|
+
value: 12
|
|
1294
|
+
}
|
|
1295
|
+
];
|
|
1296
|
+
|
|
1297
|
+
beforeEach(function () {
|
|
1298
|
+
nock.cleanAll();
|
|
1299
|
+
contextBrokerMock = nock('http://192.168.1.1:1026')
|
|
1300
|
+
.matchHeader('fiware-service', 'smartgondor')
|
|
1301
|
+
.matchHeader('fiware-servicepath', 'gardens')
|
|
1302
|
+
.post(
|
|
1303
|
+
'/v2/op/update',
|
|
1304
|
+
utils.readExampleFile(
|
|
1305
|
+
'./test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json'
|
|
1306
|
+
)
|
|
1307
|
+
)
|
|
1308
|
+
.reply(204);
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
it('should remove hidden attrs from the value', function (done) {
|
|
1312
|
+
iotAgentLib.update('gps1', 'GPS1', '', values, function (error) {
|
|
1313
|
+
should.not.exist(error);
|
|
1314
|
+
contextBrokerMock.done();
|
|
1315
|
+
done();
|
|
1316
|
+
});
|
|
1317
|
+
});
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1247
1320
|
describe('When an update comes for a multientity measurement explicitAttrs as jexl for one entity', function () {
|
|
1248
1321
|
const values = [
|
|
1249
1322
|
{
|