iotagent-node-lib 2.24.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.
Files changed (32) hide show
  1. package/.github/workflows/ci.yml +6 -7
  2. package/CHANGES_NEXT_RELEASE +1 -0
  3. package/doc/advanced-topics.md +23 -1
  4. package/doc/apiary/iotagent.apib +5 -5
  5. package/doc/deprecated.md +10 -7
  6. package/doc/expressionLanguage.md +44 -34
  7. package/doc/getting-started.md +1 -1
  8. package/examples/TTOpen-service.json +1 -1
  9. package/lib/fiware-iotagent-lib.js +2 -1
  10. package/lib/jexlTranformsMap.js +12 -1
  11. package/lib/plugins/jexlParser.js +2 -2
  12. package/lib/services/devices/deviceService.js +19 -1
  13. package/lib/services/devices/devices-NGSI-v2.js +3 -1
  14. package/lib/services/northBound/restUtils.js +3 -5
  15. package/lib/templates/deviceGroup.json +1 -1
  16. package/package.json +2 -2
  17. package/test/unit/examples/deviceProvisioningRequests/provisionNewDeviceEmpty.json +43 -0
  18. package/test/unit/examples/mongoCollections/configurations.json +3 -3
  19. package/test/unit/expressions/jexlExpression-test.js +29 -8
  20. package/test/unit/general/deviceService-test.js +31 -29
  21. package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +25 -24
  22. package/test/unit/mongodb/mongodb-group-registry-test.js +3 -3
  23. package/test/unit/mongodb/mongodb-registry-test.js +30 -21
  24. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin30.json +11 -0
  25. package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +18 -4
  26. package/test/unit/ngsi-ld/general/deviceService-test.js +31 -29
  27. package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +0 -3
  28. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityJexlExpressionPlugin1.json +22 -0
  29. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +21 -6
  30. package/test/unit/ngsiv2/general/deviceService-test.js +25 -23
  31. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +58 -0
  32. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +25 -6
