diff --git a/demo/playground/Dockerfile.acapy b/demo/playground/Dockerfile.acapy index 21b804aa0f..956205df1f 100644 --- a/demo/playground/Dockerfile.acapy +++ b/demo/playground/Dockerfile.acapy @@ -1,4 +1,4 @@ -FROM ghcr.io/hyperledger/aries-cloudagent-python:py3.9-0.8.1 +FROM ghcr.io/hyperledger/aries-cloudagent-python:py3.9-0.10.4 USER root diff --git a/demo/playground/docker-compose.yml b/demo/playground/docker-compose.yml index da74281568..7488d8f934 100644 --- a/demo/playground/docker-compose.yml +++ b/demo/playground/docker-compose.yml @@ -66,6 +66,7 @@ services: retries: 5 faber-agent: + image: playground-image build: context: . dockerfile: Dockerfile.acapy @@ -110,6 +111,7 @@ services: retries: 5 alice-agent: + image: playground-image build: context: . dockerfile: Dockerfile.acapy @@ -154,6 +156,7 @@ services: retries: 5 acme-agent: + image: playground-image build: context: . dockerfile: Dockerfile.acapy @@ -198,6 +201,7 @@ services: retries: 5 multi-agent: + image: playground-image build: context: . dockerfile: Dockerfile.acapy diff --git a/demo/playground/examples/Dockerfile.test.runner b/demo/playground/examples/Dockerfile.test.runner new file mode 100644 index 0000000000..95f0d2461c --- /dev/null +++ b/demo/playground/examples/Dockerfile.test.runner @@ -0,0 +1,20 @@ +FROM python:3.9-slim +WORKDIR /usr/src/app + +# install poetry +RUN pip3 install --no-cache-dir poetry + +# Add docker-compose-wait tool +ENV WAIT_VERSION 2.7.2 +ADD https://github.com/ufoscout/docker-compose-wait/releases/download/$WAIT_VERSION/wait /wait +RUN chmod +x /wait + +# install dependencies +COPY pyproject.toml . +COPY poetry.lock . +RUN poetry install --only main + +# add tests to image +COPY tests/* tests/ + +ENTRYPOINT ["/bin/sh", "-c", "/wait && poetry run pytest \"$@\"", "--"] \ No newline at end of file diff --git a/demo/playground/examples/docker-compose.yml b/demo/playground/examples/docker-compose.yml new file mode 100644 index 0000000000..eb60799e65 --- /dev/null +++ b/demo/playground/examples/docker-compose.yml @@ -0,0 +1,33 @@ +version: '3' +#*************************************************************** +# playground test agents * +#*************************************************************** + +networks: + app-network: + name: ${APP_NETWORK_NAME:-playgroundnet} + driver: bridge + external: true + +services: + + tests: + container_name: juggernaut + build: + context: . + dockerfile: Dockerfile.test.runner + environment: + - WAIT_BEFORE_HOSTS=3 + - WAIT_HOSTS=faber-agent:9011, alice-agent:9012, acme-agent:9013, multi-agent:9014 + - WAIT_HOSTS_TIMEOUT=60 + - WAIT_SLEEP_INTERVAL=1 + - WAIT_HOST_CONNECT_TIMEOUT=30 + # API ADMIN + - FABER=http://faber-agent:9011 + - ALICE=http://alice-agent:9012 + - ACME=http://acme-agent:9013 + - MULTI=http://multi-agent:9014 + # ADDITIONAL TEST env vars + - MEDIATOR_INVITATION_URL=${MEDIATOR_INVITATION_URL} + networks: + - app-network \ No newline at end of file diff --git a/demo/playground/examples/poetry.lock b/demo/playground/examples/poetry.lock new file mode 100644 index 0000000000..a9929fb73f --- /dev/null +++ b/demo/playground/examples/poetry.lock @@ -0,0 +1,303 @@ +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. + +[[package]] +name = "asynctest" +version = "0.13.0" +description = "Enhance the standard unittest package with features for testing asyncio libraries" +category = "main" +optional = false +python-versions = ">=3.5" +files = [ + {file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"}, + {file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"}, +] + +[[package]] +name = "certifi" +version = "2023.7.22" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, + {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.1.tar.gz", hash = "sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win32.whl", hash = "sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win32.whl", hash = "sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win32.whl", hash = "sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win32.whl", hash = "sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win32.whl", hash = "sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win32.whl", hash = "sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727"}, + {file = "charset_normalizer-3.3.1-py3-none-any.whl", hash = "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.3" +description = "Backport of PEP 654 (exception groups)" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pytest" +version = "7.4.2" +description = "pytest: simple powerful testing with Python" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, + {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.21.1" +description = "Pytest support for asyncio" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, + {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "urllib3" +version = "2.0.7" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, + {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.9" +content-hash = "c9c1bb0fed9cb41eaa74390c7ba76d4e84a6fc5a0a849f770640a4dbcfb1fbca" diff --git a/demo/playground/examples/pyproject.toml b/demo/playground/examples/pyproject.toml new file mode 100644 index 0000000000..bfc662bbd4 --- /dev/null +++ b/demo/playground/examples/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "acapy_demos_playground" +version = "0.1.0" +description = "" +authors = ["Jason Sherman "] + +[tool.poetry.dependencies] +python = "^3.9" +pytest = "^7.4.0" +pytest-asyncio = "^0.21.0" +asynctest = "^0.13.0" +requests = "^2.31.0" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" \ No newline at end of file diff --git a/demo/playground/examples/tests/__init__.py b/demo/playground/examples/tests/__init__.py new file mode 100644 index 0000000000..c35b313157 --- /dev/null +++ b/demo/playground/examples/tests/__init__.py @@ -0,0 +1,222 @@ +# pylint: disable=redefined-outer-name + +from functools import wraps +import logging +import os +import time + +import pytest +import requests + +AUTO_ACCEPT = "false" + +FABER = os.getenv("FABER") +ALICE = os.getenv("ALICE") +ACME = os.getenv("ACME") +MULTI = os.getenv("MULTI") + +# Create a named logger +logger = logging.getLogger("playground_examples") +logger.setLevel(logging.INFO) +# Create a console handler +console_handler = logging.StreamHandler() +console_handler.setLevel(logging.INFO) +# Set the formatter for the console handler +formatter = logging.Formatter( + "%(asctime)s - %(levelname)s - %(message)s", +) +console_handler.setFormatter(formatter) +# Add the console handler to the logger +logger.addHandler(console_handler) + + +def get(agent: str, path: str, **kwargs): + """Get.""" + return requests.get(f"{agent}{path}", **kwargs) + + +def post(agent: str, path: str, **kwargs): + """Post.""" + return requests.post(f"{agent}{path}", **kwargs) + + +def fail_if_not_ok(message: str): + """Fail the current test if wrapped call fails with message.""" + + def _fail_if_not_ok(func): + @wraps(func) + def _wrapper(*args, **kwargs): + response = func(*args, **kwargs) + if not response.ok: + pytest.fail(f"{message}: {response.content}") + return response + + return _wrapper + + return _fail_if_not_ok + + +def unwrap_json_response(func): + """Unwrap a requests response object to json.""" + + @wraps(func) + def _wrapper(*args, **kwargs) -> dict: + response = func(*args, **kwargs) + return response.json() + + return _wrapper + + +class Agent: + """Class for interacting with Agent over Admin API""" + + def __init__(self, url: str, headers=None): + self.url = url + self._headers = headers + + @property + def headers(self): + """Accessor for the agents http headers. + + Returns: + dict or None + + """ + return self._headers + + @headers.setter + def headers(self, headers): + """Setter for agent's http headers. + + Args: + headers: dict or None + + """ + self._headers = headers + + @unwrap_json_response + @fail_if_not_ok("Create invitation failed") + def create_invitation(self, json=None, **kwargs): + """Create invitation.""" + return post( + self.url, + "/connections/create-invitation", + params=kwargs, + headers=self._headers, + json=json, + ) + + @unwrap_json_response + @fail_if_not_ok("Receive invitation failed") + def receive_invite(self, invite: dict, **kwargs): + """Receive invitation.""" + return post( + self.url, + "/connections/receive-invitation", + params=kwargs, + headers=self._headers, + json=invite, + ) + + @unwrap_json_response + @fail_if_not_ok("Accept invitation failed") + def accept_invite(self, connection_id: str, **kwargs): + """Accept invitation.""" + return post( + self.url, + f"/connections/{connection_id}/accept-invitation", + params=kwargs, + headers=self._headers, + ) + + @unwrap_json_response + @fail_if_not_ok("Create invitation failed") + def list_connections(self, **kwargs): + """List connections.""" + results = get(self.url, "/connections", params=kwargs, headers=self._headers) + return results + + @unwrap_json_response + @fail_if_not_ok("Failed to get connection by id") + def get_connection(self, connection_id: str, **kwargs): + """Fetch a connection.""" + return get( + self.url, + f"/connections/{connection_id}", + params=kwargs, + headers=self._headers, + ) + + @unwrap_json_response + @fail_if_not_ok("Failed to ping connection") + def ping_connection(self, connection_id: str, alias: str, **kwargs): + """ping connection.""" + return post( + self.url, + f"/connections/{connection_id}/send-ping", + params=kwargs, + headers=self._headers, + json={"comment": f"{alias} pinging..."}, + ) + + @unwrap_json_response + @fail_if_not_ok("Failure requesting mediation") + def request_for_mediation(self, connection_id: str, **kwargs): + """Request mediation from mediator.""" + return post( + self.url, + f"/mediation/request/{connection_id}", + params=kwargs, + headers=self._headers, + json={}, + ) + + @unwrap_json_response + @fail_if_not_ok("Failed to check mediation request") + def get_mediation_request(self, mediation_id: str, **kwargs): + """Fetch mediation request.""" + return get( + self.url, + f"/mediation/requests/{mediation_id}", + params=kwargs, + headers=self._headers, + ) + + @unwrap_json_response + @fail_if_not_ok("Failure requesting mediation") + def create_tenant(self, wallet_name: str, wallet_key: str, **kwargs): + """Create a tenant in multitenanted acapy.""" + data = { + "key_management_mode": "managed", + "wallet_dispatch_type": "default", + "wallet_name": wallet_name, + "wallet_key": wallet_key, + "label": wallet_name, + "wallet_type": "askar", + "wallet_webhook_urls": [], + } + # multi-agent has no security for base wallet, just call multitenancy/wallet + # to create a new tenant + return post(self.url, "/multitenancy/wallet", headers={}, json=data) + + def get(self, path: str, return_json: bool = True, fail_with: str = None, **kwargs): + """Do get to agent endpoint.""" + wrapped_get = get + if fail_with: + wrapped_get = fail_if_not_ok(fail_with)(wrapped_get) + if return_json: + wrapped_get = unwrap_json_response(wrapped_get) + + return wrapped_get(self.url, path, **kwargs) + + def post( + self, path: str, return_json: bool = True, fail_with: str = None, **kwargs + ): + """Do post to agent endpoint.""" + wrapped_post = post + if fail_with: + wrapped_post = fail_if_not_ok(fail_with)(wrapped_post) + if return_json: + wrapped_post = unwrap_json_response(wrapped_post) + + return wrapped_post(self.url, path, **kwargs) diff --git a/demo/playground/examples/tests/test_mediator_ping_agents.py b/demo/playground/examples/tests/test_mediator_ping_agents.py new file mode 100644 index 0000000000..9f37e58e89 --- /dev/null +++ b/demo/playground/examples/tests/test_mediator_ping_agents.py @@ -0,0 +1,258 @@ +"""Integration tests for Basic Message Storage.""" + +# pylint: disable=redefined-outer-name + +import base64 +import os +import pytest +import time +import uuid + +import json as jsonlib + +from . import logger, Agent, FABER, ALICE, MULTI + +# add a blank line... +logger.info("start testing mediated connections...") + + +@pytest.fixture(scope="session") +def faber(): + """faber agent fixture.""" + logger.info(f"faber = {FABER}") + yield Agent(FABER) + + +@pytest.fixture(scope="session") +def alice(): + """resolver agent fixture.""" + logger.info(f"alice = {ALICE}") + yield Agent(ALICE) + + +@pytest.fixture(scope="session") +def multi_one(): + """resolver agent fixture.""" + agent = Agent(MULTI) + wallet_name = f"multi_one_{str(uuid.uuid4())[0:8]}" + resp = agent.create_tenant(wallet_name, "changeme") + wallet_id = resp["wallet_id"] + token = resp["token"] + agent.headers = {"Authorization": f"Bearer {token}"} + yield agent + + +@pytest.fixture(scope="session") +def mediation_invite(): + invitation_url = os.getenv("MEDIATOR_INVITATION_URL") + logger.info(f"MEDIATOR_INVITATION_URL = {invitation_url}") + base64_message = invitation_url.split("=", maxsplit=1)[1] + base64_bytes = base64_message.encode("ascii") + message_bytes = base64.b64decode(base64_bytes) + data = message_bytes.decode("ascii") + logger.info(f"invitation_block = {data}") + yield data + + +def initialize_mediation(agent: Agent, invitation): + connection_id = None + mediator_connection_state = None + mediation_id = None + mediation_granted = False + + invitation_json = agent.receive_invite( + invitation, auto_accept="true", alias="mediator" + ) + connection_id = invitation_json["connection_id"] + logger.info(f"connection_id: {connection_id}") + time.sleep(2) + + attempts = 0 + while mediator_connection_state != "active" and attempts < 5: + time.sleep(1) + connection_json = agent.get_connection(connection_id) + mediator_connection_state = connection_json["state"] + logger.info(f"mediator_connection_state: {mediator_connection_state}") + attempts = attempts + 1 + + if mediator_connection_state == "active": + mediation_request_json = agent.request_for_mediation(connection_id) + mediation_id = mediation_request_json["mediation_id"] + logger.info(f"mediation_id: {mediation_id}") + mediation_granted = False + attempts = 0 + while not mediation_granted and attempts < 5: + time.sleep(1) + granted_json = agent.get_mediation_request(mediation_id) + mediation_granted = granted_json["state"] == "granted" + logger.info(f"mediation_granted: {mediation_granted}") + attempts = attempts + 1 + + result = { + "connection_id": connection_id, + "mediation_id": mediation_id, + "mediator_connection_state": mediator_connection_state, + "mediation_granted": mediation_granted, + } + return result + + +@pytest.fixture(scope="session") +def faber_mediator(faber, mediation_invite): + logger.info(f"faber_mediator...") + result = initialize_mediation(faber, mediation_invite) + logger.info(f"...faber_mediator = {result}") + yield result + + +@pytest.fixture(scope="session") +def alice_mediator(alice, mediation_invite): + logger.info(f"alice_mediator...") + result = initialize_mediation(alice, mediation_invite) + logger.info(f"...alice_mediator = {result}") + yield result + + +@pytest.fixture(scope="session") +def multi_one_mediator(multi_one, mediation_invite): + logger.info(f"multi_one_mediator...") + result = initialize_mediation(multi_one, mediation_invite) + logger.info(f"...multi_one_mediator = {result}") + yield result + + +@pytest.mark.skipif( + os.getenv("MEDIATOR_INVITATION_URL") in [None, "", " "], + reason="MEDIATOR_INVITATION_URL not set. Running tests that do not require mediator.", +) +def test_mediated_single_tenants( + faber, alice, faber_mediator, alice_mediator, mediation_invite +): + assert faber_mediator["mediation_granted"] == True + assert alice_mediator["mediation_granted"] == True + + resp = faber.create_invitation( + alias="alice", + auto_accept="true", + json={"my_label": "faber", "mediation_id": faber_mediator["mediation_id"]}, + ) + faber_alice_connection_id = resp["connection_id"] + logger.info(f"faber_alice_connection_id = {faber_alice_connection_id}") + assert faber_alice_connection_id + invite = resp["invitation"] + logger.info(f"invite = {invite}") + assert invite + + mediation_invite_json = jsonlib.loads(mediation_invite) + logger.info(f"invitation service endpoint = {invite['serviceEndpoint']}") + logger.info( + f"mediator service endpoint = {mediation_invite_json['serviceEndpoint']}" + ) + assert invite["serviceEndpoint"] == mediation_invite_json["serviceEndpoint"] + + resp = alice.receive_invite(invite, alias="faber", auto_accept="true") + alice_faber_connection_id = resp["connection_id"] + logger.info(f"alice_faber_connection_id = {alice_faber_connection_id}") + assert alice_faber_connection_id + + faber_alice_connection_active = False + attempts = 0 + while not faber_alice_connection_active and attempts < 5: + time.sleep(1) + connection_resp = faber.get_connection(faber_alice_connection_id) + faber_alice_connection_active = connection_resp["state"] == "active" + logger.info(f"faber/alice active? {faber_alice_connection_active}") + attempts = attempts + 1 + + alice_faber_connection_active = False + attempts = 0 + while not alice_faber_connection_active and attempts < 5: + time.sleep(1) + connection_resp = alice.get_connection(alice_faber_connection_id) + alice_faber_connection_active = connection_resp["state"] == "active" + logger.info(f"alice/faber active? {alice_faber_connection_active}") + attempts = attempts + 1 + + assert faber_alice_connection_active == True + assert alice_faber_connection_active == True + + logger.info("faber alice pinging...") + pings = 0 + while pings < 10: + resp = faber.ping_connection(faber_alice_connection_id, "faber") + logger.info(f"faber ping alice = {resp}") + time.sleep(1) + alice.ping_connection(alice_faber_connection_id, "alice") + logger.info(f"alice ping faber = {resp}") + time.sleep(1) + pings = pings + 1 + + +@pytest.mark.skipif( + os.getenv("MEDIATOR_INVITATION_URL") in [None, "", " "], + reason="MEDIATOR_INVITATION_URL not set. Running tests that do not require mediator.", +) +def test_mediated_multi_tenants( + multi_one, alice, multi_one_mediator, alice_mediator, mediation_invite +): + assert multi_one_mediator["mediation_granted"] == True + assert alice_mediator["mediation_granted"] == True + + resp = multi_one.create_invitation( + alias="alice", + auto_accept="true", + json={ + "my_label": "multi_one", + "mediation_id": multi_one_mediator["mediation_id"], + }, + ) + multi_one_alice_connection_id = resp["connection_id"] + logger.info(f"multi_one_alice_connection_id = {multi_one_alice_connection_id}") + assert multi_one_alice_connection_id + invite = resp["invitation"] + logger.info(f"invite = {invite}") + assert invite + + mediation_invite_json = jsonlib.loads(mediation_invite) + logger.info(f"invitation service endpoint = {invite['serviceEndpoint']}") + logger.info( + f"mediator service endpoint = {mediation_invite_json['serviceEndpoint']}" + ) + assert invite["serviceEndpoint"] == mediation_invite_json["serviceEndpoint"] + + resp = alice.receive_invite(invite, alias="multi_one", auto_accept="true") + alice_multi_one_connection_id = resp["connection_id"] + logger.info(f"alice_multi_one_connection_id = {alice_multi_one_connection_id}") + assert alice_multi_one_connection_id + + multi_one_alice_connection_active = False + attempts = 0 + while not multi_one_alice_connection_active and attempts < 5: + time.sleep(1) + connection_resp = multi_one.get_connection(multi_one_alice_connection_id) + multi_one_alice_connection_active = connection_resp["state"] == "active" + logger.info(f"multi_one/alice active? {multi_one_alice_connection_active}") + attempts = attempts + 1 + + alice_multi_one_connection_active = False + attempts = 0 + while not alice_multi_one_connection_active and attempts < 5: + time.sleep(1) + connection_resp = alice.get_connection(alice_multi_one_connection_id) + alice_multi_one_connection_active = connection_resp["state"] == "active" + logger.info(f"alice/multi_one active? {alice_multi_one_connection_active}") + attempts = attempts + 1 + + assert multi_one_alice_connection_active == True + assert alice_multi_one_connection_active == True + + logger.info("multi_one alice pinging...") + pings = 0 + while pings < 10: + resp = multi_one.ping_connection(multi_one_alice_connection_id, "multi_one") + logger.info(f"multi_one ping alice = {resp}") + time.sleep(1) + alice.ping_connection(alice_multi_one_connection_id, "alice") + logger.info(f"alice ping multi_one = {resp}") + time.sleep(1) + pings = pings + 1 diff --git a/demo/playground/examples/tests/test_ping_agents.py b/demo/playground/examples/tests/test_ping_agents.py new file mode 100644 index 0000000000..b7c05b7461 --- /dev/null +++ b/demo/playground/examples/tests/test_ping_agents.py @@ -0,0 +1,164 @@ +"""Integration tests for Basic Message Storage.""" + +# pylint: disable=redefined-outer-name + +import os +import pytest +import time +import uuid + +from . import logger, Agent, FABER, ALICE, MULTI + + +@pytest.fixture(scope="session") +def faber(): + """faber agent fixture.""" + yield Agent(FABER) + + +@pytest.fixture(scope="session") +def alice(): + """resolver agent fixture.""" + yield Agent(ALICE) + + +@pytest.fixture(scope="session") +def multi_one(): + """resolver agent fixture.""" + agent = Agent(MULTI) + wallet_name = f"multi_one_{str(uuid.uuid4())[0:8]}" + resp = agent.create_tenant(wallet_name, "changeme") + wallet_id = resp["wallet_id"] + token = resp["token"] + agent.headers = {"Authorization": f"Bearer {token}"} + yield agent + + +@pytest.fixture(scope="session", autouse=True) +def alice_faber_connection(faber, alice): + """Established connection filter.""" + logger.info("faber create invitation to alice") + invite = faber.create_invitation(auto_accept="true")["invitation"] + logger.info(f"invitation = {invite}") + logger.info(f"alice receive invitation") + resp = alice.receive_invite(invite, auto_accept="true") + result = resp["connection_id"] + logger.info(f"alice/faber connection_id = {result}") + return result + + +@pytest.fixture(scope="session", autouse=True) +def faber_alice_connection(faber, alice): + """Established connection filter.""" + logger.info("alice create invitation to faber") + invite = alice.create_invitation(auto_accept="true")["invitation"] + logger.info(f"invitation = {invite}") + logger.info(f"faber receive invitation") + resp = faber.receive_invite(invite, auto_accept="true") + result = resp["connection_id"] + logger.info(f"faber/alice connection_id = {result}") + return result + + +@pytest.fixture(scope="session", autouse=True) +def alice_multi_one_connection(multi_one, alice): + """Established connection filter.""" + logger.info("multi_one create invitation to alice") + invite = multi_one.create_invitation(auto_accept="true")["invitation"] + logger.info(f"invitation = {invite}") + logger.info(f"alice receive invitation") + resp = alice.receive_invite(invite, auto_accept="true") + result = resp["connection_id"] + logger.info(f"alice/multi_one connection_id = {result}") + return result + + +@pytest.fixture(scope="session", autouse=True) +def multi_one_alice_connection(multi_one, alice): + """Established connection filter.""" + logger.info("alice create invitation to multi_one") + invite = alice.create_invitation(auto_accept="true")["invitation"] + logger.info(f"invitation = {invite}") + logger.info(f"faber receive invitation") + resp = multi_one.receive_invite(invite, auto_accept="true") + result = resp["connection_id"] + logger.info(f"multi_one/alice connection_id = {result}") + return result + + +@pytest.mark.skipif( + os.getenv("MEDIATOR_INVITATION_URL") not in [None, "", " "], + reason="MEDIATOR_INVITATION_URL is set. Running only tests that require mediator.", +) +def test_single_tenants(faber, alice, faber_alice_connection, alice_faber_connection): + faber_alice_connection_active = False + attempts = 0 + while not faber_alice_connection_active and attempts < 5: + time.sleep(1) + connection_resp = faber.get_connection(faber_alice_connection) + faber_alice_connection_active = connection_resp["state"] == "active" + logger.info(f"faber/alice active? {faber_alice_connection_active}") + attempts = attempts + 1 + + alice_faber_connection_active = False + attempts = 0 + while not alice_faber_connection_active and attempts < 5: + time.sleep(1) + connection_resp = alice.get_connection(alice_faber_connection) + alice_faber_connection_active = connection_resp["state"] == "active" + logger.info(f"alice/faber active? {alice_faber_connection_active}") + attempts = attempts + 1 + + assert faber_alice_connection_active == True + assert alice_faber_connection_active == True + + logger.info("faber alice pinging...") + pings = 0 + while pings < 10: + resp = faber.ping_connection(faber_alice_connection, "faber") + logger.info(f"faber ping alice = {resp}") + time.sleep(1) + alice.ping_connection(alice_faber_connection, "alice") + logger.info(f"alice ping faber = {resp}") + time.sleep(1) + pings = pings + 1 + + +@pytest.mark.skipif( + os.getenv("MEDIATOR_INVITATION_URL") not in [None, "", " "], + reason="MEDIATOR_INVITATION_URL is set. Running only tests that require mediator.", +) +def test_multi_tenants( + multi_one, alice, multi_one_alice_connection, alice_multi_one_connection +): + multi_one_alice_connection_active = False + attempts = 0 + while not multi_one_alice_connection_active and attempts < 5: + time.sleep(1) + connection_resp = multi_one.get_connection(multi_one_alice_connection) + multi_one_alice_connection_active = connection_resp["state"] == "active" + logger.info(f"multi_one/alice active? {multi_one_alice_connection_active}") + attempts = attempts + 1 + + alice_multi_one_connection_active = False + attempts = 0 + while not alice_multi_one_connection_active and attempts < 5: + time.sleep(1) + connection_resp = alice.get_connection(alice_multi_one_connection) + alice_multi_one_connection_active = connection_resp["state"] == "active" + logger.info(f"alice/multi_one active? {alice_multi_one_connection_active}") + attempts = attempts + 1 + + assert multi_one_alice_connection_active == True + assert alice_multi_one_connection_active == True + + logger.info("multi_one alice pinging...") + pings = 0 + while pings < 10: + resp = multi_one.ping_connection(multi_one_alice_connection, "multi_one") + logger.info(f"multi_one ping alice = {resp}") + time.sleep(1) + alice.ping_connection(alice_multi_one_connection, "alice") + logger.info(f"alice ping multi_one = {resp}") + time.sleep(1) + pings = pings + 1 diff --git a/demo/playground/scripts/mediator_ping_agents.py b/demo/playground/scripts/mediator_ping_agents.py deleted file mode 100644 index 32d68a2e80..0000000000 --- a/demo/playground/scripts/mediator_ping_agents.py +++ /dev/null @@ -1,285 +0,0 @@ -import base64 -import time - -import requests -from random_word import RandomWords - -r = RandomWords() - -FABER_ADMIN_URL = "http://localhost:9011" -ALICE_ADMIN_URL = "http://localhost:9012" -ACME_ADMIN_URL = "http://localhost:9013" -MULTI_ADMIN_URL = "http://localhost:9014" - - -MEDIATOR_INVITATION_URL = "" - - -def wait_a_bit(secs: int = 1): - total = secs - print(f"... wait {total} seconds ...") - time.sleep(total) - - -def initialize_mediation(url, headers=None): - if headers is None: - headers = {} - params = { - "alias": "mediator", - "auto_accept": "true", - } - response = requests.post( - f"{url}/connections/receive-invitation", - headers=headers, - params=params, - json=data, - ) - print(f"response = {response}") - json = response.json() - print(f"json = {json}") - mediator_connection_id = json["connection_id"] - mediator_connection_state = json["state"] - mediation_id = None - - # let's wait until active, then ask for mediation - attempts = 0 - while mediator_connection_state != "active" and attempts < 5: - wait_a_bit(5) - response = requests.get( - f"{url}/connections/{mediator_connection_id}", - headers=headers, - ) - print(f"response = {response}") - json = response.json() - print(f"json = {json}") - mediator_connection_state = json["state"] - print(f"mediator_connection_state = {mediator_connection_state}") - attempts = attempts + 1 - - if mediator_connection_state == "active": - response = requests.post( - f"{url}/mediation/request/{mediator_connection_id}", - headers=headers, - json={}, - ) - print(f"response = {response}") - mediation_request_json = response.json() - print(f"mediation request json = {mediation_request_json}") - mediation_id = mediation_request_json["mediation_id"] - print(f"mediation_id = {mediation_id}") - mediation_granted = False - attempts = 0 - while not mediation_granted and attempts < 5: - wait_a_bit(5) - response = requests.get( - f"{url}/mediation/requests/{mediation_id}", - headers=headers, - ) - print(f"response = {response}") - granted_json = response.json() - print(f"json = {granted_json}") - mediation_granted = granted_json["state"] == "granted" - print(f"mediation_granted = {mediation_granted}") - attempts = attempts + 1 - - return mediator_connection_id, mediation_id - - -def create_invitation(my_label, alias, mediation_id, url, headers=None): - if headers is None: - headers = {} - data = { - "my_label": my_label, - } - if mediation_id: - data["mediation_id"] = mediation_id - - params = { - "alias": alias, - "auto_accept": "true", - } - - response = requests.post( - f"{url}/connections/create-invitation", - headers=headers, - params=params, - json=data, - ) - print(f"response = {response}") - json = response.json() - print(f"create-invitation json = {json}") - invitation = json["invitation"] - connection_id = json["connection_id"] - recipient_keys = json["invitation"]["recipientKeys"] - return invitation, connection_id, recipient_keys - - -def receive_invitation(invitation, alias, mediation_id, url, headers=None): - if headers is None: - headers = {} - data = invitation - params = { - "alias": alias, - "auto_accept": "true", - } - if mediation_id: - params["mediation_id"] = mediation_id - - response = requests.post( - f"{url}/connections/receive-invitation", - headers=headers, - json=data, - params=params, - ) - print(f"response = {response}") - json = response.json() - print(f"receive_invitation json = {json}") - connection_id = json["connection_id"] - return connection_id - - -def fetch_connection(connection_id, url, headers=None): - if headers is None: - headers = {} - response = requests.get( - f"{url}/connections/{connection_id}", - headers=headers, - ) - print(f"response = {response}") - json = response.json() - print(f"fetch_connection json = {json}") - return json["state"] == "active" - - -def ping_connection(connection_id, alias, url, headers=None): - if headers is None: - headers = {} - response = requests.post( - f"{url}/connections/{connection_id}/send-ping", - headers=headers, - json={"comment": f"{alias} pinging..."}, - ) - print(f"ping_connection = {response}") - - -def create_tenant(wallet_name, wallet_key, url, headers=None): - if headers is None: - headers = {} - # need to create the tenant and get the token - data = { - "key_management_mode": "managed", - "wallet_dispatch_type": "default", - "wallet_name": wallet_name, - "wallet_key": wallet_key, - "label": wallet_name, - "wallet_type": "askar", - "wallet_webhook_urls": [], - } - # multi-agent has no security for base wallet, just call multitenancy/wallet - # to create a new tenant - response = requests.post(f"{url}/multitenancy/wallet", headers=headers, json=data) - print(f"response = {response}") - json = response.json() - print(f"json = {json}") - wallet_id = json["wallet_id"] - token = json["token"] - _headers = {"Authorization": f"Bearer {token}"} - - return wallet_id, token, _headers - - -if __name__ == "__main__": - _url = MEDIATOR_INVITATION_URL - base64_message = _url.split("=", maxsplit=1)[1] - base64_bytes = base64_message.encode("ascii") - message_bytes = base64.b64decode(base64_bytes) - data = message_bytes.decode("ascii") - print(f"invitation_block = {data}") - - print("\n... single tenants, initiate mediation ...\n") - - faber_mediation_connection_id, faber_mediation_id = initialize_mediation( - FABER_ADMIN_URL - ) - print("faber") - print(f" mediation_connection_id={faber_mediation_connection_id}") - print(f" mediation_id={faber_mediation_id}") - - alice_mediation_connection_id, alice_mediation_id = initialize_mediation( - ALICE_ADMIN_URL - ) - print("alice") - print(f" mediation_connection_id={alice_mediation_connection_id}") - print(f" mediation_id={alice_mediation_id}") - - print("\n... single tenants, connect ...\n") - - # faber create invitation for alice - ( - faber_invitation, - faber_alice_connection_id, - faber_recipient_keys, - ) = create_invitation("faber", "alice", faber_mediation_id, FABER_ADMIN_URL) - alice_faber_connection_id = receive_invitation( - faber_invitation, "faber", alice_mediation_id, ALICE_ADMIN_URL - ) - - connection_active = False - while not connection_active: - wait_a_bit(1) - connection_active = fetch_connection(faber_alice_connection_id, FABER_ADMIN_URL) - - print("\n... connections active, ping each other ...\n") - - pings = 0 - while connection_active and pings < 10: - ping_connection(faber_alice_connection_id, "faber", FABER_ADMIN_URL) - wait_a_bit(1) - ping_connection(alice_faber_connection_id, "alice", ALICE_ADMIN_URL) - wait_a_bit(1) - pings = pings + 1 - - print("\n... multitenant create tenant...\n") - # ok, now let's try with multitenant - multi_wallet_name = r.get_random_word() - multi_wallet_id, multi_token, multi_headers = create_tenant( - multi_wallet_name, "changeme", MULTI_ADMIN_URL - ) - - print("\n... multitenant, initiate mediation ...\n") - - multi_mediation_connection_id, multi_mediation_id = initialize_mediation( - MULTI_ADMIN_URL, multi_headers - ) - print("multi") - print(f" mediation_connection_id={multi_mediation_connection_id}") - print(f" mediation_id={multi_mediation_id}") - - print("\n... multitenant, connect ...\n") - multi_mediation_id = None - ( - multi_invitation, - multi_alice_connection_id, - multi_recipient_keys, - ) = create_invitation( - multi_wallet_name, "alice", multi_mediation_id, MULTI_ADMIN_URL, multi_headers - ) - - alice_multi_connection_id = receive_invitation( - multi_invitation, multi_wallet_name, alice_mediation_id, ALICE_ADMIN_URL - ) - - connection_active = False - while not connection_active: - wait_a_bit(1) - connection_active = fetch_connection(alice_multi_connection_id, ALICE_ADMIN_URL) - - pings = 0 - while connection_active and pings < 10: - ping_connection( - multi_alice_connection_id, "multi", MULTI_ADMIN_URL, multi_headers - ) - wait_a_bit(1) - ping_connection(alice_multi_connection_id, "alice", ALICE_ADMIN_URL) - wait_a_bit(1) - pings = pings + 1 diff --git a/demo/playground/scripts/ping_agents.py b/demo/playground/scripts/ping_agents.py deleted file mode 100644 index c8d24196d2..0000000000 --- a/demo/playground/scripts/ping_agents.py +++ /dev/null @@ -1,245 +0,0 @@ -import time - -import requests -from random_word import RandomWords - -r = RandomWords() - -FABER_ADMIN_URL = "http://localhost:9011" -ALICE_ADMIN_URL = "http://localhost:9012" -ACME_ADMIN_URL = "http://localhost:9013" -MULTI_ADMIN_URL = "http://localhost:9014" - - -def wait_a_bit(secs: int = 1): - total = secs - print(f"... wait {total} seconds ...") - time.sleep(total) - - -def create_invitation(my_label, alias, mediation_id, url, headers=None): - if headers is None: - headers = {} - data = { - "my_label": my_label, - } - if mediation_id: - data["mediation_id"] = mediation_id - - params = { - "alias": alias, - "auto_accept": "true", - } - - response = requests.post( - f"{url}/connections/create-invitation", - headers=headers, - params=params, - json=data, - ) - print(f"response = {response}") - json = response.json() - print(f"create-invitation json = {json}") - invitation = json["invitation"] - connection_id = json["connection_id"] - recipient_keys = json["invitation"]["recipientKeys"] - return invitation, connection_id, recipient_keys - - -def receive_invitation(invitation, alias, mediation_id, url, headers=None): - if headers is None: - headers = {} - data = invitation - params = { - "alias": alias, - "auto_accept": "true", - } - if mediation_id: - params["mediation_id"] = mediation_id - - response = requests.post( - f"{url}/connections/receive-invitation", - headers=headers, - json=data, - params=params, - ) - print(f"response = {response}") - json = response.json() - print(f"receive_invitation json = {json}") - connection_id = json["connection_id"] - return connection_id - - -def fetch_connection(connection_id, url, headers=None): - if headers is None: - headers = {} - response = requests.get( - f"{url}/connections/{connection_id}", - headers=headers, - ) - print(f"response = {response}") - json = response.json() - print(f"fetch_connection json = {json}") - return json["state"] == "active" - - -def ping_connection(connection_id, alias, url, headers=None): - if headers is None: - headers = {} - response = requests.post( - f"{url}/connections/{connection_id}/send-ping", - headers=headers, - json={"comment": f"{alias} pinging..."}, - ) - print(f"ping_connection = {response}") - - -def create_tenant(wallet_name, wallet_key, url, headers=None): - if headers is None: - headers = {} - # need to create the tenant and get the token - data = { - "key_management_mode": "managed", - "wallet_dispatch_type": "default", - "wallet_name": wallet_name, - "wallet_key": wallet_key, - "label": wallet_name, - "wallet_type": "askar", - "wallet_webhook_urls": [], - } - # multi-agent has no security for base wallet, just call multitenancy/wallet - # to create a new tenant - response = requests.post(f"{url}/multitenancy/wallet", headers=headers, json=data) - print(f"response = {response}") - json = response.json() - print(f"json = {json}") - wallet_id = json["wallet_id"] - token = json["token"] - _headers = {"Authorization": f"Bearer {token}"} - - return wallet_id, token, _headers - - -if __name__ == "__main__": - print("\n... single tenants, connect ...\n") - - # faber create invitation for alice - ( - faber_invitation, - faber_alice_connection_id, - faber_recipient_keys, - ) = create_invitation("faber", "alice", None, FABER_ADMIN_URL) - alice_faber_connection_id = receive_invitation( - faber_invitation, "faber", None, ALICE_ADMIN_URL - ) - - connection_active = False - attempts = 0 - while not connection_active and attempts < 5: - wait_a_bit(1) - connection_active = fetch_connection(faber_alice_connection_id, FABER_ADMIN_URL) - attempts = attempts + 1 - - print("\n... connections active, ping each other ...\n") - - pings = 0 - while connection_active and pings < 5: - ping_connection(faber_alice_connection_id, "faber", FABER_ADMIN_URL) - wait_a_bit(1) - ping_connection(alice_faber_connection_id, "alice", ALICE_ADMIN_URL) - wait_a_bit(1) - pings = pings + 1 - - print("\n... multitenant create tenant(s)...\n") - # ok, now let's try with multitenant - multi_one_wallet_name = r.get_random_word() - multi_one_wallet_id, multi_one_token, multi_one_headers = create_tenant( - multi_one_wallet_name, "changeme", MULTI_ADMIN_URL - ) - - multi_two_wallet_name = r.get_random_word() - multi_two_wallet_id, multi_two_token, multi_two_headers = create_tenant( - multi_two_wallet_name, "changeme", MULTI_ADMIN_URL - ) - - print("\n... multitenant, connect ...\n") - ( - multi_one_invitation, - multi_one_alice_connection_id, - multi_one_recipient_keys, - ) = create_invitation( - multi_one_wallet_name, "alice", None, MULTI_ADMIN_URL, multi_one_headers - ) - - alice_multi_one_connection_id = receive_invitation( - multi_one_invitation, multi_one_wallet_name, None, ALICE_ADMIN_URL - ) - - connection_active = False - attempts = 0 - while not connection_active and attempts < 5: - wait_a_bit(1) - connection_active = fetch_connection( - alice_multi_one_connection_id, ALICE_ADMIN_URL - ) - attempts = attempts + 1 - - pings = 0 - while connection_active and pings < 5: - ping_connection( - multi_one_alice_connection_id, - multi_one_wallet_name, - MULTI_ADMIN_URL, - multi_one_headers, - ) - wait_a_bit(1) - ping_connection(alice_multi_one_connection_id, "alice", ALICE_ADMIN_URL) - wait_a_bit(1) - pings = pings + 1 - - ( - multi_two_invitation, - multi_two_one_connection_id, - multi_two_recipient_keys, - ) = create_invitation( - multi_two_wallet_name, - multi_one_wallet_name, - None, - MULTI_ADMIN_URL, - multi_two_headers, - ) - - multi_one_two_connection_id = receive_invitation( - multi_two_invitation, - multi_two_wallet_name, - None, - MULTI_ADMIN_URL, - multi_one_headers, - ) - - connection_active = False - attempts = 0 - while not connection_active and attempts < 5: - wait_a_bit(1) - connection_active = fetch_connection( - multi_one_two_connection_id, MULTI_ADMIN_URL, multi_one_headers - ) - attempts = attempts + 1 - - pings = 0 - while connection_active and pings < 5: - ping_connection( - multi_two_one_connection_id, - multi_two_wallet_name, - MULTI_ADMIN_URL, - multi_two_headers, - ) - wait_a_bit(1) - ping_connection( - multi_one_two_connection_id, - multi_one_wallet_name, - MULTI_ADMIN_URL, - multi_one_headers, - ) - wait_a_bit(1) - pings = pings + 1 diff --git a/demo/playground/scripts/requirements.txt b/demo/playground/scripts/requirements.txt deleted file mode 100644 index 33c13656f4..0000000000 --- a/demo/playground/scripts/requirements.txt +++ /dev/null @@ -1,24 +0,0 @@ -aiohttp==3.8.5; python_version >= "3.6" -aiosignal==1.3.1; python_version >= "3.7" -async-timeout==4.0.2; python_version >= "3.6" -attrs==23.1.0; python_version >= "3.7" -certifi==2023.7.22; python_version >= "3.7" -charset-normalizer==3.1.0; python_full_version >= "3.7.0" and python_version >= "3.7" -colorama==0.4.6; python_version >= "3.7" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.7" and python_full_version >= "3.7.0" -exceptiongroup==1.1.1; python_version < "3.11" and python_version >= "3.7" -frozenlist==1.3.3; python_version >= "3.7" -idna==3.4; python_version >= "3.7" -iniconfig==2.0.0; python_version >= "3.7" -multidict==6.0.4; python_version >= "3.7" -packaging==23.1; python_version >= "3.7" -pluggy==1.0.0; python_version >= "3.7" -pytest==7.3.1; python_version >= "3.7" -pyyaml==6.0; python_version >= "3.6" -random-word==1.0.11; python_version >= "3" -repoze.lru==0.7 -requests==2.31.0; python_version >= "3.7" -routes==2.5.1 -six==1.16.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" -tomli==2.0.1; python_version < "3.11" and python_version >= "3.7" -urllib3==2.0.7; python_version >= "3.7" -yarl==1.9.2; python_version >= "3.7"