iotagent-node-lib 3.4.3 → 4.0.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 (94) hide show
  1. package/CHANGES_NEXT_RELEASE +0 -1
  2. package/README.md +4 -0
  3. package/doc/admin.md +1 -13
  4. package/doc/api.md +118 -14
  5. package/doc/devel/architecture.md +0 -12
  6. package/doc/index.md +1 -1
  7. package/doc/roadmap.md +22 -10
  8. package/lib/commonConfig.js +0 -11
  9. package/lib/model/Device.js +2 -1
  10. package/lib/model/Group.js +2 -1
  11. package/lib/model/dbConn.js +22 -11
  12. package/lib/plugins/expressionPlugin.js +0 -5
  13. package/lib/plugins/jexlParser.js +15 -31
  14. package/lib/services/common/genericMiddleware.js +14 -2
  15. package/lib/services/common/iotManagerService.js +2 -1
  16. package/lib/services/devices/deviceRegistryMongoDB.js +3 -1
  17. package/lib/services/devices/deviceService.js +16 -21
  18. package/lib/services/devices/devices-NGSI-LD.js +5 -98
  19. package/lib/services/devices/devices-NGSI-mixed.js +0 -14
  20. package/lib/services/devices/devices-NGSI-v2.js +3 -0
  21. package/lib/services/groups/groupRegistryMemory.js +0 -25
  22. package/lib/services/groups/groupRegistryMongoDB.js +20 -19
  23. package/lib/services/groups/groupService.js +3 -14
  24. package/lib/services/ngsi/entities-NGSI-LD.js +81 -6
  25. package/lib/services/ngsi/entities-NGSI-v2.js +304 -687
  26. package/lib/services/ngsi/ngsiUtils.js +0 -30
  27. package/lib/services/northBound/deviceProvisioningServer.js +6 -3
  28. package/lib/templates/createDevice.json +4 -0
  29. package/lib/templates/createDeviceLax.json +4 -0
  30. package/lib/templates/deviceGroup.json +4 -0
  31. package/lib/templates/updateDevice.json +4 -0
  32. package/lib/templates/updateDeviceLax.json +4 -0
  33. package/package.json +6 -2
  34. package/test/functional/README.md +378 -0
  35. package/test/functional/config-test.js +70 -0
  36. package/test/functional/functional-tests-runner.js +126 -0
  37. package/test/functional/functional-tests.js +241 -0
  38. package/test/functional/testCases.js +2944 -0
  39. package/test/functional/testUtils.js +251 -0
  40. package/test/tools/utils.js +25 -0
  41. package/test/unit/mongodb/mongodb-connectionoptions-test.js +35 -22
  42. package/test/unit/ngsi-ld/examples/contextRequests/createProvisionedDeviceWithGroupAndStatic2.json +3 -34
  43. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin6.json +8 -1
  44. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin7.json +1 -4
  45. package/test/unit/ngsi-ld/examples/contextRequests/updateContextAliasPlugin8.json +1 -6
  46. package/test/unit/ngsi-ld/general/contextBrokerOAuthSecurityAccess-test.js +67 -87
  47. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +7 -13
  48. package/test/unit/ngsi-ld/lazyAndCommands/merge-patch-test.js +43 -43
  49. package/test/unit/ngsi-ld/lazyAndCommands/polling-commands-test.js +19 -29
  50. package/test/unit/ngsi-ld/ngsiService/languageProperties-test.js +0 -1
  51. package/test/unit/ngsi-ld/ngsiService/subscriptions-test.js +35 -46
  52. package/test/unit/ngsi-ld/plugins/alias-plugin_test.js +8 -9
  53. package/test/unit/ngsi-ld/provisioning/device-provisioning-api_test.js +96 -221
  54. package/test/unit/ngsi-ld/provisioning/device-registration_test.js +18 -27
  55. package/test/unit/ngsi-ld/provisioning/device-update-registration_test.js +8 -16
  56. package/test/unit/ngsi-ld/provisioning/updateProvisionedDevices-test.js +0 -13
  57. package/test/unit/ngsiv2/examples/contextRequests/updateContextAliasPlugin8.json +4 -4
  58. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29b.json +8 -0
  59. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin30.json +1 -1
  60. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin32.json +0 -6
  61. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json +8 -0
  62. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34b.json +14 -0
  63. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin35.json +1 -11
  64. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36b.json +13 -0
  65. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin37.json +8 -0
  66. package/test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin41.json +1 -11
  67. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin10b.json +37 -0
  68. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin11.json +0 -4
  69. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin15.json +0 -4
  70. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin16.json +0 -4
  71. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin25.json +4 -0
  72. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin4.json +0 -3
  73. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin5.json +10 -12
  74. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin6.json +0 -4
  75. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin7.json +1 -5
  76. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityPlugin8.json +8 -12
  77. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin2.json +0 -4
  78. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityTimestampPlugin3.json +0 -8
  79. package/test/unit/ngsiv2/examples/contextRequests/updateContextStaticAttributesMetadata.json +7 -1
  80. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +898 -28
  81. package/test/unit/ngsiv2/ngsiService/active-devices-test.js +188 -1
  82. package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +267 -0
  83. package/test/unit/ngsiv2/plugins/alias-plugin_test.js +19 -21
  84. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +21 -24
  85. package/test/unit/ngsiv2/provisioning/device-group-utils-test.js +1 -21
  86. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +4 -6
  87. package/test/unit/ngsi-ld/ngsiService/autocast-test.js +0 -438
  88. package/test/unit/ngsi-ld/ngsiService/geoproperties-test.js +0 -381
  89. package/test/unit/ngsi-ld/provisioning/singleConfigurationMode-test.js +0 -311
  90. package/test/unit/ngsiv2/ngsiService/autocast-test.js +0 -325
  91. package/test/unit/ngsiv2/ngsiService/geoproperties-test.js +0 -427
  92. package/test/unit/ngsiv2/plugins/compress-timestamp-plugin_test.js +0 -217
  93. package/test/unit/ngsiv2/plugins/timestamp-processing-plugin_test.js +0 -119
  94. package/test/unit/ngsiv2/provisioning/singleConfigurationMode-test.js +0 -309
