diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b9f3e0b..f6c3a06c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,7 +75,6 @@ jobs: run: | npm install npm test - code-coverage: name: Coveralls Code Coverage runs-on: ubuntu-latest diff --git a/AGECONF/config.json b/AGECONF/config.json index 81eec049..69b72307 100644 --- a/AGECONF/config.json +++ b/AGECONF/config.json @@ -1,5 +1,5 @@ { - "logLevel": "DEBUG", + "logLevel": "INFO", "multiCore": false, "relaxTemplateValidation": true, "contextBroker": { @@ -71,6 +71,8 @@ "contexts": [{ "id": "urn:ngsi-ld:Device:age01_Car", "type": "Device", + "ngsiVersion": "ld", + "jsonLdContext": "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld", "service": "opcua_car", "subservice": "/demo", "polling": false, @@ -104,6 +106,8 @@ "contextSubscriptions": [{ "id": "urn:ngsi-ld:Device:age01_Car", "type": "Device", + "ngsiVersion": "ld", + "jsonLdContext": "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld", "mappings": [{ "ocb_id": "Error", "opcua_id": "ns=3;s=Error", diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index d33879f0..cc6223d7 100755 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1 +1 @@ -Upgrade NodeJS version from 8.12.0 to 8.15.0 in Dockerfile due to security issues +Code refactoring and increase test coverage \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9c84b592..6c02cf88 100755 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,55 +1,265 @@ -To get started, sign the Contributor License Agreement. +To get started, +sign +the Contributor License Agreement. # Contributor License Agreement -Thank you for your interest in [OPC UA Agent](https://github.com/Engineering-Research-and-Development/iotagent-opcua).
-In order to clarify both the intellectual property license, granted with Contributions from any person, and the contribution management guidelines, outlined in order to achieve a project systematic growth, the OPC UA Agent Project must have a Contributor License Agreement (or Agreement) that has been accepted by each Contributor, indicating his/her agreement to terms and conditions of this Contributor License Agreement. +Thank you for your interest in +[OPC UA Agent](https://github.com/Engineering-Research-and-Development/iotagent-opcua).
In order to clarify both +the intellectual property license, granted with Contributions from any person, and the contribution management +guidelines, outlined in order to achieve a project systematic growth, the OPC UA Agent Project must have a Contributor +License Agreement (or Agreement) that has been accepted by each Contributor, indicating his/her agreement to terms and +conditions of this Contributor License Agreement. -This Agreement is for your protection as a Contributor as well as the protection of ENGINEERING Ingegneria Informatica S.p.A., which keeps the copyright of OPC UA Agent software and documentation. This does not change your rights to use your own Contributions for any other purpose. +This Agreement is for your protection as a Contributor as well as the protection of ENGINEERING Ingegneria Informatica +S.p.A., which keeps the copyright of OPC UA Agent software and documentation. This does not change your rights to use +your own Contributions for any other purpose. This Agreement: -- clarifies that, to your knowledge, the technology you’ve submitted was developed by you and that you have authority to provide it; -- grants to ENGINEERING Ingegneria Informatica S.p.A. a perpetual, worldwide, no-charge, royalty-free, irrevocable, non-exclusive copyright license to use your Contribution and every derivative work, according to OPC UA Agent license. +- clarifies that, to your knowledge, the technology you’ve submitted was developed by you and that you have authority + to provide it; +- grants to ENGINEERING Ingegneria Informatica S.p.A. a perpetual, worldwide, no-charge, royalty-free, irrevocable, + non-exclusive copyright license to use your Contribution and every derivative work, according to OPC UA Agent + license. **Please read this document carefully before accepting its terms and conditions.** ## Definitions + “Contributor” is the copyright owner that is making this Agreement with ENGINEERING Ingegneria Informatica S.p.A. -“Engineering” (ENGINEERING Ingegneria Informatica S.p.A.) is the entity owner of the copyright of OPC UA Agent software and documentation. +“Engineering” (ENGINEERING Ingegneria Informatica S.p.A.) is the entity owner of the copyright of OPC UA Agent software +and documentation. -“OPC UA Agent Project” or “Project” shall mean every organization, procedure, mean, practice, term, condition and license, used by ENGINEERING Ingegneria Informatica S.p.A. for the aim of the free/open source OPC UA Agent project development by means of all its software components and documentation which are pointed out on the project site: https://github.com/Engineering-Research-and-Development/iotagent-opcua +“OPC UA Agent Project” or “Project” shall mean every organization, procedure, mean, practice, term, condition and +license, used by ENGINEERING Ingegneria Informatica S.p.A. for the aim of the free/open source OPC UA Agent project +development by means of all its software components and documentation which are pointed out on the project site: +https://github.com/Engineering-Research-and-Development/iotagent-opcua -“Contribution” shall mean any original work of authorship, including any modifications or additions to an existing work, which is intentionally submitted by the Contributor to ENGINEERING for inclusion in OPC UA Agent software or documentation. For the purpose of this definition, “submitted” means any form of electronic, verbal or written communication sent to ENGINEERING, including but not limited to communication on electronic mailing lists, source code control systems and issue tracking systems that are managed by ENGINEERING for the purpose of discussing and improving OPC UA Agent software and documentation, but excluding the communication that is conspicuously marked or otherwise designated in writing by the Contributor as “Not a Contribution”. +“Contribution” shall mean any original work of authorship, including any modifications or additions to an existing work, +which is intentionally submitted by the Contributor to ENGINEERING for inclusion in OPC UA Agent software or +documentation. For the purpose of this definition, “submitted” means any form of electronic, verbal or written +communication sent to ENGINEERING, including but not limited to communication on electronic mailing lists, source code +control systems and issue tracking systems that are managed by ENGINEERING for the purpose of discussing and improving +OPC UA Agent software and documentation, but excluding the communication that is conspicuously marked or otherwise +designated in writing by the Contributor as “Not a Contribution”. ## Acceptance and Termination procedure -The Contributor agrees and commits himself/herself to respect both the Contribution Guidelines and the Acceptance and Termination procedure, as follows. + +The Contributor agrees and commits himself/herself to respect both the Contribution Guidelines and the Acceptance and +Termination procedure, as follows. ### Acceptance and Termination procedure -To contribute, the Contributor must accept this Contributor License Agreement and the Contribution Guidelines of this Agreement. Otherwise, ENGINEERING Ingegneria Informatica S.p.A. will not consider his/her Contribution. -A Developer who has sent Contributions in solid, useful source code and/or documentation and who asked to be a Contributor will be add to our Contributor List published on OPC UA Agent website. ENGINEERING will notify to the Contributor via email his/her elevation to Contributor status. +To contribute, the Contributor must accept this Contributor License Agreement and the Contribution Guidelines of this +Agreement. Otherwise, ENGINEERING Ingegneria Informatica S.p.A. will not consider his/her Contribution. -ENGINEERING can exclude a Contributor from the Contributors list, by its exclusive right, when this Contributor has not respected the above rules repeatedly or when s/he has not contributed for a long period (more than three years). If any of these events occurs, any assignment under this Agreement for the Contributor’s Contribution shall terminate, by a communication that ENGINEERING will send to the Contributor, starting from the date of this communication. +A Developer who has sent Contributions in solid, useful source code and/or documentation and who asked to be a +Contributor will be add to our Contributor List published on OPC UA Agent website. ENGINEERING will notify to the +Contributor via email his/her elevation to Contributor status. + +ENGINEERING can exclude a Contributor from the Contributors list, by its exclusive right, when this Contributor has not +respected the above rules repeatedly or when s/he has not contributed for a long period (more than three years). If any +of these events occurs, any assignment under this Agreement for the Contributor’s Contribution shall terminate, by a +communication that ENGINEERING will send to the Contributor, starting from the date of this communication. ## Contributor’s responsibility -The Contributor owns and has the rights to contribute all source code and related material, intended to be compiled or integrated with the source code for OPC UA Agent software and documentation which the Contributor has ever delivered, and the Project has accepted, for incorporation into the technology, made available under the OPC UA Agent Project. -The Contributor grants to comply with the applicable laws and regulations, the OPC UA Agent license terms of use and the guiding principles concerning any use of copyrighted materials. +The Contributor owns and has the rights to contribute all source code and related material, intended to be compiled or +integrated with the source code for OPC UA Agent software and documentation which the Contributor has ever delivered, +and the Project has accepted, for incorporation into the technology, made available under the OPC UA Agent Project. + +The Contributor grants to comply with the applicable laws and regulations, the OPC UA Agent license terms of use and the +guiding principles concerning any use of copyrighted materials. -This project is released with [Contributor Code of Conduct](./CODE_OF_CONDUCT.md). By participating in this project, you agree to abide by its terms. +This project is released with [Contributor Code of Conduct](./CODE_OF_CONDUCT.md). By participating in this project, you +agree to abide by its terms. ## Copyright assignment by Contributor -Subject to the terms and conditions of this Agreement, the Contributor grants to ENGINEERING Ingegneria Informatica S.p.A. a perpetual, worldwide, no-charge, royalty-free, irrevocable, non-exclusive copyright license to use the Contribution and every derivative work, according to OPC UA Agent License. + +Subject to the terms and conditions of this Agreement, the Contributor grants to ENGINEERING Ingegneria Informatica +S.p.A. a perpetual, worldwide, no-charge, royalty-free, irrevocable, non-exclusive copyright license to use the +Contribution and every derivative work, according to OPC UA Agent License. The Contributor represents that s/he is legally entitled to grant the above assignment. The Contributor represents that his/her Contribution is his/her original creation. -The Contributor represents that his/her Contribution includes complete details of any third-party license or other restriction of which s/he is personally aware and which are associated with any party of his/her Contribution. +The Contributor represents that his/her Contribution includes complete details of any third-party license or other +restriction of which s/he is personally aware and which are associated with any party of his/her Contribution. + +## Ground rules & expectations + +Before we get started, here are a few things we expect from you (and that you should expect from others): + +- Be kind and thoughtful in your conversations around this project. We all come from different backgrounds and + projects, which means we likely have different perspectives on "how open source is done." Try to listen to others + rather than convince them that your way is correct. +- Please ensure that your contribution passes all tests. If there are test failures, you will need to address them + before we can merge your contribution. +- When adding content, please consider if it is widely valuable. Please don't add references or links to things you or + your employer have created as others will do so if they appreciate it. +- When reporting a vulnerability on the software, please, put in contact with IoT Agent Node Lib repository + maintainers in order to discuss it in a private way. + +## How to contribute + +If you'd like to contribute, start by searching through the +[issues](https://github.com/Engineering-Research-and-Development/iotagent-opcua/issues) and +[pull requests](https://github.com/Engineering-Research-and-Development/iotagent-opcua/pulls) to see whether someone +else has raised a similar idea or question. In adition, you can also check in the IoTAgent Node Lib framework repository +for [issues](https://github.com/telefonicaid/iotagent-node-lib/issues) and +[pull requests](https://github.com/telefonicaid/iotagent-node-lib/pulls) across all the IoT-Agents + +If you don't see your idea listed, and you think it fits into the goals of this guide, do one of the following: + +- **If your contribution is minor,** such as a typo fix, open a pull request. +- **If your contribution is major,** such as a new guide, start by opening an issue first. That way, other people can + weigh in on the discussion before you do any work. + +### Pull Request protocol + +As explained in ([FIWARE Contribution Requirements](https://fiware-requirements.readthedocs.io/en/latest/)) +contributions are done using a pull request (PR). The detailed "protocol" used in such PR is described below: + +- Direct commits to master branch (even single-line modifications) are not allowed. Every modification has to come as + a PR +- In case the PR is implementing/fixing a numbered issue, the issue number has to be referenced in the body of the PR + at creation time +- Anybody is welcome to provide comments to the PR (either direct comments or using the review feature offered by + Github) +- Use _code line comments_ instead of _general comments_, for traceability reasons (see comments lifecycle below) +- Comments lifecycle + - Comment is created, initiating a _comment thread_ + - New comments can be added as responses to the original one, starting a discussion + - After discussion, the comment thread ends in one of the following ways: + - `Fixed in ` in case the discussion involves a fix in the PR branch (which commit hash is + included as reference) + - `NTC`, if finally nothing needs to be done (NTC = Nothing To Change) +- PR can be merged when the following conditions are met: + - All comment threads are closed + - All the participants in the discussion have provided a `LGTM` general comment (LGTM = Looks good to me) +- Self-merging is not allowed (except in rare and justified circumstances) + +Some additional remarks to take into account when contributing with new PRs: + +- PR must include not only code contributions, but their corresponding pieces of documentation (new or modifications + to existing one) and tests +- PR modifications must pass full regression based on existing test (unit, functional, memory, e2e) in addition to + whichever new test added due to the new functionality +- PR should be of an appropriated size that makes review achievable. Too large PRs could be closed with a "please, + redo the work in smaller pieces" without any further discussing + +## Community + +Discussions about the Open Source Guides take place on this repository's +[Issues](https://github.com/telefonicaid/iotagent-node-lib/issues) and +[Pull Requests](https://github.com/telefonicaid/iotagent-node-lib/pulls) sections. Anybody is welcome to join these +conversations. + +Wherever possible, do not take these conversations to private channels, including contacting the maintainers directly. + +## Overview + +Being an Open Source project, everyone can contribute, provided that it respect the following points: + +- Before contributing any code, the author must make sure all the tests work (see below how to launch the tests). +- Developed code must adhere to the syntax guidelines enforced by the linters. +- Code must be developed following the branching model and change log policies defined below. +- For any new feature added, unit tests must be provided, following the example of the ones already created. + +In order to start contributing: + +1. Fork this repository clicking on the "Fork" button on the upper-right area of the page. +2. Clone your just forked repository: + +```bash +git clone https://github.com/Engineering-Research-and-Development/iotagent-opcua.git +``` + +3. Add the main iotagent-opcua repository as a remote to your forked repository (use any name for your remote + repository, it does not have to be iotagent-opcua, although we will use it in the next steps): + +```bash +git remote add iotagent-opcua https://github.com/Engineering-Research-and-Development/iotagent-opcua.git +``` + +Before starting contributing, remember to synchronize the `master` branch in your forked repository with the `master` +branch in the main iotagent-opcua repository, by following this steps + +1. Change to your local `master` branch (in case you are not in it already): + +```bash +git checkout master +``` + +2. Fetch the remote changes: + +```bash +git fetch iotagent-opcua +``` + +3. Merge them: + +```bash +git rebase iotagent-opcua/master +``` + +Contributions following this guidelines will be added to the `master` branch, and released in the next version. The +release process is explaind in the _Releasing_ section below. + +## Branching model + +There is one special branches in the repository: + +- `master`: contains the last stable development code. New features and bugfixes are always merged to `master`. + +In order to start developing a new feature or refactoring, a new branch should be created with name `task/`. +This branch must be created from the current version of the `master` branch. Once the new functionality has been +completed, a Pull Request will be created from the feature branch to `master`. Remember to check both the linters and +the tests before creating the Pull Request. + +Bugfixes work the same way as other tasks, with the exception of the branch name, that should be called `bug/`. + +In order to contribute to the repository, these same scheme should be replicated in the forked repositories, so the new +features or fixes should all come from the current version of `master` and end up in `master` again. + +All the `task/*` and `bug/*` branches are temporary, and should be removed once they have been merged. + +There is another set of branches called `release/`, one for each version of the product. This branches +point to each of the released versions of the project, they are permanent and they are created with each release. + +## Releasing + +The process of making a release consists of the following steps: + +1. Create and PR into `master` a new task branch with the following changes: + +- Change the development version number in the package.json (with a sufix `-next`), to the new target version (without + any sufix) +- Make sure all the dependencies have fixed versions (usually the IoTAgent library will be on `master`). + +2. Create a tag from the last version of `master` named with the version number and push it to the repository. +3. Create the release in Github, from the created tag. In the description, add the contents of the change log. +4. Create a release branch from the last version of `master` named with the version number. +5. Create a new task for preparing the next release, adding the sufix `-next` to the current version number (to signal + this as the development version). + +## Change log + +The project contains a version changelog, called CHANGES_NEXT_RELEASE, that can be found in the root of the project. +Whenever a new feature or bug fix is going to be merged with `develop`, a new entry should be added to this changelog. +The new entry should contain the reference number of the issue it is solving (if any). + +When a new version is released, the change log is cleared, and remains fixed in the last commit of that version. The +content of the change log is also moved to the release description in the GitHub release. ## Miscellaneous Terms -The Agreement is subject to the Italian law and any dispute arising between the Parties relating to this Agreement shall be under the exclusive jurisdiction of the Court of Rome, Italy. -These Terms constitute the entire agreement between you and ENGINEERING relating to the subject matter herein and supersede all prior communications, agreements, understandings and arrangements between you and ENGINEERING, whether oral or written. +The Agreement is subject to the Italian law and any dispute arising between the Parties relating to this Agreement shall +be under the exclusive jurisdiction of the Court of Rome, Italy. + +These Terms constitute the entire agreement between you and ENGINEERING relating to the subject matter herein and +supersede all prior communications, agreements, understandings and arrangements between you and ENGINEERING, whether +oral or written. diff --git a/README.md b/README.md index ee60132d..06497e54 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,6 @@ For checking current status of the Agent, send a request to /status service Documentation about OPC UA Client Secure connection can be found [here](docs/opc_ua_secure_connection_configuration.md) - ### How to get access to the advanced API and Documentation topics Documentation about the OPC UA Administration API can be found [here](https://opcuaiotagent.docs.apiary.io) @@ -160,12 +159,12 @@ The **IoT Agent for OPC UA** project is part of [FIWARE](https://fiware.org/) an The IoT Agent for OPC UA is licensed under [Affero General Public License (GPL) version 3](./LICENSE). -© 2020 Engineering Ingegneria Informatica S.p.A. +© 2021 Engineering Ingegneria Informatica S.p.A. The following third-party libraries are used under license -1. [node-opcua](http://node-opcua.github.io/) - **MIT** - © 2014-2018 Etienne Rossignon -2. [iotagent-node-lib](https://github.com/telefonicaid/iotagent-node-lib) - **AGPL** © 2014-2018 Telefonica +1. [node-opcua](http://node-opcua.github.io/) - **MIT** - © 2014-2021 Etienne Rossignon +2. [iotagent-node-lib](https://github.com/telefonicaid/iotagent-node-lib) - **AGPL** © 2014-2021 Telefonica Investigación y Desarrollo The full list of third-party libraries licenses can be found diff --git a/conf/config.json b/conf/config.json index 81eec049..af131999 100644 --- a/conf/config.json +++ b/conf/config.json @@ -71,6 +71,8 @@ "contexts": [{ "id": "urn:ngsi-ld:Device:age01_Car", "type": "Device", + "ngsiVersion": "ld", + "jsonLdContext": "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld", "service": "opcua_car", "subservice": "/demo", "polling": false, @@ -104,6 +106,8 @@ "contextSubscriptions": [{ "id": "urn:ngsi-ld:Device:age01_Car", "type": "Device", + "ngsiVersion": "ld", + "jsonLdContext": "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld", "mappings": [{ "ocb_id": "Error", "opcua_id": "ns=3;s=Error", diff --git a/conf/config.json.TEST_WITH_PLACEHOLDER b/conf/config.json.TEST_WITH_PLACEHOLDER index a0741156..226a19f3 100644 --- a/conf/config.json.TEST_WITH_PLACEHOLDER +++ b/conf/config.json.TEST_WITH_PLACEHOLDER @@ -1,17 +1,15 @@ { "logLevel": "INFO", - "multiCore" : false, - "relaxTemplateValidation":true, + "multiCore": false, + "relaxTemplateValidation": true, "contextBroker": { "host": "TEST_MACHINE_IP", "port": 1026, - "url": "http://TEST_MACHINE_IP:1026", - "ngsiVersion":"ld", - "jsonLdContext":"https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld", - "fallbackTenant":"opcua_car" + "service": "opcua_car", + "subservice": "/demo" }, "server": { - "port": 4003, + "port": 4001, "baseRoot": "/" }, "deviceRegistry": { @@ -29,53 +27,45 @@ "service": "opcua_car", "subservice": "/demo", "active": [ - { - "name": "MissingContextSubElementForThis", - "type": "Number", - "object_id": "MissingContextSubElementForThis" - }, { "name": "EngineBrake", - "type": "Number", - "object_id": "EngineBrake" - }, - { - "name": "Speed", - "type": "Number", - "object_id": "Speed" + "type": "Number" }, { "name": "Acceleration", - "type": "Number", - "object_id": "Acceleration" + "type": "Number" }, { "name": "EngineStopped", - "type": "Boolean", - "object_id": "EngineStopped" + "type": "Boolean" }, { "name": "Engine_Temperature", - "type": "Number", - "object_id": "Engine_Temperature" + "type": "Number" }, { "name": "Engine_Oxigen", - "type": "Number", - "object_id": "Engine_Oxigen" + "type": "Number" + } + ], + "lazy": [ + { + "name": "Speed", + "type": "Number" } ], - "lazy": [], "commands": [ + { + "name": "Error", + "type": "command" + }, { "name": "Stop", - "type": "command", - "object_id": "Stop" + "type": "command" }, { "name": "Accelerate", - "type": "command", - "object_id": "Accelerate" + "type": "command" } ] } @@ -83,28 +73,22 @@ "browseServerOptions": null, "service": "opcua_car", "subservice": "/demo", - "providerUrl": "http://TEST_MACHINE_IP:4003", + "providerUrl": "http://TEST_MACHINE_IP:4001", "pollingExpiration": "200000", "pollingDaemonFrequency": "20000", "deviceRegistrationDuration": "P1M", "defaultType": null, "contexts": [ { - "id": "urn:ngsi-ld:Device:age01_Car", + "id": "age01_Car", "type": "Device", "service": "opcua_car", "subservice": "/demo", "polling": false, "mappings": [ { - "ocb_id": "EngineBrake", - "opcua_id": "ns=3;s=EngineBrake", - "object_id": null, - "inputArguments": [] - }, - { - "ocb_id": "Speed", - "opcua_id": "ns=3;s=Speed", + "ocb_id": "Error", + "opcua_id": "ns=3;s=Error", "object_id": null, "inputArguments": [] }, @@ -137,9 +121,26 @@ ], "contextSubscriptions": [ { - "id": "urn:ngsi-ld:Device:age01_Car", + "id": "age01_Car", "type": "Device", "mappings": [ + { + "ocb_id": "Error", + "opcua_id": "ns=3;s=Error", + "object_id": "ns=3;i=1000", + "inputArguments": [ + { + "dataType": 12, + "type": "Error Type" + } + ] + }, + { + "ocb_id": "Speed", + "opcua_id": "ns=3;s=Speed", + "object_id": "ns=3;i=1000", + "inputArguments": [] + }, { "ocb_id": "Stop", "opcua_id": "ns=3;s=Stop", @@ -153,13 +154,11 @@ "inputArguments": [ { "dataType": 6, - "type": "Intensity", - "value": 2, - "arrayType": 0 + "type": "Intensity" } ] } ] } ] -} +} \ No newline at end of file diff --git a/conf/config.properties.WITH_PLACEHOLDER b/conf/config.properties.WITH_PLACEHOLDER index e3ea4670..be9b8665 100755 --- a/conf/config.properties.WITH_PLACEHOLDER +++ b/conf/config.properties.WITH_PLACEHOLDER @@ -6,7 +6,7 @@ namespaceNumericIdentifier=1000 context-broker-host=TEST_MACHINE_IP context-broker-port=1026 server-base-root=/ -server-port=4003 +server-port=4001 device-registry-type=memory mongodb-host=TEST_MACHINE_IP mongodb-port=27017 @@ -15,11 +15,11 @@ mongodb-retries=5 mongodb-retry-time=5 fiware-service=opcua_car fiware-service-path=/demo -provider-url=http://TEST_MACHINE_IP:4003 +provider-url=http://TEST_MACHINE_IP:4001 device-registration-duration=P1M #endpoint=opc.tcp://TEST_MACHINE_IP:4334/UA/EnergyMESServer endpoint=opc.tcp://TEST_MACHINE_IP:5001/UA/CarServer -log-level=DEBUG +log-level=INFO #DATATYPE MAPPING OPCUA --> NGSI OPC-datatype-Number=Number OPC-datatype-Decimal128=Number @@ -39,6 +39,9 @@ maxNotificationsPerPublish=100 publishingEnabled=true priority=10 +#SubscriptionsStrategy +uniqueSubscription=false + #MONITORING PARAMETERS samplingInterval=1 queueSize=10000 diff --git a/iot_agent_modules/run/findType.js b/iot_agent_modules/run/findType.js index 57f1dc22..48d71503 100755 --- a/iot_agent_modules/run/findType.js +++ b/iot_agent_modules/run/findType.js @@ -9,7 +9,6 @@ module.exports = { return device.active[i].type; } } - console.log('ritorno null???'); return null; } }; diff --git a/package.json b/package.json index 8f328711..f0097113 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "url": "https://github.com/Engineering-Research-and-Development/iotagent-opcua/issues" }, "engines": { - "node": ">=8.0.0" + "node": ">=12.0.0" }, "scripts": { "clean": "rm -rf package-lock.json && rm -rf node_modules && rm -rf coverage", diff --git a/replace_local_ip.sh b/replace_local_ip.sh index 418f78b9..a49e129f 100755 --- a/replace_local_ip.sh +++ b/replace_local_ip.sh @@ -3,4 +3,6 @@ MACHINE_IP=$(hostname -I | cut -d ' ' -f 1) sed -i "s/TEST_MACHINE_IP/$MACHINE_IP/g" conf/config.properties -sed -i "s/TEST_MACHINE_IP/$MACHINE_IP/g" conf/config.json \ No newline at end of file +sed -i "s/TEST_MACHINE_IP/$MACHINE_IP/g" conf/config.json +sed -i "s/TEST_MACHINE_IP/$MACHINE_IP/g" conf/config.properties.WITH_PLACEHOLDER +sed -i "s/TEST_MACHINE_IP/$MACHINE_IP/g" conf/config.json.TEST_WITH_PLACEHOLDER \ No newline at end of file diff --git a/roadmap.md b/roadmap.md index 611bf2c4..221495ef 100644 --- a/roadmap.md +++ b/roadmap.md @@ -14,9 +14,10 @@ guidelines only, and this section may be revised to provide newer information at ## Short term The following list of features are planned to be addressed in the short term, and incorporated in the next release of -the product planned for **June 2021**: +the product planned for **October 2021**: -- NGSI-LD full compliance +- Test Coverage increasing +- Documentation improvement - Features improvement and Bug Fixing from validation scenarios ## Medium term @@ -24,7 +25,6 @@ the product planned for **June 2021**: The following list of features are planned to be addressed in the medium term, typically within the subsequent release(s) generated in the next **6 months** after next planned release: -- Test Coverage increasing - Mapping Tool: introduction of OPC UA Companions - Investigate compatibility with future NodeJS LTS diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 0954fbcf..b4d56401 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -47,7 +47,7 @@ services: - "1026:1026" depends_on: - orion_mongo - command: -statCounters -dbhost orion_mongo -logForHumans -logLevel INFO -t 255 + command: -statCounters -dbhost orion_mongo -logLevel INFO orion_mongo: hostname: orion_mongo diff --git a/tests/test.js b/tests/test.js index 71cc7ca6..973c60e6 100644 --- a/tests/test.js +++ b/tests/test.js @@ -3,11 +3,14 @@ var async = require('async'); var PropertiesReader = require('properties-reader'); var path = require('path'); -var properties = PropertiesReader(path.resolve(__dirname, '../conf/config.properties')); +var properties = PropertiesReader(path.resolve(__dirname, '../conf/config.properties.WITH_PLACEHOLDER')); var testProperties = PropertiesReader(path.resolve(__dirname, './test-file-paths.properties')); var fs = require('fs'); - -// var config = require(path.resolve(__dirname, '../conf/config.json')); +var fT = require('../iot_agent_modules/run/findType'); +var mG = require('../iot_agent_modules/run/mongoGroup'); +var rSfN = require('../iot_agent_modules/run/removeSuffixFromName'); +var cR = require('../iot_agent_modules/run/createResponse'); +var config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../conf/config.json.TEST_WITH_PLACEHOLDER'), 'utf8')); // Set Up global.logContextTest = { @@ -20,11 +23,9 @@ loggerTest.format = loggerTest.formatters.pipe; var child = require('child_process'); var hostIP = null; -/* function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } -*/ describe('The agent is monitoring active attributes...', function() { /* @@ -34,7 +35,6 @@ describe('The agent is monitoring active attributes...', function() { function() { console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@ WAIT 5 secs'); var myTimeout = setTimeout(init, 5000); - function init() { // Set Up global.logContext = { @@ -43,7 +43,6 @@ describe('The agent is monitoring active attributes...', function() { srv: '', subsrv: '' }; - try { // node-opcue dependencies require('requirish')._(module); @@ -56,56 +55,43 @@ describe('The agent is monitoring active attributes...', function() { } process.exit(1); } - var server = require('../iot_agent_modules/services/server'); var run = require('../iot_agent_modules/run/run'); var fs = require('fs'); - // custom simple logger - var logger = require('logops'); + var logger = require('logops'); var PropertiesReader = require('properties-reader'); - loggerTest.info(logContextTest, 'INITIALIZING TESTING ENVIRONMENT...'); - // var iotAgentConfig = require('../conf/config.json'); // var iotAgentProp = require('./config.properties'); - var properties = PropertiesReader(path.resolve(__dirname, '../conf/config.properties')); global.properties = properties; var endpointUrl = properties.get('endpoint'); var userName = properties.get('userName'); var password = properties.get('password'); - if (endpointUrl == null) { loggerTest.info(logContext, '/AGE/config-test.properties: endpoint not found...'); process.exit(1); } - var doAuto = false; var configPath = path.resolve(__dirname, '../conf/config.json'); - if (fs.existsSync(configPath)) { var config = require(configPath); - if (hostIP != null) { var port = config.providerUrl.split(':')[2]; config.providerUrl = hostIP + ':' + port; } global.config = config; - } else { doAuto = true; } - if (doAuto) { logContext.op = 'Index.MappingTool'; loggerTest.info(logContext, '---------------- MAPPING TOOL ----------------'); - var loadingBar; loadingBar = setInterval(function() { process.stdout.write('.'); }, 3000); - var exec = require('child_process').exec; try { if (userName != 0 && password != 0) { @@ -137,7 +123,6 @@ describe('The agent is monitoring active attributes...', function() { ); var config = require(configPath); } - run.run(); server.start(); process.exit(0); @@ -201,8 +186,8 @@ describe('The agent is monitoring active attributes...', function() { // var iotAgentConfig = require('../conf/config.json'); // var iotAgentProp = require('./config.properties'); - var properties = PropertiesReader(path.resolve(__dirname, '../conf/config.properties')); - properties.set('uniqueSubscription', false); + var properties = PropertiesReader(path.resolve(__dirname, '../conf/config.properties.WITH_PLACEHOLDER')); + properties.set('uniqueSubscription', true); global.properties = properties; var endpointUrl = properties.get('endpoint'); var userName = properties.get('userName'); @@ -246,7 +231,7 @@ describe('The agent is monitoring active attributes...', function() { ' -e ' + endpointUrl + ' -f ' + - require(path.resolve(__dirname, '../conf/config.properties')) + + require(path.resolve(__dirname, '../conf/config.properties.WITH_PLACEHOLDER')) + ' -u ' + userName + ' -p ' + @@ -258,7 +243,7 @@ describe('The agent is monitoring active attributes...', function() { ' -e ' + endpointUrl + ' -f ' + - path.resolve(__dirname, '../conf/config.properties'); + path.resolve(__dirname, '../conf/config.properties.WITH_PLACEHOLDER'); } var child = exec(cmdjava, function(err, stdout, stderr) { clearInterval(loadingBar); @@ -302,12 +287,263 @@ describe('The agent is monitoring active attributes...', function() { } }); - it('verify update of active attributes on Context Broker', function(done) { + describe('Test Iot Agent lib', function() { + beforeEach(function(done) { + // Set up + done(); + }); + + afterEach(function(done) { + // Clean Up + done(); + }); + after(function(done) { + // Clean Up + done(); + }); + + describe('get temp ', function() { + it('verify get temp', function(done) { + this.timeout(0); + // Run test + var value = null; + var temperatureRequest = { + url: + 'http://' + + properties.get('context-broker-host') + + ':' + + properties.get('context-broker-port') + + '/v2/entities/' + + properties.get('entity-id') + + '/attrs/Engine_Temperature', + method: 'GET', + headers: { + 'fiware-service': properties.get('fiware-service'), + 'fiware-servicepath': properties.get('fiware-service-path') + } + }; + + function myTimer() { + var updated = false; + request(temperatureRequest, function(error, response, body) { + console.log('temperatureRequest'); + console.log('error:', error); + console.log('body', body); + if (error) { + console.log('An error occurred during temperature request send'); + console.log(error); + } + + var bodyObject = {}; + bodyObject = JSON.parse(body); + + console.log(typeof bodyObject); + + if (value != null) { + if (bodyObject.value != 0) { + value = bodyObject.value; + var text = 'value updated ' + value; + loggerTest.info(logContextTest, text); + updated = true; + } + } else { + value = bodyObject.value; + } + if (!updated) { + var text = 'value ' + value; + loggerTest.info(logContextTest, text); + setTimeout(myTimer, 2000); + } + }); + } + myTimer(); + done(); + }); + }); + + describe('test lib...', function() { + it('verify get about', function(done) { + this.timeout(0); + + var getAbout = { + url: 'http://' + 'localhost' + ':' + properties.get('server-port') + '/iot/about', + headers: { + 'fiware-service': properties.get('fiware-service'), + 'fiware-servicepath': properties.get('fiware-service-path') + }, + method: 'GET' + }; + + function myTimer() { + request(getAbout, function(error, response, body) { + console.log('getAbout'); + console.log('error:', error); + console.log('body', body); + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + + if (error == null) { + loggerTest.info(logContextTest, 'REST - GET DEVICES SUCCESS'); + done(); + } else { + loggerTest.info(logContextTest, 'REST - GET DEVICES FAILURE'); + done(new Error('REST - GET DEVICES FAILURE')); + } + }); + } + + myTimer(); + }); + }); + + describe('Test service group API', function() { + it('verify get services', function(done) { + this.timeout(0); + + // Run test + var getServiceGroup = { + url: 'http://' + 'localhost' + ':' + properties.get('server-port') + '/iot/services', + headers: { + 'fiware-service': properties.get('fiware-service'), + 'fiware-servicepath': properties.get('fiware-service-path') + }, + method: 'GET' + }; + + function myTimer() { + request(getServiceGroup, function(error, response, body) { + console.log('getServiceGroup'); + console.log('error:', error); + console.log('body', body); + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + + if (error == null) { + loggerTest.info(logContextTest, 'REST - GET DEVICES SUCCESS'); + done(); + } else { + loggerTest.info(logContextTest, 'REST - GET DEVICES FAILURE'); + done(new Error('REST - GET DEVICES FAILURE')); + } + }); + } + + myTimer(); + }); + }); + }); + + it('verify commands execution as context provider', function(done) { + this.timeout(0); + + var commandsRequest = { + url: + 'http://' + + properties.get('context-broker-host') + + ':' + + properties.get('context-broker-port') + + '/v1/updateContext', + method: 'POST', + json: { + contextElements: [ + { + type: 'Device', + isPattern: 'false', + id: 'age01_Car', + attributes: [ + { + name: 'Stop', + type: 'command', + value: null + } + ] + } + ], + updateAction: 'UPDATE' + }, + + headers: { + 'content-type': 'application/json', + 'fiware-service': properties.get('fiware-service'), + 'fiware-servicepath': properties.get('fiware-service-path') + } + }; + function myTimer() { + request.post(commandsRequest, function(error, response, body) { + console.log('commandsRequest'); + console.log('error:', error); + console.log('body', body); + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + if (error == null) { + loggerTest.info(logContextTest, 'commandsRequest SUCCESSFULLY POSTED'); + done(); + } else { + loggerTest.info(logContextTest, 'commandsRequest FAILURE POSTED'); + done(new Error(error)); + } + }); + } + + myTimer(); + }); + + it('verify accelerateRequest as context provider', function(done) { + this.timeout(0); + + var accelerateRequest = { + url: + 'http://' + + properties.get('context-broker-host') + + ':' + + properties.get('context-broker-port') + + '/v1/updateContext', + method: 'POST', + json: { + contextElements: [ + { + type: 'Device', + isPattern: 'false', + id: 'age01_Car', + attributes: [ + { + name: 'Accelerate', + type: 'command', + value: ['1'] + } + ] + } + ], + updateAction: 'UPDATE' + }, + headers: { + 'content-type': 'application/json', + 'fiware-service': properties.get('fiware-service'), + 'fiware-servicepath': properties.get('fiware-service-path') + } + }; + function myTimer() { + request.post(accelerateRequest, function(error, response, body) { + console.log('accelerateRequest'); + console.log('error:', error); + console.log('body', body); + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + if (error == null) { + loggerTest.info(logContextTest, 'accelerateRequest SUCCESSFULLY POSTED'); + done(); + } else { + loggerTest.info(logContextTest, 'accelerateRequest FAILURE POSTED'); + done(new Error(error)); + } + }); + } + + myTimer(); + }); + + it('verify get of lazy attributes on Context Broker', function(done) { console.log('verify update of active attributes on Context Broker'); this.timeout(0); // Run test var value = null; - var temperatureRequest = { + var speedRequest = { url: 'http://' + properties.get('context-broker-host') + @@ -315,7 +551,7 @@ describe('The agent is monitoring active attributes...', function() { properties.get('context-broker-port') + '/v2/entities/' + properties.get('entity-id') + - '/attrs/Engine_Temperature', + '/attrs/Speed', method: 'GET', headers: { 'fiware-service': properties.get('fiware-service'), @@ -325,9 +561,12 @@ describe('The agent is monitoring active attributes...', function() { function myTimer() { var updated = false; - request(temperatureRequest, function(error, response, body) { + request(speedRequest, function(error, response, body) { + console.log('speedRequest'); + console.log('error:', error); + console.log('body', body); if (error) { - console.log('An error occurred during temperature request send'); + console.log('An error occurred during speed request send'); console.log(error); } @@ -348,6 +587,7 @@ describe('The agent is monitoring active attributes...', function() { } } else { value = bodyObject.value; + done(); } if (!updated) { @@ -362,304 +602,58 @@ describe('The agent is monitoring active attributes...', function() { done(); }); +}); - it('stop car srv', function(done) { - setTimeout(function() { - child.exec(path.resolve(__dirname, './stop_carsrv.sh'), function(err, stdout, stderr) { - if (err) { - console.log('An error occurred during car server stop ...'); - console.log(err); - } - console.log('car stop script log'); - console.log('STDOUT: '); - console.log(stdout); - console.log('STDERR: '); - console.log(stderr); - done(); - }); - }, 5000); - }); - - it('start car srv', function(done) { - setTimeout(function() { - child.exec(path.resolve(__dirname, './start_carsrv.sh'), function(err, stdout, stderr) { - if (err) { - console.log('An error occurred during car server restart ...'); - console.log(err); - } - console.log('car start script log'); - console.log('STDOUT: '); - console.log(stdout); - console.log('STDERR: '); - console.log(stderr); - done(); - }); - }, 5000); - - function resetReconnectionFlag() { - var flagPath = path.resolve(__dirname, './connectionRestablishedFlag'); - try { - if (fs.existsSync(flagPath)) { - fs.unlinkSync(flagPath); - done(); - } else { - setTimeout(resetReconnectionFlag, 1000); - } - } catch (err) { - console.error(err); - } - } - - //resetReconnectionFlag(); - - /* - // TODO: fix this - //var childProcess = child.spawn(path.resolve(__dirname, '../tests/print.sh'), {stdio: [process.stdout, "ignore", process.stderr]}); - childProcess.on('exit', function (code) { - if(code == 0) { - done(); - } else { - done(new Error("backoff hunter exit code: ", code)); - } - }); - */ - }); - - // METHOD NOT WORKING ON ORION-LD - it('verify commands execution as context provider', function(done) { +describe('Add Device', function() { + it('verify the addition of a new device', function(done) { this.timeout(0); - console.log('verify commands execution as context provider'); - async.series( - [ - function(callback) { - // STOP CAR locally (for Travis unreachability) - var json = { - contextElements: [ - { - type: 'Device', - isPattern: 'false', - id: 'age01_Car', - attributes: [ - { - name: 'Stop', - type: 'command', - value: null - } - ] - } - ], - updateAction: 'UPDATE' - }; - var stopRequest = { - url: - 'http://' + - properties.get('context-broker-host') + - ':' + - properties.get('context-broker-port') + - '/v1/updateContext', - method: 'POST', - json: json, - headers: { - 'fiware-service': properties.get('fiware-service'), - 'fiware-servicepath': properties.get('fiware-service-path') - } - }; - - function sendRequest() { - request(stopRequest, function(error, response, body) { - console.log('stopRequest locally error =' + JSON.stringify(error)); - console.log('stopRequest locally response =' + JSON.stringify(response)); - console.log('stopRequest locally body =' + JSON.stringify(body)); - if (body) { - if (body.errorCode != undefined) { - setTimeout(sendRequest, 2000); - } else { - callback(); - } - } else { - callback(); - } - }); - } - - sendRequest(); - }, - function(callback) { - // Accelerate CAR locally (for Travis unreachability) - var json = { - contextElements: [ - { - type: 'Device', - isPattern: 'false', - id: 'age01_Car', - attributes: [ - { - name: 'Accelerate', - type: 'command', - value: [2] - } - ] - } + // Run test + var addDeviceRequest = { + url: 'http://' + 'localhost' + ':' + properties.get('server-port') + '/iot/devices', + headers: { + 'fiware-service': properties.get('fiware-service'), + 'fiware-servicepath': properties.get('fiware-service-path'), + 'content-type': 'application/json' + }, + method: 'POST', + json: { + devices: [ + { + device_id: 'age05_Car', + entity_name: 'age05_Car', + entity_type: 'Device', + attributes: [ + { object_id: 'ns=3;s=EngineBrake', name: 'EngineBrake', type: 'Number' }, + { object_id: 'ns=3;s=Acceleration', name: 'Acceleration', type: 'Number' }, + { object_id: 'ns=3;s=EngineStopped', name: 'EngineStopped', type: 'Boolean' }, + { object_id: 'ns=3;s=Temperature', name: 'Temperature', type: 'Number' }, + { object_id: 'ns=3;s=Oxigen', name: 'Oxigen', type: 'Number' } ], - updateAction: 'UPDATE' - }; - - var accelerateRequest = { - url: - 'http://' + - properties.get('context-broker-host') + - ':' + - properties.get('context-broker-port') + - '/v1/updateContext', - method: 'POST', - json: json, - headers: { - 'fiware-service': properties.get('fiware-service'), - 'fiware-servicepath': properties.get('fiware-service-path') - } - }; - - function sendRequest() { - request(accelerateRequest, function(error, response, body) { - console.log('accelerateRequest locally error =' + JSON.stringify(error)); - console.log('accelerateRequest locally response =' + JSON.stringify(response)); - console.log('accelerateRequest locally body =' + JSON.stringify(body)); - - if (body) { - if (body.errorCode != undefined) { - setTimeout(sendRequest, 2000); - } else { - callback(); - } - } else { - callback(); - } - }); + lazy: [{ object_id: 'ns=3;s=Speed', name: 'Speed', type: 'Number' }], + commands: [] } - - sendRequest(); - } - /* - function(callback) { - // Declares test done when the value retrieved from the agent is != null - var myVar = null; - var value = null; - - setTimeout(function() { - function myTimer() { - var updated = false; - - var json = { - entities: [ - { - type: 'Device', - isPattern: 'false', - id: 'age01_Car' - } - ], - attributes: ['Speed'] - }; - - var speedRequest = { - url: - 'http://' + - properties.get('context-broker-host') + - ':' + - properties.get('context-broker-port') + - '/v1/updateContext', - method: 'POST', - json: json, - headers: { - 'fiware-service': properties.get('fiware-service'), - 'fiware-servicepath': properties.get('fiware-service-path') - } - }; - - - request(speedRequest, function(error, response, body) { - console.log('speedRequest locally error =' + JSON.stringify(error)); - console.log('speedRequest locally response =' + JSON.stringify(response)); - console.log('speedRequest locally body =' + JSON.stringify(body)); - - var bodyObject = {}; - bodyObject = body; - bodyObjectValue = bodyObject.contextResponses[0].contextElement.attributes[0].value; - - if (value != null) { - if (value != bodyObjectValue) { - value = bodyObjectValue; - var text = 'value updated ' + value; - loggerTest.info(logContextTest, text.rainbow); - updated = true; - clearInterval(myVar); - callback(); - } - } else { - value = bodyObjectValue; - } - if (!updated) { - var text = 'value ' + value; - loggerTest.info(logContextTest, text.rainbow); - } - }); - - } - - myVar = setInterval(myTimer, 2000); - }, 10000); - }*/ - ], - function(err, results) { - done(); + ] } - ); - }); + }; - /* - it('verify reconnection mechanisms (OPC UA side)', function(done) { - var composeFilePath = path.resolve(__dirname, '../tests/docker-compose.yml'); - var stopCar = 'docker-compose -f ' + composeFilePath + ' stop iotcarsrv'; - child.exec(stopCar, function(err, stdout, stderr) { - if(err) { - console.log("An error occurred during carsrv stopping ..."); - console.log(err); - } + function myTimer() { + request.post(addDeviceRequest, function(error, response, body) { + console.log('addDeviceRequest'); + console.log('error:', error); + console.log('body', body); + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); - setTimeout(function() { - var startCar = 'docker-compose -f ' + composeFilePath + ' up -d iotcarsrv'; - child.exec(startCar, function(err, stdout, stderr) { - if(err) { - console.log("An error occurred during carsrv starting ..."); - console.log(err); - } + if (error == null) { + loggerTest.info(logContextTest, 'REST - ADD DEVICE SUCCESS'); done(); - }); - }, 5000); - }); - }); - */ - - it('delete device', function(done) { - // Delete device - // TODO: parametrize age01_Car in the whole test.js file. - - var deviceDeleteRequest = { - url: 'http://' + 'localhost' + ':' + properties.get('server-port') + '/iot/devices/age01_Car', - headers: { - 'fiware-service': properties.get('fiware-service'), - 'fiware-servicepath': properties.get('fiware-service-path') - }, - method: 'DELETE' - }; - - request(deviceDeleteRequest, function(error, response, body) { - if (error == null) { - done(); - } else { - done(new Error(error)); - } - }); + } else { + loggerTest.info(logContextTest, 'REST - ADD DEVICE FAILURE'); + done(); + } + }); + } + myTimer(); }); }); @@ -694,6 +688,9 @@ describe('Verify REST Devices Management', function() { function myTimer() { request(getDeviceRequest, function(error, response, body) { + console.log('getDeviceRequest'); + console.log('error:', error); + console.log('body', body); loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); if (error == null) { @@ -705,216 +702,369 @@ describe('Verify REST Devices Management', function() { } }); } + myTimer(); + }); + }); +}); - myTimer(); // immediate first run +describe('Verify Northbound flow', function() { + it('verify commands execution as context provider', function(done) { + this.timeout(0); + // Run test - // done(); - }); + var accelerateCar = { + url: + 'http://' + + properties.get('context-broker-host') + + ':' + + properties.get('context-broker-port') + + '/v2/entities/' + + properties.get('entity-id') + + '/attrs/Accelerate?type=Device', + method: 'PUT', + json: { + value: ['1'], + type: 'command' + }, + headers: { + 'content-type': 'application/json', + 'fiware-service': config.service, + 'fiware-servicepath': config.subservice + } + }; - // The new device contains missing active attributes, existent active - // and lazy attributes - it('verify the addition of a new device', function(done) { - this.timeout(0); - // Run test + function myTimer() { + request.put(accelerateCar, function(error, response, body) { + console.log('stopRequest'); + console.log('error:', error); + console.log('body', body); + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); - fs.readFile(testProperties.get('add-device-1'), 'utf8', (err, jsonString) => { - if (err) { - console.log('Error reading file from disk:', err); - return; + if (error == null) { + loggerTest.info(logContextTest, 'REST - accelerateCar command'); + + done(); + } else { + loggerTest.info(logContextTest, 'REST - accelerateCar command'); + done(new Error('REST - accelerateCar command')); } + }); + } + myTimer(); + }); - try { - const device = JSON.parse(jsonString); - - var addDeviceRequest = { - url: 'http://' + 'localhost' + ':' + properties.get('server-port') + '/iot/devices', - headers: { - 'fiware-service': properties.get('fiware-service'), - 'fiware-servicepath': properties.get('fiware-service-path'), - 'content-type': 'application/json' - }, - method: 'POST', - json: device - }; - - function myTimer() { - request.post(addDeviceRequest, function(error, response, body) { - loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); - - if (error == null) { - loggerTest.info(logContextTest, 'REST - ADD DEVICE SUCCESS'); - - done(); - } else { - loggerTest.info(logContextTest, 'REST - ADD DEVICE FAILURE'); - done(new Error('REST - ADD DEVICE FAILURE')); - } - }); - } + it('verify speed', function(done) { + this.timeout(0); + var speedRequest2 = { + url: + 'http://' + + properties.get('context-broker-host') + + ':' + + properties.get('context-broker-port') + + '/v2/entities/' + + properties.get('entity-id') + + '/attrs/Speed', + method: 'GET', + headers: { + 'fiware-service': config.service, + 'fiware-servicepath': config.subservice + } + }; + + function myTimer() { + request.post(speedRequest2, function(error, response, body) { + console.log('speedRequest'); + console.log('error:', error); + console.log('body', body); + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + + if (error == null) { + loggerTest.info(logContextTest, 'REST - speed check'); - //myTimer(); // immediate first run done(); - } catch (err) { - console.log('Error parsing JSON string:', err); + } else { + loggerTest.info(logContextTest, 'REST - speed check'); + done(new Error('REST - speed check')); } }); - - // done(); - }); + } + myTimer(); }); }); describe('Verify ADMIN API services', function() { - describe('The agent is active...', function() { - it('verify version service', function(done) { - this.timeout(0); - // Run test + it('verify version service', function(done) { + this.timeout(0); + // Run test - var value = null; + var value = null; - var versionRequest = { - url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/version', - method: 'GET' - }; - function myTimer() { - var updated = false; + var versionRequest = { + url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/version', + method: 'GET' + }; + function myTimer() { + var updated = false; - request(versionRequest, function(error, response, body) { - loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + request(versionRequest, function(error, response, body) { + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); - if (error == null) { - loggerTest.info(logContextTest, 'VERSION SERVICE SUCCESSFULLY READ'); - done(); - } else { - loggerTest.info(logContextTest, 'VERSION SERVICE FAILURE READ'); - done(new Error(error)); - } - }); - } + if (error == null) { + loggerTest.info(logContextTest, 'VERSION SERVICE SUCCESSFULLY READ'); + done(); + } else { + loggerTest.info(logContextTest, 'VERSION SERVICE FAILURE READ'); + done(new Error(error)); + } + }); + } + myTimer(); + }); - myTimer(); // immediate first run + it('verify status service', function(done) { + this.timeout(0); + // Run test - // done(); - }); + var value = null; - it('verify status service', function(done) { - this.timeout(0); - // Run test + var statusRequest = { + url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/status', + method: 'GET' + }; + function myTimer() { + var updated = false; - var value = null; + request(statusRequest, function(error, response, body) { + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); - var statusRequest = { - url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/status', - method: 'GET' - }; - function myTimer() { - var updated = false; + if (error == null) { + loggerTest.info(logContextTest, 'STATUS SERVICE SUCCESSFULLY READ'); + done(); + } else { + loggerTest.info(logContextTest, 'STATUS SERVICE FAILURE READ'); + done(new Error(error)); + } + }); + } + myTimer(); + }); - request(statusRequest, function(error, response, body) { - loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + it('verify config service', function(done) { + this.timeout(0); + // Run test - if (error == null) { - loggerTest.info(logContextTest, 'STATUS SERVICE SUCCESSFULLY READ'); - done(); - } else { - loggerTest.info(logContextTest, 'STATUS SERVICE FAILURE READ'); - done(new Error(error)); - } - }); - } + var value = null; - myTimer(); // immediate first run + var configRequest = { + url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/config', + method: 'GET' + }; + function myTimer() { + var updated = false; - // done(); - }); + request(configRequest, function(error, response, body) { + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); - it('verify config service', function(done) { - this.timeout(0); - // Run test + if (error == null) { + loggerTest.info(logContextTest, 'CONFIG SERVICE SUCCESSFULLY READ'); + done(); + } else { + loggerTest.info(logContextTest, 'CONFIG SERVICE FAILURE READ'); + done(new Error(error)); + } + }); + } + myTimer(); + }); - var value = null; + it('verify commandsList service', function(done) { + this.timeout(0); + // Run test - var configRequest = { - url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/config', - method: 'GET' - }; - function myTimer() { - var updated = false; + var value = null; - request(configRequest, function(error, response, body) { - loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + var commandsListRequest = { + url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/commandsList', + method: 'GET' + }; - if (error == null) { - loggerTest.info(logContextTest, 'CONFIG SERVICE SUCCESSFULLY READ'); - done(); - } else { - loggerTest.info(logContextTest, 'CONFIG SERVICE FAILURE READ'); - done(new Error(error)); - } - }); - } + function myTimer() { + request(commandsListRequest, function(error, response, body) { + console.log('commandsListRequest'); + console.log('error:', error); + console.log('body', body); + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + + if (error == null) { + loggerTest.info(logContextTest, 'COMMANDS LIST SERVICE SUCCESSFULLY READ'); + done(); + } else { + loggerTest.info(logContextTest, 'COMMANDS LIST SERVICE FAILURE READ'); + done(new Error(error)); + } + }); + } + myTimer(); + }); - myTimer(); // immediate first run + it('verify config post service', function(done) { + this.timeout(0); - // done(); - }); + var jsonRequest = { + url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/json', + method: 'POST', + json: true, + body: config + }; + function myTimer() { + request(jsonRequest, function(error, response, body) { + loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); + if (error == null) { + loggerTest.info(logContextTest, 'CONFIG JSON SERVICE SUCCESSFULLY POSTED'); + done(); + } else { + loggerTest.info(logContextTest, 'CONFIG JSON SERVICE FAILURE POSTED'); + done(new Error(error)); + } + }); + } + myTimer(); + }); +}); - it('verify commandsList service', function(done) { - this.timeout(0); - // Run test +describe('Test findType module', function() { + it('verify functionalities of findType module', function(done) { + if (fT.findType('Engine_Temperature', config.types.Device).toString() == 'Number') { + done(); + } else { + done(new Error('missing type')); + } + }); - var value = null; + it('verify functionalities of findType module (undefined device)', function(done) { + if (fT.findType('Engine_Temperature', undefined) == null) { + done(); + } else { + done(new Error('wrong behaviour for undefined device')); + } + }); +}); - var commandsListRequest = { - url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/commandsList', - method: 'GET' - }; +describe('Build mongoGroup module', function() { + it('builg group', function(done) { + mG.mongoGroup(config); + done(); + }); +}); - function myTimer() { - request(commandsListRequest, function(error, response, body) { - loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); +describe('test removeSuffixFromName module', function() { + it('removing SuffixFromName', function(done) { + if (rSfN.removeSuffixFromName('testR', 'R').toString() == 'test') { + done(); + } else { + done(new Error('removing SuffixFromName failed')); + } + }); - if (error == null) { - loggerTest.info(logContextTest, 'COMMANDS LIST SERVICE SUCCESSFULLY READ'); - done(); - } else { - loggerTest.info(logContextTest, 'COMMANDS LIST SERVICE FAILURE READ'); - done(new Error(error)); - } - }); - } + it('no SuffixFromName', function(done) { + if (rSfN.removeSuffixFromName('test', 'B').toString() == 'test') { + done(); + } else { + done(new Error('removing SuffixFromName failed')); + } + }); +}); - myTimer(); // immediate first run +describe('Test createResponde module', function() { + it('creating response', function(done) { + if (cR.createResponse('test', 'string', config.types.Device.active, '1,2,3,4,5', [1, 2, 3, 4, 5]) != null) { + done(); + } else { + done(new Error('creating response failed')); + } + }); +}); - // done(); - }); +describe('stop and start car server + delete device', function() { + it('stop car srv', function(done) { + setTimeout(function() { + child.exec(path.resolve(__dirname, './stop_carsrv.sh'), function(err, stdout, stderr) { + if (err) { + console.log('An error occurred during car server stop ...'); + console.log(err); + } + console.log('car stop script log'); + console.log('STDOUT: '); + console.log(stdout); + console.log('STDERR: '); + console.log(stderr); + done(); + }); + }, 5000); + }); - it('verify config post service', function(done) { - this.timeout(0); - // Run test + it('start car srv', function(done) { + setTimeout(function() { + child.exec(path.resolve(__dirname, './start_carsrv.sh'), function(err, stdout, stderr) { + if (err) { + console.log('An error occurred during car server restart ...'); + console.log(err); + } + console.log('car start script log'); + console.log('STDOUT: '); + console.log(stdout); + console.log('STDERR: '); + console.log(stderr); + done(); + }); + }, 5000); + }); - var jsonRequest = { - url: 'http://' + 'localhost' + ':' + properties.get('api-port') + '/json', - method: 'POST', - json: true, - body: config - }; - function myTimer() { - request(jsonRequest, function(error, response, body) { - loggerTest.info(logContextTest, 'RESPONSE=' + JSON.stringify(response)); - if (error == null) { - loggerTest.info(logContextTest, 'CONFIG JSON SERVICE SUCCESSFULLY POSTED'); - done(); - } else { - loggerTest.info(logContextTest, 'CONFIG JSON SERVICE FAILURE POSTED'); - done(new Error(error)); + it('verify reconnection mechanisms (OPC UA side)', function(done) { + var composeFilePath = path.resolve(__dirname, '../tests/docker-compose.yml'); + var stopCar = 'docker-compose -f ' + composeFilePath + ' stop iotcarsrv'; + child.exec(stopCar, function(err, stdout, stderr) { + if (err) { + console.log('An error occurred during carsrv stopping ...'); + console.log(err); + } + + setTimeout(function() { + var startCar = 'docker-compose -f ' + composeFilePath + ' up -d iotcarsrv'; + child.exec(startCar, function(err, stdout, stderr) { + if (err) { + console.log('An error occurred during carsrv starting ...'); + console.log(err); } + + done(); }); - } + }, 5000); + }); + }); - myTimer(); // immediate first run + it('delete device', function(done) { + // Delete device + // TODO: parametrize age01_Car in the whole test.js file. - // done(); + var deviceDeleteRequest = { + url: 'http://' + 'localhost' + ':' + properties.get('server-port') + '/iot/devices/age01_Car', + headers: { + 'fiware-service': properties.get('fiware-service'), + 'fiware-servicepath': properties.get('fiware-service-path') + }, + method: 'DELETE' + }; + + request(deviceDeleteRequest, function(error, response, body) { + console.log('deviceDeleteRequest'); + console.log('error:', error); + console.log('body', body); + if (error == null) { + done(); + } else { + done(new Error(error)); + } }); }); }); diff --git a/travis_ip.sh b/travis_ip.sh deleted file mode 100755 index 418f78b9..00000000 --- a/travis_ip.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -MACHINE_IP=$(hostname -I | cut -d ' ' -f 1) - -sed -i "s/TEST_MACHINE_IP/$MACHINE_IP/g" conf/config.properties -sed -i "s/TEST_MACHINE_IP/$MACHINE_IP/g" conf/config.json \ No newline at end of file