iotagent-node-lib 2.23.0 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/.github/workflows/ci.yml +6 -7
  2. package/.nyc_output/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +1 -0
  3. package/.nyc_output/processinfo/33364de2-1199-4ec2-b33c-cae063ef8cc4.json +1 -0
  4. package/.nyc_output/processinfo/index.json +1 -1
  5. package/CHANGES_NEXT_RELEASE +1 -2
  6. package/doc/advanced-topics.md +78 -3
  7. package/doc/apiary/iotagent.apib +5 -5
  8. package/doc/architecture.md +52 -5
  9. package/doc/deprecated.md +10 -7
  10. package/doc/expressionLanguage.md +46 -35
  11. package/doc/getting-started.md +1 -1
  12. package/doc/usermanual.md +18 -16
  13. package/examples/TTOpen-service.json +1 -1
  14. package/lib/errors.js +9 -1
  15. package/lib/fiware-iotagent-lib.js +2 -1
  16. package/lib/jexlTranformsMap.js +12 -1
  17. package/lib/plugins/bidirectionalData.js +104 -6
  18. package/lib/plugins/expressionPlugin.js +10 -0
  19. package/lib/plugins/jexlParser.js +2 -2
  20. package/lib/plugins/pluginUtils.js +2 -1
  21. package/lib/request-shim.js +2 -1
  22. package/lib/services/devices/deviceService.js +53 -21
  23. package/lib/services/devices/devices-NGSI-v2.js +3 -1
  24. package/lib/services/ngsi/entities-NGSI-v2.js +14 -4
  25. package/lib/services/northBound/contextServer-NGSI-LD.js +96 -20
  26. package/lib/services/northBound/contextServer-NGSI-v2.js +1 -0
  27. package/lib/services/northBound/restUtils.js +3 -5
  28. package/lib/templates/deviceGroup.json +1 -1
  29. package/package.json +2 -2
  30. package/test/unit/examples/deviceProvisioningRequests/provisionNewDeviceEmpty.json +43 -0
  31. package/test/unit/examples/mongoCollections/configurations.json +3 -3
  32. package/test/unit/expressions/jexlExpression-test.js +29 -8
  33. package/test/unit/general/deviceService-test.js +31 -29
  34. package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +62 -10
  35. package/test/unit/mongodb/mongodb-group-registry-test.js +24 -0
  36. package/test/unit/mongodb/mongodb-registry-test.js +68 -10
  37. package/test/unit/ngsi-ld/examples/contextRequests/updateContextExpressionPlugin30.json +11 -0
  38. package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithDatasetId.json +21 -0
  39. package/test/unit/ngsi-ld/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json +17 -0
  40. package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +18 -4
  41. package/test/unit/ngsi-ld/general/deviceService-test.js +31 -29
  42. package/test/unit/ngsi-ld/lazyAndCommands/command-test.js +656 -2
  43. package/test/unit/ngsi-ld/ngsiService/unsupported-endpoints-test.js +111 -0
  44. package/test/unit/ngsi-ld/plugins/bidirectional-plugin_test.js +221 -0
  45. package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +0 -3
  46. package/test/unit/ngsiv2/examples/contextRequests/updateContextMultientityJexlExpressionPlugin1.json +22 -0
  47. package/test/unit/ngsiv2/examples/subscriptionRequests/bidirectionalNotificationWithMetadata.json +19 -0
  48. package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +21 -6
  49. package/test/unit/ngsiv2/general/deviceService-test.js +25 -23
  50. package/test/unit/ngsiv2/lazyAndCommands/command-test.js +106 -0
  51. package/test/unit/ngsiv2/plugins/bidirectional-plugin_test.js +115 -0
  52. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +58 -0
  53. package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +25 -6
  54. package/.nyc_output/6e3d7795-bf8c-4a50-bd2f-f8221f27aeae.json +0 -1
  55. package/.nyc_output/processinfo/6e3d7795-bf8c-4a50-bd2f-f8221f27aeae.json +0 -1
  56. package/config +0 -0
  57. package/docker/Mosquitto/Dockerfile.debian +0 -38
  58. package/docker/Mosquitto/Dockerfile.debian~ +0 -23
  59. package/lib/plugins/multiEntity.js_avg2 +0 -343
  60. package/test/unit/ngsiv2/plugins/multientity-plugin_test.js_avg2 +0 -1224