@@ -33,7 +33,6 @@ const nock = require('nock');
33
33
  const timekeeper = require('timekeeper');
34
34
  let contextBrokerMock;
35
35
  const iotAgentConfig = {
36
- logLevel: 'FATAL',
37
36
  contextBroker: {
38
37
  host: '192.168.1.1',
39
38
  port: '1026',
@@ -62,7 +61,8 @@ const iotAgentConfig = {
62
61
  {
63
62
  object_id: 'a',
64
63
  name: 'alive',
65
- type: 'None'
64
+ type: 'None',
65
+ skipValue: 'null passes'
66
66
  },
67
67
  {
68
68
  object_id: 'u',
@@ -96,7 +96,8 @@ const iotAgentConfig = {
96
96
  object_id: 'p',
97
97
  name: 'pressure',
98
98
  type: 'Number',
99
- expression: 'pressure * / 20'
99
+ expression: 'pressure * / 20',
100
+ skipValue: 'null passes'
100
101
  }
101
102
  ]
102
103
  },
@@ -141,6 +142,20 @@ const iotAgentConfig = {
141
142
  }
142
143
  ]
143
144
  },
145
+ WeatherStationWithIdNumber: {
146
+ commands: [],
147
+ type: 'WeatherStation',
148
+ entityNameExp: 'id',
149
+ lazy: [],
150
+ active: [
151
+ {
152
+ object_id: 'p',
153
+ name: 'pressure',
154
+ type: 'Number',
155
+ expression: 'pressure * 20'
156
+ }
157
+ ]
158
+ },
144
159
  WeatherStationUndef: {
145
160
  commands: [],
146
161
  type: 'WeatherStation',
@@ -271,7 +286,7 @@ const iotAgentConfig = {
271
286
  commands: [],
272
287
  type: 'GPS',
273
288
  lazy: [],
274
- static: [
289
+ staticAttributes: [
275
290
  {
276
291
  name: 'color',
277
292
  type: 'string',
@@ -295,7 +310,7 @@ const iotAgentConfig = {
295
310
  commands: [],
296
311
  type: 'GPS',
297
312
  lazy: [],
298
- static: [
313
+ staticAttributes: [
299
314
  {
300
315
  name: 'color',
301
316
  type: 'string',
@@ -319,7 +334,7 @@ const iotAgentConfig = {
319
334
  commands: [],
320
335
  type: 'GPS',
321
336
  lazy: [],
322
- static: [
337
+ staticAttributes: [
323
338
  {
324
339
  name: 'color',
325
340
  type: 'string',
@@ -343,11 +358,11 @@ const iotAgentConfig = {
343
358
  commands: [],
344
359
  type: 'GPS',
345
360
  lazy: [],
346
- static: [
361
+ staticAttributes: [
347
362
  {
348
363
  name: 'lat',
349
364
  type: 'string',
350
- value: '52'
365
+ value: 52
351
366
  }
352
367
  ],
353
368
  active: [
@@ -362,13 +377,13 @@ const iotAgentConfig = {
362
377
  expression: "{coordinates: [lon,lat], type: 'Point'}"
363
378
  }
364
379
  ],
365
- explicitAttrs: "theLocation ? [{object_id: 'theLocation'}] : []"
380
+ explicitAttrs: "mylocation ? [{object_id: 'theLocation'}] : []"
366
381
  },
367
382
  GPS6: {
368
383
  commands: [],
369
384
  type: 'GPS',
370
385
  lazy: [],
371
- static: [
386
+ staticAttributes: [
372
387
  {
373
388
  name: 'lat',
374
389
  type: 'Number',
@@ -393,7 +408,7 @@ const iotAgentConfig = {
393
408
  commands: [],
394
409
  type: 'GPS',
395
410
  lazy: [],
396
- static: [
411
+ staticAttributes: [
397
412
  {
398
413
  name: 'color',
399
414
  type: 'string',
@@ -455,6 +470,260 @@ const iotAgentConfig = {
455
470
  skipValue: null
456
471
  }
457
472
  ]
473
+ },
474
+ nestedExpressionsObj: {
475
+ commands: [],
476
+ type: 'nestedExpressionsObj',
477
+ lazy: [],
478
+ active: [
479
+ {
480
+ name: 'value3',
481
+ object_id: 'v3',
482
+ type: 'Number',
483
+ expression: 'v*2'
484
+ },
485
+ {
486
+ name: 'value2',
487
+ object_id: 'v2',
488
+ type: 'Number',
489
+ expression: 'v3*2'
490
+ },
491
+ {
492
+ name: 'value1',
493
+ object_id: 'v1',
494
+ type: 'Number',
495
+ expression: 'v2*2'
496
+ }
497
+ ]
498
+ },
499
+ nestedExpressionsName: {
500
+ commands: [],
501
+ type: 'nestedExpressionsName',
502
+ lazy: [],
503
+ active: [
504
+ {
505
+ name: 'prefix',
506
+ object_id: 't1',
507
+ type: 'text',
508
+ expression: '"pre_"+t'
509
+ },
510
+ {
511
+ name: 'postfix',
512
+ object_id: 't2',
513
+ type: 'text',
514
+ expression: 'prefix+"_post"'
515
+ }
516
+ ]
517
+ },
518
+ nestedExpressionsSkip: {
519
+ commands: [],
520
+ type: 'nestedExpressionsSkip',
521
+ lazy: [],
522
+ active: [
523
+ {
524
+ name: 'prefix',
525
+ object_id: 't1',
526
+ type: 'text',
527
+ expression: '"pre_"+t'
528
+ },
529
+ {
530
+ name: 'postfix',
531
+ object_id: 't2',
532
+ type: 'text',
533
+ expression: 'prefix+"_post"'
534
+ },
535
+ {
536
+ name: 't',
537
+ object_id: 't',
538
+ type: 'text',
539
+ expression: 'null'
540
+ }
541
+ ]
542
+ },
543
+ nestedExpressionDirect: {
544
+ commands: [],
545
+ type: 'nestedExpressionsDirect',
546
+ lazy: [],
547
+ active: [
548
+ {
549
+ name: 'correctedLevel',
550
+ type: 'Number',
551
+ expression: 'level * 0.897'
552
+ },
553
+ {
554
+ name: 'normalizedLevel',
555
+ type: 'Number',
556
+ expression: 'correctedLevel / 100'
557
+ }
558
+ ]
559
+ },
560
+ nestedExpressionReverse: {
561
+ commands: [],
562
+ type: 'nestedExpressionsReverse',
563
+ lazy: [],
564
+ active: [
565
+ {
566
+ name: 'normalizedLevel',
567
+ type: 'Number',
568
+ expression: 'correctedLevel / 100'
569
+ },
570
+ {
571
+ name: 'correctedLevel',
572
+ type: 'Number',
573
+ expression: 'level * 0.897'
574
+ }
575
+ ]
576
+ },
577
+ nestedExpressionsAnti: {
578
+ commands: [],
579
+ type: 'nestedExpressionsAnti',
580
+ lazy: [],
581
+ active: [
582
+ {
583
+ name: 'a',
584
+ type: 'Number',
585
+ expression: 'b*10'
586
+ },
587
+ {
588
+ name: 'b',
589
+ type: 'Number',
590
+ expression: 'a*10'
591
+ }
592
+ ]
593
+ },
594
+ testNull: {
595
+ commands: [],
596
+ type: 'testNull',
597
+ lazy: [],
598
+ active: [
599
+ {
600
+ name: 'a',
601
+ type: 'Number',
602
+ expression: 'v'
603
+ },
604
+ {
605
+ name: 'b',
606
+ type: 'Number',
607
+ expression: 'v*3'
608
+ },
609
+ {
610
+ name: 'c',
611
+ type: 'Boolean',
612
+ expression: 'v==null'
613
+ },
614
+ {
615
+ name: 'd',
616
+ type: 'Text',
617
+ expression: "v?'no soy null':'soy null'"
618
+ },
619
+ {
620
+ name: 'e',
621
+ type: 'Text',
622
+ expression: "v==null?'soy null':'no soy null'"
623
+ },
624
+ {
625
+ name: 'f',
626
+ type: 'Text',
627
+ expression: "(v*3)==null?'soy null':'no soy null'"
628
+ },
629
+ {
630
+ name: 'g',
631
+ type: 'Boolean',
632
+ expression: 'v == undefined'
633
+ }
634
+ ]
635
+ },
636
+ testNullSkip: {
637
+ commands: [],
638
+ type: 'testNullSkip',
639
+ lazy: [],
640
+ active: [
641
+ {
642
+ name: 'a',
643
+ type: 'Number',
644
+ expression: 'v',
645
+ skipValue: 'avoidNull'
646
+ },
647
+ {
648
+ name: 'b',
649
+ type: 'Number',
650
+ expression: 'v*3',
651
+ skipValue: 'avoidNull'
652
+ },
653
+ {
654
+ name: 'c',
655
+ type: 'Boolean',
656
+ expression: 'v==null',
657
+ skipValue: 'avoidNull'
658
+ },
659
+ {
660
+ name: 'd',
661
+ type: 'Text',
662
+ expression: "v?'no soy null':'soy null'",
663
+ skipValue: 'avoidNull'
664
+ },
665
+ {
666
+ name: 'e',
667
+ type: 'Text',
668
+ expression: "v==null?'soy null':'no soy null'",
669
+ skipValue: 'avoidNull'
670
+ },
671
+ {
672
+ name: 'f',
673
+ type: 'Text',
674
+ expression: "(v*3)==null?'soy null':'no soy null'",
675
+ skipValue: 'avoidNull'
676
+ },
677
+ {
678
+ name: 'g',
679
+ type: 'Boolean',
680
+ expression: 'v == undefined',
681
+ skipValue: 'avoidNull'
682
+ }
683
+ ]
684
+ },
685
+ testNullExplicit: {
686
+ type: 'testNullExplicit',
687
+ explicitAttrs: true,
688
+ commands: [],
689
+ lazy: [],
690
+ active: [
691
+ {
692
+ name: 'a',
693
+ type: 'Number',
694
+ expression: 'v'
695
+ },
696
+ {
697
+ name: 'b',
698
+ type: 'Number',
699
+ expression: 'v*3'
700
+ },
701
+ {
702
+ name: 'c',
703
+ type: 'Boolean',
704
+ expression: 'v==null'
705
+ },
706
+ {
707
+ name: 'd',
708
+ type: 'Text',
709
+ expression: "v?'no soy null':'soy null'"
710
+ },
711
+ {
712
+ name: 'e',
713
+ type: 'Text',
714
+ expression: "v==null?'soy null':'no soy null'"
715
+ },
716
+ {
717
+ name: 'f',
718
+ type: 'Text',
719
+ expression: "(v*3)==null?'soy null':'no soy null'"
720
+ },
721
+ {
722
+ name: 'g',
723
+ type: 'Boolean',
724
+ expression: 'v == undefined'
725
+ }
726
+ ]
458
727
  }
459
728
  },
460
729
  service: 'smartgondor',
@@ -465,7 +734,6 @@ const iotAgentConfig = {
465
734
  };
466
735
 
467
736
  const iotAgentConfigTS = {
468
- logLevel: 'FATAL',
469
737
  contextBroker: {
470
738
  host: '192.168.1.1',
471
739
  port: '1026',
@@ -598,6 +866,298 @@ describe('Java expression language (JEXL) based transformations plugin', functio
598
866
  });
599
867
  });
600
868
 
869
+ describe('When applying expressions with null values', function () {
870
+ // Case: Update for an attribute with bad expression
871
+ const values = [
872
+ {
873
+ name: 'v',
874
+ type: 'Number',
875
+ value: null
876
+ }
877
+ ];
878
+
879
+ beforeEach(function () {
880
+ nock.cleanAll();
881
+
882
+ contextBrokerMock = nock('http://192.168.1.1:1026')
883
+ .matchHeader('fiware-service', 'smartgondor')
884
+ .matchHeader('fiware-servicepath', 'gardens')
885
+ .post('/v2/entities?options=upsert', {
886
+ id: 'testNull1',
887
+ type: 'testNull',
888
+ v: {
889
+ value: null,
890
+ type: 'Number'
891
+ },
892
+ c: {
893
+ value: true,
894
+ type: 'Boolean'
895
+ },
896
+ d: {
897
+ value: 'soy null',
898
+ type: 'Text'
899
+ },
900
+ e: {
901
+ value: 'soy null',
902
+ type: 'Text'
903
+ },
904
+ f: {
905
+ value: 'no soy null',
906
+ type: 'Text'
907
+ },
908
+ g: {
909
+ value: true,
910
+ type: 'Boolean'
911
+ }
912
+ })
913
+ .reply(204);
914
+ });
915
+
916
+ it('it should be handled properly', function (done) {
917
+ iotAgentLib.update('testNull1', 'testNull', '', values, function (error) {
918
+ should.not.exist(error);
919
+ contextBrokerMock.done();
920
+ done();
921
+ });
922
+ });
923
+ });
924
+
925
+ describe('When applying expressions without values (NaN)', function () {
926
+ // Case: Update for an attribute with bad expression
927
+ const values = [
928
+ {
929
+ name: 'z',
930
+ type: 'Number',
931
+ value: null
932
+ }
933
+ ];
934
+
935
+ beforeEach(function () {
936
+ nock.cleanAll();
937
+
938
+ contextBrokerMock = nock('http://192.168.1.1:1026')
939
+ .matchHeader('fiware-service', 'smartgondor')
940
+ .matchHeader('fiware-servicepath', 'gardens')
941
+ .post('/v2/entities?options=upsert', {
942
+ id: 'testNull2',
943
+ type: 'testNull',
944
+ z: {
945
+ value: null,
946
+ type: 'Number'
947
+ },
948
+ c: {
949
+ value: true,
950
+ type: 'Boolean'
951
+ },
952
+ d: {
953
+ value: 'soy null',
954
+ type: 'Text'
955
+ },
956
+ e: {
957
+ value: 'soy null',
958
+ type: 'Text'
959
+ },
960
+ f: {
961
+ value: 'no soy null',
962
+ type: 'Text'
963
+ },
964
+ g: {
965
+ value: true,
966
+ type: 'Boolean'
967
+ }
968
+ })
969
+ .reply(204);
970
+ });
971
+
972
+ it('it should be handled properly', function (done) {
973
+ iotAgentLib.update('testNull2', 'testNull', '', values, function (error) {
974
+ should.not.exist(error);
975
+ contextBrokerMock.done();
976
+ done();
977
+ });
978
+ });
979
+ });
980
+
981
+ describe('When applying expressions with null values - Skip values disabled', function () {
982
+ // Case: Update for an attribute with bad expression
983
+ const values = [
984
+ {
985
+ name: 'v',
986
+ type: 'Number',
987
+ value: null
988
+ }
989
+ ];
990
+
991
+ beforeEach(function () {
992
+ nock.cleanAll();
993
+
994
+ contextBrokerMock = nock('http://192.168.1.1:1026')
995
+ .matchHeader('fiware-service', 'smartgondor')
996
+ .matchHeader('fiware-servicepath', 'gardens')
997
+ .post('/v2/entities?options=upsert', {
998
+ id: 'testNullSkip1',
999
+ type: 'testNullSkip',
1000
+ v: {
1001
+ value: null,
1002
+ type: 'Number'
1003
+ },
1004
+ a: {
1005
+ value: null,
1006
+ type: 'Number'
1007
+ },
1008
+ b: {
1009
+ value: null,
1010
+ type: 'Number'
1011
+ },
1012
+ c: {
1013
+ value: true,
1014
+ type: 'Boolean'
1015
+ },
1016
+ d: {
1017
+ value: 'soy null',
1018
+ type: 'Text'
1019
+ },
1020
+ e: {
1021
+ value: 'soy null',
1022
+ type: 'Text'
1023
+ },
1024
+ f: {
1025
+ value: 'no soy null',
1026
+ type: 'Text'
1027
+ },
1028
+ g: {
1029
+ value: true,
1030
+ type: 'Boolean'
1031
+ }
1032
+ })
1033
+ .reply(204);
1034
+ });
1035
+
1036
+ it('it should be handled properly', function (done) {
1037
+ iotAgentLib.update('testNullSkip1', 'testNullSkip', '', values, function (error) {
1038
+ should.not.exist(error);
1039
+ contextBrokerMock.done();
1040
+ done();
1041
+ });
1042
+ });
1043
+ });
1044
+
1045
+ describe('When applying expressions without values (NaN) - Skip values disabled', function () {
1046
+ // Case: Update for an attribute with bad expression
1047
+ const values = [
1048
+ {
1049
+ name: 'z',
1050
+ type: 'Number',
1051
+ value: null
1052
+ }
1053
+ ];
1054
+
1055
+ beforeEach(function () {
1056
+ nock.cleanAll();
1057
+
1058
+ contextBrokerMock = nock('http://192.168.1.1:1026')
1059
+ .matchHeader('fiware-service', 'smartgondor')
1060
+ .matchHeader('fiware-servicepath', 'gardens')
1061
+ .post('/v2/entities?options=upsert', {
1062
+ id: 'testNullSkip2',
1063
+ type: 'testNullSkip',
1064
+ z: {
1065
+ value: null,
1066
+ type: 'Number'
1067
+ },
1068
+ a: {
1069
+ value: null,
1070
+ type: 'Number'
1071
+ },
1072
+ b: {
1073
+ value: null,
1074
+ type: 'Number'
1075
+ },
1076
+ c: {
1077
+ value: true,
1078
+ type: 'Boolean'
1079
+ },
1080
+ d: {
1081
+ value: 'soy null',
1082
+ type: 'Text'
1083
+ },
1084
+ e: {
1085
+ value: 'soy null',
1086
+ type: 'Text'
1087
+ },
1088
+ f: {
1089
+ value: 'no soy null',
1090
+ type: 'Text'
1091
+ },
1092
+ g: {
1093
+ value: true,
1094
+ type: 'Boolean'
1095
+ }
1096
+ })
1097
+ .reply(204);
1098
+ });
1099
+
1100
+ it('it should be handled properly', function (done) {
1101
+ iotAgentLib.update('testNullSkip2', 'testNullSkip', '', values, function (error) {
1102
+ should.not.exist(error);
1103
+ contextBrokerMock.done();
1104
+ done();
1105
+ });
1106
+ });
1107
+ });
1108
+
1109
+ describe('When applying expressions with not explicit measures - explicitAttrs = true', function () {
1110
+ // Case: Update for an attribute with bad expression
1111
+ const values = [
1112
+ {
1113
+ name: 'v',
1114
+ type: 'Number',
1115
+ value: null
1116
+ }
1117
+ ];
1118
+
1119
+ beforeEach(function () {
1120
+ nock.cleanAll();
1121
+
1122
+ contextBrokerMock = nock('http://192.168.1.1:1026')
1123
+ .matchHeader('fiware-service', 'smartgondor')
1124
+ .matchHeader('fiware-servicepath', 'gardens')
1125
+ .post('/v2/entities?options=upsert', {
1126
+ id: 'testNullExplicit1',
1127
+ type: 'testNullExplicit',
1128
+ c: {
1129
+ value: true,
1130
+ type: 'Boolean'
1131
+ },
1132
+ d: {
1133
+ value: 'soy null',
1134
+ type: 'Text'
1135
+ },
1136
+ e: {
1137
+ value: 'soy null',
1138
+ type: 'Text'
1139
+ },
1140
+ f: {
1141
+ value: 'no soy null',
1142
+ type: 'Text'
1143
+ },
1144
+ g: {
1145
+ value: true,
1146
+ type: 'Boolean'
1147
+ }
1148
+ })
1149
+ .reply(204);
1150
+ });
1151
+
1152
+ it('it should be handled properly', function (done) {
1153
+ iotAgentLib.update('testNullExplicit1', 'testNullExplicit', '', values, function (error) {
1154
+ should.not.exist(error);
1155
+ contextBrokerMock.done();
1156
+ done();
1157
+ });
1158
+ });
1159
+ });
1160
+
601
1161
  describe('When there are expression attributes that are just calculated (not sent by the device)', function () {
602
1162
  // Case: Expression which results is sent as a new attribute
603
1163
  const values = [
@@ -615,7 +1175,6 @@ describe('Java expression language (JEXL) based transformations plugin', functio
615
1175
 
616
1176
  beforeEach(function () {
617
1177
  nock.cleanAll();
618
-
619
1178
  contextBrokerMock = nock('http://192.168.1.1:1026')
620
1179
  .matchHeader('fiware-service', 'smartgondor')
621
1180
  .matchHeader('fiware-servicepath', 'gardens')
@@ -828,7 +1387,6 @@ describe('Java expression language (JEXL) based transformations plugin', functio
828
1387
 
829
1388
  beforeEach(function () {
830
1389
  nock.cleanAll();
831
-
832
1390
  contextBrokerMock = nock('http://192.168.1.1:1026')
833
1391
  .matchHeader('fiware-service', 'smartgondor')
834
1392
  .matchHeader('fiware-servicepath', 'gardens')
@@ -1078,6 +1636,48 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1078
1636
  });
1079
1637
  });
1080
1638
  });
1639
+
1640
+ describe('When a measure arrives with id number', function () {
1641
+ const values = [
1642
+ {
1643
+ name: 'p',
1644
+ type: 'centigrades',
1645
+ value: '52'
1646
+ }
1647
+ ];
1648
+ const typeInformation = {
1649
+ service: 'smartgondor',
1650
+ subservice: 'gardens',
1651
+ name: '1234',
1652
+ id: '1234',
1653
+ type: 'WeatherStation',
1654
+ active: [{ object_id: 'p', name: 'pressure', type: 'Number', expression: 'pressure * 20' }]
1655
+ };
1656
+
1657
+ beforeEach(function () {
1658
+ nock.cleanAll();
1659
+
1660
+ contextBrokerMock = nock('http://192.168.1.1:1026')
1661
+ .matchHeader('fiware-service', 'smartgondor')
1662
+ .matchHeader('fiware-servicepath', 'gardens')
1663
+ .post(
1664
+ '/v2/entities?options=upsert',
1665
+ utils.readExampleFile(
1666
+ './test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin29b.json'
1667
+ )
1668
+ )
1669
+ .reply(204);
1670
+ });
1671
+
1672
+ it('should calculate the expression', function (done) {
1673
+ iotAgentLib.update(1234, 'WeatherStationWithIdNumber', '', values, typeInformation, function (error) {
1674
+ should.not.exist(error);
1675
+ contextBrokerMock.done();
1676
+ done();
1677
+ });
1678
+ });
1679
+ });
1680
+
1081
1681
  describe('When a measure arrives and there is not enough information to calculate an expression', function () {
1082
1682
  const values = [
1083
1683
  {
@@ -1133,7 +1733,6 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1133
1733
 
1134
1734
  beforeEach(function () {
1135
1735
  nock.cleanAll();
1136
-
1137
1736
  contextBrokerMock = nock('http://192.168.1.1:1026')
1138
1737
  .matchHeader('fiware-service', 'smartgondor')
1139
1738
  .matchHeader('fiware-servicepath', 'gardens')
@@ -1177,7 +1776,6 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1177
1776
 
1178
1777
  beforeEach(function () {
1179
1778
  nock.cleanAll();
1180
-
1181
1779
  contextBrokerMock = nock('http://192.168.1.1:1026')
1182
1780
  .matchHeader('fiware-service', 'smartgondor')
1183
1781
  .matchHeader('fiware-servicepath', 'gardens')
@@ -1226,7 +1824,6 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1226
1824
 
1227
1825
  beforeEach(function () {
1228
1826
  nock.cleanAll();
1229
-
1230
1827
  contextBrokerMock = nock('http://192.168.1.1:1026')
1231
1828
  .matchHeader('fiware-service', 'smartgondor')
1232
1829
  .matchHeader('fiware-servicepath', 'gardens')
@@ -1270,14 +1867,13 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1270
1867
 
1271
1868
  beforeEach(function () {
1272
1869
  nock.cleanAll();
1273
-
1274
1870
  contextBrokerMock = nock('http://192.168.1.1:1026')
1275
1871
  .matchHeader('fiware-service', 'smartgondor')
1276
1872
  .matchHeader('fiware-servicepath', 'gardens')
1277
1873
  .post(
1278
1874
  '/v2/entities?options=upsert',
1279
1875
  utils.readExampleFile(
1280
- './test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json'
1876
+ './test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34b.json'
1281
1877
  )
1282
1878
  )
1283
1879
  .reply(204);
@@ -1314,14 +1910,13 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1314
1910
 
1315
1911
  beforeEach(function () {
1316
1912
  nock.cleanAll();
1317
-
1318
1913
  contextBrokerMock = nock('http://192.168.1.1:1026')
1319
1914
  .matchHeader('fiware-service', 'smartgondor')
1320
1915
  .matchHeader('fiware-servicepath', 'gardens')
1321
1916
  .post(
1322
1917
  '/v2/entities?options=upsert',
1323
1918
  utils.readExampleFile(
1324
- './test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34.json'
1919
+ './test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin34b.json'
1325
1920
  )
1326
1921
  )
1327
1922
  .reply(204);
@@ -1363,7 +1958,6 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1363
1958
 
1364
1959
  beforeEach(function () {
1365
1960
  nock.cleanAll();
1366
-
1367
1961
  contextBrokerMock = nock('http://192.168.1.1:1026')
1368
1962
  .matchHeader('fiware-service', 'smartgondor')
1369
1963
  .matchHeader('fiware-servicepath', 'gardens')
@@ -1402,14 +1996,13 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1402
1996
 
1403
1997
  beforeEach(function () {
1404
1998
  nock.cleanAll();
1405
-
1406
1999
  contextBrokerMock = nock('http://192.168.1.1:1026')
1407
2000
  .matchHeader('fiware-service', 'smartgondor')
1408
2001
  .matchHeader('fiware-servicepath', 'gardens')
1409
2002
  .post(
1410
2003
  '/v2/entities?options=upsert',
1411
2004
  utils.readExampleFile(
1412
- './test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36.json'
2005
+ './test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin36b.json'
1413
2006
  )
1414
2007
  )
1415
2008
  .reply(204);
@@ -1436,7 +2029,6 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1436
2029
 
1437
2030
  beforeEach(function () {
1438
2031
  nock.cleanAll();
1439
-
1440
2032
  contextBrokerMock = nock('http://192.168.1.1:1026')
1441
2033
  .matchHeader('fiware-service', 'smartgondor')
1442
2034
  .matchHeader('fiware-servicepath', 'gardens')
@@ -1485,6 +2077,16 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1485
2077
 
1486
2078
  beforeEach(function () {
1487
2079
  nock.cleanAll();
2080
+ contextBrokerMock = nock('http://192.168.1.1:1026')
2081
+ .matchHeader('fiware-service', 'smartgondor')
2082
+ .matchHeader('fiware-servicepath', 'gardens')
2083
+ .post(
2084
+ '/v2/entities?options=upsert',
2085
+ utils.readExampleFile(
2086
+ './test/unit/ngsiv2/examples/contextRequests/updateContextExpressionPlugin37.json'
2087
+ )
2088
+ )
2089
+ .reply(204);
1488
2090
  });
1489
2091
 
1490
2092
  it('should calculate them and remove non-explicitAttrs by jexl expression with context from the payload ', function (done) {
@@ -1522,7 +2124,6 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1522
2124
 
1523
2125
  beforeEach(function () {
1524
2126
  nock.cleanAll();
1525
-
1526
2127
  contextBrokerMock = nock('http://192.168.1.1:1026')
1527
2128
  .matchHeader('fiware-service', 'smartgondor')
1528
2129
  .matchHeader('fiware-servicepath', 'gardens')
@@ -1534,7 +2135,6 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1534
2135
  )
1535
2136
  .reply(204);
1536
2137
  });
1537
-
1538
2138
  afterEach(function (done) {
1539
2139
  done();
1540
2140
  });
@@ -1547,6 +2147,277 @@ describe('Java expression language (JEXL) based transformations plugin', functio
1547
2147
  });
1548
2148
  });
1549
2149
  });
2150
+
2151
+ describe('When using nested expressions by pointing to previous objetc_ids in a device ', function () {
2152
+ const values = [
2153
+ {
2154
+ name: 'v',
2155
+ type: 'Number',
2156
+ value: 5
2157
+ }
2158
+ ];
2159
+
2160
+ beforeEach(function () {
2161
+ nock.cleanAll();
2162
+
2163
+ contextBrokerMock = nock('http://192.168.1.1:1026')
2164
+ .matchHeader('fiware-service', 'smartgondor')
2165
+ .matchHeader('fiware-servicepath', 'gardens')
2166
+ .post('/v2/entities?options=upsert', {
2167
+ id: 'nested1',
2168
+ type: 'nestedExpressionsObj',
2169
+ v: {
2170
+ value: 5,
2171
+ type: 'Number'
2172
+ },
2173
+ value3: {
2174
+ value: 10,
2175
+ type: 'Number'
2176
+ }
2177
+ })
2178
+ .reply(204);
2179
+ });
2180
+
2181
+ afterEach(function (done) {
2182
+ done();
2183
+ });
2184
+
2185
+ it('should not calculate values using nested object_ids', function (done) {
2186
+ iotAgentLib.update('nested1', 'nestedExpressionsObj', '', values, function (error) {
2187
+ should.not.exist(error);
2188
+ contextBrokerMock.done();
2189
+ done();
2190
+ });
2191
+ });
2192
+ });
2193
+
2194
+ describe('When using nested expressions by pointing to previous attributes names in a device ', function () {
2195
+ const values = [
2196
+ {
2197
+ name: 't',
2198
+ type: 'Text',
2199
+ value: 'nestedText'
2200
+ }
2201
+ ];
2202
+
2203
+ beforeEach(function () {
2204
+ nock.cleanAll();
2205
+
2206
+ contextBrokerMock = nock('http://192.168.1.1:1026')
2207
+ .matchHeader('fiware-service', 'smartgondor')
2208
+ .matchHeader('fiware-servicepath', 'gardens')
2209
+ .post('/v2/entities?options=upsert', {
2210
+ id: 'nested2',
2211
+ type: 'nestedExpressionsName',
2212
+ t: {
2213
+ value: 'nestedText',
2214
+ type: 'Text'
2215
+ },
2216
+ prefix: {
2217
+ value: 'pre_nestedText',
2218
+ type: 'text'
2219
+ },
2220
+ postfix: {
2221
+ value: 'pre_nestedText_post',
2222
+ type: 'text'
2223
+ }
2224
+ })
2225
+ .reply(204);
2226
+ });
2227
+
2228
+ afterEach(function (done) {
2229
+ done();
2230
+ });
2231
+
2232
+ it('should calculate values using nested attributes names', function (done) {
2233
+ iotAgentLib.update('nested2', 'nestedExpressionsName', '', values, function (error) {
2234
+ should.not.exist(error);
2235
+ contextBrokerMock.done();
2236
+ done();
2237
+ });
2238
+ });
2239
+ });
2240
+
2241
+ describe('When using nested expressions by pointing to previous attributes names and skipValue ', function () {
2242
+ const values = [
2243
+ {
2244
+ name: 't',
2245
+ type: 'Text',
2246
+ value: 'nestedText'
2247
+ }
2248
+ ];
2249
+
2250
+ beforeEach(function () {
2251
+ nock.cleanAll();
2252
+
2253
+ contextBrokerMock = nock('http://192.168.1.1:1026')
2254
+ .matchHeader('fiware-service', 'smartgondor')
2255
+ .matchHeader('fiware-servicepath', 'gardens')
2256
+ .post('/v2/entities?options=upsert', {
2257
+ id: 'nested3',
2258
+ type: 'nestedExpressionsSkip',
2259
+ prefix: {
2260
+ value: 'pre_nestedText',
2261
+ type: 'text'
2262
+ },
2263
+ postfix: {
2264
+ value: 'pre_nestedText_post',
2265
+ type: 'text'
2266
+ }
2267
+ })
2268
+ .reply(204);
2269
+ });
2270
+
2271
+ afterEach(function (done) {
2272
+ done();
2273
+ });
2274
+
2275
+ it('should calculate values using nested attributes names and skip measures', function (done) {
2276
+ iotAgentLib.update('nested3', 'nestedExpressionsSkip', '', values, function (error) {
2277
+ should.not.exist(error);
2278
+ contextBrokerMock.done();
2279
+ done();
2280
+ });
2281
+ });
2282
+ });
2283
+
2284
+ describe('When using nested expressions - Direct case', function () {
2285
+ const values = [
2286
+ {
2287
+ name: 'level',
2288
+ type: 'Number',
2289
+ value: 100
2290
+ }
2291
+ ];
2292
+
2293
+ beforeEach(function () {
2294
+ nock.cleanAll();
2295
+
2296
+ contextBrokerMock = nock('http://192.168.1.1:1026')
2297
+ .matchHeader('fiware-service', 'smartgondor')
2298
+ .matchHeader('fiware-servicepath', 'gardens')
2299
+ .post('/v2/entities?options=upsert', {
2300
+ id: 'nestedDirect',
2301
+ type: 'nestedExpressionsDirect',
2302
+ level: {
2303
+ value: 100,
2304
+ type: 'Number'
2305
+ },
2306
+ correctedLevel: {
2307
+ value: 89.7,
2308
+ type: 'Number'
2309
+ },
2310
+ normalizedLevel: {
2311
+ value: 0.897,
2312
+ type: 'Number'
2313
+ }
2314
+ })
2315
+ .reply(204);
2316
+ });
2317
+
2318
+ afterEach(function (done) {
2319
+ done();
2320
+ });
2321
+
2322
+ it('should calculate values using nested attributes names and skip measures', function (done) {
2323
+ iotAgentLib.update('nestedDirect', 'nestedExpressionDirect', '', values, function (error) {
2324
+ should.not.exist(error);
2325
+ contextBrokerMock.done();
2326
+ done();
2327
+ });
2328
+ });
2329
+ });
2330
+
2331
+ describe('When using nested expressions - Reverse case - Antipattern', function () {
2332
+ const values = [
2333
+ {
2334
+ name: 'level',
2335
+ type: 'Number',
2336
+ value: 100
2337
+ }
2338
+ ];
2339
+
2340
+ beforeEach(function () {
2341
+ nock.cleanAll();
2342
+
2343
+ contextBrokerMock = nock('http://192.168.1.1:1026')
2344
+ .matchHeader('fiware-service', 'smartgondor')
2345
+ .matchHeader('fiware-servicepath', 'gardens')
2346
+ .post('/v2/entities?options=upsert', {
2347
+ id: 'nestedReverse',
2348
+ type: 'nestedExpressionsReverse',
2349
+ level: {
2350
+ value: 100,
2351
+ type: 'Number'
2352
+ },
2353
+ correctedLevel: {
2354
+ value: 89.7,
2355
+ type: 'Number'
2356
+ }
2357
+ })
2358
+ .reply(204);
2359
+ });
2360
+
2361
+ afterEach(function (done) {
2362
+ done();
2363
+ });
2364
+
2365
+ it('should calculate values using nested attributes names and skip measures', function (done) {
2366
+ iotAgentLib.update('nestedReverse', 'nestedExpressionReverse', '', values, function (error) {
2367
+ should.not.exist(error);
2368
+ contextBrokerMock.done();
2369
+ done();
2370
+ });
2371
+ });
2372
+ });
2373
+
2374
+ describe('When using nested expressions - Antipattern', function () {
2375
+ const values = [
2376
+ {
2377
+ name: 'a',
2378
+ type: 'Number',
2379
+ value: 10
2380
+ },
2381
+ {
2382
+ name: 'b',
2383
+ type: 'Number',
2384
+ value: 20
2385
+ }
2386
+ ];
2387
+
2388
+ beforeEach(function () {
2389
+ nock.cleanAll();
2390
+
2391
+ contextBrokerMock = nock('http://192.168.1.1:1026')
2392
+ .matchHeader('fiware-service', 'smartgondor')
2393
+ .matchHeader('fiware-servicepath', 'gardens')
2394
+ .post('/v2/entities?options=upsert', {
2395
+ id: 'nestedAnti',
2396
+ type: 'nestedExpressionsAnti',
2397
+ a: {
2398
+ value: 200,
2399
+ type: 'Number'
2400
+ },
2401
+ b: {
2402
+ value: 2000,
2403
+ type: 'Number'
2404
+ }
2405
+ })
2406
+ .reply(204);
2407
+ });
2408
+
2409
+ afterEach(function (done) {
2410
+ done();
2411
+ });
2412
+
2413
+ it('should calculate values using nested attributes names and skip measures', function (done) {
2414
+ iotAgentLib.update('nestedAnti', 'nestedExpressionsAnti', '', values, function (error) {
2415
+ should.not.exist(error);
2416
+ contextBrokerMock.done();
2417
+ done();
2418
+ });
2419
+ });
2420
+ });
1550
2421
  });
1551
2422
 
1552
2423
  describe('Java expression language (JEXL) based transformations plugin - Timestamps', function () {
@@ -1633,7 +2504,6 @@ describe('Java expression language (JEXL) based transformations plugin - Timesta
1633
2504
 
1634
2505
  timekeeper.freeze(time);
1635
2506
  nock.cleanAll();
1636
-
1637
2507
  contextBrokerMock = nock('http://192.168.1.1:1026')
1638
2508
  .matchHeader('fiware-service', 'smartgondor')
1639
2509
  .matchHeader('fiware-servicepath', 'gardens')