From 5da4b58fe8364a9ae4956e4091ec6b8f50ee1cd9 Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Mon, 12 Aug 2024 12:52:33 -0700 Subject: [PATCH 1/7] Add github action check for python code --- .github/workflows/lint-and-test.yaml | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/lint-and-test.yaml diff --git a/.github/workflows/lint-and-test.yaml b/.github/workflows/lint-and-test.yaml new file mode 100644 index 0000000..2b7d9c3 --- /dev/null +++ b/.github/workflows/lint-and-test.yaml @@ -0,0 +1,41 @@ +name: Lint and Test + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + lint-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: "Setup Python" + uses: "actions/setup-python@v4" + with: + python-version: "3.11" + cache: "pipenv" + cache-dependency-path: "Pipfile.lock" + - name: "Install pipenv" + run: "pip install pipenv wheel" + - name: "Install dependencies" + run: "pipenv install --dev" + - name: "Run pyre" + run: | + set -o pipefail + pipenv run pyre | tee >(sed 's, ,:,' | awk -F: '{sub(" ", "", $5); print "::error file=" ENVIRON["PWD"] "/" $1 ",line=" $2 ",col=" $3 ",title=" $4 "::" $5}') + - name: "Run ruff" + run: "pipenv run ruff check --output-format github ." + - name: "Run black" + run: | + set -o pipefail + pipenv run black --check --diff . + - name: Run tests + run: | + pipenv run pytest -n 4 From f76a790794d3773df2e9108028dae87468fbd667 Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Mon, 12 Aug 2024 12:57:07 -0700 Subject: [PATCH 2/7] Fix a ruff error --- nwc_backend/models/nwc_connection.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nwc_backend/models/nwc_connection.py b/nwc_backend/models/nwc_connection.py index d72cd8f..d399b0d 100644 --- a/nwc_backend/models/nwc_connection.py +++ b/nwc_backend/models/nwc_connection.py @@ -10,7 +10,6 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship from nwc_backend.db import UUID as DBUUID -from nwc_backend.models.nip47_request_method import Nip47RequestMethod from nwc_backend.models.client_app import ClientApp from nwc_backend.models.model_base import ModelBase from nwc_backend.models.nip47_request_method import Nip47RequestMethod From b1ca69f5357d87cf69c9774dda9f1692d3b48573 Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Mon, 12 Aug 2024 13:00:19 -0700 Subject: [PATCH 3/7] Add pytest dep --- .github/workflows/lint-and-test.yaml | 2 +- Pipfile | 1 + Pipfile.lock | 37 +++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-and-test.yaml b/.github/workflows/lint-and-test.yaml index 2b7d9c3..67bbe5f 100644 --- a/.github/workflows/lint-and-test.yaml +++ b/.github/workflows/lint-and-test.yaml @@ -38,4 +38,4 @@ jobs: pipenv run black --check --diff . - name: Run tests run: | - pipenv run pytest -n 4 + pipenv run pytest diff --git a/Pipfile b/Pipfile index 58b0421..7525adc 100644 --- a/Pipfile +++ b/Pipfile @@ -18,6 +18,7 @@ authlib = "*" black = "*" pyre-check = "*" ruff = "*" +pytest = "*" [requires] python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock index 9821894..aa286ef 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "564cf7552586b8111ec5d59e298ffd6cdd55cf7b789f210b763a215bb8088ffa" + "sha256": "c5c5b5a82f5babc700d36953d98f7f6263f92c1463f0d72411d5c23aa86b0704" }, "pipfile-spec": 6, "requires": { @@ -112,6 +112,7 @@ "sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==3.10.3" }, "aiosignal": { @@ -128,6 +129,7 @@ "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==1.13.2" }, "annotated-types": { @@ -160,6 +162,7 @@ "sha256:d35800b973099bbadc49b42b256ecb80041ad56b7fe1216a362c7943c088f377" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==1.3.1" }, "blinker": { @@ -1056,6 +1059,7 @@ "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==2.9.0" }, "python-dotenv": { @@ -1064,6 +1068,7 @@ "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==1.0.1" }, "python-multipart": { @@ -1137,6 +1142,7 @@ "sha256:f9092310f4eb120903da692a5e4354f05d48c28ca7ec3054d3d94dd862412c58" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==0.19.6" }, "requests": { @@ -1145,6 +1151,7 @@ "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==2.32.3" }, "rich": { @@ -1703,6 +1710,7 @@ "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==24.8.0" }, "click": { @@ -1721,6 +1729,14 @@ "markers": "python_version >= '3.6'", "version": "==0.5.7" }, + "iniconfig": { + "hashes": [ + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, "intervaltree": { "hashes": [ "sha256:902b1b88936918f9b2a19e0e5eb7ccb430ae45cde4f39ea4b36932920d33952d" @@ -1805,6 +1821,14 @@ "markers": "python_version >= '3.8'", "version": "==4.2.2" }, + "pluggy": { + "hashes": [ + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, "psutil": { "hashes": [ "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", @@ -1843,6 +1867,7 @@ "sha256:e082f926dff71661959535c3936fca5ad40a44858b5fd3e99009a616a1b57083" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==0.9.22" }, "pyre-extensions": { @@ -1852,6 +1877,15 @@ ], "version": "==0.0.30" }, + "pytest": { + "hashes": [ + "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", + "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==8.3.2" + }, "pyyaml": { "hashes": [ "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", @@ -1932,6 +1966,7 @@ "sha256:fcc8054f1a717e2213500edaddcf1dbb0abad40d98e1bd9d0ad364f75c763eea" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==0.5.7" }, "sortedcontainers": { From 7c1591f4ef2f8c554a1d5410588dffe732274251 Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Mon, 12 Aug 2024 13:15:59 -0700 Subject: [PATCH 4/7] Fix pyre error --- nwc_backend/event_handlers/lookup_user_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nwc_backend/event_handlers/lookup_user_handler.py b/nwc_backend/event_handlers/lookup_user_handler.py index 82904e0..6549c08 100644 --- a/nwc_backend/event_handlers/lookup_user_handler.py +++ b/nwc_backend/event_handlers/lookup_user_handler.py @@ -14,7 +14,7 @@ async def lookup_user( access_token: str, request: Nip47Request ) -> dict[str, Any] | Nip47Error: - receiver = request.get("receiver") + receiver = request.params.get("receiver") if receiver is None: return Nip47Error( code=ErrorCode.OTHER, From 403cbd6521c5ce33c90e04577f495b59c8e7d777 Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Mon, 12 Aug 2024 17:09:14 -0700 Subject: [PATCH 5/7] Add a test case --- Pipfile | 1 + Pipfile.lock | 11 ++- .../__tests__/lookup_user_test.py | 81 +++++++++++++++++++ .../event_handlers/lookup_user_handler.py | 4 +- pytest.ini | 2 + 5 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 nwc_backend/event_handlers/__tests__/lookup_user_test.py create mode 100644 pytest.ini diff --git a/Pipfile b/Pipfile index 7525adc..6ac77ff 100644 --- a/Pipfile +++ b/Pipfile @@ -19,6 +19,7 @@ black = "*" pyre-check = "*" ruff = "*" pytest = "*" +pytest-asyncio = "*" [requires] python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock index aa286ef..e23fb39 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c5c5b5a82f5babc700d36953d98f7f6263f92c1463f0d72411d5c23aa86b0704" + "sha256": "644d003403bcabb31db01c58be6cd03d4471db87f4c7336247c243bc7638ac9d" }, "pipfile-spec": 6, "requires": { @@ -1886,6 +1886,15 @@ "markers": "python_version >= '3.8'", "version": "==8.3.2" }, + "pytest-asyncio": { + "hashes": [ + "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2", + "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.23.8" + }, "pyyaml": { "hashes": [ "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", diff --git a/nwc_backend/event_handlers/__tests__/lookup_user_test.py b/nwc_backend/event_handlers/__tests__/lookup_user_test.py new file mode 100644 index 0000000..00d6838 --- /dev/null +++ b/nwc_backend/event_handlers/__tests__/lookup_user_test.py @@ -0,0 +1,81 @@ +import os + +os.environ["NOSTR_PRIVKEY"] = ( + "nsec166ah7ez498kjl87a088yn34gvcjpzmy9eymuwwgtwcywh84j865s0qxnul" +) +os.environ["RELAY"] = "wss://fake.relay.url" +os.environ["VASP_UMA_API_BASE_URL"] = "https://fake.vasp.uma.api.url" + +import pytest +from nwc_backend.models.nip47_request import Nip47Request, ErrorCode, Nip47Error +from nwc_backend.vasp_client import ReceivingAddress, VaspUmaClient, LookupUserResponse +from nwc_backend.event_handlers.lookup_user_handler import lookup_user +from uma_auth.models.currency_preference import CurrencyPreference + + +class MockVaspUmaClient(VaspUmaClient): + lookup_user_response = LookupUserResponse( + currencies=[ + CurrencyPreference( + code="USD", + symbol="$", + name="US Dollar", + multiplier=1000, + decimals=2, + min=1000, + max=1000000, + ) + ] + ) + + async def lookup_user( + self, + access_token: str, + receiving_address: ReceivingAddress, + base_sending_currency_code: str, + ) -> LookupUserResponse: + return self.lookup_user_response + + +@pytest.fixture +def vasp_client_mock(): + return MockVaspUmaClient() + + +async def test_lookup_user_success(vasp_client_mock): + access_token = "your_access_token" + request = Nip47Request( + params={ + "receiver": {"lud16": "$alice@vasp.net"}, + "base_sending_currency_code": "USD", + } + ) + + result = await lookup_user(access_token, request, vasp_client_mock) + + assert isinstance(result, dict) + assert result == vasp_client_mock.lookup_user_response.to_dict() + + +async def test_lookup_user_missing_receiver(vasp_client_mock): + access_token = "your_access_token" + request = Nip47Request(params={}) + + result = await lookup_user(access_token, request, vasp_client_mock) + + assert isinstance(result, Nip47Error) + assert result.code == ErrorCode.OTHER + assert result.message == "Require receiver in the request params." + + +async def test_lookup_user_multiple_receivers(vasp_client_mock): + access_token = "your_access_token" + request = Nip47Request( + params={"receiver": {"bolt12": "bolt12_address", "lud16": "lud16_address"}} + ) + + result = await lookup_user(access_token, request, vasp_client_mock) + + assert isinstance(result, Nip47Error) + assert result.code == ErrorCode.OTHER + assert result.message == "Expect receiver to contain exactly one address." diff --git a/nwc_backend/event_handlers/lookup_user_handler.py b/nwc_backend/event_handlers/lookup_user_handler.py index 6549c08..ccc27ba 100644 --- a/nwc_backend/event_handlers/lookup_user_handler.py +++ b/nwc_backend/event_handlers/lookup_user_handler.py @@ -12,7 +12,7 @@ async def lookup_user( - access_token: str, request: Nip47Request + access_token: str, request: Nip47Request, vasp_client=vasp_uma_client ) -> dict[str, Any] | Nip47Error: receiver = request.params.get("receiver") if receiver is None: @@ -39,7 +39,7 @@ async def lookup_user( ) try: - response = await vasp_uma_client.lookup_user( + response = await vasp_client.lookup_user( access_token=access_token, receiving_address=receiving_address, base_sending_currency_code=request.params.get("base_sending_currency_code"), diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..4088045 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +asyncio_mode=auto From 8b42997933c0c6b5d884b2f58044bb7f84015ad8 Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Mon, 12 Aug 2024 17:15:40 -0700 Subject: [PATCH 6/7] Fix pyre test --- .../__tests__/lookup_user_test.py | 30 ++++++++++--------- .../event_handlers/lookup_user_handler.py | 11 +++++-- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/nwc_backend/event_handlers/__tests__/lookup_user_test.py b/nwc_backend/event_handlers/__tests__/lookup_user_test.py index 00d6838..f3e9da3 100644 --- a/nwc_backend/event_handlers/__tests__/lookup_user_test.py +++ b/nwc_backend/event_handlers/__tests__/lookup_user_test.py @@ -1,4 +1,5 @@ import os +from typing import Optional os.environ["NOSTR_PRIVKEY"] = ( "nsec166ah7ez498kjl87a088yn34gvcjpzmy9eymuwwgtwcywh84j865s0qxnul" @@ -10,29 +11,30 @@ from nwc_backend.models.nip47_request import Nip47Request, ErrorCode, Nip47Error from nwc_backend.vasp_client import ReceivingAddress, VaspUmaClient, LookupUserResponse from nwc_backend.event_handlers.lookup_user_handler import lookup_user -from uma_auth.models.currency_preference import CurrencyPreference class MockVaspUmaClient(VaspUmaClient): - lookup_user_response = LookupUserResponse( - currencies=[ - CurrencyPreference( - code="USD", - symbol="$", - name="US Dollar", - multiplier=1000, - decimals=2, - min=1000, - max=1000000, - ) - ] + lookup_user_response = LookupUserResponse.from_dict( + { + "currencies": [ + { + "code": "USD", + "symbol": "$", + "name": "US Dollar", + "multiplier": 1000, + "decimals": 2, + "min": 1000, + "max": 1000000, + } + ] + } ) async def lookup_user( self, access_token: str, receiving_address: ReceivingAddress, - base_sending_currency_code: str, + base_sending_currency_code: Optional[str], ) -> LookupUserResponse: return self.lookup_user_response diff --git a/nwc_backend/event_handlers/lookup_user_handler.py b/nwc_backend/event_handlers/lookup_user_handler.py index ccc27ba..c6e2a06 100644 --- a/nwc_backend/event_handlers/lookup_user_handler.py +++ b/nwc_backend/event_handlers/lookup_user_handler.py @@ -8,11 +8,18 @@ from nostr_sdk import ErrorCode, Nip47Error from nwc_backend.models.nip47_request import Nip47Request -from nwc_backend.vasp_client import AddressType, ReceivingAddress, vasp_uma_client +from nwc_backend.vasp_client import ( + AddressType, + ReceivingAddress, + VaspUmaClient, + vasp_uma_client, +) async def lookup_user( - access_token: str, request: Nip47Request, vasp_client=vasp_uma_client + access_token: str, + request: Nip47Request, + vasp_client: VaspUmaClient = vasp_uma_client, ) -> dict[str, Any] | Nip47Error: receiver = request.params.get("receiver") if receiver is None: From 80c6bf4c823b2f33fcd679b46bb5d6fe879a15e0 Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Mon, 12 Aug 2024 17:21:10 -0700 Subject: [PATCH 7/7] Fix test pythonpath --- .github/workflows/lint-and-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-and-test.yaml b/.github/workflows/lint-and-test.yaml index 67bbe5f..5d2310c 100644 --- a/.github/workflows/lint-and-test.yaml +++ b/.github/workflows/lint-and-test.yaml @@ -38,4 +38,4 @@ jobs: pipenv run black --check --diff . - name: Run tests run: | - pipenv run pytest + PYTHONPATH=. pipenv run pytest