diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 51cdf740a3..5da53d0d4c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -53,7 +53,9 @@ _Put an `x` in the boxes that apply._ - [ ] I built the documentation and updated it with the latest changes - [ ] I've added an item in `HISTORY.rst` for this release - [ ] I bumped the version number in the `aea/__version__.py` file. -- [ ] I bumped the version number in every Docker image of the repo and published it. Also, I built and published them with tag `latest` +- [ ] I bumped the version number in every Docker image of the repo and published it. Also, I built and published them with tag `latest` + (check the READMEs of [`aea-develop`](../develop-image/README.md#publish) + and [`aea-deploy`](../deploy-image/README.md#publish)) - [ ] I have checked that the documentation about the `aea cli` tool works ## Further comments diff --git a/HISTORY.rst b/HISTORY.rst index bf8c31ef21..f34354f8da 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -69,3 +69,10 @@ Release History - Adds full test coverage on cli - Improves docs - Multiple additional minor fixes and changes + +0.1.9 (2019-10-18) +------------------- + +- Stability improvements +- Higher test coverage, including on Python 3.6 +- Multiple additional minor fixes and changes diff --git a/Jenkinsfile b/Jenkinsfile index a730d19161..925bcdf581 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -37,13 +37,13 @@ pipeline { } // docs -// stage('Unit Tests: Python 3.6') { -// -// steps { -// sh 'tox -e py36 -- --no-integration-tests' -// } -// -// } // unit tests: python 3.6 + stage('Unit Tests: Python 3.6') { + + steps { + sh 'tox -e py36 -- --no-integration-tests --ci' + } + + } // unit tests: python 3.6 stage('Unit Tests: Python 3.7') { diff --git a/Pipfile b/Pipfile index 3cc92f43a0..3815b5eb49 100644 --- a/Pipfile +++ b/Pipfile @@ -33,7 +33,7 @@ colorlog = "*" jsonschema = "*" protobuf = "*" flask = "*" -connexion = {git = "https://github.com/neverpanic/connexion.git",editable = true,ref = "jsonschema-3"} +connexion = ">=2.4.0" watchdog = "*" python-dotenv = "*" fetchai-ledger-api = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 26fa2b2a07..00ec23c1cd 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "eeff9998b99b29ddb9eafda38d9f37c6493fc54c6a63333cdb8945c31e7f30f9" + "sha256": "538f6a0573e14e00ff12b0989c0499023dfd326a3ce9c48ddb00ed3fc6d2f916" }, "pipfile-spec": 6, "requires": { @@ -28,13 +28,6 @@ ], "version": "==0.26.2" }, - "asn1crypto": { - "hashes": [ - "sha256:5abe83e773026162e4869f4ac16edf7554f661e8cc0bb6d2be3bc6915456731b", - "sha256:8f3f9470d4ba7aa53afb00278dc26aac22dc3a0d4ed1335fd772f034e094401e" - ], - "version": "==1.1.0" - }, "attrdict": { "hashes": [ "sha256:35c90698b55c683946091177177a9e9c0713a0860f0e049febd72649ccd77b70", @@ -67,6 +60,7 @@ }, "cffi": { "hashes": [ + "sha256:08f99e8b38d5134d504aa7e486af8e4fde66a2f388bbecc270cdd1e00fa09ff8", "sha256:1112d2fc92a867a6103bce6740a549e74b1d320cf28875609f6e93857eee4f2d", "sha256:1b9ab50c74e075bd2ae489853c5f7f592160b379df53b7f72befcbe145475a36", "sha256:24eff2997436b6156c2f30bed215c782b1d8fd8c6a704206053c79af95962e45", @@ -74,6 +68,9 @@ "sha256:362e896cea1249ed5c2a81cf6477fabd9e1a5088aa7ea08358a4c6b0998294d2", "sha256:40eddb3589f382cb950f2dcf1c39c9b8d7bd5af20665ce273815b0d24635008b", "sha256:5ed40760976f6b8613d4a0db5e423673ca162d4ed6c9ed92d1f4e58a47ee01b5", + "sha256:632c6112c1e914c486f06cfe3f0cc507f44aa1e00ebf732cedb5719e6aa0466a", + "sha256:64d84f0145e181f4e6cc942088603c8db3ae23485c37eeda71cb3900b5e67cb4", + "sha256:6cb4edcf87d0e7f5bdc7e5c1a0756fbb37081b2181293c5fdf203347df1cd2a2", "sha256:6f19c9df4785305669335b934c852133faed913c0faa63056248168966f7a7d5", "sha256:719537b4c5cd5218f0f47826dd705fb7a21d83824920088c4214794457113f3f", "sha256:7b0e337a70e58f1a36fb483fd63880c9e74f1db5c532b4082bceac83df1523fa", @@ -82,10 +79,12 @@ "sha256:8978115c6f0b0ce5880bc21c967c65058be8a15f1b81aa5fdbdcbea0e03952d1", "sha256:8f7eec920bc83692231d7306b3e311586c2e340db2dc734c43c37fbf9c981d24", "sha256:8fe230f612c18af1df6f348d02d682fe2c28ca0a6c3856c99599cdacae7cf226", + "sha256:92068ebc494b5f9826b822cec6569f1f47b9a446a3fef477e1d11d7fac9ea895", "sha256:b57e1c8bcdd7340e9c9d09613b5e7fdd0c600be142f04e2cc1cc8cb7c0b43529", "sha256:ba956c9b44646bc1852db715b4a252e52a8f5a4009b57f1dac48ba3203a7bde1", "sha256:ca42034c11eb447497ea0e7b855d87ccc2aebc1e253c22e7d276b8599c112a27", "sha256:dc9b2003e9a62bbe0c84a04c61b0329e86fccd85134a78d7aca373bbbf788165", + "sha256:dd308802beb4b2961af8f037becbdf01a1e85009fdfc14088614c1b3c383fae5", "sha256:e77cd105b19b8cd721d101687fcf665fd1553eb7b57556a1ef0d453b6fc42faa", "sha256:f56dff1bd81022f1c980754ec721fb8da56192b026f17f0f99b965da5ab4fbd2", "sha256:fa4cc13c03ea1d0d37ce8528e0ecc988d2365e8ac64d8d86cafab4038cb4ce89", @@ -127,31 +126,39 @@ "version": "==4.0.2" }, "connexion": { - "editable": true, - "git": "https://github.com/neverpanic/connexion.git", - "ref": "2f0d92b5765196f7229d1b7ef4db9d97d8476676" + "hashes": [ + "sha256:6e0569b646f2e6229923dc4e4c6e0325e223978bd19105779fd81e16bcb22fdf", + "sha256:7b4268e9ea837241e530738b35040345b78c8748d05d2c22805350aca0cd5b1c" + ], + "index": "pypi", + "version": "==2.4.0" }, "cryptography": { "hashes": [ - "sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c", - "sha256:25dd1581a183e9e7a806fe0543f485103232f940fcfc301db65e630512cce643", - "sha256:3452bba7c21c69f2df772762be0066c7ed5dc65df494a1d53a58b683a83e1216", - "sha256:41a0be220dd1ed9e998f5891948306eb8c812b512dc398e5a01846d855050799", - "sha256:5751d8a11b956fbfa314f6553d186b94aa70fdb03d8a4d4f1c82dcacf0cbe28a", - "sha256:5f61c7d749048fa6e3322258b4263463bfccefecb0dd731b6561cb617a1d9bb9", - "sha256:72e24c521fa2106f19623a3851e9f89ddfdeb9ac63871c7643790f872a305dfc", - "sha256:7b97ae6ef5cba2e3bb14256625423413d5ce8d1abb91d4f29b6d1a081da765f8", - "sha256:961e886d8a3590fd2c723cf07be14e2a91cf53c25f02435c04d39e90780e3b53", - "sha256:96d8473848e984184b6728e2c9d391482008646276c3ff084a1bd89e15ff53a1", - "sha256:ae536da50c7ad1e002c3eee101871d93abdc90d9c5f651818450a0d3af718609", - "sha256:b0db0cecf396033abb4a93c95d1602f268b3a68bb0a9cc06a7cff587bb9a7292", - "sha256:cfee9164954c186b191b91d4193989ca994703b2fff406f71cf454a2d3c7327e", - "sha256:e6347742ac8f35ded4a46ff835c60e68c22a536a8ae5c4422966d06946b6d4c6", - "sha256:f27d93f0139a3c056172ebb5d4f9056e770fdf0206c2f422ff2ebbad142e09ed", - "sha256:f57b76e46a58b63d1c6375017f4564a28f19a5ca912691fd2e4261b3414b618d" + "sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c", + "sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595", + "sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad", + "sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651", + "sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2", + "sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff", + "sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d", + "sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42", + "sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d", + "sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e", + "sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912", + "sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793", + "sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13", + "sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7", + "sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0", + "sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879", + "sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f", + "sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9", + "sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2", + "sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf", + "sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8" ], "index": "pypi", - "version": "==2.7" + "version": "==2.8" }, "cytoolz": { "hashes": [ @@ -573,11 +580,11 @@ }, "web3": { "hashes": [ - "sha256:5d1d301da95b29e2d515ec4139dfd77d8edee127fa238800489a5e2f877314a4", - "sha256:812b753fc09a6d675acbadf437447d4cfdbfb7290ac6203f2cc06fc80080e0b5" + "sha256:a6bbf8090fd880be1a736872bf42163b44a56691d97b7e139d7f16247c1d7f8d", + "sha256:c0e070670a7d8c6ed4b8585347fec79a924c01520362ba41b411a5d0a9c8e6f9" ], "index": "pypi", - "version": "==5.2.0" + "version": "==5.2.1" }, "websocket-client": { "hashes": [ @@ -837,26 +844,30 @@ }, "mypy": { "hashes": [ - "sha256:1d98fd818ad3128a5408148c9e4a5edce6ed6b58cc314283e631dd5d9216527b", - "sha256:22ee018e8fc212fe601aba65d3699689dd29a26410ef0d2cc1943de7bec7e3ac", - "sha256:3a24f80776edc706ec8d05329e854d5b9e464cd332e25cde10c8da2da0a0db6c", - "sha256:42a78944e80770f21609f504ca6c8173f7768043205b5ac51c9144e057dcf879", - "sha256:4b2b20106973548975f0c0b1112eceb4d77ed0cafe0a231a1318f3b3a22fc795", - "sha256:591a9625b4d285f3ba69f541c84c0ad9e7bffa7794da3fa0585ef13cf95cb021", - "sha256:5b4b70da3d8bae73b908a90bb2c387b977e59d484d22c604a2131f6f4397c1a3", - "sha256:84edda1ffeda0941b2ab38ecf49302326df79947fa33d98cdcfbf8ca9cf0bb23", - "sha256:b2b83d29babd61b876ae375786960a5374bba0e4aba3c293328ca6ca5dc448dd", - "sha256:cc4502f84c37223a1a5ab700649b5ab1b5e4d2bf2d426907161f20672a21930b", - "sha256:e29e24dd6e7f39f200a5bb55dcaa645d38a397dd5a6674f6042ef02df5795046" + "sha256:1521c186a3d200c399bd5573c828ea2db1362af7209b2adb1bb8532cea2fb36f", + "sha256:31a046ab040a84a0fc38bc93694876398e62bc9f35eca8ccbf6418b7297f4c00", + "sha256:3b1a411909c84b2ae9b8283b58b48541654b918e8513c20a400bb946aa9111ae", + "sha256:48c8bc99380575deb39f5d3400ebb6a8a1cb5cc669bbba4d3bb30f904e0a0e7d", + "sha256:540c9caa57a22d0d5d3c69047cc9dd0094d49782603eb03069821b41f9e970e9", + "sha256:672e418425d957e276c291930a3921b4a6413204f53fe7c37cad7bc57b9a3391", + "sha256:6ed3b9b3fdc7193ea7aca6f3c20549b377a56f28769783a8f27191903a54170f", + "sha256:9371290aa2cad5ad133e4cdc43892778efd13293406f7340b9ffe99d5ec7c1d9", + "sha256:ace6ac1d0f87d4072f05b5468a084a45b4eda970e4d26704f201e06d47ab2990", + "sha256:b428f883d2b3fe1d052c630642cc6afddd07d5cd7873da948644508be3b9d4a7", + "sha256:d5bf0e6ec8ba346a2cf35cb55bf4adfddbc6b6576fcc9e10863daa523e418dbb", + "sha256:d7574e283f83c08501607586b3167728c58e8442947e027d2d4c7dcd6d82f453", + "sha256:dc889c84241a857c263a2b1cd1121507db7d5b5f5e87e77147097230f374d10b", + "sha256:f4748697b349f373002656bf32fede706a0e713d67bfdcf04edf39b1f61d46eb" ], "index": "pypi", - "version": "==0.730" + "version": "==0.740" }, "mypy-extensions": { "hashes": [ - "sha256:a161e3b917053de87dbe469987e173e49fb454eca10ef28b48b384538cc11458" + "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", + "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" ], - "version": "==0.4.2" + "version": "==0.4.3" }, "packaging": { "hashes": [ @@ -1030,20 +1041,25 @@ }, "typed-ast": { "hashes": [ + "sha256:1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", + "sha256:48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", + "sha256:7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", + "sha256:838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", + "sha256:fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" ], "version": "==1.4.0" @@ -1058,10 +1074,10 @@ }, "virtualenv": { "hashes": [ - "sha256:680af46846662bb38c5504b78bad9ed9e4f3ba2d54f54ba42494fdf94337fe30", - "sha256:f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2" + "sha256:3e3597e89c73df9313f5566e8fc582bd7037938d15b05329c232ec57a11a7ad5", + "sha256:5d370508bf32e522d79096e8cbea3499d47e624ac7e11e9089f9397a0b3318df" ], - "version": "==16.7.5" + "version": "==16.7.6" }, "virtualenv-clone": { "hashes": [ diff --git a/README.md b/README.md index a1b56153b1..f66852947d 100644 --- a/README.md +++ b/README.md @@ -50,10 +50,6 @@ The following dependency is only relevant if you intend to contribute to the rep The following steps are only relevant if you intend to contribute to the repository. They are not required for agent development. -- Clear cache - - pipenv --clear - - Install development dependencies: pipenv install --dev diff --git a/aea/__version__.py b/aea/__version__.py index 6d4c90140f..0d65f86f57 100644 --- a/aea/__version__.py +++ b/aea/__version__.py @@ -23,7 +23,7 @@ __title__ = 'aea' __description__ = 'Autonomous Economic Agent framework' __url__ = 'https://github.com/fetchai/agents-aea.git' -__version__ = '0.1.8' +__version__ = '0.1.9' __author__ = 'Fetch.AI Limited' __license__ = 'Apache 2.0' __copyright__ = '2019 Fetch.AI Limited' diff --git a/aea/cli_gui/__init__.py b/aea/cli_gui/__init__.py index bcaea9821c..2fd2b2a791 100644 --- a/aea/cli_gui/__init__.py +++ b/aea/cli_gui/__init__.py @@ -101,19 +101,22 @@ def get_agents(): return agent_list -def get_registered_items(item_type): - """Return list of all protocols, connections or skills in the registry.""" - item_dir = os.path.join(flask.app.agents_dir, "packages/" + item_type + "s") - +def _add_items(item_dir, item_type, items_list): file_list = glob.glob(os.path.join(item_dir, '*')) - - items_list = [] - for path in file_list: if is_item_dir(path, item_type): head, tail = os.path.split(path) desc = read_description(path, item_type) - items_list.append({"id": tail, "description": desc}) + if not {"id": tail, "description": desc} in items_list: + items_list.append({"id": tail, "description": desc}) + + +def get_registered_items(item_type): + """Return list of all protocols, connections or skills in the registry.""" + items_list = [] + + _add_items(os.path.join(flask.app.agents_dir, "packages/" + item_type + "s"), item_type, items_list) + _add_items(os.path.join(flask.app.module_dir, "aea/" + item_type + "s"), item_type, items_list) return items_list diff --git a/aea/configurations/loader.py b/aea/configurations/loader.py index dd1b1db805..a9c7b2ff2d 100644 --- a/aea/configurations/loader.py +++ b/aea/configurations/loader.py @@ -45,7 +45,8 @@ class ConfigLoader(Generic[T]): def __init__(self, schema_filename: str, configuration_type: Type[T]): """Initialize the parser for configuration files.""" self.schema = json.load(open(os.path.join(_SCHEMAS_DIR, schema_filename))) - self.resolver = jsonschema.RefResolver("file://{}/".format(Path(_SCHEMAS_DIR).absolute()), self.schema) + root_path = "file://{}{}".format(Path(_SCHEMAS_DIR).absolute(), os.path.sep) + self.resolver = jsonschema.RefResolver(root_path, self.schema) self.validator = Draft4Validator(self.schema, resolver=self.resolver) self.configuration_type = configuration_type # type: Type[T] diff --git a/aea/connections/base.py b/aea/connections/base.py index 541eb8810d..fdabb359f0 100644 --- a/aea/connections/base.py +++ b/aea/connections/base.py @@ -26,7 +26,7 @@ from aea.configurations.base import ConnectionConfig if TYPE_CHECKING: - from aea.mail.base import Envelope + from aea.mail.base import Envelope # pragma: no cover class Channel(ABC): diff --git a/aea/connections/local/connection.py b/aea/connections/local/connection.py index 2b59091788..a2db07006c 100644 --- a/aea/connections/local/connection.py +++ b/aea/connections/local/connection.py @@ -121,7 +121,7 @@ def handle_agent_message(self, envelope: Envelope) -> None: if destination not in self._queues: msg = OEFMessage(oef_type=OEFMessage.Type.DIALOGUE_ERROR, id=STUB_DIALOGUE_ID, dialogue_id=STUB_DIALOGUE_ID, origin=destination) msg_bytes = OEFSerializer().encode(msg) - error_envelope = Envelope(to=destination, sender=envelope.sender, protocol_id=OEFMessage.protocol_id, message=msg_bytes) + error_envelope = Envelope(to=envelope.sender, sender=DEFAULT_OEF, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self._send(error_envelope) return else: @@ -140,7 +140,7 @@ def register_service(self, public_key: str, service_description: Description): def register_service_wide(self, public_key: str, service_description: Description): """Register service wide.""" - raise NotImplementedError + raise NotImplementedError # pragma: no cover def unregister_service(self, public_key: str, msg_id: int, service_description: Description) -> None: """ diff --git a/aea/registries/base.py b/aea/registries/base.py index c3da730473..53caf8ec07 100644 --- a/aea/registries/base.py +++ b/aea/registries/base.py @@ -146,7 +146,8 @@ def populate(self, directory: str) -> None: logger.warning("No protocol found.") return - protocols_packages = list(filter(lambda x: PACKAGE_NAME_REGEX.match(x), protocols_spec.loader.contents())) # type: ignore + loader_contents = [path.name for path in Path(directory, "protocols").iterdir()] + protocols_packages = list(filter(lambda x: PACKAGE_NAME_REGEX.match(x), loader_contents)) # type: ignore logger.debug("Processing the following protocol package: {}".format(protocols_packages)) for protocol_name in protocols_packages: try: diff --git a/aea/skills/base.py b/aea/skills/base.py index 933ac9dba2..e2f6427dc5 100644 --- a/aea/skills/base.py +++ b/aea/skills/base.py @@ -493,7 +493,8 @@ def from_dir(cls, directory: str, agent_context: AgentContext) -> Optional['Skil skill_module = importlib.util.module_from_spec(skills_spec) sys.modules[skill_config.name + "_skill"] = skill_module - skills_packages = list(filter(lambda x: not x.startswith("__"), skills_spec.loader.contents())) # type: ignore + loader_contents = [path.name for path in Path(directory).iterdir()] + skills_packages = list(filter(lambda x: not x.startswith("__"), loader_contents)) # type: ignore logger.debug("Processing the following skill package: {}".format(skills_packages)) skill_context = SkillContext(agent_context) diff --git a/deploy-image/README.md b/deploy-image/README.md index df3076d28f..c582d1ba1b 100644 --- a/deploy-image/README.md +++ b/deploy-image/README.md @@ -6,12 +6,30 @@ All the commands must be executed from the parent directory, if not stated other We recommend using the following command for building: - ./deploy-image/scripts/docker-build-img.sh \ - -t aea-deploy:latest -- + ./deploy-image/scripts/docker-build-img.sh -t aea-deploy:latest -- ## Run docker run --env AGENT_REPO_URL=https://github.com/fetchai/echo_agent.git aea-deploy:latest +## Publish + +First, be sure you tagged the image with the `latest` tag: + + docker tag aea-deploy: aea-deploy:latest + +Then, publish the images. First, the `aea-deploy:` + + ./develop-image/scripts/docker-publish-img.sh + +And then, the `aea-deploy:latest` image: + +- In `docker-env.sh`, uncomment `DOCKER_IMAGE_TAG=aea-deploy:latest` + +- Run the publish command again: + + ./develop-image/scripts/docker-publish-img.sh + + ## TODO We need to add support for setting the connection endpoints for OEF/Ledger so they can be used a deploytime. I would suggest these are set as environment variables if possible. diff --git a/deploy-image/docker-env.sh b/deploy-image/docker-env.sh index 5050b3df09..95bf4ed780 100755 --- a/deploy-image/docker-env.sh +++ b/deploy-image/docker-env.sh @@ -1,5 +1,8 @@ #!/bin/bash -DOCKER_IMAGE_TAG=aea-deploy:0.1.8 +# Swap the following lines if you want to work with 'latest' +DOCKER_IMAGE_TAG=aea-deploy:0.1.9 +# DOCKER_IMAGE_TAG=aea-deploy:latest + DOCKER_BUILD_CONTEXT_DIR=.. DOCKERFILE=./Dockerfile diff --git a/develop-image/README.md b/develop-image/README.md index e32e4ec717..1a133baf29 100644 --- a/develop-image/README.md +++ b/develop-image/README.md @@ -23,3 +23,22 @@ E.g.: As before, to pass params to the `docker run` command: ./develop-image/scripts/docker-run.sh -p 8080:80 -- /bin/bash + + +## Publish + +First, be sure you tagged the image with the `latest` tag: + + docker tag aea-develop: aea-develop:latest + +Then, publish the images. First, the `aea-develop:` + + ./develop-image/scripts/docker-publish-img.sh + +And then, the `aea-develop:latest` image: + +- In `docker-env.sh`, uncomment `DOCKER_IMAGE_TAG=aea-develop:latest` + +- Run the publish command again: + + ./develop-image/scripts/docker-publish-img.sh diff --git a/develop-image/docker-env.sh b/develop-image/docker-env.sh index d60a4e7601..af077bb35c 100755 --- a/develop-image/docker-env.sh +++ b/develop-image/docker-env.sh @@ -1,5 +1,8 @@ #!/bin/bash -DOCKER_IMAGE_TAG=aea-develop:0.1.8 +# Swap the following lines if you want to work with 'latest' +DOCKER_IMAGE_TAG=aea-develop:0.1.9 +# DOCKER_IMAGE_TAG=aea-develop:latest + DOCKER_BUILD_CONTEXT_DIR=.. DOCKERFILE=./Dockerfile diff --git a/docs/cli-gui.md b/docs/cli-gui.md index 991663195e..9718319ce3 100644 --- a/docs/cli-gui.md +++ b/docs/cli-gui.md @@ -4,7 +4,13 @@ These instructions will take you through building an agent, starting an OEF Node ## Preliminaries -Ensure you have the framework installed and the CLI is working by following the [quick-start guide](quickstart.md). +Ensure you have the framework installed and the CLI is working by following the [quick-start guide](quickstart.md). + +Please install the extra dependencies for the CLI GUI: + ```python + pip install aea[cli_gui] + ``` + ## Starting the GUI Go to your working folder, where you want to create new agents. If you followed the quick start guide, this will be in the my_aea directory. Start the local web-server: diff --git a/docs/quickstart.md b/docs/quickstart.md index f74c9e794f..eb08c19907 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -24,6 +24,12 @@ touch Pipfile && pipenv --python 3.7 && pipenv shell ``` +At some point, you will need [Docker](https://www.docker.com/) installed on your machine +(e.g. to run an OEF Node). + +If you don't have it, please check the official documentation [here](https://docs.docker.com/install/) +and follow the instructions for your platform. + ## Installation Install the Autonomous Economic Agent framework. diff --git a/docs/skill-guide.md b/docs/skill-guide.md index 610d9ea4dc..2f96d3f941 100644 --- a/docs/skill-guide.md +++ b/docs/skill-guide.md @@ -13,7 +13,7 @@ aea create my_agent && cd my_agent aea scaffold skill my_search ``` -In the following steps, we will replace each one of the scaffolded `Behaviour`, `Handler` and `Task` in `my_agent/skills/my_search` with our implementation. +In the following steps, we will replace each one of the scaffolded `Behaviour`, `Handler` and `Task` in `my_agent/skills/my_search` with our implementation. We will build a simple skill which lets the agent send a search query to the [OEF](https://docs.fetch.ai/oef/) and process the resulting response. ## Step 2: Develop a Behaviour diff --git a/setup.py b/setup.py index 78a42e2006..3c0ca4a23d 100644 --- a/setup.py +++ b/setup.py @@ -76,7 +76,7 @@ def get_all_extras() -> Dict: cli_gui = [ "flask", - "connexion[swagger-ui] @ git+https://github.com/neverpanic/connexion.git@jsonschema-3#egg=connexion[swagger-ui]", + "connexion[swagger-ui]", *cli_deps ] @@ -137,7 +137,10 @@ def get_all_extras() -> Dict: zip_safe=False, include_package_data=True, data_files=[ - ("aea/skills/base/schemas/", glob.glob("aea/skills/base/schemas/*.json")), + ( + os.path.join("aea", "skills", "base", "schemas"), + glob.glob(os.path.join("aea", "skills", "base", "schemas", "*.json")) + ), ], license=about['__license__'], ) diff --git a/tests/conftest.py b/tests/conftest.py index a461a2826a..ce2b4193db 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,6 +23,7 @@ import logging import os import socket +import sys import time from threading import Timer from typing import Optional @@ -224,6 +225,8 @@ def _create_oef_docker_image(oef_addr_, oef_port_) -> Container: @pytest.fixture(scope="session") def network_node(oef_addr, oef_port, pytestconfig): """Network node initialization.""" + if sys.version_info < (3, 7): + pytest.skip("Python version < 3.7 not supported by the OEF.") if pytestconfig.getoption("no_integration_tests"): pytest.skip('skipped: no OEF running') return diff --git a/tests/test_cli/test_commands/test_gui.py b/tests/test_cli/test_commands/test_gui.py index 9507302ab8..8c22a7d732 100644 --- a/tests/test_cli/test_commands/test_gui.py +++ b/tests/test_cli/test_commands/test_gui.py @@ -47,7 +47,7 @@ def setup_class(cls): cls.t = tempfile.mkdtemp() os.chdir(cls.t) cls.proc = subprocess.Popen(["aea", *CLI_LOG_OPTION, "gui"]) - time.sleep(3.0) + time.sleep(5.0) def test_gui(self, pytestconfig): """Test that the gui process has been spawned correctly.""" diff --git a/tests/test_cli/test_commands/test_run.py b/tests/test_cli/test_commands/test_run.py index 0c3f413999..68ae740c30 100644 --- a/tests/test_cli/test_commands/test_run.py +++ b/tests/test_cli/test_commands/test_run.py @@ -199,6 +199,10 @@ def setup_class(cls): assert result.exit_code == 0 os.chdir(Path(cls.t, cls.agent_name)) + + result = cls.runner.invoke(cli, [*CLI_LOG_OPTION, "add", "connection", "local"]) + assert result.exit_code == 0 + shutil.copytree(Path(CUR_PATH, "data", "exception_skill"), Path(cls.t, cls.agent_name, "skills", "exception")) config_path = Path(cls.t, cls.agent_name, DEFAULT_AEA_CONFIG_FILE) config = yaml.safe_load(open(config_path)) @@ -206,7 +210,7 @@ def setup_class(cls): yaml.safe_dump(config, open(config_path, "w")) try: - cli.main([*CLI_LOG_OPTION, "run"]) + cli.main([*CLI_LOG_OPTION, "run", "--connection", "local"]) except SystemExit as e: cls.exit_code = e.code diff --git a/tests/test_connections/test_local/test_misc.py b/tests/test_connections/test_local/test_misc.py index 36aca131f6..e9295f79b7 100644 --- a/tests/test_connections/test_local/test_misc.py +++ b/tests/test_connections/test_local/test_misc.py @@ -31,6 +31,10 @@ def test_connection(): """Test that two mailbox can connect to the node.""" node = LocalNode() + + node._queues['m_key'] = "m_key" + assert node.connect("m_key") is None, "The connect function must return None." + mailbox1 = MailBox(OEFLocalConnection("mailbox1", node)) mailbox2 = MailBox(OEFLocalConnection("mailbox2", node)) @@ -97,6 +101,5 @@ def test_communication(): msg = FIPASerializer().decode(envelope.message) assert envelope.protocol_id == "fipa" assert msg.get("performative") == FIPAMessage.Performative.DECLINE - mailbox1.disconnect() mailbox2.disconnect() diff --git a/tests/test_connections/test_local/test_search_services.py b/tests/test_connections/test_local/test_search_services.py index dfcaca957b..b61a2608c1 100644 --- a/tests/test_connections/test_local/test_search_services.py +++ b/tests/test_connections/test_local/test_search_services.py @@ -18,9 +18,13 @@ # ------------------------------------------------------------------------------ """This module contains the tests for the search feature of the local OEF node.""" +import time +import pytest from aea.connections.local.connection import LocalNode, OEFLocalConnection from aea.mail.base import MailBox, Envelope +from aea.protocols.fipa.message import FIPAMessage +from aea.protocols.fipa.serialization import FIPASerializer from aea.protocols.oef.message import OEFMessage from aea.protocols.oef.models import Query, DataModel, Description from aea.protocols.oef.serialization import DEFAULT_OEF, OEFSerializer @@ -47,7 +51,8 @@ def test_empty_search_result(self): # build and send the request search_services_request = OEFMessage(oef_type=OEFMessage.Type.SEARCH_SERVICES, id=request_id, query=query) msg_bytes = OEFSerializer().encode(search_services_request) - envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) + envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, + message=msg_bytes) self.mailbox1.send(envelope) # check the result @@ -59,6 +64,21 @@ def test_empty_search_result(self): assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT assert search_result.get("agents") == [] + # build and send the request + search_agents_request = OEFMessage(oef_type=OEFMessage.Type.SEARCH_AGENTS, id=request_id, query=query) + msg_bytes = OEFSerializer().encode(search_agents_request) + envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, + message=msg_bytes) + self.mailbox1.send(envelope) + + # check the result + response_envelope = self.mailbox1.inbox.get(block=True, timeout=5.0) + assert response_envelope.protocol_id == OEFMessage.protocol_id + assert response_envelope.sender == DEFAULT_OEF + search_result = OEFSerializer().decode(response_envelope.message) + assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT + assert search_result.get("agents") == [] + @classmethod def teardown_class(cls): """Teardown the test.""" @@ -83,9 +103,11 @@ def setup_class(cls): service_id = '' cls.data_model = DataModel("foobar", attributes=[]) service_description = Description({"foo": 1, "bar": "baz"}, data_model=cls.data_model) - register_service_request = OEFMessage(oef_type=OEFMessage.Type.REGISTER_SERVICE, id=request_id, service_description=service_description, service_id=service_id) + register_service_request = OEFMessage(oef_type=OEFMessage.Type.REGISTER_SERVICE, id=request_id, + service_description=service_description, service_id=service_id) msg_bytes = OEFSerializer().encode(register_service_request) - envelope = Envelope(to=DEFAULT_OEF, sender=cls.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) + envelope = Envelope(to=DEFAULT_OEF, sender=cls.public_key_1, protocol_id=OEFMessage.protocol_id, + message=msg_bytes) cls.mailbox1.send(envelope) def test_not_empty_search_result(self): @@ -96,7 +118,8 @@ def test_not_empty_search_result(self): # build and send the request search_services_request = OEFMessage(oef_type=OEFMessage.Type.SEARCH_SERVICES, id=request_id, query=query) msg_bytes = OEFSerializer().encode(search_services_request) - envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) + envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, + message=msg_bytes) self.mailbox1.send(envelope) # check the result @@ -114,63 +137,185 @@ def teardown_class(cls): cls.mailbox1.disconnect() -# class TestFilteredSearchResult: -# """Test that the query system of the search gives the expected result.""" -# -# @classmethod -# def setup_class(cls): -# """Set up the test.""" -# cls.node = LocalNode() -# -# cls.public_key_1 = "mailbox1" -# cls.public_key_2 = "mailbox2" -# cls.mailbox1 = MailBox(OEFLocalConnection(cls.public_key_1, cls.node)) -# cls.mailbox2 = MailBox(OEFLocalConnection(cls.public_key_2, cls.node)) -# cls.mailbox1.connect() -# cls.mailbox2.connect() -# -# # register 'mailbox2' as a service 'foobar'. -# request_id = 1 -# service_id = '' -# cls.data_model_foobar = DataModel("foobar", attributes=[]) -# service_description = Description({"foo": 1, "bar": "baz"}, data_model=cls.data_model_foobar) -# register_service_request = OEFMessage(oef_type=OEFMessage.Type.REGISTER_SERVICE, id=request_id, service_description=service_description, service_id=service_id) -# msg_bytes = OEFSerializer().encode(register_service_request) -# envelope = Envelope(to=DEFAULT_OEF, sender=cls.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) -# cls.mailbox1.send(envelope) -# -# time.sleep(2.0) -# -# # register 'mailbox2' as a service 'barfoo'. -# cls.data_model_barfoo = DataModel("barfoo", attributes=[]) -# service_description = Description({"foo": 1, "bar": "baz"}, data_model=cls.data_model_barfoo) -# register_service_request = OEFMessage(oef_type=OEFMessage.Type.REGISTER_SERVICE, id=request_id, service_description=service_description, service_id=service_id) -# msg_bytes = OEFSerializer().encode(register_service_request) -# envelope = Envelope(to=DEFAULT_OEF, sender=cls.public_key_2, protocol_id=OEFMessage.protocol_id, message=msg_bytes) -# cls.mailbox2.send(envelope) -# -# def test_filtered_search_result(self): -# """Test that the search result contains only the entries matching the query.""" -# request_id = 1 -# query = Query(constraints=[], model=self.data_model_barfoo) -# -# # build and send the request -# search_services_request = OEFMessage(oef_type=OEFMessage.Type.SEARCH_SERVICES, id=request_id, query=query) -# msg_bytes = OEFSerializer().encode(search_services_request) -# envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) -# self.mailbox1.send(envelope) -# -# # check the result -# response_envelope = self.mailbox1.inbox.get(block=True, timeout=5.0) -# assert response_envelope.protocol_id == OEFMessage.protocol_id -# assert response_envelope.to == self.public_key_1 -# assert response_envelope.sender == DEFAULT_OEF -# search_result = OEFSerializer().decode(response_envelope.message) -# assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT -# assert search_result.get("agents") == [self.public_key_2] -# -# @classmethod -# def teardown_class(cls): -# """Teardown the test.""" -# cls.mailbox1.disconnect() -# cls.mailbox2.disconnect() +class TestFilteredSearchResult: + """Test that the query system of the search gives the expected result.""" + + @classmethod + def setup_class(cls): + """Set up the test.""" + cls.node = LocalNode() + + cls.public_key_1 = "mailbox1" + cls.public_key_2 = "mailbox2" + cls.mailbox1 = MailBox(OEFLocalConnection(cls.public_key_1, cls.node)) + cls.mailbox2 = MailBox(OEFLocalConnection(cls.public_key_2, cls.node)) + cls.mailbox1.connect() + cls.mailbox2.connect() + + # register 'mailbox2' as a service 'foobar'. + request_id = 1 + service_id = '' + cls.data_model_foobar = DataModel("foobar", attributes=[]) + service_description = Description({"foo": 1, "bar": "baz"}, data_model=cls.data_model_foobar) + register_service_request = OEFMessage(oef_type=OEFMessage.Type.REGISTER_SERVICE, id=request_id, + service_description=service_description, service_id=service_id) + msg_bytes = OEFSerializer().encode(register_service_request) + envelope = Envelope(to=DEFAULT_OEF, sender=cls.public_key_1, protocol_id=OEFMessage.protocol_id, + message=msg_bytes) + cls.mailbox1.send(envelope) + + time.sleep(2.0) + + # register 'mailbox2' as a service 'barfoo'. + cls.data_model_barfoo = DataModel("barfoo", attributes=[]) + service_description = Description({"foo": 1, "bar": "baz"}, data_model=cls.data_model_barfoo) + register_service_request = OEFMessage(oef_type=OEFMessage.Type.REGISTER_SERVICE, id=request_id, + service_description=service_description, service_id=service_id) + msg_bytes = OEFSerializer().encode(register_service_request) + envelope = Envelope(to=DEFAULT_OEF, sender=cls.public_key_2, protocol_id=OEFMessage.protocol_id, + message=msg_bytes) + cls.mailbox2.send(envelope) + + data_model = DataModel("foobar", attributes=[]) + service_description = Description({"foo": 1, "bar": "baz"}, data_model=data_model) + msg = OEFMessage(oef_type=OEFMessage.Type.UNREGISTER_SERVICE, id=0, service_description=service_description, + service_id="Test_service") + msg_bytes = OEFSerializer().encode(msg) + envelope = Envelope(to="mailbox2", sender="mailbox1", protocol_id=OEFMessage.protocol_id, message=msg_bytes) + cls.mailbox1.send(envelope) + + def test_filtered_search_result(self): + """Test that the search result contains only the entries matching the query.""" + request_id = 1 + query = Query(constraints=[], model=self.data_model_barfoo) + + # build and send the request + search_services_request = OEFMessage(oef_type=OEFMessage.Type.SEARCH_SERVICES, id=request_id, query=query) + msg_bytes = OEFSerializer().encode(search_services_request) + envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, + message=msg_bytes) + self.mailbox1.send(envelope) + + # check the result + response_envelope = self.mailbox1.inbox.get(block=True, timeout=5.0) + assert response_envelope.protocol_id == OEFMessage.protocol_id + assert response_envelope.to == self.public_key_1 + assert response_envelope.sender == DEFAULT_OEF + search_result = OEFSerializer().decode(response_envelope.message) + assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT + assert search_result.get("agents") == [self.public_key_2] + + def test_filtered_search_agents(self): + """Test that the search result contains only the entries matching the query.""" + request_id = 1 + + query = Query(constraints=[], model=self.data_model_foobar) + # build and send the request + search_agents_request = OEFMessage(oef_type=OEFMessage.Type.SEARCH_AGENTS, id=request_id, query=query) + msg_bytes = OEFSerializer().encode(search_agents_request) + envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, + message=msg_bytes) + self.mailbox1.send(envelope) + + # check the result + response_envelope = self.mailbox1.inbox.get(block=True, timeout=5.0) + assert response_envelope.protocol_id == OEFMessage.protocol_id + assert response_envelope.sender == DEFAULT_OEF + search_result = OEFSerializer().decode(response_envelope.message) + assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT + assert search_result.get("agents") == [] + + @classmethod + def teardown_class(cls): + """Teardown the test.""" + cls.mailbox1.disconnect() + cls.mailbox2.disconnect() + + +class TestUnregister: + """Test that the unregister service results to Error Message.""" + + @classmethod + def setup_class(cls): + """Set up the test.""" + cls.node = LocalNode() + + cls.public_key_1 = "mailbox1" + cls.mailbox1 = MailBox(OEFLocalConnection(cls.public_key_1, cls.node)) + + cls.mailbox1.connect() + + def test_unregister_service_result(self): + """Test that at the beginning, the search request returns an empty search result.""" + data_model = DataModel("foobar", attributes=[]) + service_description = Description({"foo": 1, "bar": "baz"}, data_model=data_model) + msg = OEFMessage(oef_type=OEFMessage.Type.UNREGISTER_SERVICE, id=0, service_description=service_description, + service_id="Test_service") + msg_bytes = OEFSerializer().encode(msg) + envelope = Envelope(to=DEFAULT_OEF, sender="mailbox1", protocol_id=OEFMessage.protocol_id, message=msg_bytes) + self.mailbox1.send(envelope) + + # check the result + response_envelope = self.mailbox1.inbox.get(block=True, timeout=5.0) + assert response_envelope.protocol_id == OEFMessage.protocol_id + assert response_envelope.sender == DEFAULT_OEF + result = OEFSerializer().decode(response_envelope.message) + assert result.get("type") == OEFMessage.Type.OEF_ERROR + + @classmethod + def teardown_class(cls): + """Teardown the test.""" + cls.mailbox1.disconnect() + + +class TestAgentMessage: + """Test the the OEF will return Dialogue Error if it doesn't know the public key.""" + + @classmethod + def setup_class(cls): + """Set up the test.""" + cls.node = LocalNode() + + cls.public_key_1 = "mailbox1" + cls.mailbox1 = MailBox(OEFLocalConnection(cls.public_key_1, cls.node)) + + def test_messages(self): + """Test that at the beginning, the search request returns an empty search result.""" + msg = FIPAMessage(0, 0, 0, FIPAMessage.Performative.CFP, query=None) + msg_bytes = FIPASerializer().encode(msg) + envelope = Envelope(to=DEFAULT_OEF, sender="mailbox1", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) + with pytest.raises(ConnectionError): + OEFLocalConnection(self.public_key_1, self.node).send(envelope) + + self.mailbox1.connect() + msg = FIPAMessage(0, 0, 0, FIPAMessage.Performative.CFP, query=None) + msg_bytes = FIPASerializer().encode(msg) + envelope = Envelope(to="mailbox3", sender="mailbox1", protocol_id=FIPAMessage.protocol_id, message=msg_bytes) + self.mailbox1.send(envelope) + + # check the result + response_envelope = self.mailbox1.inbox.get(block=True, timeout=5.0) + assert response_envelope.protocol_id == OEFMessage.protocol_id + assert response_envelope.sender == DEFAULT_OEF + result = OEFSerializer().decode(response_envelope.message) + assert result.get("type") == OEFMessage.Type.DIALOGUE_ERROR + + @classmethod + def teardown_class(cls): + """Teardown the test.""" + cls.mailbox1.disconnect() + + +class TestOEFConnectionFromJson: + """Test the the OEF will return a connection after reading the .json file.""" + + @classmethod + def setup_class(cls): + """Set up the test.""" + cls.node = LocalNode() + cls.public_key_1 = "mailbox1" + + @classmethod + def teardown_class(cls): + """Teardown the test.""" + cls.mailbox1.disconnect() diff --git a/tests/test_crypto/test_crypto.py b/tests/test_crypto/test_crypto.py index 2b38890db1..1685c7d957 100644 --- a/tests/test_crypto/test_crypto.py +++ b/tests/test_crypto/test_crypto.py @@ -18,23 +18,40 @@ # ------------------------------------------------------------------------------ """This module contains the tests of the crypto module.""" +import os +from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat, \ - load_pem_private_key - -from aea.crypto.base import DefaultCrypto +from aea.crypto.base import DefaultCrypto, _load_pem_private_key_from_path from ..conftest import ROOT_DIR -def test_initialization_from_existing_private_key(): - """Test that the initialization from an existing private key works correctly.""" - private_key_pem_path = ROOT_DIR + "/tests/data/priv.pem" +PRIVATE_KEY_PEM_PATH = os.path.join(ROOT_DIR, "tests/data/priv.pem") - private_key = load_pem_private_key(open(private_key_pem_path, "rb").read(), None, default_backend()) - c = DefaultCrypto(private_key_pem_path=private_key_pem_path) +def test_initialization_from_existing_private_key(): + """Test that the initialization from an existing private key works correctly.""" + private_key = _load_pem_private_key_from_path(path=PRIVATE_KEY_PEM_PATH) + assert private_key is not None, "The private key is not None after the loading!" + c = DefaultCrypto(private_key_pem_path=PRIVATE_KEY_PEM_PATH) expected_public_key = private_key.public_key().public_bytes(encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo) actual_public_key = c.public_key_pem assert expected_public_key == actual_public_key + + +def test_return_fingerprint(): + """Test that the fingerprint is not None.""" + c = DefaultCrypto(private_key_pem_path=PRIVATE_KEY_PEM_PATH) + assert c.fingerprint is not None, "The fingerprint must be None" + + +def test_sign_data(): + """Test the sign message and the verification of the message.""" + c = DefaultCrypto(private_key_pem_path=PRIVATE_KEY_PEM_PATH) + my_signature = c.sign_data(b"Hello") + assert len(my_signature) > 0, "Signed data must not be none" + assert c.is_confirmed_integrity(b"Hello", my_signature, c.public_key), "The verification must be True" + obj = DefaultCrypto(private_key_pem_path=PRIVATE_KEY_PEM_PATH) + + # TODO: I am not sure about this :) + assert type(obj._pvk_obj_to_pem(obj._private_key)) == bytes, "Must return the bytes for the .pem file!" diff --git a/tox.ini b/tox.ini index 8673016b87..525421ec9e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # envlist = flake8, mypy, py37, py36, docs -envlist = flake8, mypy, py37, docs +envlist = flake8, mypy, py37, py36, docs skipsdist = True ignore_basepython_conflict = True