From 08eee8a64710caa14686da0f9ffcf9d3c7f90182 Mon Sep 17 00:00:00 2001 From: fbarbu15 Date: Mon, 16 Dec 2024 12:38:24 +0200 Subject: [PATCH] test_: add python linters (#6212) * test_: add python linters * test_: add python linters * test_: add python linters * test_: add python linters * test_: enabled pyright typeCheckingMode * test_: enabled pyright typeCheckingMode --- .github/workflows/pytest-lint.yml | 33 +++++ .gitignore | 1 - Makefile | 5 + pyrightconfig.json | 5 + tests-functional/.pre-commit-config.yaml | 31 +++++ tests-functional/README.MD | 18 ++- tests-functional/clients/rpc.py | 17 ++- tests-functional/clients/services/service.py | 2 +- tests-functional/clients/signals.py | 35 +++--- tests-functional/clients/status_backend.py | 49 ++++---- tests-functional/conftest.py | 12 +- tests-functional/requirements.txt | 3 + tests-functional/{ => resources}/constants.py | 6 +- tests-functional/resources/enums.py | 3 +- tests-functional/tests/test_accounts.py | 3 +- tests-functional/tests/test_app_general.py | 1 - tests-functional/tests/test_cases.py | 67 +++++----- .../tests/test_contact_request.py | 30 +++-- tests-functional/tests/test_eth_api.py | 24 +++- .../tests/test_init_status_app.py | 42 ++++--- tests-functional/tests/test_logging.py | 34 ++--- .../tests/test_one_to_one_messages.py | 13 +- tests-functional/tests/test_router.py | 46 +++---- tests-functional/tests/test_waku_rpc.py | 15 +-- .../tests/test_wakuext_profile.py | 40 ++++-- .../tests/test_wallet_activity_session.py | 84 ++++++++----- tests-functional/tests/test_wallet_rpc.py | 116 +++++++++++++----- tests-functional/tests/test_wallet_signals.py | 54 +++++--- tests-functional/utils/__init__.py | 0 .../{ => utils}/schema_builder.py | 0 tests-functional/{ => utils}/wallet_utils.py | 71 +++++------ 31 files changed, 544 insertions(+), 316 deletions(-) create mode 100644 .github/workflows/pytest-lint.yml create mode 100644 pyrightconfig.json create mode 100644 tests-functional/.pre-commit-config.yaml rename tests-functional/{ => resources}/constants.py (91%) create mode 100644 tests-functional/utils/__init__.py rename tests-functional/{ => utils}/schema_builder.py (100%) rename tests-functional/{ => utils}/wallet_utils.py (63%) diff --git a/.github/workflows/pytest-lint.yml b/.github/workflows/pytest-lint.yml new file mode 100644 index 000000000..ed3d833a8 --- /dev/null +++ b/.github/workflows/pytest-lint.yml @@ -0,0 +1,33 @@ +name: Pytest Lint + +on: + pull_request: + branches: + - master + push: + branches: + - "test-linting" + +jobs: + pytest-lint: + timeout-minutes: 10 + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v4 + with: + python-version: '3.12' + cache: 'pip' + + - name: Set up virtual environment in /tests-functional/ + run: | + python -m venv tests-functional/.venv + echo "tests-functional/.venv/bin" >> $GITHUB_PATH # Add virtualenv to PATH for subsequent steps + + - name: Install dependencies based on requirements.txt + run: pip install -r tests-functional/requirements.txt + + - name: Run pytest-lint + run: pre-commit run --all-files --verbose --config tests-functional/.pre-commit-config.yaml diff --git a/.gitignore b/.gitignore index d3655f9cc..5c7b40b26 100644 --- a/.gitignore +++ b/.gitignore @@ -109,7 +109,6 @@ tests-functional/coverage tests-functional/reports tests-functional/signals tests-functional/*.log -pyrightconfig.json .venv diff --git a/Makefile b/Makefile index a5da26342..d4be1f241 100644 --- a/Makefile +++ b/Makefile @@ -428,3 +428,8 @@ run-anvil: codecov-validate: SHELL := /bin/sh codecov-validate: curl -X POST --data-binary @.codecov.yml https://codecov.io/validate + +.PHONY: pytest-lint +pytest-lint: + @echo "Running python linting on all files..." + pre-commit run --all-files --verbose --config tests-functional/.pre-commit-config.yaml diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 000000000..0bd385c32 --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,5 @@ +{ + "include": ["tests-functional"], + "venvPath": "./tests-functional", // Ensure the virtual environment (.venv) is located in ./tests-functional + "venv": ".venv" +} diff --git a/tests-functional/.pre-commit-config.yaml b/tests-functional/.pre-commit-config.yaml new file mode 100644 index 000000000..9095bbfd6 --- /dev/null +++ b/tests-functional/.pre-commit-config.yaml @@ -0,0 +1,31 @@ +repos: +- repo: https://github.com/psf/black + rev: 24.10.0 # Latest version of Black + hooks: + - id: black + args: [--line-length=150] + files: ^tests-functional/.*\.py$ + # Black: Automatically formats Python code to adhere to its strict style guidelines. + # - Ensures consistent code formatting across the project. + # - Helps maintain readability and avoids debates about style in code reviews. + +- repo: https://github.com/RobertCraigie/pyright-python + rev: v1.1.388 # Version of Pyright used + hooks: + - id: pyright + files: ^tests-functional/.*\.py$ + # Pyright: A static type checker for Python. + # - Validates type hints and ensures type correctness in code. + # - Identifies type mismatches, missing imports, and potential runtime errors. + # - Ensures better type safety and helps catch bugs early. + +- repo: https://github.com/pycqa/flake8 + rev: 7.1.1 # Latest version of Flake8 + hooks: + - id: flake8 + args: ["--max-line-length=150"] + files: ^tests-functional/.*\.py$ + # Flake8: A lightweight Python linter for style and syntax checking. + # - Detects unused imports, undefined variables, and redefined functions (e.g., F811). + # - Checks for adherence to Python coding standards (PEP 8). + # - Helps maintain clean, bug-free code. diff --git a/tests-functional/README.MD b/tests-functional/README.MD index 343a31950..be18550ee 100644 --- a/tests-functional/README.MD +++ b/tests-functional/README.MD @@ -12,10 +12,18 @@ Functional tests for status-go ## How to Install -* Install [Docker](https://docs.docker.com/engine/install/) and [Docker Compose](https://docs.docker.com/compose/install/) -* Install [Python 3.10.14](https://www.python.org/downloads/) -* In `./tests-functional`, run `pip install -r requirements.txt` -* **Optional (for test development)**: Use Python virtual environment for better dependency management. You can follow the guide [here](https://akrabat.com/creating-virtual-environments-with-pyenv/): +1. Install [Docker](https://docs.docker.com/engine/install/) and [Docker Compose](https://docs.docker.com/compose/install/) +2. Install [Python 3](https://www.python.org/downloads/) (tested with 3.10 and 3.12 and it works with both) +3. **Set up a virtual environment (required for linting):** + - In `./tests-functional`, run: + ```bash + python3 -m venv .venv + source .venv/bin/activate + pip install -r requirements.txt + pre-commit install + ``` + - **Important**: The virtual environment must be created in the `./tests-functional` directory for pre-commit linting and type-checking tools like Pyright to work correctly. + - **Optional (for test development)**: Use Python virtual environment for better dependency management. You can follow the guide [here](https://akrabat.com/creating-virtual-environments-with-pyenv/) ## How to Run @@ -39,4 +47,4 @@ Functional tests for status-go - Every test has two types of verifications: - `verify_is_valid_json_rpc_response()` checks for status code 200, non-empty response, JSON-RPC structure, presence of the `result` field, and expected ID. - `jsonschema.validate()` is used to check that the response contains expected data, including required fields and types. Schemas are stored in `/schemas/wallet_MethodName` - - New schemas can be generated using `./tests-functional/schema_builder.py` by passing a response to the `CustomSchemaBuilder(schema_name).create_schema(response.json())` method, should be used only on test creation phase, please search `how to create schema:` to see an example in a test \ No newline at end of file + - New schemas can be generated using `./tests-functional/utils/schema_builder.py` by passing a response to the `CustomSchemaBuilder(schema_name).create_schema(response.json())` method, should be used only on test creation phase, please search `how to create schema:` to see an example in a test \ No newline at end of file diff --git a/tests-functional/clients/rpc.py b/tests-functional/clients/rpc.py index 875ad3522..ce54baff7 100644 --- a/tests-functional/clients/rpc.py +++ b/tests-functional/clients/rpc.py @@ -17,11 +17,9 @@ class RpcClient: try: return response.json()[key] except json.JSONDecodeError: - raise AssertionError( - f"Invalid JSON in response: {response.content}") + raise AssertionError(f"Invalid JSON in response: {response.content}") except KeyError: - raise AssertionError( - f"Key '{key}' not found in the JSON response: {response.content}") + raise AssertionError(f"Key '{key}' not found in the JSON response: {response.content}") def verify_is_valid_json_rpc_response(self, response, _id=None): assert response.status_code == 200, f"Got response {response.content}, status code {response.status_code}" @@ -31,9 +29,7 @@ class RpcClient: if _id: try: if _id != response.json()["id"]: - raise AssertionError( - f"got id: {response.json()['id']} instead of expected id: {_id}" - ) + raise AssertionError(f"got id: {response.json()['id']} instead of expected id: {_id}") except KeyError: raise AssertionError(f"no id in response {response.json()}") return response @@ -44,7 +40,9 @@ class RpcClient: self._check_decode_and_key_errors_in_response(response, "error") @retry(stop=stop_after_delay(10), wait=wait_fixed(0.5), reraise=True) - def rpc_request(self, method, params=None, request_id=13, url=None): + def rpc_request(self, method, params=None, request_id=None, url=None): + if not request_id: + request_id = 13 if params is None: params = [] url = url if url else self.rpc_url @@ -69,5 +67,4 @@ class RpcClient: def verify_json_schema(self, response, method): with open(f"{option.base_dir}/schemas/{method}", "r") as schema: - jsonschema.validate(instance=response, - schema=json.load(schema)) + jsonschema.validate(instance=response, schema=json.load(schema)) diff --git a/tests-functional/clients/services/service.py b/tests-functional/clients/services/service.py index 871f1b430..c244215f8 100644 --- a/tests-functional/clients/services/service.py +++ b/tests-functional/clients/services/service.py @@ -3,7 +3,7 @@ from clients.rpc import RpcClient class Service: def __init__(self, client: RpcClient, name: str): - assert name is not "" + assert name != "" self.rpc_client = client self.name = name diff --git a/tests-functional/clients/signals.py b/tests-functional/clients/signals.py index 127d0f23e..49e098a08 100644 --- a/tests-functional/clients/signals.py +++ b/tests-functional/clients/signals.py @@ -5,10 +5,11 @@ import time import websocket import os from pathlib import Path -from constants import SIGNALS_DIR, LOG_SIGNALS_TO_FILE +from resources.constants import SIGNALS_DIR, LOG_SIGNALS_TO_FILE from datetime import datetime from enum import Enum + class SignalType(Enum): MESSAGES_NEW = "messages.new" MESSAGE_DELIVERED = "message.delivered" @@ -22,6 +23,7 @@ class SignalType(Enum): WALLET_TRANSACTION_STATUS_CHANGED = "wallet.transaction.status-changed" WALLET_ROUTER_TRANSACTIONS_SENT = "wallet.router.transactions-sent" + class SignalClient: def __init__(self, ws_url, await_signals): self.url = f"{ws_url}/signals" @@ -37,11 +39,15 @@ class SignalClient: "received": [], "delta_count": 1, "expected_count": 1, - "accept_fn": None - } for signal in self.await_signals + "accept_fn": None, + } + for signal in self.await_signals } if LOG_SIGNALS_TO_FILE: - self.signal_file_path = os.path.join(SIGNALS_DIR, f"signal_{ws_url.split(':')[-1]}_{datetime.now().strftime('%H%M%S')}.log") + self.signal_file_path = os.path.join( + SIGNALS_DIR, + f"signal_{ws_url.split(':')[-1]}_{datetime.now().strftime('%H%M%S')}.log", + ) Path(SIGNALS_DIR).mkdir(parents=True, exist_ok=True) def on_message(self, ws, signal): @@ -77,8 +83,7 @@ class SignalClient: received_signals = self.received_signals.get(signal_type) while (not received_signals) or len(received_signals["received"]) < received_signals["expected_count"]: if time.time() - start_time >= timeout: - raise TimeoutError( - f"Signal {signal_type} is not received in {timeout} seconds") + raise TimeoutError(f"Signal {signal_type} is not received in {timeout} seconds") time.sleep(0.2) logging.debug(f"Signal {signal_type} is received in {round(time.time() - start_time)} seconds") delta_count = received_signals["delta_count"] @@ -97,17 +102,13 @@ class SignalClient: start_time = time.time() while True: if time.time() - start_time >= timeout: - raise TimeoutError( - f"Signal {signal_type} containing {event_pattern} is not received in {timeout} seconds" - ) + raise TimeoutError(f"Signal {signal_type} containing {event_pattern} is not received in {timeout} seconds") if not self.received_signals.get(signal_type): time.sleep(0.2) continue for event in self.received_signals[signal_type]["received"]: if event_pattern in str(event): - logging.info( - f"Signal {signal_type} containing {event_pattern} is received in {round(time.time() - start_time)} seconds" - ) + logging.info(f"Signal {signal_type} containing {event_pattern} is received in {round(time.time() - start_time)} seconds") return event time.sleep(0.2) @@ -121,10 +122,12 @@ class SignalClient: logging.info("Connection opened") def _connect(self): - ws = websocket.WebSocketApp(self.url, - on_message=self.on_message, - on_error=self._on_error, - on_close=self._on_close) + ws = websocket.WebSocketApp( + self.url, + on_message=self.on_message, + on_error=self._on_error, + on_close=self._on_close, + ) ws.on_open = self._on_open ws.run_forever() diff --git a/tests-functional/clients/status_backend.py b/tests-functional/clients/status_backend.py index b0481c7ee..430a0a747 100644 --- a/tests-functional/clients/status_backend.py +++ b/tests-functional/clients/status_backend.py @@ -12,7 +12,7 @@ from clients.signals import SignalClient from clients.rpc import RpcClient from datetime import datetime from conftest import option -from constants import user_1, DEFAULT_DISPLAY_NAME, USER_DIR +from resources.constants import user_1, DEFAULT_DISPLAY_NAME, USER_DIR class StatusBackend(RpcClient, SignalClient): @@ -29,7 +29,6 @@ class StatusBackend(RpcClient, SignalClient): url = f"http://127.0.0.1:{host_port}" option.status_backend_port_range.remove(host_port) - self.api_url = f"{url}/statusgo" self.ws_url = f"{url}".replace("http", "ws") self.rpc_url = f"{url}/statusgo/CallRPC" @@ -59,7 +58,8 @@ class StatusBackend(RpcClient, SignalClient): "labels": {"com.docker.compose.project": docker_project_name}, "entrypoint": [ "status-backend", - "--address", "0.0.0.0:3333", + "--address", + "0.0.0.0:3333", ], "ports": {"3333/tcp": host_port}, "environment": { @@ -78,8 +78,7 @@ class StatusBackend(RpcClient, SignalClient): container = self.docker_client.containers.run(**container_args) - network = self.docker_client.networks.get( - f"{docker_project_name}_default") + network = self.docker_client.networks.get(f"{docker_project_name}_default") network.connect(container) option.status_backend_containers.append(container.id) @@ -99,8 +98,7 @@ class StatusBackend(RpcClient, SignalClient): def api_request(self, method, data, url=None): url = url if url else self.api_url url = f"{url}/{method}" - logging.info( - f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}") + logging.info(f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}") response = requests.post(url, json=data) logging.info(f"Got response: {response.content}") return response @@ -113,8 +111,7 @@ class StatusBackend(RpcClient, SignalClient): error = response.json()["error"] assert not error, f"Error: {error}" except json.JSONDecodeError: - raise AssertionError( - f"Invalid JSON in response: {response.content}") + raise AssertionError(f"Invalid JSON in response: {response.content}") except KeyError: pass @@ -133,7 +130,12 @@ class StatusBackend(RpcClient, SignalClient): } return self.api_valid_request(method, data) - def create_account_and_login(self, data_dir=USER_DIR, display_name=DEFAULT_DISPLAY_NAME, password=user_1.password): + def create_account_and_login( + self, + data_dir=USER_DIR, + display_name=DEFAULT_DISPLAY_NAME, + password=user_1.password, + ): method = "CreateAccountAndLogin" data = { "rootDataDir": data_dir, @@ -146,8 +148,13 @@ class StatusBackend(RpcClient, SignalClient): } return self.api_valid_request(method, data) - def restore_account_and_login(self, data_dir=USER_DIR, display_name=DEFAULT_DISPLAY_NAME, user=user_1, - network_id=31337): + def restore_account_and_login( + self, + data_dir=USER_DIR, + display_name=DEFAULT_DISPLAY_NAME, + user=user_1, + network_id=31337, + ): method = "RestoreAccountAndLogin" data = { "rootDataDir": data_dir, @@ -172,9 +179,9 @@ class StatusBackend(RpcClient, SignalClient): "NativeCurrencyDecimals": 18, "IsTest": False, "Layer": 1, - "Enabled": True + "Enabled": True, } - ] + ], } return self.api_valid_request(method, data) @@ -197,12 +204,11 @@ class StatusBackend(RpcClient, SignalClient): # ToDo: change this part for waiting for `node.login` signal when websockets are migrated to StatusBackend while time.time() - start_time <= timeout: try: - self.rpc_valid_request(method='accounts_getKeypairs') + self.rpc_valid_request(method="accounts_getKeypairs") return except AssertionError: time.sleep(3) - raise TimeoutError( - f"RPC client was not started after {timeout} seconds") + raise TimeoutError(f"RPC client was not started after {timeout} seconds") @retry(stop=stop_after_delay(10), wait=wait_fixed(0.5), reraise=True) def start_messenger(self, params=[]): @@ -210,9 +216,9 @@ class StatusBackend(RpcClient, SignalClient): response = self.rpc_request(method, params) json_response = response.json() - if 'error' in json_response: - assert json_response['error']['code'] == -32000 - assert json_response['error']['message'] == "messenger already started" + if "error" in json_response: + assert json_response["error"]["code"] == -32000 + assert json_response["error"]["message"] == "messenger already started" return self.verify_is_valid_json_rpc_response(response) @@ -239,8 +245,7 @@ class StatusBackend(RpcClient, SignalClient): for account in accounts: if account.get("name") == display_name: return account.get("public-key") - raise ValueError( - f"Public key not found for display name: {display_name}") + raise ValueError(f"Public key not found for display name: {display_name}") def send_contact_request(self, contact_id: str, message: str): method = "wakuext_sendContactRequest" diff --git a/tests-functional/conftest.py b/tests-functional/conftest.py index a95eceac2..61ecf4ce3 100644 --- a/tests-functional/conftest.py +++ b/tests-functional/conftest.py @@ -1,8 +1,8 @@ import os import docker -import pytest as pytest -from dataclasses import dataclass +from dataclasses import dataclass, field +from typing import List def pytest_addoption(parser): @@ -43,9 +43,12 @@ def pytest_addoption(parser): default=None, ) + @dataclass class Option: - pass + status_backend_port_range: List[int] = field(default_factory=list) + status_backend_containers: List[str] = field(default_factory=list) + base_dir: str = "" option = Option() @@ -55,7 +58,7 @@ def pytest_configure(config): global option option = config.option - executor_number = int(os.getenv('EXECUTOR_NUMBER', 5)) + executor_number = int(os.getenv("EXECUTOR_NUMBER", 5)) base_port = 7000 range_size = 100 @@ -66,6 +69,7 @@ def pytest_configure(config): option.base_dir = os.path.dirname(os.path.abspath(__file__)) + def pytest_unconfigure(): docker_client = docker.from_env() for container_id in option.status_backend_containers: diff --git a/tests-functional/requirements.txt b/tests-functional/requirements.txt index 0e756191d..64e10d02f 100644 --- a/tests-functional/requirements.txt +++ b/tests-functional/requirements.txt @@ -7,3 +7,6 @@ websocket-client~=1.4.2 tenacity~=9.0.0 pytest-dependency~=0.6.0 docker==7.1.0 +pyright==1.1.388 +black==24.10.0 +pre-commit==3.6.2 \ No newline at end of file diff --git a/tests-functional/constants.py b/tests-functional/resources/constants.py similarity index 91% rename from tests-functional/constants.py rename to tests-functional/resources/constants.py index 7df8ffaef..7abb6732c 100644 --- a/tests-functional/constants.py +++ b/tests-functional/resources/constants.py @@ -15,17 +15,17 @@ user_1 = Account( address="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", private_key="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", password="Strong12345", - passphrase="test test test test test test test test test test test junk" + passphrase="test test test test test test test test test test test junk", ) user_2 = Account( address="0x70997970c51812dc3a010c7d01b50e0d17dc79c8", private_key="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", password="Strong12345", - passphrase="test test test test test test test test test test nest junk" + passphrase="test test test test test test test test test test nest junk", ) DEFAULT_DISPLAY_NAME = "Mr_Meeseeks" PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "../")) TESTS_DIR = os.path.join(PROJECT_ROOT, "tests-functional") SIGNALS_DIR = os.path.join(TESTS_DIR, "signals") -LOG_SIGNALS_TO_FILE = False # used for debugging purposes +LOG_SIGNALS_TO_FILE = False # used for debugging purposes USER_DIR = option.user_dir if option.user_dir else "/usr/status-user" diff --git a/tests-functional/resources/enums.py b/tests-functional/resources/enums.py index 2c6944dd6..caa001f73 100644 --- a/tests-functional/resources/enums.py +++ b/tests-functional/resources/enums.py @@ -1,5 +1,6 @@ from enum import Enum + class MessageContentType(Enum): UNKNOWN_CONTENT_TYPE = 0 TEXT_PLAIN = 1 @@ -18,5 +19,5 @@ class MessageContentType(Enum): SYSTEM_MESSAGE_PINNED_MESSAGE = 14 SYSTEM_MESSAGE_MUTUAL_EVENT_SENT = 15 SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED = 16 - SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED = 17 + SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED = 17 BRIDGE_MESSAGE = 18 diff --git a/tests-functional/tests/test_accounts.py b/tests-functional/tests/test_accounts.py index de99af1f9..cf63505eb 100644 --- a/tests-functional/tests/test_accounts.py +++ b/tests-functional/tests/test_accounts.py @@ -2,7 +2,7 @@ import random import pytest -from constants import user_1 +from resources.constants import user_1 from test_cases import StatusBackendTestCase @@ -18,7 +18,6 @@ class TestAccounts(StatusBackendTestCase): # ("accounts_hasPairedDevices", []), # randomly crashes app, to be reworked/fixed # ("accounts_remainingAccountCapacity", []), # randomly crashes app, to be reworked/fixed ("multiaccounts_getIdentityImages", [user_1.private_key]), - ], ) def test_(self, method, params): diff --git a/tests-functional/tests/test_app_general.py b/tests-functional/tests/test_app_general.py index 907483f60..353fc032d 100644 --- a/tests-functional/tests/test_app_general.py +++ b/tests-functional/tests/test_app_general.py @@ -13,7 +13,6 @@ class TestAppGeneral(StatusBackendTestCase): "method, params", [ ("appgeneral_getCurrencies", []), - ], ) def test_(self, method, params): diff --git a/tests-functional/tests/test_cases.py b/tests-functional/tests/test_cases.py index 57710eb0e..2617e7410 100644 --- a/tests-functional/tests/test_cases.py +++ b/tests-functional/tests/test_cases.py @@ -11,23 +11,19 @@ from clients.services.wallet import WalletService from clients.signals import SignalClient, SignalType from clients.status_backend import RpcClient, StatusBackend from conftest import option -from constants import user_1, user_2, DEFAULT_DISPLAY_NAME +from resources.constants import user_1, user_2, DEFAULT_DISPLAY_NAME class StatusDTestCase: network_id = 31337 def setup_method(self): - self.rpc_client = RpcClient( - option.rpc_url_statusd - ) + self.rpc_client = RpcClient(option.rpc_url_statusd) class StatusBackendTestCase: - await_signals = [ - SignalType.NODE_LOGIN.value - ] + await_signals = [SignalType.NODE_LOGIN.value] network_id = 31337 @@ -59,8 +55,7 @@ class WalletTestCase(StatusBackendTestCase): if key in transfer_tx_data: transfer_tx_data[key] = new_value else: - logging.info( - f"Warning: The key '{key}' does not exist in the transferTx parameters and will be ignored.") + logging.info(f"Warning: The key '{key}' does not exist in the transferTx parameters and will be ignored.") params = [ { "fromAddress": user_1.address, @@ -74,7 +69,7 @@ class WalletTestCase(StatusBackendTestCase): { "bridgeName": "Transfer", "chainID": 31337, - "transferTx": transfer_tx_data + "transferTx": transfer_tx_data, } ], f"{option.password}", @@ -87,8 +82,7 @@ class WalletTestCase(StatusBackendTestCase): tx_hash = None self.rpc_client.verify_is_valid_json_rpc_response(response) try: - tx_hash = response.json( - )["result"]["hashes"][str(self.network_id)][0] + tx_hash = response.json()["result"]["hashes"][str(self.network_id)][0] except (KeyError, json.JSONDecodeError): raise Exception(response.content) return tx_hash @@ -102,7 +96,7 @@ class TransactionTestCase(WalletTestCase): class EthRpcTestCase(WalletTestCase): - @pytest.fixture(autouse=True, scope='class') + @pytest.fixture(autouse=True, scope="class") def tx_data(self): tx_hash = self.send_valid_multi_transaction() self.wait_until_tx_not_pending(tx_hash) @@ -133,11 +127,10 @@ class EthRpcTestCase(WalletTestCase): response = self.rpc_client.rpc_valid_request(method, params) start_time = time.time() - while response.json()["result"]["isPending"] == True: + while response.json()["result"]["isPending"] is True: time_passed = time.time() - start_time if time_passed >= timeout: - raise TimeoutError( - f"Tx {tx_hash} is still pending after {timeout} seconds") + raise TimeoutError(f"Tx {tx_hash} is still pending after {timeout} seconds") time.sleep(0.5) response = self.rpc_client.rpc_valid_request(method, params) return response.json()["result"]["tx"] @@ -159,23 +152,36 @@ class NetworkConditionTestCase: @contextmanager def add_latency(self): - pass - #TODO: To be implemented when we have docker exec capability + try: + # TODO: To be implemented when we have docker exec capability + yield + finally: + pass @contextmanager def add_packet_loss(self): - pass - #TODO: To be implemented when we have docker exec capability + try: + # TODO: To be implemented when we have docker exec capability + yield + finally: + pass @contextmanager def add_low_bandwith(self): - pass - #TODO: To be implemented when we have docker exec capability + try: + # TODO: To be implemented when we have docker exec capability + yield + finally: + pass @contextmanager def node_pause(self, node): - pass - #TODO: To be implemented when we have docker exec capability + try: + # TODO: To be implemented when we have docker exec capability + yield + finally: + pass + class OneToOneMessageTestCase(NetworkConditionTestCase): @@ -186,13 +192,15 @@ class OneToOneMessageTestCase(NetworkConditionTestCase): backend.start_messenger() return backend - def validate_signal_event_against_response(self, signal_event, fields_to_validate, expected_message): expected_message_id = expected_message.get("id") signal_event_messages = signal_event.get("event", {}).get("messages") assert len(signal_event_messages) > 0, "No messages found in the signal event" - message = next((message for message in signal_event_messages if message.get("id") == expected_message_id), None) + message = next( + (message for message in signal_event_messages if message.get("id") == expected_message_id), + None, + ) assert message, f"Message with ID {expected_message_id} not found in the signal event" message_mismatch = [] @@ -200,17 +208,14 @@ class OneToOneMessageTestCase(NetworkConditionTestCase): response_value = expected_message[response_field] event_value = message[event_field] if response_value != event_value: - message_mismatch.append( - f"Field '{response_field}': Expected '{response_value}', Found '{event_value}'" - ) + message_mismatch.append(f"Field '{response_field}': Expected '{response_value}', Found '{event_value}'") if not message_mismatch: return raise AssertionError( "Some Sender RPC responses are not matching the signals received by the receiver.\n" - "Details of mismatches:\n" + - "\n".join(message_mismatch) + "Details of mismatches:\n" + "\n".join(message_mismatch) ) def get_message_by_content_type(self, response, content_type): diff --git a/tests-functional/tests/test_contact_request.py b/tests-functional/tests/test_contact_request.py index c3e8b0cbd..2078174f8 100644 --- a/tests-functional/tests/test_contact_request.py +++ b/tests-functional/tests/test_contact_request.py @@ -2,14 +2,14 @@ from time import sleep from uuid import uuid4 import pytest from test_cases import OneToOneMessageTestCase -from constants import DEFAULT_DISPLAY_NAME +from resources.constants import DEFAULT_DISPLAY_NAME from clients.signals import SignalType from resources.enums import MessageContentType + @pytest.mark.rpc class TestContactRequests(OneToOneMessageTestCase): - @pytest.mark.dependency(name="test_contact_request_baseline") def test_contact_request_baseline(self, execution_number=1): @@ -21,7 +21,7 @@ class TestContactRequests(OneToOneMessageTestCase): message_text = f"test_contact_request_{execution_number}_{uuid4()}" sender = self.initialize_backend(await_signals=await_signals) - receiver = self.initialize_backend(await_signals=await_signals) + receiver = self.initialize_backend(await_signals=await_signals) pk_sender = sender.get_pubkey(DEFAULT_DISPLAY_NAME) pk_receiver = receiver.get_pubkey(DEFAULT_DISPLAY_NAME) @@ -34,25 +34,31 @@ class TestContactRequests(OneToOneMessageTestCase): response = sender.send_contact_request(pk_receiver, message_text) expected_message = self.get_message_by_content_type(response, content_type=MessageContentType.CONTACT_REQUEST.value) - messages_new_event = receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id"), timeout=60) + messages_new_event = receiver.find_signal_containing_pattern( + SignalType.MESSAGES_NEW.value, + event_pattern=expected_message.get("id"), + timeout=60, + ) signal_messages_texts = [] if "messages" in messages_new_event.get("event", {}): - signal_messages_texts.extend( - message["text"] - for message in messages_new_event["event"]["messages"] - if "text" in message - ) + signal_messages_texts.extend(message["text"] for message in messages_new_event["event"]["messages"] if "text" in message) assert f"@{pk_sender} sent you a contact request" in signal_messages_texts, "Couldn't find the signal corresponding to the contact request" self.validate_signal_event_against_response( signal_event=messages_new_event, fields_to_validate={"text": "text"}, - expected_message=expected_message + expected_message=expected_message, ) - @pytest.mark.skip(reason="Skipping because of error 'Not enough status-backend containers, please add more'. Unkipping when we merge https://github.com/status-im/status-go/pull/6159") + @pytest.mark.skip( + reason=( + "Skipping because of error 'Not enough status-backend containers, " + "please add more'. Unkipping when we merge " + "https://github.com/status-im/status-go/pull/6159" + ) + ) @pytest.mark.parametrize("execution_number", range(10)) @pytest.mark.dependency(depends=["test_contact_request_baseline"]) def test_multiple_contact_requests(self, execution_number): @@ -84,7 +90,7 @@ class TestContactRequests(OneToOneMessageTestCase): SignalType.MESSAGE_DELIVERED.value, ] sender = self.initialize_backend(await_signals=await_signals) - receiver = self.initialize_backend(await_signals=await_signals) + receiver = self.initialize_backend(await_signals=await_signals) pk_receiver = receiver.get_pubkey(DEFAULT_DISPLAY_NAME) with self.node_pause(receiver): diff --git a/tests-functional/tests/test_eth_api.py b/tests-functional/tests/test_eth_api.py index ef86d4302..dbcfc4b66 100644 --- a/tests-functional/tests/test_eth_api.py +++ b/tests-functional/tests/test_eth_api.py @@ -35,13 +35,17 @@ class TestEth(EthRpcTestCase): self.rpc_client.rpc_valid_request("ethclient_suggestGasPrice", [self.network_id]) def test_header_by_number(self, tx_data): - response = self.rpc_client.rpc_valid_request("ethclient_headerByNumber", - [self.network_id, tx_data.block_number]) + response = self.rpc_client.rpc_valid_request("ethclient_headerByNumber", [self.network_id, tx_data.block_number]) validate_header(response.json()["result"], tx_data.block_number, tx_data.block_hash) def test_block_by_number(self, tx_data): response = self.rpc_client.rpc_valid_request("ethclient_blockByNumber", [self.network_id, tx_data.block_number]) - validate_block(response.json()["result"], tx_data.block_number, tx_data.block_hash, tx_data.tx_hash) + validate_block( + response.json()["result"], + tx_data.block_number, + tx_data.block_hash, + tx_data.tx_hash, + ) def test_header_by_hash(self, tx_data): response = self.rpc_client.rpc_valid_request("ethclient_headerByHash", [self.network_id, tx_data.block_hash]) @@ -49,7 +53,12 @@ class TestEth(EthRpcTestCase): def test_block_by_hash(self, tx_data): response = self.rpc_client.rpc_valid_request("ethclient_blockByHash", [self.network_id, tx_data.block_hash]) - validate_block(response.json()["result"], tx_data.block_number, tx_data.block_hash, tx_data.tx_hash) + validate_block( + response.json()["result"], + tx_data.block_number, + tx_data.block_hash, + tx_data.tx_hash, + ) def test_transaction_by_hash(self, tx_data): response = self.rpc_client.rpc_valid_request("ethclient_transactionByHash", [self.network_id, tx_data.tx_hash]) @@ -57,4 +66,9 @@ class TestEth(EthRpcTestCase): def test_transaction_receipt(self, tx_data): response = self.rpc_client.rpc_valid_request("ethclient_transactionReceipt", [self.network_id, tx_data.tx_hash]) - validate_receipt(response.json()["result"], tx_data.tx_hash, tx_data.block_number, tx_data.block_hash) + validate_receipt( + response.json()["result"], + tx_data.tx_hash, + tx_data.block_number, + tx_data.block_hash, + ) diff --git a/tests-functional/tests/test_init_status_app.py b/tests-functional/tests/test_init_status_app.py index aa69f8dfc..87d212a52 100644 --- a/tests-functional/tests/test_init_status_app.py +++ b/tests-functional/tests/test_init_status_app.py @@ -3,6 +3,7 @@ import pytest from clients.signals import SignalType import os + @pytest.mark.create_account @pytest.mark.rpc class TestInitialiseApp: @@ -11,7 +12,6 @@ class TestInitialiseApp: def test_init_app(self): await_signals = [ - SignalType.MEDIASERVER_STARTED.value, SignalType.NODE_STARTED.value, SignalType.NODE_READY.value, @@ -24,13 +24,18 @@ class TestInitialiseApp: assert backend_client is not None backend_client.verify_json_schema( - backend_client.wait_for_signal(SignalType.MEDIASERVER_STARTED.value), "signal_mediaserver_started") + backend_client.wait_for_signal(SignalType.MEDIASERVER_STARTED.value), + "signal_mediaserver_started", + ) backend_client.verify_json_schema( - backend_client.wait_for_signal(SignalType.NODE_STARTED.value), "signal_node_started") + backend_client.wait_for_signal(SignalType.NODE_STARTED.value), + "signal_node_started", + ) backend_client.verify_json_schema( - backend_client.wait_for_signal(SignalType.NODE_READY.value), "signal_node_ready") - backend_client.verify_json_schema( - backend_client.wait_for_login(), "signal_node_login") + backend_client.wait_for_signal(SignalType.NODE_READY.value), + "signal_node_ready", + ) + backend_client.verify_json_schema(backend_client.wait_for_login(), "signal_node_login") @pytest.mark.rpc @@ -45,7 +50,6 @@ class TestInitializeLogging: def test_no_logging(self, tmp_path): self.check_logs(tmp_path, log_enabled=False, api_logging_enabled=False) - def assert_file_first_line(self, path, pattern: str, expected: bool): assert os.path.exists(path) == expected if not expected: @@ -63,20 +67,20 @@ class TestInitializeLogging: logs_dir.mkdir() backend = StatusBackend() - backend.api_valid_request("InitializeApplication", { - "dataDir": str(data_dir), - "logDir": str(logs_dir), - "logEnabled": log_enabled, - "apiLoggingEnabled": api_logging_enabled, - }) + backend.api_valid_request( + "InitializeApplication", + { + "dataDir": str(data_dir), + "logDir": str(logs_dir), + "logEnabled": log_enabled, + "apiLoggingEnabled": api_logging_enabled, + }, + ) - self.assert_file_first_line( - logs_dir / "geth.log", - pattern="logging initialised", - expected=log_enabled) + self.assert_file_first_line(logs_dir / "geth.log", pattern="logging initialised", expected=log_enabled) self.assert_file_first_line( logs_dir / "api.log", pattern='"method": "InitializeApplication"', - expected=api_logging_enabled) - + expected=api_logging_enabled, + ) diff --git a/tests-functional/tests/test_logging.py b/tests-functional/tests/test_logging.py index d47d0ddbf..98d9e7826 100644 --- a/tests-functional/tests/test_logging.py +++ b/tests-functional/tests/test_logging.py @@ -1,8 +1,7 @@ import re -import time from test_cases import StatusBackend import pytest -import os + @pytest.mark.rpc @pytest.mark.skip("waiting for status-backend to be executed on the same host/container") @@ -27,7 +26,10 @@ class TestLogging: # Configure logging backend_client.rpc_valid_request("wakuext_setLogLevel", [{"logLevel": "ERROR"}]) - backend_client.rpc_valid_request("wakuext_setLogNamespaces", [{"logNamespaces": "test1.test2:debug,test1.test2.test3:info"}]) + backend_client.rpc_valid_request( + "wakuext_setLogNamespaces", + [{"logNamespaces": "test1.test2:debug,test1.test2.test3:info"}], + ) # Re-login (logging settings take effect after re-login) backend_client.logout() @@ -36,19 +38,23 @@ class TestLogging: # Test logging backend_client.rpc_valid_request("wakuext_logTest") - self.expect_logs(tmp_path / "geth.log", "test message", [ - r"DEBUG\s+test1\.test2", - r"INFO\s+test1\.test2", - r"INFO\s+test1\.test2\.test3", - r"WARN\s+test1\.test2", - r"WARN\s+test1\.test2\.test3", - r"ERROR\s+test1", - r"ERROR\s+test1\.test2", - r"ERROR\s+test1\.test2\.test3", - ]) + self.expect_logs( + tmp_path / "geth.log", + "test message", + [ + r"DEBUG\s+test1\.test2", + r"INFO\s+test1\.test2", + r"INFO\s+test1\.test2\.test3", + r"WARN\s+test1\.test2", + r"WARN\s+test1\.test2\.test3", + r"ERROR\s+test1", + r"ERROR\s+test1\.test2", + r"ERROR\s+test1\.test2\.test3", + ], + ) def expect_logs(self, log_file, filter_keyword, expected_logs): - with open(log_file, 'r') as f: + with open(log_file, "r") as f: log_content = f.read() filtered_logs = [line for line in log_content.splitlines() if filter_keyword in line] diff --git a/tests-functional/tests/test_one_to_one_messages.py b/tests-functional/tests/test_one_to_one_messages.py index 9790cfe8f..9aa880057 100644 --- a/tests-functional/tests/test_one_to_one_messages.py +++ b/tests-functional/tests/test_one_to_one_messages.py @@ -2,10 +2,11 @@ from time import sleep from uuid import uuid4 import pytest from test_cases import OneToOneMessageTestCase -from constants import DEFAULT_DISPLAY_NAME +from resources.constants import DEFAULT_DISPLAY_NAME from clients.signals import SignalType from resources.enums import MessageContentType + @pytest.mark.rpc class TestOneToOneMessages(OneToOneMessageTestCase): @@ -33,11 +34,15 @@ class TestOneToOneMessages(OneToOneMessageTestCase): sleep(0.01) for i, expected_message in enumerate(sent_messages): - messages_new_event = self.receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=expected_message.get("id"), timeout=60) + messages_new_event = self.receiver.find_signal_containing_pattern( + SignalType.MESSAGES_NEW.value, + event_pattern=expected_message.get("id"), + timeout=60, + ) self.validate_signal_event_against_response( signal_event=messages_new_event, fields_to_validate={"text": "text"}, - expected_message=expected_message + expected_message=expected_message, ) @pytest.mark.dependency(depends=["test_one_to_one_message_baseline"]) @@ -73,5 +78,3 @@ class TestOneToOneMessages(OneToOneMessageTestCase): sleep(30) self.receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=message_text) self.sender.wait_for_signal("messages.delivered") - - diff --git a/tests-functional/tests/test_router.py b/tests-functional/tests/test_router.py index 29b65a481..c757514d7 100644 --- a/tests-functional/tests/test_router.py +++ b/tests-functional/tests/test_router.py @@ -3,10 +3,11 @@ import uuid import pytest from conftest import option -from constants import user_1, user_2 +from resources.constants import user_1, user_2 from test_cases import StatusBackendTestCase from clients.signals import SignalType + @pytest.mark.rpc @pytest.mark.transaction @pytest.mark.wallet @@ -19,6 +20,7 @@ class TestTransactionFromRoute(StatusBackendTestCase): SignalType.WALLET_TRANSACTION_STATUS_CHANGED.value, SignalType.WALLET_ROUTER_TRANSACTIONS_SENT.value, ] + def test_tx_from_route(self): _uuid = str(uuid.uuid4()) @@ -39,28 +41,22 @@ class TestTransactionFromRoute(StatusBackendTestCase): "disabledFromChainIDs": [10, 42161], "disabledToChainIDs": [10, 42161], "gasFeeMode": 1, - "fromLockedAmount": {} + "fromLockedAmount": {}, } ] response = self.rpc_client.rpc_valid_request(method, params) routes = self.rpc_client.wait_for_signal(SignalType.WALLET_SUGGESTED_ROUTES.value) - assert routes['event']['Uuid'] == _uuid + assert routes["event"]["Uuid"] == _uuid method = "wallet_buildTransactionsFromRoute" - params = [ - { - "uuid": _uuid, - "slippagePercentage": 0 - } - ] + params = [{"uuid": _uuid, "slippagePercentage": 0}] response = self.rpc_client.rpc_valid_request(method, params) - wallet_router_sign_transactions = self.rpc_client.wait_for_signal( - SignalType.WALLET_ROUTER_SIGN_TRANSACTIONS.value) + wallet_router_sign_transactions = self.rpc_client.wait_for_signal(SignalType.WALLET_ROUTER_SIGN_TRANSACTIONS.value) - assert wallet_router_sign_transactions['event']['signingDetails']['signOnKeycard'] == False - transaction_hashes = wallet_router_sign_transactions['event']['signingDetails']['hashes'] + assert wallet_router_sign_transactions["event"]["signingDetails"]["signOnKeycard"] is False + transaction_hashes = wallet_router_sign_transactions["event"]["signingDetails"]["hashes"] assert transaction_hashes, "Transaction hashes are empty!" @@ -69,36 +65,28 @@ class TestTransactionFromRoute(StatusBackendTestCase): for hash in transaction_hashes: method = "wallet_signMessage" - params = [ - hash, - user_1.address, - option.password - ] + params = [hash, user_1.address, option.password] response = self.rpc_client.rpc_valid_request(method, params) - if response.json()["result"].startswith("0x"): - tx_signature = response.json()["result"][2:] + result = response.json().get("result") + assert result and result.startswith("0x"), f"Invalid transaction signature for hash {hash}: {result}" + + tx_signature = result[2:] signature = { "r": tx_signature[:64], "s": tx_signature[64:128], - "v": tx_signature[128:] + "v": tx_signature[128:], } tx_signatures[hash] = signature method = "wallet_sendRouterTransactionsWithSignatures" - params = [ - { - "uuid": _uuid, - "Signatures": tx_signatures - } - ] + params = [{"uuid": _uuid, "Signatures": tx_signatures}] response = self.rpc_client.rpc_valid_request(method, params) - tx_status = self.rpc_client.wait_for_signal( - SignalType.WALLET_TRANSACTION_STATUS_CHANGED.value) + tx_status = self.rpc_client.wait_for_signal(SignalType.WALLET_TRANSACTION_STATUS_CHANGED.value) assert tx_status["event"]["chainId"] == 31337 assert tx_status["event"]["status"] == "Success" diff --git a/tests-functional/tests/test_waku_rpc.py b/tests-functional/tests/test_waku_rpc.py index 332937993..927cb2234 100644 --- a/tests-functional/tests/test_waku_rpc.py +++ b/tests-functional/tests/test_waku_rpc.py @@ -15,7 +15,10 @@ class TestRpc(StatusBackendTestCase): "method, params", [ ("wakuext_peers", []), - ("wakuext_activityCenterNotifications", [{"cursor": "", "limit": 20, "activityTypes": [5], "readType": 2}]) + ( + "wakuext_activityCenterNotifications", + [{"cursor": "", "limit": 20, "activityTypes": [5], "readType": 2}], + ), ], ) def test_(self, method, params): @@ -41,17 +44,11 @@ class TestRpcMessaging(StatusBackendTestCase): # get chat public key for user in self.user_1, self.user_2: - response = self.rpc_client.rpc_request( - "accounts_getAccounts", [], _id, url=user.rpc_url - ) + response = self.rpc_client.rpc_request("accounts_getAccounts", [], _id, url=user.rpc_url) self.rpc_client.verify_is_valid_json_rpc_response(response) user.chat_public_key = next( - ( - item["public-key"] - for item in response.json()["result"] - if item["chat"] - ), + (item["public-key"] for item in response.json()["result"] if item["chat"]), None, ) diff --git a/tests-functional/tests/test_wakuext_profile.py b/tests-functional/tests/test_wakuext_profile.py index 3b6814b1e..be814ac36 100644 --- a/tests-functional/tests/test_wakuext_profile.py +++ b/tests-functional/tests/test_wakuext_profile.py @@ -12,15 +12,22 @@ class TestProfile(StatusBackendTestCase): [ ("wakuext_setDisplayName", ["new valid username"]), ("wakuext_setBio", ["some valid bio"]), - ("wakuext_setCustomizationColor", [{'customizationColor': 'magenta', - 'keyUid': '0xea42dd9a4e668b0b76c7a5210ca81576d51cd19cdd0f6a0c22196219dc423f29'}]), + ( + "wakuext_setCustomizationColor", + [ + { + "customizationColor": "magenta", + "keyUid": "0xea42dd9a4e668b0b76c7a5210ca81576d51cd19cdd0f6a0c22196219dc423f29", + } + ], + ), ("wakuext_setUserStatus", [3, ""]), ("wakuext_setSyncingOnMobileNetwork", [{"enabled": False}]), ("wakuext_togglePeerSyncing", [{"enabled": True}]), ("wakuext_backupData", []), ], ) - def test_(self, method, params): + def test_wakuext_(self, method, params): _id = str(random.randint(1, 8888)) self.rpc_client.rpc_valid_request(method, params, _id) @@ -32,11 +39,21 @@ class TestProfile(StatusBackendTestCase): ("settings_saveSetting", "preview-privacy?", False, True), ("settings_saveSetting", "default-sync-period", 777600, 259200), ("settings_saveSetting", "appearance", 0, 1), - ("settings_saveSetting", "profile-pictures-show-to", 2, 1), # obsolete from v1 - ("settings_saveSetting", "profile-pictures-visibility", 2, 1), # obsolete from v1 + ( + "settings_saveSetting", + "profile-pictures-show-to", + 2, + 1, + ), # obsolete from v1 + ( + "settings_saveSetting", + "profile-pictures-visibility", + 2, + 1, + ), # obsolete from v1 ], ) - def test_(self, method, setting_name, default_value, changed_value): + def test_settings_(self, method, setting_name, default_value, changed_value): _id = str(random.randint(1, 8888)) logging.info("Step: check that %s is %s by default " % (setting_name, default_value)) @@ -59,14 +76,14 @@ class TestProfile(StatusBackendTestCase): ("settings_saveSetting", "remember-syncing-choice?", True), ("settings_saveSetting", "remote-push-notifications-enabled?", True), ("settings_saveSetting", "syncing-on-mobile-network?", True), - ## advanced token settings + # advanced token settings ("settings_saveSetting", "wallet-set-up-passed?", True), ("settings_saveSetting", "opensea-enabled?", True), ("settings_saveSetting", "waku-bloom-filter-mode", True), ("settings_saveSetting", "webview-allow-permission-requests?", True), ("settings_saveSetting", "token-group-by-community?", True), ("settings_saveSetting", "display-assets-below-balance?", True), - ## token management settings for collectibles + # token management settings for collectibles ("settings_saveSetting", "collectible-group-by-collection?", True), ("settings_saveSetting", "collectible-group-by-community?", True), ], @@ -89,7 +106,11 @@ class TestProfile(StatusBackendTestCase): [ ("settings_saveSetting", "send-status-updates?", False), ("settings_saveSetting", "link-preview-request-enabled", False), - ("settings_saveSetting", "show-community-asset-when-sending-tokens?", False), + ( + "settings_saveSetting", + "show-community-asset-when-sending-tokens?", + False, + ), ("settings_saveSetting", "url-unfurling-mode", 0), ], ) @@ -104,4 +125,3 @@ class TestProfile(StatusBackendTestCase): self.rpc_client.rpc_valid_request(method, [setting_name, set_value], _id) response = self.rpc_client.rpc_valid_request("settings_getSettings", []) assert setting_name not in response.json()["result"] - diff --git a/tests-functional/tests/test_wallet_activity_session.py b/tests-functional/tests/test_wallet_activity_session.py index e6b1b77ab..1163c5eb4 100644 --- a/tests-functional/tests/test_wallet_activity_session.py +++ b/tests-functional/tests/test_wallet_activity_session.py @@ -1,9 +1,9 @@ import json import random -import wallet_utils +from utils import wallet_utils import pytest -from constants import user_1 +from resources.constants import user_1 from test_cases import StatusBackendTestCase from clients.signals import SignalType @@ -11,10 +11,12 @@ EventActivityFilteringDone = "wallet-activity-filtering-done" EventActivityFilteringUpdate = "wallet-activity-filtering-entries-updated" EventActivitySessionUpdated = "wallet-activity-session-updated" + def validate_entry(entry, tx_data): assert entry["transactions"][0]["chainId"] == tx_data["tx_status"]["chainId"] assert entry["transactions"][0]["hash"] == tx_data["tx_status"]["hash"] + @pytest.mark.wallet @pytest.mark.rpc class TestWalletActivitySession(StatusBackendTestCase): @@ -25,64 +27,88 @@ class TestWalletActivitySession(StatusBackendTestCase): "wallet.router.sign-transactions", "wallet.router.sending-transactions-started", "wallet.transaction.status-changed", - "wallet.router.transactions-sent"] + "wallet.router.transactions-sent", + ] def setup_method(self): self.request_id = str(random.randint(1, 8888)) def test_wallet_start_activity_filter_session(self): - tx_data = [] # (routes, build_tx, tx_signatures, tx_status) + tx_data = [] # (routes, build_tx, tx_signatures, tx_status) # Set up a transactions for account before starting session tx_data.append(wallet_utils.send_router_transaction(self.rpc_client)) # Start activity session method = "wallet_startActivityFilterSessionV2" - params = [[user_1.address], [self.network_id], - {"period": {"startTimestamp": 0, "endTimestamp": 0}, "types": [], "statuses": [], - "counterpartyAddresses": [], "assets": [], "collectibles": [], "filterOutAssets": False, - "filterOutCollectibles": False}, 10] - self.rpc_client.prepare_wait_for_signal("wallet", 1, lambda signal : signal["event"]["type"] == EventActivityFilteringDone) + params = [ + [user_1.address], + [self.network_id], + { + "period": {"startTimestamp": 0, "endTimestamp": 0}, + "types": [], + "statuses": [], + "counterpartyAddresses": [], + "assets": [], + "collectibles": [], + "filterOutAssets": False, + "filterOutCollectibles": False, + }, + 10, + ] + self.rpc_client.prepare_wait_for_signal( + "wallet", + 1, + lambda signal: signal["event"]["type"] == EventActivityFilteringDone, + ) response = self.rpc_client.rpc_valid_request(method, params, self.request_id) - event_response = self.rpc_client.wait_for_signal("wallet", timeout=10)['event'] + event_response = self.rpc_client.wait_for_signal("wallet", timeout=10)["event"] - # Check response + # Check response sessionID = int(response.json()["result"]) assert sessionID > 0 # Check response event - assert int(event_response['requestId']) == sessionID - message = json.loads(event_response['message'].replace("'", "\"")) - assert int(message['errorCode']) == 1 - assert len(message['activities']) > 0 # Should have at least 1 entry + assert int(event_response["requestId"]) == sessionID + message = json.loads(event_response["message"].replace("'", '"')) + assert int(message["errorCode"]) == 1 + assert len(message["activities"]) > 0 # Should have at least 1 entry # First activity entry should match last sent transaction - validate_entry(message['activities'][0], tx_data[-1]) + validate_entry(message["activities"][0], tx_data[-1]) # Trigger new transaction - self.rpc_client.prepare_wait_for_signal("wallet", 1, lambda signal : signal["event"]["type"] == EventActivitySessionUpdated and signal['event']['requestId'] == sessionID) + self.rpc_client.prepare_wait_for_signal( + "wallet", + 1, + lambda signal: signal["event"]["type"] == EventActivitySessionUpdated and signal["event"]["requestId"] == sessionID, + ) tx_data.append(wallet_utils.send_router_transaction(self.rpc_client)) print(tx_data[-1]) - event_response = self.rpc_client.wait_for_signal("wallet", timeout=10)['event'] + event_response = self.rpc_client.wait_for_signal("wallet", timeout=10)["event"] # Check response event - assert int(event_response['requestId']) == sessionID - message = json.loads(event_response['message'].replace("'", "\"")) - assert message['hasNewOnTop'] # New entries reported + assert int(event_response["requestId"]) == sessionID + message = json.loads(event_response["message"].replace("'", '"')) + assert message["hasNewOnTop"] # New entries reported # Reset activity session method = "wallet_resetActivityFilterSession" params = [sessionID, 10] - self.rpc_client.prepare_wait_for_signal("wallet", 1, lambda signal : signal["event"]["type"] == EventActivityFilteringDone and signal['event']['requestId'] == sessionID) + self.rpc_client.prepare_wait_for_signal( + "wallet", + 1, + lambda signal: signal["event"]["type"] == EventActivityFilteringDone and signal["event"]["requestId"] == sessionID, + ) response = self.rpc_client.rpc_valid_request(method, params, self.request_id) - event_response = self.rpc_client.wait_for_signal("wallet", timeout=10)['event'] + event_response = self.rpc_client.wait_for_signal("wallet", timeout=10)["event"] # Check response event - assert int(event_response['requestId']) == sessionID - message = json.loads(event_response['message'].replace("'", "\"")) - assert int(message['errorCode']) == 1 - assert len(message['activities']) > 1 # Should have at least 2 entries + assert int(event_response["requestId"]) == sessionID + message = json.loads(event_response["message"].replace("'", '"')) + assert int(message["errorCode"]) == 1 + assert len(message["activities"]) > 1 # Should have at least 2 entries # First activity entry should match last sent transaction - validate_entry(message['activities'][0], tx_data[-1]) + validate_entry(message["activities"][0], tx_data[-1]) # Second activity entry should match second to last sent transaction - validate_entry(message['activities'][1], tx_data[-2]) + validate_entry(message["activities"][1], tx_data[-2]) diff --git a/tests-functional/tests/test_wallet_rpc.py b/tests-functional/tests/test_wallet_rpc.py index 39cbbed77..317c8e151 100644 --- a/tests-functional/tests/test_wallet_rpc.py +++ b/tests-functional/tests/test_wallet_rpc.py @@ -5,8 +5,8 @@ import jsonschema import pytest from conftest import option -from constants import user_1 -from test_cases import StatusBackendTestCase, TransactionTestCase, StatusDTestCase +from resources.constants import user_1 +from test_cases import StatusBackendTestCase, TransactionTestCase @pytest.mark.wallet @@ -18,12 +18,12 @@ class TestTransactionRpc(TransactionTestCase): "method, params", [ ( - "wallet_checkRecentHistoryForChainIDs", - [[31337], ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"]], + "wallet_checkRecentHistoryForChainIDs", + [[31337], ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"]], ), ( - "wallet_getPendingTransactionsForIdentities", - [[{"chainId": None, "hash": None}]], + "wallet_getPendingTransactionsForIdentities", + [[{"chainId": None, "hash": None}]], ), ], ) @@ -42,35 +42,41 @@ class TestTransactionRpc(TransactionTestCase): self.rpc_client.verify_is_valid_json_rpc_response(response) # how to create schema: - # from schema_builder import CustomSchemaBuilder + # from utils.schema_builder import CustomSchemaBuilder # CustomSchemaBuilder(method).create_schema(response.json()) - with open(f"{option.base_dir}/schemas/wallet_createMultiTransaction/transferTx_positive", "r") as schema: + with open( + f"{option.base_dir}/schemas/wallet_createMultiTransaction/transferTx_positive", + "r", + ) as schema: jsonschema.validate(instance=response.json(), schema=json.load(schema)) @pytest.mark.parametrize( "method, changed_values, expected_error_code, expected_error_text", [ ( - "transferTx_value_not_enough_balance", - {'value': '0x21e438ea8139cd35004'}, -32000, "Insufficient funds for gas", + "transferTx_value_not_enough_balance", + {"value": "0x21e438ea8139cd35004"}, + -32000, + "Insufficient funds for gas", ), ( - "transferTx_from_from_invalid_string", - {'from': 'some_invalid_address'}, -32602, "cannot unmarshal hex string without 0x prefix", + "transferTx_from_from_invalid_string", + {"from": "some_invalid_address"}, + -32602, + "cannot unmarshal hex string without 0x prefix", ), ], ) - def test_create_multi_transaction_validation(self, method, - changed_values, - expected_error_code, expected_error_text): + def test_create_multi_transaction_validation(self, method, changed_values, expected_error_code, expected_error_text): response = self.wallet_create_multi_transaction(**changed_values) self.rpc_client.verify_is_json_rpc_error(response) - actual_error_code, actual_error_text = response.json()['error']['code'], response.json()['error']['message'] - assert expected_error_code == actual_error_code, \ - f"got code: {actual_error_code} instead of expected: {expected_error_code}" - assert expected_error_text in actual_error_text, \ - f"got error: {actual_error_text} that does not include: {expected_error_text}" + actual_error_code, actual_error_text = ( + response.json()["error"]["code"], + response.json()["error"]["message"], + ) + assert expected_error_code == actual_error_code, f"got code: {actual_error_code} instead of expected: {expected_error_code}" + assert expected_error_text in actual_error_text, f"got error: {actual_error_text} that does not include: {expected_error_text}" self.rpc_client.verify_json_schema(response.json(), "wallet_createMultiTransaction/transferTx_error") @@ -87,19 +93,69 @@ class TestRpc(StatusBackendTestCase): ("wallet_getTokenList", []), ("wallet_getCryptoOnRamps", []), ("wallet_getCachedCurrencyFormats", []), - ("wallet_fetchPrices", - [["WETH9", "USDC", "ZEENUS", "EUROC", "WEENUS", "XEENUS", "WETH", "ETH", "STT", "UNI", "YEENUS", "DAI"], - ["usd"]]), - - ("wallet_fetchMarketValues", - [["WETH9", "USDC", "ZEENUS", "EUROC", "WEENUS", "XEENUS", "WETH", "ETH", "STT", "UNI", "YEENUS", "DAI"], - "usd"]), - ("wallet_fetchTokenDetails", - [["WETH9", "USDC", "ZEENUS", "EUROC", "WEENUS", "XEENUS", "WETH", "ETH", "STT", "UNI", "YEENUS", "DAI"]]), + ( + "wallet_fetchPrices", + [ + [ + "WETH9", + "USDC", + "ZEENUS", + "EUROC", + "WEENUS", + "XEENUS", + "WETH", + "ETH", + "STT", + "UNI", + "YEENUS", + "DAI", + ], + ["usd"], + ], + ), + ( + "wallet_fetchMarketValues", + [ + [ + "WETH9", + "USDC", + "ZEENUS", + "EUROC", + "WEENUS", + "XEENUS", + "WETH", + "ETH", + "STT", + "UNI", + "YEENUS", + "DAI", + ], + "usd", + ], + ), + ( + "wallet_fetchTokenDetails", + [ + [ + "WETH9", + "USDC", + "ZEENUS", + "EUROC", + "WEENUS", + "XEENUS", + "WETH", + "ETH", + "STT", + "UNI", + "YEENUS", + "DAI", + ] + ], + ), ("wallet_checkRecentHistoryForChainIDs", [[31337], [user_1.address]]), ("wallet_getWalletConnectActiveSessions", [1728995277]), ("wallet_stopSuggestedRoutesAsyncCalculation", []), - ] + ], ) def test_(self, method, params): _id = str(random.randint(1, 8888)) diff --git a/tests-functional/tests/test_wallet_signals.py b/tests-functional/tests/test_wallet_signals.py index 984dc6516..dd6222c61 100644 --- a/tests-functional/tests/test_wallet_signals.py +++ b/tests-functional/tests/test_wallet_signals.py @@ -3,7 +3,7 @@ import random import pytest -from constants import user_1 +from resources.constants import user_1 from test_cases import StatusBackendTestCase @@ -13,8 +13,7 @@ class TestWalletSignals(StatusBackendTestCase): def setup_class(self): self.await_signals.append("wallet") - super().setup_class(self) - + super().setup_class() def setup_method(self): self.request_id = str(random.randint(1, 8888)) @@ -22,26 +21,49 @@ class TestWalletSignals(StatusBackendTestCase): @pytest.mark.skip def test_wallet_get_owned_collectibles_async(self): method = "wallet_getOwnedCollectiblesAsync" - params = [0, [self.network_id, ], [user_1.address], None, 0, 25, 1, - {"fetch-type": 2, "max-cache-age-seconds": 3600}] + params = [ + 0, + [ + self.network_id, + ], + [user_1.address], + None, + 0, + 25, + 1, + {"fetch-type": 2, "max-cache-age-seconds": 3600}, + ] self.rpc_client.rpc_valid_request(method, params, self.request_id) signal_response = self.rpc_client.wait_for_signal("wallet", timeout=60) self.rpc_client.verify_json_schema(signal_response, method) - assert signal_response['event']['type'] == "wallet-owned-collectibles-filtering-done" - message = json.loads(signal_response['event']['message'].replace("'", "\"")) - assert user_1.address in message['ownershipStatus'].keys() + assert signal_response["event"]["type"] == "wallet-owned-collectibles-filtering-done" + message = json.loads(signal_response["event"]["message"].replace("'", '"')) + assert user_1.address in message["ownershipStatus"].keys() @pytest.mark.skip def test_wallet_filter_activity_async(self): method = "wallet_filterActivityAsync" - params = [1, [user_1.address], [self.network_id], - {"period": {"startTimestamp": 0, "endTimestamp": 0}, "types": [], "statuses": [], - "counterpartyAddresses": [], "assets": [], "collectibles": [], "filterOutAssets": False, - "filterOutCollectibles": False}, 0, 50] + params = [ + 1, + [user_1.address], + [self.network_id], + { + "period": {"startTimestamp": 0, "endTimestamp": 0}, + "types": [], + "statuses": [], + "counterpartyAddresses": [], + "assets": [], + "collectibles": [], + "filterOutAssets": False, + "filterOutCollectibles": False, + }, + 0, + 50, + ] self.rpc_client.rpc_valid_request(method, params, self.request_id) signal_response = self.rpc_client.wait_for_signal("wallet", timeout=60) self.rpc_client.verify_json_schema(signal_response, method) - assert signal_response['event']['type'] == "wallet-activity-filtering-done" - message = json.loads(signal_response['event']['message'].replace("'", "\"")) - for item in message['activities']: - assert user_1.address in item['sender'], item['recipient'] + assert signal_response["event"]["type"] == "wallet-activity-filtering-done" + message = json.loads(signal_response["event"]["message"].replace("'", '"')) + for item in message["activities"]: + assert user_1.address in item["sender"], item["recipient"] diff --git a/tests-functional/utils/__init__.py b/tests-functional/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests-functional/schema_builder.py b/tests-functional/utils/schema_builder.py similarity index 100% rename from tests-functional/schema_builder.py rename to tests-functional/utils/schema_builder.py diff --git a/tests-functional/wallet_utils.py b/tests-functional/utils/wallet_utils.py similarity index 63% rename from tests-functional/wallet_utils.py rename to tests-functional/utils/wallet_utils.py index f2f14e148..d1c870060 100644 --- a/tests-functional/wallet_utils.py +++ b/tests-functional/utils/wallet_utils.py @@ -2,19 +2,17 @@ import json import logging import jsonschema import uuid -import threading -import time + from conftest import option -from constants import user_1, user_2 +from resources.constants import user_1, user_2 -from clients.signals import SignalClient def verify_json_schema(response, method): with open(f"{option.base_dir}/schemas/{method}", "r") as schema: - jsonschema.validate(instance=response, - schema=json.load(schema)) - + jsonschema.validate(instance=response, schema=json.load(schema)) + + def get_suggested_routes(rpc_client, **kwargs): _uuid = str(uuid.uuid4()) amount_in = "0xde0b6b3a7640000" @@ -33,47 +31,44 @@ def get_suggested_routes(rpc_client, **kwargs): "disabledFromChainIDs": [10, 42161], "disabledToChainIDs": [10, 42161], "gasFeeMode": 1, - "fromLockedAmount": {} + "fromLockedAmount": {}, } for key, new_value in kwargs.items(): if key in input_params: input_params[key] = new_value else: - logging.info( - f"Warning: The key '{key}' does not exist in the input_params parameters and will be ignored.") + logging.info(f"Warning: The key '{key}' does not exist in the input_params parameters and will be ignored.") params = [input_params] rpc_client.prepare_wait_for_signal("wallet.suggested.routes", 1) _ = rpc_client.rpc_valid_request(method, params) routes = rpc_client.wait_for_signal("wallet.suggested.routes") - assert routes['event']['Uuid'] == _uuid + assert routes["event"]["Uuid"] == _uuid + + return routes["event"] - return routes['event'] def build_transactions_from_route(rpc_client, uuid, **kwargs): method = "wallet_buildTransactionsFromRoute" - build_tx_params = { - "uuid": uuid, - "slippagePercentage": 0 - } + build_tx_params = {"uuid": uuid, "slippagePercentage": 0} for key, new_value in kwargs.items(): if key in build_tx_params: build_tx_params[key] = new_value else: - logging.info( - f"Warning: The key '{key}' does not exist in the build_tx_params parameters and will be ignored.") + logging.info(f"Warning: The key '{key}' does not exist in the build_tx_params parameters and will be ignored.") params = [build_tx_params] _ = rpc_client.rpc_valid_request(method, params) wallet_router_sign_transactions = rpc_client.wait_for_signal("wallet.router.sign-transactions") - assert wallet_router_sign_transactions['event']['signingDetails']['signOnKeycard'] == False - transaction_hashes = wallet_router_sign_transactions['event']['signingDetails']['hashes'] + assert wallet_router_sign_transactions["event"]["signingDetails"]["signOnKeycard"] is False + transaction_hashes = wallet_router_sign_transactions["event"]["signingDetails"]["hashes"] assert transaction_hashes, "Transaction hashes are empty!" - return wallet_router_sign_transactions['event'] + return wallet_router_sign_transactions["event"] + def sign_messages(rpc_client, hashes): tx_signatures = {} @@ -81,51 +76,45 @@ def sign_messages(rpc_client, hashes): for hash in hashes: method = "wallet_signMessage" - params = [ - hash, - user_1.address, - option.password - ] + params = [hash, user_1.address, option.password] response = rpc_client.rpc_valid_request(method, params) - if response.json()["result"].startswith("0x"): - tx_signature = response.json()["result"][2:] + result = response.json().get("result") + assert result and result.startswith("0x"), f"Invalid transaction signature for hash {hash}: {result}" + + tx_signature = result[2:] signature = { "r": tx_signature[:64], "s": tx_signature[64:128], - "v": tx_signature[128:] + "v": tx_signature[128:], } tx_signatures[hash] = signature return tx_signatures + def send_router_transactions_with_signatures(rpc_client, uuid, tx_signatures): method = "wallet_sendRouterTransactionsWithSignatures" - params = [ - { - "uuid": uuid, - "Signatures": tx_signatures - } - ] + params = [{"uuid": uuid, "Signatures": tx_signatures}] _ = rpc_client.rpc_valid_request(method, params) - tx_status = rpc_client.wait_for_signal( - "wallet.transaction.status-changed") + tx_status = rpc_client.wait_for_signal("wallet.transaction.status-changed") assert tx_status["event"]["status"] == "Success" return tx_status["event"] + def send_router_transaction(rpc_client, **kwargs): routes = get_suggested_routes(rpc_client, **kwargs) - build_tx = build_transactions_from_route(rpc_client, routes['Uuid']) - tx_signatures = sign_messages(rpc_client, build_tx['signingDetails']['hashes']) - tx_status = send_router_transactions_with_signatures(rpc_client, routes['Uuid'], tx_signatures) + build_tx = build_transactions_from_route(rpc_client, routes["Uuid"]) + tx_signatures = sign_messages(rpc_client, build_tx["signingDetails"]["hashes"]) + tx_status = send_router_transactions_with_signatures(rpc_client, routes["Uuid"], tx_signatures) return { "routes": routes, "build_tx": build_tx, "tx_signatures": tx_signatures, - "tx_status": tx_status + "tx_status": tx_status, }