iotagent-node-lib 4.2.0 → 4.3.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.
@@ -263,40 +263,50 @@ function handleGetDevice(req, res, next) {
263
263
  } else if (device) {
264
264
  res.status(200).json(toProvisioningAPIFormat(device));
265
265
  } else {
266
- next(new errors.DeviceNotFound(req.params.deviceId));
266
+ next(new errors.DeviceNotFound(req.params.deviceId), {
267
+ apikey: req.query.apikey,
268
+ service: req.headers['fiware-service'],
269
+ subservice: req.headers['fiware-servicepath']
270
+ });
267
271
  }
268
272
  }
269
273
  );
270
274
  }
271
275
 
272
- /**
273
- * This middleware handles the removal of a particular device specified with the deviceId.
274
- */
275
- function handleRemoveDevice(req, res, next) {
276
- function getDevice(deviceId, apikey, service, subservice, callback) {
277
- deviceService.getDevice(deviceId, apikey, service, subservice, function (error, device) {
278
- if (error) {
279
- callback(error);
280
- } else if (device) {
281
- callback(null, device);
282
- } else {
283
- callback(new errors.DeviceNotFound(deviceId));
284
- }
285
- });
286
- }
287
-
288
- function applyRemoveDeviceHandler(device, callback) {
289
- if (removeDeviceHandler) {
290
- removeDeviceHandler(device, callback);
291
- } else {
276
+ function getDevice(deviceId, apikey, service, subservice, callback) {
277
+ deviceService.getDevice(deviceId, apikey, service, subservice, function (error, device) {
278
+ if (error) {
279
+ callback(error);
280
+ } else if (device) {
292
281
  callback(null, device);
282
+ } else {
283
+ callback(
284
+ new errors.DeviceNotFound(deviceId, {
285
+ apikey: apikey,
286
+ service: service,
287
+ subservice: subservice
288
+ })
289
+ );
293
290
  }
294
- }
291
+ });
292
+ }
295
293
 
296
- function unregisterDevice(deviceId, apikey, service, subservice, device, callback) {
297
- return deviceService.unregister(deviceId, apikey, service, subservice, callback);
294
+ function applyRemoveDeviceHandler(device, callback) {
295
+ if (removeDeviceHandler) {
296
+ removeDeviceHandler(device, callback);
297
+ } else {
298
+ callback(null, device);
298
299
  }
300
+ }
299
301
 
302
+ function unregisterDevice(deviceId, apikey, service, subservice, device, callback) {
303
+ return deviceService.unregister(deviceId, apikey, service, subservice, callback);
304
+ }
305
+
306
+ /**
307
+ * This middleware handles the removal of a particular device specified with the deviceId.
308
+ */
309
+ function handleRemoveDevice(req, res, next) {
300
310
  async.waterfall(
301
311
  [
302
312
  apply(statsRegistry.add, 'deviceRemovalRequests', 1),
@@ -320,7 +330,13 @@ function handleRemoveDevice(req, res, next) {
320
330
  if (error && error.code !== 404) {
321
331
  next(error);
322
332
  } else if (error && error.code === 404) {
323
- next(new errors.DeviceNotFound(req.params.deviceId));
333
+ next(
334
+ new errors.DeviceNotFound(req.params.deviceId, {
335
+ apikey: req.query.apikey,
336
+ service: req.headers['fiware-service'],
337
+ subservice: req.headers['fiware-servicepath']
338
+ })
339
+ );
324
340
  } else {
325
341
  res.status(204).send();
326
342
  }
@@ -328,6 +344,56 @@ function handleRemoveDevice(req, res, next) {
328
344
  );
329
345
  }
330
346
 
347
+ /**
348
+ * This middleware handles the removal of several devices specified in a array into a body
349
+ */
350
+ function handleRemoveDevices(req, res, next) {
351
+ logger.debug(context, 'Handling delete of devices: %j', req.body);
352
+ let theErrorOut = false;
353
+ for (let devicetoRemove of req.body.devices) {
354
+ let theError = theErrorOut;
355
+ async.waterfall(
356
+ [
357
+ apply(statsRegistry.add, 'deviceRemovalRequests', 1),
358
+ apply(
359
+ getDevice,
360
+ devicetoRemove.deviceId,
361
+ devicetoRemove.apikey,
362
+ req.headers['fiware-service'],
363
+ req.headers['fiware-servicepath']
364
+ ),
365
+ applyRemoveDeviceHandler,
366
+ apply(
367
+ unregisterDevice,
368
+ devicetoRemove.deviceId,
369
+ devicetoRemove.apikey,
370
+ req.headers['fiware-service'],
371
+ req.headers['fiware-servicepath']
372
+ )
373
+ ],
374
+ function (error) {
375
+ if (error && error.code !== 404) {
376
+ theError = !theError ? error : theError;
377
+ } else if (error && error.code === 404) {
378
+ theError = !theError
379
+ ? new errors.DeviceNotFound(devicetoRemove.deviceId, {
380
+ apikey: devicetoRemove.apikey,
381
+ service: req.headers['fiware-service'],
382
+ subservice: req.headers['fiware-servicepath']
383
+ })
384
+ : theError;
385
+ }
386
+ }
387
+ ); // waterfall
388
+ theErrorOut = theError;
389
+ } // for
390
+ if (theErrorOut) {
391
+ next(theErrorOut);
392
+ } else {
393
+ res.status(204).send();
394
+ }
395
+ }
396
+
331
397
  /**
332
398
  * This middleware handles updates in the provisioning devices. The only attribute
333
399
  */
@@ -379,7 +445,13 @@ function handleUpdateDevice(req, res, next) {
379
445
  }
380
446
  );
381
447
  } else {
382
- next(new errors.DeviceNotFound(req.params.deviceId));
448
+ next(
449
+ new errors.DeviceNotFound(req.params.deviceId, {
450
+ apikey: req.query.apikey,
451
+ service: req.headers['fiware-service'],
452
+ subservice: req.headers['fiware-servicepath']
453
+ })
454
+ );
383
455
  }
384
456
  }
385
457
  );
@@ -414,6 +486,8 @@ function loadContextRoutes(router) {
414
486
  handleUpdateDevice
415
487
  );
416
488
 
489
+ router.post('/iot/op/delete', restUtils.checkRequestAttributes('headers', mandatoryHeaders), handleRemoveDevices);
490
+
417
491
  router.delete(
418
492
  '/iot/devices/:deviceId',
419
493
  restUtils.checkRequestAttributes('headers', mandatoryHeaders),
@@ -65,7 +65,7 @@ function checkMandatoryQueryParams(mandatoryAttributes, body, callback) {
65
65
  }
66
66
 
67
67
  if (missing.length !== 0) {
68
- const error = new errors.MissingAttributes('Missing attributes: ' + JSON.stringify(missing));
68
+ const error = new errors.MissingAttributes('Missing attributes: ' + JSON.stringify(missing), body);
69
69
  error.code = '400';
70
70
 
71
71
  callback(error);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "iotagent-node-lib",
3
3
  "license": "AGPL-3.0-only",
4
4
  "description": "IoT Agent library to interface with NGSI Context Broker",
5
- "version": "4.2.0",
5
+ "version": "4.3.0",
6
6
  "homepage": "https://github.com/telefonicaid/iotagent-node-lib",
7
7
  "keywords": [
8
8
  "fiware",
@@ -96,26 +96,26 @@ const testCases = [
96
96
  type: globalEnv.entity_type,
97
97
  a: {
98
98
  value: false,
99
- type: 'string'
99
+ type: 'Text'
100
100
  },
101
101
  b: {
102
102
  value: 10,
103
- type: 'string'
103
+ type: 'Text'
104
104
  },
105
105
  c: {
106
- type: 'string',
106
+ type: 'Text',
107
107
  value: 'text'
108
108
  },
109
109
  d: {
110
- type: 'string',
110
+ type: 'Text',
111
111
  value: 10.5
112
112
  },
113
113
  e: {
114
- type: 'string',
114
+ type: 'Text',
115
115
  value: [1, 2]
116
116
  },
117
117
  f: {
118
- type: 'string',
118
+ type: 'Text',
119
119
  value: {
120
120
  a: 1,
121
121
  b: 2
@@ -149,26 +149,26 @@ const testCases = [
149
149
  type: globalEnv.entity_type,
150
150
  a: {
151
151
  value: false,
152
- type: 'string'
152
+ type: 'Text'
153
153
  },
154
154
  b: {
155
155
  value: 10,
156
- type: 'string'
156
+ type: 'Text'
157
157
  },
158
158
  c: {
159
- type: 'string',
159
+ type: 'Text',
160
160
  value: 'text'
161
161
  },
162
162
  d: {
163
- type: 'string',
163
+ type: 'Text',
164
164
  value: 10.5
165
165
  },
166
166
  e: {
167
- type: 'string',
167
+ type: 'Text',
168
168
  value: [1, 2]
169
169
  },
170
170
  f: {
171
- type: 'string',
171
+ type: 'Text',
172
172
  value: {
173
173
  a: 1,
174
174
  b: 2
@@ -363,26 +363,26 @@ const testCases = [
363
363
  type: globalEnv.entity_type,
364
364
  u: {
365
365
  value: false,
366
- type: 'string'
366
+ type: 'Text'
367
367
  },
368
368
  v: {
369
369
  value: 10,
370
- type: 'string'
370
+ type: 'Text'
371
371
  },
372
372
  w: {
373
- type: 'string',
373
+ type: 'Text',
374
374
  value: 'text'
375
375
  },
376
376
  y: {
377
- type: 'string',
377
+ type: 'Text',
378
378
  value: 10.5
379
379
  },
380
380
  x: {
381
- type: 'string',
381
+ type: 'Text',
382
382
  value: [1, 2]
383
383
  },
384
384
  z: {
385
- type: 'string',
385
+ type: 'Text',
386
386
  value: {
387
387
  a: 1,
388
388
  b: 2
@@ -416,26 +416,26 @@ const testCases = [
416
416
  type: globalEnv.entity_type,
417
417
  u: {
418
418
  value: false,
419
- type: 'string'
419
+ type: 'Text'
420
420
  },
421
421
  v: {
422
422
  value: 10,
423
- type: 'string'
423
+ type: 'Text'
424
424
  },
425
425
  w: {
426
- type: 'string',
426
+ type: 'Text',
427
427
  value: 'text'
428
428
  },
429
429
  y: {
430
- type: 'string',
430
+ type: 'Text',
431
431
  value: 10.5
432
432
  },
433
433
  x: {
434
- type: 'string',
434
+ type: 'Text',
435
435
  value: [1, 2]
436
436
  },
437
437
  z: {
438
- type: 'string',
438
+ type: 'Text',
439
439
  value: {
440
440
  a: 1,
441
441
  b: 2
@@ -573,7 +573,7 @@ const testCases = [
573
573
  },
574
574
  b: {
575
575
  value: 1,
576
- type: 'string'
576
+ type: 'Text'
577
577
  }
578
578
  }
579
579
  }
@@ -726,7 +726,7 @@ const testCases = [
726
726
  type: globalEnv.entity_type,
727
727
  b: {
728
728
  value: 1,
729
- type: 'string'
729
+ type: 'Text'
730
730
  }
731
731
  }
732
732
  }
@@ -872,7 +872,7 @@ const testCases = [
872
872
  type: globalEnv.entity_type,
873
873
  b: {
874
874
  value: 1,
875
- type: 'string'
875
+ type: 'Text'
876
876
  }
877
877
  }
878
878
  }
@@ -1029,7 +1029,7 @@ const testCases = [
1029
1029
  },
1030
1030
  b: {
1031
1031
  value: 1,
1032
- type: 'string'
1032
+ type: 'Text'
1033
1033
  }
1034
1034
  }
1035
1035
  }
@@ -1529,7 +1529,7 @@ const testCases = [
1529
1529
  type: globalEnv.entity_type,
1530
1530
  b: {
1531
1531
  value: 10,
1532
- type: 'string'
1532
+ type: 'Text'
1533
1533
  }
1534
1534
  }
1535
1535
  }
@@ -1594,7 +1594,7 @@ const testCases = [
1594
1594
  type: globalEnv.entity_type,
1595
1595
  b: {
1596
1596
  value: 10,
1597
- type: 'string'
1597
+ type: 'Text'
1598
1598
  },
1599
1599
  static_a: {
1600
1600
  value: 3,
@@ -1688,7 +1688,7 @@ const testCases = [
1688
1688
  type: globalEnv.entity_type,
1689
1689
  a: {
1690
1690
  value: 10,
1691
- type: 'string'
1691
+ type: 'Text'
1692
1692
  },
1693
1693
  static_a: {
1694
1694
  value: {
@@ -2029,7 +2029,7 @@ const testCases = [
2029
2029
  type: globalEnv.entity_type,
2030
2030
  b: {
2031
2031
  value: 10,
2032
- type: 'string'
2032
+ type: 'Text'
2033
2033
  },
2034
2034
  attr_a: {
2035
2035
  value: 3,
@@ -2090,7 +2090,7 @@ const testCases = [
2090
2090
  type: globalEnv.entity_type,
2091
2091
  b: {
2092
2092
  value: 10,
2093
- type: 'string'
2093
+ type: 'Text'
2094
2094
  },
2095
2095
  attr_a: {
2096
2096
  value: 3,
@@ -2354,7 +2354,7 @@ const testCases = [
2354
2354
  },
2355
2355
  d: {
2356
2356
  value: 12,
2357
- type: 'string'
2357
+ type: 'Text'
2358
2358
  },
2359
2359
  static_a: {
2360
2360
  value: 3,
@@ -112,7 +112,9 @@ function jsonToIotaMeasures(json) {
112
112
  if (key === 'TimeInstant') {
113
113
  measure.type = 'DateTime';
114
114
  } else {
115
- measure.type = 'string';
115
+ // Although the type is not meaningfull and we could have picked any string for this,
116
+ // we have aligned with DEFAULT_ATTRIBUTE_TYPE constant in IOTA-JSON and IOTA-UL repositories
117
+ measure.type = 'Text';
116
118
  }
117
119
  measures.push(measure);
118
120
  }
@@ -600,7 +600,6 @@ describe('NGSI-LD - Active attributes test', function () {
600
600
  should.exist(error.name);
601
601
  error.code.should.equal(207);
602
602
  error.details.notUpdated.should.equal('someEntities');
603
- error.message.should.equal('Error accesing entity data for device: light1 of type: Light');
604
603
  error.name.should.equal('ENTITY_GENERIC_ERROR');
605
604
  contextBrokerMock.done();
606
605
  done();
@@ -905,17 +905,17 @@ describe('NGSI-v2 - Active attributes test', function () {
905
905
  const valuesIdType = [
906
906
  {
907
907
  name: 'id',
908
- type: 'text',
908
+ type: 'aTypeProvidedByIoTACodeCallingUpdateOnLib1',
909
909
  value: 'idIoTA'
910
910
  },
911
911
  {
912
912
  name: 'type',
913
- type: 'text',
913
+ type: 'aTypeProvidedByIoTACodeCallingUpdateOnLib2',
914
914
  value: 'typeIoTA'
915
915
  },
916
916
  {
917
917
  name: 'm',
918
- type: 'text',
918
+ type: 'aTypeProvidedByIoTACodeCallingUpdateOnLib3',
919
919
  value: 'measIoTA'
920
920
  }
921
921
  ];
@@ -923,6 +923,9 @@ describe('NGSI-v2 - Active attributes test', function () {
923
923
  beforeEach(function (done) {
924
924
  nock.cleanAll();
925
925
 
926
+ // Note that in the case of measure_id and measure_type the type provided by the IOTA when calling iotAgentLib.update()
927
+ // is used (thus ignoring the one of the StupidDevice group for id or type, which is 'text') but in the case of measIoTA the type provided in the
928
+ // provisioning ('String') is used
926
929
  contextBrokerMock = nock('http://192.168.1.1:1026')
927
930
  .matchHeader('fiware-service', 'smartgondor')
928
931
  .matchHeader('fiware-servicepath', 'gardens')
@@ -934,11 +937,11 @@ describe('NGSI-v2 - Active attributes test', function () {
934
937
  type: 'String'
935
938
  },
936
939
  measure_id: {
937
- type: 'text',
940
+ type: 'aTypeProvidedByIoTACodeCallingUpdateOnLib1',
938
941
  value: 'idIoTA'
939
942
  },
940
943
  measure_type: {
941
- type: 'text',
944
+ type: 'aTypeProvidedByIoTACodeCallingUpdateOnLib2',
942
945
  value: 'typeIoTA'
943
946
  }
944
947
  })
@@ -161,7 +161,7 @@ describe('NGSI-v2 - Device provisioning API: Remove provisioned devices', functi
161
161
  method: 'DELETE'
162
162
  };
163
163
 
164
- it('should return a 200 OK and no errors', function (done) {
164
+ it('should return a 204 OK and no errors', function (done) {
165
165
  request(options, function (error, response, body) {
166
166
  should.not.exist(error);
167
167
  response.statusCode.should.equal(204);
@@ -231,7 +231,42 @@ describe('NGSI-v2 - Device provisioning API: Remove provisioned devices', functi
231
231
  method: 'DELETE'
232
232
  };
233
233
 
234
- it('should return a 200 OK and no errors', function (done) {
234
+ it('should return a 204 OK and no errors', function (done) {
235
+ request(options, function (error, response, body) {
236
+ should.not.exist(error);
237
+ response.statusCode.should.equal(204);
238
+ done();
239
+ });
240
+ });
241
+ });
242
+
243
+ describe('When a request to remove a provision devices arrives', function () {
244
+ const options = {
245
+ url: 'http://localhost:' + iotAgentConfig.server.port + '/iot/op/delete',
246
+ headers: {
247
+ 'fiware-service': 'smartgondor',
248
+ 'fiware-servicepath': '/gardens'
249
+ },
250
+ method: 'POST',
251
+ json: {
252
+ devices: [
253
+ {
254
+ deviceId: 'Light1',
255
+ apikey: ''
256
+ },
257
+ {
258
+ deviceId: 'Light2',
259
+ apikey: ''
260
+ },
261
+ {
262
+ deviceId: 'Light3',
263
+ apikey: ''
264
+ }
265
+ ]
266
+ }
267
+ };
268
+
269
+ it('should return a 204 OK and no errors', function (done) {
235
270
  request(options, function (error, response, body) {
236
271
  should.not.exist(error);
237
272
  response.statusCode.should.equal(204);