@@ -365,6 +365,522 @@ describe('NGSI-LD - Command functionalities', function () {
365
365
  });
366
366
  });
367
367
 
368
+ describe('When a sequential command with datasetId updates via PATCH /attrs/attr-name arrives to the IoT Agent', function () {
369
+ const options = {
370
+ url: 'http://localhost:' + iotAgentConfig.server.port + '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs',
371
+ method: 'PUT',
372
+ json: {
373
+ position: [
374
+ {
375
+ type: 'Property',
376
+ value: [1, 2, 3],
377
+ datasetId: 'urn:ngsi-ld:this'
378
+ },
379
+ {
380
+ type: 'Property',
381
+ value: [28, -104, 23],
382
+ datasetId: 'urn:ngsi-ld:that'
383
+ }
384
+ ]
385
+ },
386
+ headers: {
387
+ 'fiware-service': 'smartgondor',
388
+ 'content-type': 'application/ld+json'
389
+ }
390
+ };
391
+
392
+ beforeEach(function (done) {
393
+ logger.setLevel('ERROR');
394
+ iotAgentLib.register(device3, function (error) {
395
+ done();
396
+ });
397
+ });
398
+
399
+ it('should call the client handler once including datasetId', function (done) {
400
+ let handlerCalled = 0;
401
+
402
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
403
+ id.should.equal('urn:ngsi-ld:' + device3.type + ':' + device3.id);
404
+ type.should.equal(device3.type);
405
+ attributes[0].name.should.equal('position');
406
+ attributes[0].datasetId.should.equal('urn:ngsi-ld:this');
407
+ attributes[1].name.should.equal('position');
408
+ attributes[1].datasetId.should.equal('urn:ngsi-ld:that');
409
+ JSON.stringify(attributes[0].value).should.equal('[1,2,3]');
410
+ JSON.stringify(attributes[1].value).should.equal('[28,-104,23]');
411
+ handlerCalled++;
412
+ callback(null, {
413
+ id,
414
+ type,
415
+ attributes: [
416
+ {
417
+ name: 'position',
418
+ type: 'Array',
419
+ value: '[28, -104, 23]'
420
+ },
421
+ {
422
+ name: 'orientation',
423
+ type: 'Array',
424
+ value: '[1, 2, 3]'
425
+ }
426
+ ]
427
+ });
428
+ });
429
+
430
+ request(options, function (error, response, body) {
431
+ should.not.exist(error);
432
+ handlerCalled.should.equal(1);
433
+ done();
434
+ });
435
+ });
436
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
437
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
438
+ callback(null, {
439
+ id,
440
+ type,
441
+ attributes: [
442
+ {
443
+ name: 'position',
444
+ type: 'Array',
445
+ value: '[28, -104, 23]'
446
+ }
447
+ ]
448
+ });
449
+ });
450
+
451
+ request(options, function (error, response, body) {
452
+ should.not.exist(error);
453
+ done();
454
+ });
455
+ });
456
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
457
+ let serviceReceived = false;
458
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
459
+ serviceReceived = service === 'smartgondor';
460
+ callback(null, {
461
+ id,
462
+ type,
463
+ attributes: [
464
+ {
465
+ name: 'position',
466
+ type: 'Array',
467
+ value: '[28, -104, 23]'
468
+ }
469
+ ]
470
+ });
471
+ });
472
+
473
+ request(options, function (error, response, body) {
474
+ serviceReceived.should.equal(true);
475
+ done();
476
+ });
477
+ });
478
+ });
479
+
480
+ describe('When a command update PATCH attrs/attr-name with datasetId arrives to the IoT Agent as Context Provider', function () {
481
+ const options = {
482
+ url:
483
+ 'http://localhost:' +
484
+ iotAgentConfig.server.port +
485
+ '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs/position',
486
+ method: 'PATCH',
487
+ json: {
488
+ type: 'Property',
489
+ value: [28, -104, 23],
490
+ datasetId: 'urn:ngsi-ld:this'
491
+ },
492
+ headers: {
493
+ 'fiware-service': 'smartgondor',
494
+ 'content-type': 'application/ld+json'
495
+ }
496
+ };
497
+
498
+ beforeEach(function (done) {
499
+ logger.setLevel('ERROR');
500
+ iotAgentLib.register(device3, function (error) {
501
+ done();
502
+ });
503
+ });
504
+
505
+ it('should call the client handler once including datasetId', function (done) {
506
+ let handlerCalled = 0;
507
+
508
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
509
+ id.should.equal('urn:ngsi-ld:' + device3.type + ':' + device3.id);
510
+ type.should.equal(device3.type);
511
+ attributes[0].name.should.equal('position');
512
+ attributes[0].datasetId.should.equal('urn:ngsi-ld:this');
513
+ JSON.stringify(attributes[0].value).should.equal('[28,-104,23]');
514
+ handlerCalled++;
515
+ callback(null, {
516
+ id,
517
+ type,
518
+ attributes: [
519
+ {
520
+ name: 'position',
521
+ type: 'Array',
522
+ value: '[28, -104, 23]'
523
+ }
524
+ ]
525
+ });
526
+ });
527
+
528
+ request(options, function (error, response, body) {
529
+ should.not.exist(error);
530
+ handlerCalled.should.equal(1);
531
+ done();
532
+ });
533
+ });
534
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
535
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
536
+ callback(null, {
537
+ id,
538
+ type,
539
+ attributes: [
540
+ {
541
+ name: 'position',
542
+ type: 'Array',
543
+ value: '[28, -104, 23]'
544
+ }
545
+ ]
546
+ });
547
+ });
548
+
549
+ request(options, function (error, response, body) {
550
+ should.not.exist(error);
551
+ done();
552
+ });
553
+ });
554
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
555
+ let serviceReceived = false;
556
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
557
+ serviceReceived = service === 'smartgondor';
558
+ callback(null, {
559
+ id,
560
+ type,
561
+ attributes: [
562
+ {
563
+ name: 'position',
564
+ type: 'Array',
565
+ value: '[28, -104, 23]'
566
+ }
567
+ ]
568
+ });
569
+ });
570
+
571
+ request(options, function (error, response, body) {
572
+ serviceReceived.should.equal(true);
573
+ done();
574
+ });
575
+ });
576
+ });
577
+
578
+ describe('When a command update PATCH attrs/attr-name with metadata arrives to the IoT Agent as Context Provider', function () {
579
+ const options = {
580
+ url:
581
+ 'http://localhost:' +
582
+ iotAgentConfig.server.port +
583
+ '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs/position',
584
+ method: 'PATCH',
585
+ json: {
586
+ type: 'Property',
587
+ value: [28, -104, 23],
588
+ qos: 1
589
+ },
590
+ headers: {
591
+ 'fiware-service': 'smartgondor',
592
+ 'content-type': 'application/ld+json'
593
+ }
594
+ };
595
+
596
+ beforeEach(function (done) {
597
+ logger.setLevel('ERROR');
598
+ iotAgentLib.register(device3, function (error) {
599
+ done();
600
+ });
601
+ });
602
+
603
+ it('should call the client handler once including metadata', function (done) {
604
+ let handlerCalled = 0;
605
+
606
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
607
+ id.should.equal('urn:ngsi-ld:' + device3.type + ':' + device3.id);
608
+ type.should.equal(device3.type);
609
+ attributes[0].name.should.equal('position');
610
+ attributes[0].metadata.qos.should.equal(1);
611
+ JSON.stringify(attributes[0].value).should.equal('[28,-104,23]');
612
+ handlerCalled++;
613
+ callback(null, {
614
+ id,
615
+ type,
616
+ attributes: [
617
+ {
618
+ name: 'position',
619
+ type: 'Array',
620
+ value: '[28, -104, 23]'
621
+ }
622
+ ]
623
+ });
624
+ });
625
+
626
+ request(options, function (error, response, body) {
627
+ should.not.exist(error);
628
+ handlerCalled.should.equal(1);
629
+ done();
630
+ });
631
+ });
632
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
633
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
634
+ callback(null, {
635
+ id,
636
+ type,
637
+ attributes: [
638
+ {
639
+ name: 'position',
640
+ type: 'Array',
641
+ value: '[28, -104, 23]'
642
+ }
643
+ ]
644
+ });
645
+ });
646
+
647
+ request(options, function (error, response, body) {
648
+ should.not.exist(error);
649
+ done();
650
+ });
651
+ });
652
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
653
+ let serviceReceived = false;
654
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
655
+ serviceReceived = service === 'smartgondor';
656
+ callback(null, {
657
+ id,
658
+ type,
659
+ attributes: [
660
+ {
661
+ name: 'position',
662
+ type: 'Array',
663
+ value: '[28, -104, 23]'
664
+ }
665
+ ]
666
+ });
667
+ });
668
+
669
+ request(options, function (error, response, body) {
670
+ serviceReceived.should.equal(true);
671
+ done();
672
+ });
673
+ });
674
+ });
675
+
676
+ describe('When a command overwrite PUT attrs/attr-name arrives to the IoT Agent as Context Provider', function () {
677
+ const options = {
678
+ url:
679
+ 'http://localhost:' +
680
+ iotAgentConfig.server.port +
681
+ '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs/position',
682
+ method: 'PUT',
683
+ json: {
684
+ type: 'Property',
685
+ value: [28, -104, 23]
686
+ },
687
+ headers: {
688
+ 'fiware-service': 'smartgondor',
689
+ 'content-type': 'application/ld+json'
690
+ }
691
+ };
692
+
693
+ beforeEach(function (done) {
694
+ logger.setLevel('ERROR');
695
+ iotAgentLib.register(device3, function (error) {
696
+ done();
697
+ });
698
+ });
699
+
700
+ it('should call the client handler once', function (done) {
701
+ let handlerCalled = 0;
702
+
703
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
704
+ id.should.equal('urn:ngsi-ld:' + device3.type + ':' + device3.id);
705
+ type.should.equal(device3.type);
706
+ attributes[0].name.should.equal('position');
707
+ JSON.stringify(attributes[0].value).should.equal('[28,-104,23]');
708
+ handlerCalled++;
709
+ callback(null, {
710
+ id,
711
+ type,
712
+ attributes: [
713
+ {
714
+ name: 'position',
715
+ type: 'Array',
716
+ value: '[28, -104, 23]'
717
+ }
718
+ ]
719
+ });
720
+ });
721
+
722
+ request(options, function (error, response, body) {
723
+ should.not.exist(error);
724
+ handlerCalled.should.equal(1);
725
+ done();
726
+ });
727
+ });
728
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
729
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
730
+ callback(null, {
731
+ id,
732
+ type,
733
+ attributes: [
734
+ {
735
+ name: 'position',
736
+ type: 'Array',
737
+ value: '[28, -104, 23]'
738
+ }
739
+ ]
740
+ });
741
+ });
742
+
743
+ request(options, function (error, response, body) {
744
+ should.not.exist(error);
745
+ done();
746
+ });
747
+ });
748
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
749
+ let serviceReceived = false;
750
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
751
+ serviceReceived = service === 'smartgondor';
752
+ callback(null, {
753
+ id,
754
+ type,
755
+ attributes: [
756
+ {
757
+ name: 'position',
758
+ type: 'Array',
759
+ value: '[28, -104, 23]'
760
+ }
761
+ ]
762
+ });
763
+ });
764
+
765
+ request(options, function (error, response, body) {
766
+ serviceReceived.should.equal(true);
767
+ done();
768
+ });
769
+ });
770
+ });
771
+
772
+ describe('When a sequential command with datasetId overwrites via PUT /attrs/attr-name arrives to the IoT Agent', function () {
773
+ const options = {
774
+ url: 'http://localhost:' + iotAgentConfig.server.port + '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs',
775
+ method: 'PUT',
776
+ json: {
777
+ position: [
778
+ {
779
+ type: 'Property',
780
+ value: [1, 2, 3],
781
+ datasetId: 'urn:ngsi-ld:this'
782
+ },
783
+ {
784
+ type: 'Property',
785
+ value: [28, -104, 23],
786
+ datasetId: 'urn:ngsi-ld:that'
787
+ }
788
+ ]
789
+ },
790
+ headers: {
791
+ 'fiware-service': 'smartgondor',
792
+ 'content-type': 'application/ld+json'
793
+ }
794
+ };
795
+
796
+ beforeEach(function (done) {
797
+ logger.setLevel('ERROR');
798
+ iotAgentLib.register(device3, function (error) {
799
+ done();
800
+ });
801
+ });
802
+
803
+ it('should call the client handler once', function (done) {
804
+ let handlerCalled = 0;
805
+
806
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
807
+ id.should.equal('urn:ngsi-ld:' + device3.type + ':' + device3.id);
808
+ type.should.equal(device3.type);
809
+ attributes[0].name.should.equal('position');
810
+ attributes[0].datasetId.should.equal('urn:ngsi-ld:this');
811
+ attributes[1].name.should.equal('position');
812
+ attributes[1].datasetId.should.equal('urn:ngsi-ld:that');
813
+ JSON.stringify(attributes[0].value).should.equal('[1,2,3]');
814
+ JSON.stringify(attributes[1].value).should.equal('[28,-104,23]');
815
+ handlerCalled++;
816
+ callback(null, {
817
+ id,
818
+ type,
819
+ attributes: [
820
+ {
821
+ name: 'position',
822
+ type: 'Array',
823
+ value: '[28, -104, 23]'
824
+ },
825
+ {
826
+ name: 'orientation',
827
+ type: 'Array',
828
+ value: '[1, 2, 3]'
829
+ }
830
+ ]
831
+ });
832
+ });
833
+
834
+ request(options, function (error, response, body) {
835
+ should.not.exist(error);
836
+ handlerCalled.should.equal(1);
837
+ done();
838
+ });
839
+ });
840
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
841
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
842
+ callback(null, {
843
+ id,
844
+ type,
845
+ attributes: [
846
+ {
847
+ name: 'position',
848
+ type: 'Array',
849
+ value: '[28, -104, 23]'
850
+ }
851
+ ]
852
+ });
853
+ });
854
+
855
+ request(options, function (error, response, body) {
856
+ should.not.exist(error);
857
+ done();
858
+ });
859
+ });
860
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
861
+ let serviceReceived = false;
862
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
863
+ serviceReceived = service === 'smartgondor';
864
+ callback(null, {
865
+ id,
866
+ type,
867
+ attributes: [
868
+ {
869
+ name: 'position',
870
+ type: 'Array',
871
+ value: '[28, -104, 23]'
872
+ }
873
+ ]
874
+ });
875
+ });
876
+
877
+ request(options, function (error, response, body) {
878
+ serviceReceived.should.equal(true);
879
+ done();
880
+ });
881
+ });
882
+ });
883
+
368
884
  describe('When multiple command overwrites via PUT /attrs arrive to the IoT Agent as Context Provider', function () {
369
885
  const options = {
370
886
  url: 'http://localhost:' + iotAgentConfig.server.port + '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs',
@@ -471,7 +987,7 @@ describe('NGSI-LD - Command functionalities', function () {
471
987
  });
472
988
  });
473
989
 
474
- describe('When a command overwrite PUT attrs/attr-name arrives to the IoT Agent as Context Provider', function () {
990
+ describe('When a command overwrite PUT attrs/attr-name with datasetId arrives to the IoT Agent as Context Provider', function () {
475
991
  const options = {
476
992
  url:
477
993
  'http://localhost:' +
@@ -480,7 +996,8 @@ describe('NGSI-LD - Command functionalities', function () {
480
996
  method: 'PUT',
481
997
  json: {
482
998
  type: 'Property',
483
- value: [28, -104, 23]
999
+ value: [28, -104, 23],
1000
+ datasetId: 'urn:ngsi-ld:this'
484
1001
  },
485
1002
  headers: {
486
1003
  'fiware-service': 'smartgondor',
@@ -502,6 +1019,105 @@ describe('NGSI-LD - Command functionalities', function () {
502
1019
  id.should.equal('urn:ngsi-ld:' + device3.type + ':' + device3.id);
503
1020
  type.should.equal(device3.type);
504
1021
  attributes[0].name.should.equal('position');
1022
+ attributes[0].datasetId.should.equal('urn:ngsi-ld:this');
1023
+ JSON.stringify(attributes[0].value).should.equal('[28,-104,23]');
1024
+ handlerCalled++;
1025
+ callback(null, {
1026
+ id,
1027
+ type,
1028
+ attributes: [
1029
+ {
1030
+ name: 'position',
1031
+ type: 'Array',
1032
+ value: '[28, -104, 23]'
1033
+ }
1034
+ ]
1035
+ });
1036
+ });
1037
+
1038
+ request(options, function (error, response, body) {
1039
+ should.not.exist(error);
1040
+ handlerCalled.should.equal(1);
1041
+ done();
1042
+ });
1043
+ });
1044
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
1045
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
1046
+ callback(null, {
1047
+ id,
1048
+ type,
1049
+ attributes: [
1050
+ {
1051
+ name: 'position',
1052
+ type: 'Array',
1053
+ value: '[28, -104, 23]'
1054
+ }
1055
+ ]
1056
+ });
1057
+ });
1058
+
1059
+ request(options, function (error, response, body) {
1060
+ should.not.exist(error);
1061
+ done();
1062
+ });
1063
+ });
1064
+ it('should create the attribute with the "_status" prefix in the Context Broker', function (done) {
1065
+ let serviceReceived = false;
1066
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
1067
+ serviceReceived = service === 'smartgondor';
1068
+ callback(null, {
1069
+ id,
1070
+ type,
1071
+ attributes: [
1072
+ {
1073
+ name: 'position',
1074
+ type: 'Array',
1075
+ value: '[28, -104, 23]'
1076
+ }
1077
+ ]
1078
+ });
1079
+ });
1080
+
1081
+ request(options, function (error, response, body) {
1082
+ serviceReceived.should.equal(true);
1083
+ done();
1084
+ });
1085
+ });
1086
+ });
1087
+
1088
+ describe('When a command update PUT attrs/attr-name with metadata arrives to the IoT Agent as Context Provider', function () {
1089
+ const options = {
1090
+ url:
1091
+ 'http://localhost:' +
1092
+ iotAgentConfig.server.port +
1093
+ '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2/attrs/position',
1094
+ method: 'PUT',
1095
+ json: {
1096
+ type: 'Property',
1097
+ value: [28, -104, 23],
1098
+ qos: 1
1099
+ },
1100
+ headers: {
1101
+ 'fiware-service': 'smartgondor',
1102
+ 'content-type': 'application/ld+json'
1103
+ }
1104
+ };
1105
+
1106
+ beforeEach(function (done) {
1107
+ logger.setLevel('ERROR');
1108
+ iotAgentLib.register(device3, function (error) {
1109
+ done();
1110
+ });
1111
+ });
1112
+
1113
+ it('should call the client handler once including metadata', function (done) {
1114
+ let handlerCalled = 0;
1115
+
1116
+ iotAgentLib.setCommandHandler(function (id, type, service, subservice, attributes, callback) {
1117
+ id.should.equal('urn:ngsi-ld:' + device3.type + ':' + device3.id);
1118
+ type.should.equal(device3.type);
1119
+ attributes[0].name.should.equal('position');
1120
+ attributes[0].metadata.qos.should.equal(1);
505
1121
  JSON.stringify(attributes[0].value).should.equal('[28,-104,23]');
506
1122
  handlerCalled++;
507
1123
  callback(null, {
@@ -615,4 +1231,42 @@ describe('NGSI-LD - Command functionalities', function () {
615
1231
  });
616
1232
  });
617
1233
  });
1234
+
1235
+ describe('When a query arrives to the IoT Agent with registered commands but no lazy attributes', function () {
1236
+ const options = {
1237
+ url:
1238
+ 'http://localhost:' +
1239
+ iotAgentConfig.server.port +
1240
+ '/ngsi-ld/v1/entities/urn:ngsi-ld:Robot:r2d2',
1241
+ method: 'GET',
1242
+ headers: {
1243
+ 'fiware-service': 'smartgondor',
1244
+ 'content-type': 'application/ld+json'
1245
+ }
1246
+ };
1247
+
1248
+ beforeEach(function (done) {
1249
+ logger.setLevel('ERROR');
1250
+ iotAgentLib.register(device3, function (error) {
1251
+ done();
1252
+ });
1253
+ });
1254
+
1255
+ it('should return the a valid empty response', function (done) {
1256
+ iotAgentLib.setDataQueryHandler(function (id, type, service, subservice, attributes, callback) {
1257
+ should.exist(attributes);
1258
+ attributes.length.should.equal(0);
1259
+ callback(null, {
1260
+ id: 'urn:ngsi-ld:Robot:r2d2',
1261
+ type: 'Robot'
1262
+ });
1263
+ });
1264
+
1265
+ request(options, function (error, response, body) {
1266
+ should.not.exist(error);
1267
+ response.statusCode.should.equal(200);
1268
+ done();
1269
+ });
1270
+ });
1271
+ });
618
1272
  });