@@ -134,7 +134,7 @@ const groupCreation = {
134
134
  apikey: '801230BJKL23Y9090DSFL123HJK09H324HV8732',
135
135
  entity_type: 'TheLightType',
136
136
  trust: '8970A9078A803H3BL98PINEQRW8342HBAMS',
137
- cbHost: 'http://unexistentHost:1026',
137
+ cbHost: 'http://192.168.1.1:1026',
138
138
  commands: [],
139
139
  lazy: [],
140
140
  attributes: [
@@ -181,7 +181,7 @@ describe('NGSI-v2 - Device Service: utils', function () {
181
181
 
182
182
  describe('When an existing device tries to be retrieved with retrieveOrCreate()', function () {
183
183
  beforeEach(function (done) {
184
- contextBrokerMock = nock('http://unexistentHost:1026')
184
+ contextBrokerMock = nock('http://192.168.1.1:1026')
185
185
  .matchHeader('fiware-service', 'testservice')
186
186
  .matchHeader('fiware-servicepath', '/testingPath')
187
187
  .post('/v2/registrations')
@@ -193,12 +193,12 @@ describe('NGSI-v2 - Device Service: utils', function () {
193
193
  .post('/v2/entities?options=upsert')
194
194
  .reply(204);
195
195
 
196
- async.series([request.bind(request, groupCreation), request.bind(request, deviceCreation)], function (
197
- error,
198
- results
199
- ) {
200
- done();
201
- });
196
+ async.series(
197
+ [request.bind(request, groupCreation), request.bind(request, deviceCreation)],
198
+ function (error, results) {
199
+ done();
200
+ }
201
+ );
202
202
  });
203
203
 
204
204
  it('should return the existing device', function (done) {
@@ -214,7 +214,7 @@ describe('NGSI-v2 - Device Service: utils', function () {
214
214
 
215
215
  describe('When an unexisting device tries to be retrieved for an existing APIKey', function () {
216
216
  beforeEach(function (done) {
217
- contextBrokerMock = nock('http://unexistentHost:1026')
217
+ contextBrokerMock = nock('http://192.168.1.1:1026')
218
218
  .matchHeader('fiware-service', 'testservice')
219
219
  .matchHeader('fiware-servicepath', '/testingPath')
220
220
  .post('/v2/registrations')
@@ -232,32 +232,34 @@ describe('NGSI-v2 - Device Service: utils', function () {
232
232
  });
233
233
 
234
234
  it('should register the device and return it', function (done) {
235
- iotAgentLib.retrieveDevice('UNEXISTENT_DEV', '801230BJKL23Y9090DSFL123HJK09H324HV8732', function (
236
- error,
237
- device
238
- ) {
239
- should.not.exist(error);
240
- should.exist(device);
235
+ iotAgentLib.retrieveDevice(
236
+ 'UNEXISTENT_DEV',
237
+ '801230BJKL23Y9090DSFL123HJK09H324HV8732',
238
+ function (error, device) {
239
+ should.not.exist(error);
240
+ should.exist(device);
241
241
 
242
- device.id.should.equal('UNEXISTENT_DEV');
243
- should.exist(device.protocol);
244
- device.protocol.should.equal('MQTT_UL');
245
- done();
246
- });
242
+ device.id.should.equal('UNEXISTENT_DEV');
243
+ should.exist(device.protocol);
244
+ device.protocol.should.equal('MQTT_UL');
245
+ done();
246
+ }
247
+ );
247
248
  });
248
249
  });
249
250
 
250
251
  describe('When an unexisting device tries to be retrieved for an unexisting APIKey', function () {
251
252
  it('should raise an error', function (done) {
252
- iotAgentLib.retrieveDevice('UNEXISTENT_DEV_AND_GROUP', 'H2332Y909DSF3H346yh20JK092', function (
253
- error,
254
- device
255
- ) {
256
- should.exist(error);
257
- error.name.should.equal('DEVICE_GROUP_NOT_FOUND');
258
- should.not.exist(device);
259
- done();
260
- });
253
+ iotAgentLib.retrieveDevice(
254
+ 'UNEXISTENT_DEV_AND_GROUP',
255
+ 'H2332Y909DSF3H346yh20JK092',
256
+ function (error, device) {
257
+ should.exist(error);
258
+ error.name.should.equal('DEVICE_GROUP_NOT_FOUND');
259
+ should.not.exist(device);
260
+ done();
261
+ }
262
+ );
261
263
  });
262
264
  });
263
265
  });
@@ -96,16 +96,19 @@ describe('NGSI-v2 - In memory device registry', function () {
96
96
  iotAgentLib.clearRegistry(done);
97
97
  });
98
98
  it('should return the appropriate device', function (done) {
99
- iotAgentLib.getDevicesByAttribute('internalId', 'internal3', 'smartgondor', 'gardens', function (
100
- error,
101
- devices
102
- ) {
103
- should.not.exist(error);
104
- should.exist(devices);
105
- devices.length.should.equal(1);
106
- devices[0].id.should.equal('id3');
107
- done();
108
- });
99
+ iotAgentLib.getDevicesByAttribute(
100
+ 'internalId',
101
+ 'internal3',
102
+ 'smartgondor',
103
+ 'gardens',
104
+ function (error, devices) {
105
+ should.not.exist(error);
106
+ should.exist(devices);
107
+ devices.length.should.equal(1);
108
+ devices[0].id.should.equal('id3');
109
+ done();
110
+ }
111
+ );
109
112
  });
110
113
  });
111
114
 
@@ -194,9 +197,9 @@ describe('NGSI-v2 - In memory device registry', function () {
194
197
  });
195
198
  });
196
199
  });
197
-
198
- describe('When a the registry is queried for device in a particular name and type', function (){
199
- beforeEach(function (done) {
200
+
201
+ describe('When a the registry is queried for device in a particular name and type', function () {
202
+ beforeEach(function (done) {
200
203
  contextBrokerMock = nock('http://192.168.1.1:1026')
201
204
  .post('/v2/entities?options=upsert')
202
205
  .times(10)
@@ -204,21 +207,21 @@ describe('NGSI-v2 - In memory device registry', function () {
204
207
 
205
208
  const devices = [];
206
209
 
207
- for (let i = 0; i < 10; i++)
208
- {
209
- devices.push(
210
- {
210
+ for (let i = 0; i < 10; i++) {
211
+ devices.push({
211
212
  id: 'id' + i,
212
- name : 'name' + i,
213
+ name: 'name' + i,
213
214
  type: 'Light' + i,
214
215
  internalId: 'internal' + i,
215
216
  service: 'smartgondor',
216
217
  subservice: 'gardens',
217
- active: [ {
218
+ active: [
219
+ {
218
220
  id: 'attrId',
219
221
  type: 'attrType' + i,
220
222
  value: i
221
- }]
223
+ }
224
+ ]
222
225
  });
223
226
  }
224
227
 
@@ -230,10 +233,8 @@ describe('NGSI-v2 - In memory device registry', function () {
230
233
  afterEach(function (done) {
231
234
  iotAgentLib.clearRegistry(done);
232
235
  });
233
- it('should return the name and type of device', function (done)
234
- {
235
- iotAgentLib.getDeviceByNameAndType('name5', 'Light5','smartgondor', 'gardens' ,function(error, device)
236
- {
236
+ it('should return the name and type of device', function (done) {
237
+ iotAgentLib.getDeviceByNameAndType('name5', 'Light5', 'smartgondor', 'gardens', function (error, device) {
237
238
  should.not.exist(error);
238
239
  should.exist(device);
239
240
  should.exist(device.name);
@@ -448,16 +448,16 @@ describe('MongoDB Group Registry test', function () {
448
448
  });
449
449
  });
450
450
  });
451
-
451
+
452
452
  describe('When the device info request with name and type', function () {
453
453
  beforeEach(function (done) {
454
454
  async.series([async.apply(request, optionsCreation)], done);
455
455
  });
456
-
456
+
457
457
  afterEach(function (done) {
458
458
  iotAgentLib.clearRegistry(done);
459
459
  });
460
-
460
+
461
461
  it('should return the name and type of device', function (done) {
462
462
  request(optionsGet, function (error, response, body) {
463
463
  should.exist(body);
@@ -440,16 +440,19 @@ describe('NGSI-v2 - MongoDB Device Registry', function () {
440
440
  iotAgentLib.clearRegistry(done);
441
441
  });
442
442
  it('should return the appropriate device', function (done) {
443
- iotAgentLib.getDevicesByAttribute('internalId', 'internal3', 'smartgondor', 'gardens', function (
444
- error,
445
- devices
446
- ) {
447
- should.not.exist(error);
448
- should.exist(devices);
449
- devices.length.should.equal(1);
450
- devices[0].id.should.equal('id3');
451
- done();
452
- });
443
+ iotAgentLib.getDevicesByAttribute(
444
+ 'internalId',
445
+ 'internal3',
446
+ 'smartgondor',
447
+ 'gardens',
448
+ function (error, devices) {
449
+ should.not.exist(error);
450
+ should.exist(devices);
451
+ devices.length.should.equal(1);
452
+ devices[0].id.should.equal('id3');
453
+ done();
454
+ }
455
+ );
453
456
  });
454
457
  });
455
458
 
@@ -507,8 +510,8 @@ describe('NGSI-v2 - MongoDB Device Registry', function () {
507
510
  });
508
511
  });
509
512
  });
510
-
511
- describe('When the device is queried with the name and type', function () {
513
+
514
+ describe('When the device is queried with the name and type', function () {
512
515
  beforeEach(function (done) {
513
516
  contextBrokerMock = nock('http://192.168.1.1:1026')
514
517
  .post('/v2/entities?options=upsert')
@@ -545,15 +548,21 @@ describe('NGSI-v2 - MongoDB Device Registry', function () {
545
548
  iotAgentLib.clearRegistry(done);
546
549
  });
547
550
  it('should return the device with name and type', function (done) {
548
- iotAgentLib.getDeviceByNameAndType('Light4:id4', 'Light4', 'smartgondor', 'gardens', function ( error, device ) {
549
- should.not.exist(error);
550
- should.exist(device);
551
- should.exist(device.name);
552
- should.exist(device.type);
553
- device.name.should.equal('Light4:id4');
554
- device.type.should.equal('Light4');
555
- done();
556
- });
551
+ iotAgentLib.getDeviceByNameAndType(
552
+ 'Light4:id4',
553
+ 'Light4',
554
+ 'smartgondor',
555
+ 'gardens',
556
+ function (error, device) {
557
+ should.not.exist(error);
558
+ should.exist(device);
559
+ should.exist(device.name);
560
+ should.exist(device.type);
561
+ device.name.should.equal('Light4:id4');
562
+ device.type.should.equal('Light4');
563
+ done();
564
+ }
565
+ );
557
566
  });
558
567
  });
559
568
  });
@@ -0,0 +1,11 @@
1
+ [
2
+ {
3
+ "@context": "http://context.json-ld",
4
+ "pressure": {
5
+ "type": "Property",
6
+ "value": 52
7
+ },
8
+ "id": "urn:ngsi-ld:Light:light1",
9
+ "type": "Light"
10
+ }
11
+ ]
@@ -321,11 +321,25 @@ describe('NGSI-LD: JEXL', function () {
321
321
  }
322
322
  ];
323
323
 
324
- it('should apply the expression before sending the values', function (done) {
324
+ beforeEach(function () {
325
+ nock.cleanAll();
326
+
327
+ contextBrokerMock = nock('http://192.168.1.1:1026')
328
+ .matchHeader('fiware-service', 'smartgondor')
329
+ .matchHeader('fiware-servicepath', 'gardens')
330
+ .post(
331
+ '/ngsi-ld/v1/entityOperations/upsert/?options=update',
332
+ utils.readExampleFile(
333
+ './test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin30.json'
334
+ )
335
+ )
336
+ .reply(204);
337
+ });
338
+
339
+ it('should ignore the expression before sending the values', function (done) {
325
340
  iotAgentLib.update('light1', 'LightError', '', values, function (error) {
326
- should.exist(error);
327
- error.name.should.equal('INVALID_EXPRESSION');
328
- error.code.should.equal(400);
341
+ should.not.exist(error);
342
+ contextBrokerMock.done();
329
343
  done();
330
344
  });
331
345
  });
@@ -137,7 +137,7 @@ const groupCreation = {
137
137
  apikey: '801230BJKL23Y9090DSFL123HJK09H324HV8732',
138
138
  entity_type: 'TheLightType',
139
139
  trust: '8970A9078A803H3BL98PINEQRW8342HBAMS',
140
- cbHost: 'http://unexistentHost:1026',
140
+ cbHost: 'http://192.168.1.1:1026',
141
141
  commands: [],
142
142
  lazy: [],
143
143
  attributes: [
@@ -187,17 +187,17 @@ describe('NGSI-LD - 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://unexistenthost:1026')
190
+ contextBrokerMock = nock('http://192.168.1.1:1026')
191
191
  .matchHeader('fiware-service', 'testservice')
192
192
  .post('/ngsi-ld/v1/entityOperations/upsert/')
193
193
  .reply(204);
194
194
 
195
- async.series([request.bind(request, groupCreation), request.bind(request, deviceCreation)], function (
196
- error,
197
- results
198
- ) {
199
- done();
200
- });
195
+ async.series(
196
+ [request.bind(request, groupCreation), request.bind(request, deviceCreation)],
197
+ function (error, results) {
198
+ done();
199
+ }
200
+ );
201
201
  });
202
202
 
203
203
  it('should return the existing device', function (done) {
@@ -216,7 +216,7 @@ describe('NGSI-LD - Device Service: utils', function () {
216
216
  // This mock does not check the payload since the aim of the test is not to verify
217
217
  // device provisioning functionality. Appropriate verification is done in tests under
218
218
  // provisioning folder
219
- contextBrokerMock = nock('http://unexistenthost:1026')
219
+ contextBrokerMock = nock('http://192.168.1.1:1026')
220
220
  .matchHeader('fiware-service', 'testservice')
221
221
  .post('/ngsi-ld/v1/entityOperations/upsert/')
222
222
  .reply(204);
@@ -227,32 +227,34 @@ describe('NGSI-LD - Device Service: utils', function () {
227
227
  });
228
228
 
229
229
  it('should register the device and return it', function (done) {
230
- iotAgentLib.retrieveDevice('UNEXISTENT_DEV', '801230BJKL23Y9090DSFL123HJK09H324HV8732', function (
231
- error,
232
- device
233
- ) {
234
- should.not.exist(error);
235
- should.exist(device);
230
+ iotAgentLib.retrieveDevice(
231
+ 'UNEXISTENT_DEV',
232
+ '801230BJKL23Y9090DSFL123HJK09H324HV8732',
233
+ function (error, device) {
234
+ should.not.exist(error);
235
+ should.exist(device);
236
236
 
237
- device.id.should.equal('UNEXISTENT_DEV');
238
- should.exist(device.protocol);
239
- device.protocol.should.equal('MQTT_UL');
240
- done();
241
- });
237
+ device.id.should.equal('UNEXISTENT_DEV');
238
+ should.exist(device.protocol);
239
+ device.protocol.should.equal('MQTT_UL');
240
+ done();
241
+ }
242
+ );
242
243
  });
243
244
  });
244
245
 
245
246
  describe('When an unexisting device tries to be retrieved for an unexisting APIKey', function () {
246
247
  it('should raise an error', function (done) {
247
- iotAgentLib.retrieveDevice('UNEXISTENT_DEV_AND_GROUP', 'H2332Y909DSF3H346yh20JK092', function (
248
- error,
249
- device
250
- ) {
251
- should.exist(error);
252
- error.name.should.equal('DEVICE_GROUP_NOT_FOUND');
253
- should.not.exist(device);
254
- done();
255
- });
248
+ iotAgentLib.retrieveDevice(
249
+ 'UNEXISTENT_DEV_AND_GROUP',
250
+ 'H2332Y909DSF3H346yh20JK092',
251
+ function (error, device) {
252
+ should.exist(error);
253
+ error.name.should.equal('DEVICE_GROUP_NOT_FOUND');
254
+ should.not.exist(device);
255
+ done();
256
+ }
257
+ );
256
258
  });
257
259
  });
258
260
  });
@@ -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',
@@ -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
+ }
@@ -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: 'centigrades',
441
- value: '52'
440
+ type: 'Number',
441
+ value: 1040
442
442
  }
443
443
  ];
444
444
 
445
- it('should apply the expression before sending the values', function (done) {
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
- error.name.should.equal('INVALID_EXPRESSION');
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://unexistentHost:1026',
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://unexistenthost:1026')
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://unexistenthost:1026')
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('UNEXISTENT_DEV', '801230BJKL23Y9090DSFL123HJK09H324HV8732', function (
233
- error,
234
- device
235
- ) {
236
- should.not.exist(error);
237
- should.exist(device);
232
+ iotAgentLib.retrieveDevice(
233
+ 'UNEXISTENT_DEV',
234
+ '801230BJKL23Y9090DSFL123HJK09H324HV8732',
235
+ function (error, device) {
236
+ should.not.exist(error);
237
+ should.exist(device);
238
238
 
239
- device.id.should.equal('UNEXISTENT_DEV');
240
- should.exist(device.protocol);
241
- device.protocol.should.equal('MQTT_UL');
242
- done();
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('UNEXISTENT_DEV_AND_GROUP', 'H2332Y909DSF3H346yh20JK092', function (
250
- error,
251
- device
252
- ) {
253
- should.exist(error);
254
- error.name.should.equal('DEVICE_GROUP_NOT_FOUND');
255
- should.not.exist(device);
256
- done();
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
  });
@@ -540,6 +540,26 @@ const iotAgentConfig = {
540
540
  }
541
541
  ],
542
542
  explicitAttrs: '[ "attr1", "attr2" ]'
543
+ },
544
+ LightMultiDefault: {
545
+ commands: [],
546
+ type: 'Light',
547
+ lazy: [],
548
+ active: [
549
+ {
550
+ object_id: 'p',
551
+ name: 'pressure',
552
+ type: 'Number',
553
+ entity_type: 'myType',
554
+ entity_name: 'Ligth:mymulti'
555
+ },
556
+ {
557
+ object_id: 'q',
558
+ name: 'pressure',
559
+ type: 'Number'
560
+ }
561
+ ],
562
+ expressionLanguage: 'jexl'
543
563
  }
544
564
  },
545
565
  service: 'smartgondor',
@@ -1356,6 +1376,44 @@ describe('NGSI-v2 - Multi-entity plugin', function () {
1356
1376
  });
1357
1377
  }
1358
1378
  );
1379
+
1380
+ describe('When pseudo-multientity device is provisioned (entity_type and default entity_id)', function () {
1381
+ // Case: Expression which results is sent as a new attribute
1382
+ const values = [
1383
+ {
1384
+ name: 'p',
1385
+ type: 'Number',
1386
+ value: 90
1387
+ },
1388
+ {
1389
+ name: 'q',
1390
+ type: 'Number',
1391
+ value: 60
1392
+ }
1393
+ ];
1394
+
1395
+ beforeEach(function () {
1396
+ nock.cleanAll();
1397
+ contextBrokerMock = nock('http://192.168.1.1:1026')
1398
+ .matchHeader('fiware-service', 'smartgondor')
1399
+ .matchHeader('fiware-servicepath', 'gardens')
1400
+ .post(
1401
+ '/v2/op/update',
1402
+ utils.readExampleFile(
1403
+ './test/unit/ngsiv2/examples/contextRequests/updateContextMultientityJexlExpressionPlugin1.json'
1404
+ )
1405
+ )
1406
+ .reply(204);
1407
+ });
1408
+
1409
+ it('should work without invalid expression error', function (done) {
1410
+ iotAgentLib.update('lightPseudo:id', 'LightMultiDefault', '', values, function (error) {
1411
+ should.not.exist(error);
1412
+ contextBrokerMock.done();
1413
+ done();
1414
+ });
1415
+ });
1416
+ });
1359
1417
  });
1360
1418
 
1361
1419
  describe('NGSI-v2 - Multi-entity plugin is executed before timestamp process plugin', function () {