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
This commit is contained in:
fbarbu15 2024-12-16 12:38:24 +02:00 committed by GitHub
parent 66850321ef
commit 08eee8a647
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 544 additions and 316 deletions

33
.github/workflows/pytest-lint.yml vendored Normal file
View File

@ -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

1
.gitignore vendored
View File

@ -109,7 +109,6 @@ tests-functional/coverage
tests-functional/reports tests-functional/reports
tests-functional/signals tests-functional/signals
tests-functional/*.log tests-functional/*.log
pyrightconfig.json
.venv .venv

View File

@ -428,3 +428,8 @@ run-anvil:
codecov-validate: SHELL := /bin/sh codecov-validate: SHELL := /bin/sh
codecov-validate: codecov-validate:
curl -X POST --data-binary @.codecov.yml https://codecov.io/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

5
pyrightconfig.json Normal file
View File

@ -0,0 +1,5 @@
{
"include": ["tests-functional"],
"venvPath": "./tests-functional", // Ensure the virtual environment (.venv) is located in ./tests-functional
"venv": ".venv"
}

View File

@ -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.

View File

@ -12,10 +12,18 @@ Functional tests for status-go
## How to Install ## How to Install
* Install [Docker](https://docs.docker.com/engine/install/) and [Docker Compose](https://docs.docker.com/compose/install/) 1. 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/) 2. Install [Python 3](https://www.python.org/downloads/) (tested with 3.10 and 3.12 and it works with both)
* In `./tests-functional`, run `pip install -r requirements.txt` 3. **Set up a virtual environment (required for linting):**
* **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/): - 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 ## How to Run
@ -39,4 +47,4 @@ Functional tests for status-go
- Every test has two types of verifications: - 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. - `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` - `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 - 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

View File

@ -17,11 +17,9 @@ class RpcClient:
try: try:
return response.json()[key] return response.json()[key]
except json.JSONDecodeError: except json.JSONDecodeError:
raise AssertionError( raise AssertionError(f"Invalid JSON in response: {response.content}")
f"Invalid JSON in response: {response.content}")
except KeyError: except KeyError:
raise AssertionError( raise AssertionError(f"Key '{key}' not found in the JSON response: {response.content}")
f"Key '{key}' not found in the JSON response: {response.content}")
def verify_is_valid_json_rpc_response(self, response, _id=None): 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}" assert response.status_code == 200, f"Got response {response.content}, status code {response.status_code}"
@ -31,9 +29,7 @@ class RpcClient:
if _id: if _id:
try: try:
if _id != response.json()["id"]: if _id != response.json()["id"]:
raise AssertionError( raise AssertionError(f"got id: {response.json()['id']} instead of expected id: {_id}")
f"got id: {response.json()['id']} instead of expected id: {_id}"
)
except KeyError: except KeyError:
raise AssertionError(f"no id in response {response.json()}") raise AssertionError(f"no id in response {response.json()}")
return response return response
@ -44,7 +40,9 @@ class RpcClient:
self._check_decode_and_key_errors_in_response(response, "error") self._check_decode_and_key_errors_in_response(response, "error")
@retry(stop=stop_after_delay(10), wait=wait_fixed(0.5), reraise=True) @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: if params is None:
params = [] params = []
url = url if url else self.rpc_url url = url if url else self.rpc_url
@ -69,5 +67,4 @@ class RpcClient:
def verify_json_schema(self, response, method): def verify_json_schema(self, response, method):
with open(f"{option.base_dir}/schemas/{method}", "r") as schema: with open(f"{option.base_dir}/schemas/{method}", "r") as schema:
jsonschema.validate(instance=response, jsonschema.validate(instance=response, schema=json.load(schema))
schema=json.load(schema))

View File

@ -3,7 +3,7 @@ from clients.rpc import RpcClient
class Service: class Service:
def __init__(self, client: RpcClient, name: str): def __init__(self, client: RpcClient, name: str):
assert name is not "" assert name != ""
self.rpc_client = client self.rpc_client = client
self.name = name self.name = name

View File

@ -5,10 +5,11 @@ import time
import websocket import websocket
import os import os
from pathlib import Path 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 datetime import datetime
from enum import Enum from enum import Enum
class SignalType(Enum): class SignalType(Enum):
MESSAGES_NEW = "messages.new" MESSAGES_NEW = "messages.new"
MESSAGE_DELIVERED = "message.delivered" MESSAGE_DELIVERED = "message.delivered"
@ -22,6 +23,7 @@ class SignalType(Enum):
WALLET_TRANSACTION_STATUS_CHANGED = "wallet.transaction.status-changed" WALLET_TRANSACTION_STATUS_CHANGED = "wallet.transaction.status-changed"
WALLET_ROUTER_TRANSACTIONS_SENT = "wallet.router.transactions-sent" WALLET_ROUTER_TRANSACTIONS_SENT = "wallet.router.transactions-sent"
class SignalClient: class SignalClient:
def __init__(self, ws_url, await_signals): def __init__(self, ws_url, await_signals):
self.url = f"{ws_url}/signals" self.url = f"{ws_url}/signals"
@ -37,11 +39,15 @@ class SignalClient:
"received": [], "received": [],
"delta_count": 1, "delta_count": 1,
"expected_count": 1, "expected_count": 1,
"accept_fn": None "accept_fn": None,
} for signal in self.await_signals }
for signal in self.await_signals
} }
if LOG_SIGNALS_TO_FILE: 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) Path(SIGNALS_DIR).mkdir(parents=True, exist_ok=True)
def on_message(self, ws, signal): def on_message(self, ws, signal):
@ -77,8 +83,7 @@ class SignalClient:
received_signals = self.received_signals.get(signal_type) received_signals = self.received_signals.get(signal_type)
while (not received_signals) or len(received_signals["received"]) < received_signals["expected_count"]: while (not received_signals) or len(received_signals["received"]) < received_signals["expected_count"]:
if time.time() - start_time >= timeout: if time.time() - start_time >= timeout:
raise TimeoutError( raise TimeoutError(f"Signal {signal_type} is not received in {timeout} seconds")
f"Signal {signal_type} is not received in {timeout} seconds")
time.sleep(0.2) time.sleep(0.2)
logging.debug(f"Signal {signal_type} is received in {round(time.time() - start_time)} seconds") logging.debug(f"Signal {signal_type} is received in {round(time.time() - start_time)} seconds")
delta_count = received_signals["delta_count"] delta_count = received_signals["delta_count"]
@ -97,17 +102,13 @@ class SignalClient:
start_time = time.time() start_time = time.time()
while True: while True:
if time.time() - start_time >= timeout: if time.time() - start_time >= timeout:
raise TimeoutError( raise TimeoutError(f"Signal {signal_type} containing {event_pattern} is not received in {timeout} seconds")
f"Signal {signal_type} containing {event_pattern} is not received in {timeout} seconds"
)
if not self.received_signals.get(signal_type): if not self.received_signals.get(signal_type):
time.sleep(0.2) time.sleep(0.2)
continue continue
for event in self.received_signals[signal_type]["received"]: for event in self.received_signals[signal_type]["received"]:
if event_pattern in str(event): if event_pattern in str(event):
logging.info( logging.info(f"Signal {signal_type} containing {event_pattern} is received in {round(time.time() - start_time)} seconds")
f"Signal {signal_type} containing {event_pattern} is received in {round(time.time() - start_time)} seconds"
)
return event return event
time.sleep(0.2) time.sleep(0.2)
@ -121,10 +122,12 @@ class SignalClient:
logging.info("Connection opened") logging.info("Connection opened")
def _connect(self): def _connect(self):
ws = websocket.WebSocketApp(self.url, ws = websocket.WebSocketApp(
on_message=self.on_message, self.url,
on_error=self._on_error, on_message=self.on_message,
on_close=self._on_close) on_error=self._on_error,
on_close=self._on_close,
)
ws.on_open = self._on_open ws.on_open = self._on_open
ws.run_forever() ws.run_forever()

View File

@ -12,7 +12,7 @@ from clients.signals import SignalClient
from clients.rpc import RpcClient from clients.rpc import RpcClient
from datetime import datetime from datetime import datetime
from conftest import option 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): class StatusBackend(RpcClient, SignalClient):
@ -29,7 +29,6 @@ class StatusBackend(RpcClient, SignalClient):
url = f"http://127.0.0.1:{host_port}" url = f"http://127.0.0.1:{host_port}"
option.status_backend_port_range.remove(host_port) option.status_backend_port_range.remove(host_port)
self.api_url = f"{url}/statusgo" self.api_url = f"{url}/statusgo"
self.ws_url = f"{url}".replace("http", "ws") self.ws_url = f"{url}".replace("http", "ws")
self.rpc_url = f"{url}/statusgo/CallRPC" self.rpc_url = f"{url}/statusgo/CallRPC"
@ -59,7 +58,8 @@ class StatusBackend(RpcClient, SignalClient):
"labels": {"com.docker.compose.project": docker_project_name}, "labels": {"com.docker.compose.project": docker_project_name},
"entrypoint": [ "entrypoint": [
"status-backend", "status-backend",
"--address", "0.0.0.0:3333", "--address",
"0.0.0.0:3333",
], ],
"ports": {"3333/tcp": host_port}, "ports": {"3333/tcp": host_port},
"environment": { "environment": {
@ -78,8 +78,7 @@ class StatusBackend(RpcClient, SignalClient):
container = self.docker_client.containers.run(**container_args) container = self.docker_client.containers.run(**container_args)
network = self.docker_client.networks.get( network = self.docker_client.networks.get(f"{docker_project_name}_default")
f"{docker_project_name}_default")
network.connect(container) network.connect(container)
option.status_backend_containers.append(container.id) option.status_backend_containers.append(container.id)
@ -99,8 +98,7 @@ class StatusBackend(RpcClient, SignalClient):
def api_request(self, method, data, url=None): def api_request(self, method, data, url=None):
url = url if url else self.api_url url = url if url else self.api_url
url = f"{url}/{method}" url = f"{url}/{method}"
logging.info( logging.info(f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}")
f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}")
response = requests.post(url, json=data) response = requests.post(url, json=data)
logging.info(f"Got response: {response.content}") logging.info(f"Got response: {response.content}")
return response return response
@ -113,8 +111,7 @@ class StatusBackend(RpcClient, SignalClient):
error = response.json()["error"] error = response.json()["error"]
assert not error, f"Error: {error}" assert not error, f"Error: {error}"
except json.JSONDecodeError: except json.JSONDecodeError:
raise AssertionError( raise AssertionError(f"Invalid JSON in response: {response.content}")
f"Invalid JSON in response: {response.content}")
except KeyError: except KeyError:
pass pass
@ -133,7 +130,12 @@ class StatusBackend(RpcClient, SignalClient):
} }
return self.api_valid_request(method, data) 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" method = "CreateAccountAndLogin"
data = { data = {
"rootDataDir": data_dir, "rootDataDir": data_dir,
@ -146,8 +148,13 @@ class StatusBackend(RpcClient, SignalClient):
} }
return self.api_valid_request(method, data) 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, def restore_account_and_login(
network_id=31337): self,
data_dir=USER_DIR,
display_name=DEFAULT_DISPLAY_NAME,
user=user_1,
network_id=31337,
):
method = "RestoreAccountAndLogin" method = "RestoreAccountAndLogin"
data = { data = {
"rootDataDir": data_dir, "rootDataDir": data_dir,
@ -172,9 +179,9 @@ class StatusBackend(RpcClient, SignalClient):
"NativeCurrencyDecimals": 18, "NativeCurrencyDecimals": 18,
"IsTest": False, "IsTest": False,
"Layer": 1, "Layer": 1,
"Enabled": True "Enabled": True,
} }
] ],
} }
return self.api_valid_request(method, data) 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 # ToDo: change this part for waiting for `node.login` signal when websockets are migrated to StatusBackend
while time.time() - start_time <= timeout: while time.time() - start_time <= timeout:
try: try:
self.rpc_valid_request(method='accounts_getKeypairs') self.rpc_valid_request(method="accounts_getKeypairs")
return return
except AssertionError: except AssertionError:
time.sleep(3) time.sleep(3)
raise TimeoutError( raise TimeoutError(f"RPC client was not started after {timeout} seconds")
f"RPC client was not started after {timeout} seconds")
@retry(stop=stop_after_delay(10), wait=wait_fixed(0.5), reraise=True) @retry(stop=stop_after_delay(10), wait=wait_fixed(0.5), reraise=True)
def start_messenger(self, params=[]): def start_messenger(self, params=[]):
@ -210,9 +216,9 @@ class StatusBackend(RpcClient, SignalClient):
response = self.rpc_request(method, params) response = self.rpc_request(method, params)
json_response = response.json() json_response = response.json()
if 'error' in json_response: if "error" in json_response:
assert json_response['error']['code'] == -32000 assert json_response["error"]["code"] == -32000
assert json_response['error']['message'] == "messenger already started" assert json_response["error"]["message"] == "messenger already started"
return return
self.verify_is_valid_json_rpc_response(response) self.verify_is_valid_json_rpc_response(response)
@ -239,8 +245,7 @@ class StatusBackend(RpcClient, SignalClient):
for account in accounts: for account in accounts:
if account.get("name") == display_name: if account.get("name") == display_name:
return account.get("public-key") return account.get("public-key")
raise ValueError( raise ValueError(f"Public key not found for display name: {display_name}")
f"Public key not found for display name: {display_name}")
def send_contact_request(self, contact_id: str, message: str): def send_contact_request(self, contact_id: str, message: str):
method = "wakuext_sendContactRequest" method = "wakuext_sendContactRequest"

View File

@ -1,8 +1,8 @@
import os import os
import docker import docker
import pytest as pytest
from dataclasses import dataclass from dataclasses import dataclass, field
from typing import List
def pytest_addoption(parser): def pytest_addoption(parser):
@ -43,9 +43,12 @@ def pytest_addoption(parser):
default=None, default=None,
) )
@dataclass @dataclass
class Option: 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() option = Option()
@ -55,7 +58,7 @@ def pytest_configure(config):
global option global option
option = config.option option = config.option
executor_number = int(os.getenv('EXECUTOR_NUMBER', 5)) executor_number = int(os.getenv("EXECUTOR_NUMBER", 5))
base_port = 7000 base_port = 7000
range_size = 100 range_size = 100
@ -66,6 +69,7 @@ def pytest_configure(config):
option.base_dir = os.path.dirname(os.path.abspath(__file__)) option.base_dir = os.path.dirname(os.path.abspath(__file__))
def pytest_unconfigure(): def pytest_unconfigure():
docker_client = docker.from_env() docker_client = docker.from_env()
for container_id in option.status_backend_containers: for container_id in option.status_backend_containers:

View File

@ -7,3 +7,6 @@ websocket-client~=1.4.2
tenacity~=9.0.0 tenacity~=9.0.0
pytest-dependency~=0.6.0 pytest-dependency~=0.6.0
docker==7.1.0 docker==7.1.0
pyright==1.1.388
black==24.10.0
pre-commit==3.6.2

View File

@ -15,17 +15,17 @@ user_1 = Account(
address="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", address="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
private_key="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", private_key="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
password="Strong12345", 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( user_2 = Account(
address="0x70997970c51812dc3a010c7d01b50e0d17dc79c8", address="0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
private_key="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", private_key="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
password="Strong12345", 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" DEFAULT_DISPLAY_NAME = "Mr_Meeseeks"
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "../")) PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "../"))
TESTS_DIR = os.path.join(PROJECT_ROOT, "tests-functional") TESTS_DIR = os.path.join(PROJECT_ROOT, "tests-functional")
SIGNALS_DIR = os.path.join(TESTS_DIR, "signals") 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" USER_DIR = option.user_dir if option.user_dir else "/usr/status-user"

View File

@ -1,5 +1,6 @@
from enum import Enum from enum import Enum
class MessageContentType(Enum): class MessageContentType(Enum):
UNKNOWN_CONTENT_TYPE = 0 UNKNOWN_CONTENT_TYPE = 0
TEXT_PLAIN = 1 TEXT_PLAIN = 1
@ -18,5 +19,5 @@ class MessageContentType(Enum):
SYSTEM_MESSAGE_PINNED_MESSAGE = 14 SYSTEM_MESSAGE_PINNED_MESSAGE = 14
SYSTEM_MESSAGE_MUTUAL_EVENT_SENT = 15 SYSTEM_MESSAGE_MUTUAL_EVENT_SENT = 15
SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED = 16 SYSTEM_MESSAGE_MUTUAL_EVENT_ACCEPTED = 16
SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED = 17 SYSTEM_MESSAGE_MUTUAL_EVENT_REMOVED = 17
BRIDGE_MESSAGE = 18 BRIDGE_MESSAGE = 18

View File

@ -2,7 +2,7 @@ import random
import pytest import pytest
from constants import user_1 from resources.constants import user_1
from test_cases import StatusBackendTestCase from test_cases import StatusBackendTestCase
@ -18,7 +18,6 @@ class TestAccounts(StatusBackendTestCase):
# ("accounts_hasPairedDevices", []), # randomly crashes app, to be reworked/fixed # ("accounts_hasPairedDevices", []), # randomly crashes app, to be reworked/fixed
# ("accounts_remainingAccountCapacity", []), # randomly crashes app, to be reworked/fixed # ("accounts_remainingAccountCapacity", []), # randomly crashes app, to be reworked/fixed
("multiaccounts_getIdentityImages", [user_1.private_key]), ("multiaccounts_getIdentityImages", [user_1.private_key]),
], ],
) )
def test_(self, method, params): def test_(self, method, params):

View File

@ -13,7 +13,6 @@ class TestAppGeneral(StatusBackendTestCase):
"method, params", "method, params",
[ [
("appgeneral_getCurrencies", []), ("appgeneral_getCurrencies", []),
], ],
) )
def test_(self, method, params): def test_(self, method, params):

View File

@ -11,23 +11,19 @@ from clients.services.wallet import WalletService
from clients.signals import SignalClient, SignalType from clients.signals import SignalClient, SignalType
from clients.status_backend import RpcClient, StatusBackend from clients.status_backend import RpcClient, StatusBackend
from conftest import option 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: class StatusDTestCase:
network_id = 31337 network_id = 31337
def setup_method(self): def setup_method(self):
self.rpc_client = RpcClient( self.rpc_client = RpcClient(option.rpc_url_statusd)
option.rpc_url_statusd
)
class StatusBackendTestCase: class StatusBackendTestCase:
await_signals = [ await_signals = [SignalType.NODE_LOGIN.value]
SignalType.NODE_LOGIN.value
]
network_id = 31337 network_id = 31337
@ -59,8 +55,7 @@ class WalletTestCase(StatusBackendTestCase):
if key in transfer_tx_data: if key in transfer_tx_data:
transfer_tx_data[key] = new_value transfer_tx_data[key] = new_value
else: else:
logging.info( logging.info(f"Warning: The key '{key}' does not exist in the transferTx parameters and will be ignored.")
f"Warning: The key '{key}' does not exist in the transferTx parameters and will be ignored.")
params = [ params = [
{ {
"fromAddress": user_1.address, "fromAddress": user_1.address,
@ -74,7 +69,7 @@ class WalletTestCase(StatusBackendTestCase):
{ {
"bridgeName": "Transfer", "bridgeName": "Transfer",
"chainID": 31337, "chainID": 31337,
"transferTx": transfer_tx_data "transferTx": transfer_tx_data,
} }
], ],
f"{option.password}", f"{option.password}",
@ -87,8 +82,7 @@ class WalletTestCase(StatusBackendTestCase):
tx_hash = None tx_hash = None
self.rpc_client.verify_is_valid_json_rpc_response(response) self.rpc_client.verify_is_valid_json_rpc_response(response)
try: try:
tx_hash = response.json( tx_hash = response.json()["result"]["hashes"][str(self.network_id)][0]
)["result"]["hashes"][str(self.network_id)][0]
except (KeyError, json.JSONDecodeError): except (KeyError, json.JSONDecodeError):
raise Exception(response.content) raise Exception(response.content)
return tx_hash return tx_hash
@ -102,7 +96,7 @@ class TransactionTestCase(WalletTestCase):
class EthRpcTestCase(WalletTestCase): class EthRpcTestCase(WalletTestCase):
@pytest.fixture(autouse=True, scope='class') @pytest.fixture(autouse=True, scope="class")
def tx_data(self): def tx_data(self):
tx_hash = self.send_valid_multi_transaction() tx_hash = self.send_valid_multi_transaction()
self.wait_until_tx_not_pending(tx_hash) self.wait_until_tx_not_pending(tx_hash)
@ -133,11 +127,10 @@ class EthRpcTestCase(WalletTestCase):
response = self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request(method, params)
start_time = time.time() start_time = time.time()
while response.json()["result"]["isPending"] == True: while response.json()["result"]["isPending"] is True:
time_passed = time.time() - start_time time_passed = time.time() - start_time
if time_passed >= timeout: if time_passed >= timeout:
raise TimeoutError( raise TimeoutError(f"Tx {tx_hash} is still pending after {timeout} seconds")
f"Tx {tx_hash} is still pending after {timeout} seconds")
time.sleep(0.5) time.sleep(0.5)
response = self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request(method, params)
return response.json()["result"]["tx"] return response.json()["result"]["tx"]
@ -159,23 +152,36 @@ class NetworkConditionTestCase:
@contextmanager @contextmanager
def add_latency(self): def add_latency(self):
pass try:
#TODO: To be implemented when we have docker exec capability # TODO: To be implemented when we have docker exec capability
yield
finally:
pass
@contextmanager @contextmanager
def add_packet_loss(self): def add_packet_loss(self):
pass try:
#TODO: To be implemented when we have docker exec capability # TODO: To be implemented when we have docker exec capability
yield
finally:
pass
@contextmanager @contextmanager
def add_low_bandwith(self): def add_low_bandwith(self):
pass try:
#TODO: To be implemented when we have docker exec capability # TODO: To be implemented when we have docker exec capability
yield
finally:
pass
@contextmanager @contextmanager
def node_pause(self, node): def node_pause(self, node):
pass try:
#TODO: To be implemented when we have docker exec capability # TODO: To be implemented when we have docker exec capability
yield
finally:
pass
class OneToOneMessageTestCase(NetworkConditionTestCase): class OneToOneMessageTestCase(NetworkConditionTestCase):
@ -186,13 +192,15 @@ class OneToOneMessageTestCase(NetworkConditionTestCase):
backend.start_messenger() backend.start_messenger()
return backend return backend
def validate_signal_event_against_response(self, signal_event, fields_to_validate, expected_message): def validate_signal_event_against_response(self, signal_event, fields_to_validate, expected_message):
expected_message_id = expected_message.get("id") expected_message_id = expected_message.get("id")
signal_event_messages = signal_event.get("event", {}).get("messages") signal_event_messages = signal_event.get("event", {}).get("messages")
assert len(signal_event_messages) > 0, "No messages found in the signal event" 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" assert message, f"Message with ID {expected_message_id} not found in the signal event"
message_mismatch = [] message_mismatch = []
@ -200,17 +208,14 @@ class OneToOneMessageTestCase(NetworkConditionTestCase):
response_value = expected_message[response_field] response_value = expected_message[response_field]
event_value = message[event_field] event_value = message[event_field]
if response_value != event_value: if response_value != event_value:
message_mismatch.append( message_mismatch.append(f"Field '{response_field}': Expected '{response_value}', Found '{event_value}'")
f"Field '{response_field}': Expected '{response_value}', Found '{event_value}'"
)
if not message_mismatch: if not message_mismatch:
return return
raise AssertionError( raise AssertionError(
"Some Sender RPC responses are not matching the signals received by the receiver.\n" "Some Sender RPC responses are not matching the signals received by the receiver.\n"
"Details of mismatches:\n" + "Details of mismatches:\n" + "\n".join(message_mismatch)
"\n".join(message_mismatch)
) )
def get_message_by_content_type(self, response, content_type): def get_message_by_content_type(self, response, content_type):

View File

@ -2,14 +2,14 @@ from time import sleep
from uuid import uuid4 from uuid import uuid4
import pytest import pytest
from test_cases import OneToOneMessageTestCase from test_cases import OneToOneMessageTestCase
from constants import DEFAULT_DISPLAY_NAME from resources.constants import DEFAULT_DISPLAY_NAME
from clients.signals import SignalType from clients.signals import SignalType
from resources.enums import MessageContentType from resources.enums import MessageContentType
@pytest.mark.rpc @pytest.mark.rpc
class TestContactRequests(OneToOneMessageTestCase): class TestContactRequests(OneToOneMessageTestCase):
@pytest.mark.dependency(name="test_contact_request_baseline") @pytest.mark.dependency(name="test_contact_request_baseline")
def test_contact_request_baseline(self, execution_number=1): 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()}" message_text = f"test_contact_request_{execution_number}_{uuid4()}"
sender = self.initialize_backend(await_signals=await_signals) 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_sender = sender.get_pubkey(DEFAULT_DISPLAY_NAME)
pk_receiver = receiver.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) response = sender.send_contact_request(pk_receiver, message_text)
expected_message = self.get_message_by_content_type(response, content_type=MessageContentType.CONTACT_REQUEST.value) 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 = [] signal_messages_texts = []
if "messages" in messages_new_event.get("event", {}): if "messages" in messages_new_event.get("event", {}):
signal_messages_texts.extend( signal_messages_texts.extend(message["text"] for message in messages_new_event["event"]["messages"] if "text" in message)
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" 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( self.validate_signal_event_against_response(
signal_event=messages_new_event, signal_event=messages_new_event,
fields_to_validate={"text": "text"}, 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.parametrize("execution_number", range(10))
@pytest.mark.dependency(depends=["test_contact_request_baseline"]) @pytest.mark.dependency(depends=["test_contact_request_baseline"])
def test_multiple_contact_requests(self, execution_number): def test_multiple_contact_requests(self, execution_number):
@ -84,7 +90,7 @@ class TestContactRequests(OneToOneMessageTestCase):
SignalType.MESSAGE_DELIVERED.value, SignalType.MESSAGE_DELIVERED.value,
] ]
sender = self.initialize_backend(await_signals=await_signals) 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) pk_receiver = receiver.get_pubkey(DEFAULT_DISPLAY_NAME)
with self.node_pause(receiver): with self.node_pause(receiver):

View File

@ -35,13 +35,17 @@ class TestEth(EthRpcTestCase):
self.rpc_client.rpc_valid_request("ethclient_suggestGasPrice", [self.network_id]) self.rpc_client.rpc_valid_request("ethclient_suggestGasPrice", [self.network_id])
def test_header_by_number(self, tx_data): def test_header_by_number(self, tx_data):
response = self.rpc_client.rpc_valid_request("ethclient_headerByNumber", response = self.rpc_client.rpc_valid_request("ethclient_headerByNumber", [self.network_id, tx_data.block_number])
[self.network_id, tx_data.block_number])
validate_header(response.json()["result"], tx_data.block_number, tx_data.block_hash) validate_header(response.json()["result"], tx_data.block_number, tx_data.block_hash)
def test_block_by_number(self, tx_data): def test_block_by_number(self, tx_data):
response = self.rpc_client.rpc_valid_request("ethclient_blockByNumber", [self.network_id, tx_data.block_number]) 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): def test_header_by_hash(self, tx_data):
response = self.rpc_client.rpc_valid_request("ethclient_headerByHash", [self.network_id, tx_data.block_hash]) 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): def test_block_by_hash(self, tx_data):
response = self.rpc_client.rpc_valid_request("ethclient_blockByHash", [self.network_id, tx_data.block_hash]) 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): def test_transaction_by_hash(self, tx_data):
response = self.rpc_client.rpc_valid_request("ethclient_transactionByHash", [self.network_id, tx_data.tx_hash]) 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): def test_transaction_receipt(self, tx_data):
response = self.rpc_client.rpc_valid_request("ethclient_transactionReceipt", [self.network_id, tx_data.tx_hash]) 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,
)

View File

@ -3,6 +3,7 @@ import pytest
from clients.signals import SignalType from clients.signals import SignalType
import os import os
@pytest.mark.create_account @pytest.mark.create_account
@pytest.mark.rpc @pytest.mark.rpc
class TestInitialiseApp: class TestInitialiseApp:
@ -11,7 +12,6 @@ class TestInitialiseApp:
def test_init_app(self): def test_init_app(self):
await_signals = [ await_signals = [
SignalType.MEDIASERVER_STARTED.value, SignalType.MEDIASERVER_STARTED.value,
SignalType.NODE_STARTED.value, SignalType.NODE_STARTED.value,
SignalType.NODE_READY.value, SignalType.NODE_READY.value,
@ -24,13 +24,18 @@ class TestInitialiseApp:
assert backend_client is not None assert backend_client is not None
backend_client.verify_json_schema( 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.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.verify_json_schema(
backend_client.wait_for_signal(SignalType.NODE_READY.value), "signal_node_ready") backend_client.wait_for_signal(SignalType.NODE_READY.value),
backend_client.verify_json_schema( "signal_node_ready",
backend_client.wait_for_login(), "signal_node_login") )
backend_client.verify_json_schema(backend_client.wait_for_login(), "signal_node_login")
@pytest.mark.rpc @pytest.mark.rpc
@ -45,7 +50,6 @@ class TestInitializeLogging:
def test_no_logging(self, tmp_path): def test_no_logging(self, tmp_path):
self.check_logs(tmp_path, log_enabled=False, api_logging_enabled=False) self.check_logs(tmp_path, log_enabled=False, api_logging_enabled=False)
def assert_file_first_line(self, path, pattern: str, expected: bool): def assert_file_first_line(self, path, pattern: str, expected: bool):
assert os.path.exists(path) == expected assert os.path.exists(path) == expected
if not expected: if not expected:
@ -63,20 +67,20 @@ class TestInitializeLogging:
logs_dir.mkdir() logs_dir.mkdir()
backend = StatusBackend() backend = StatusBackend()
backend.api_valid_request("InitializeApplication", { backend.api_valid_request(
"dataDir": str(data_dir), "InitializeApplication",
"logDir": str(logs_dir), {
"logEnabled": log_enabled, "dataDir": str(data_dir),
"apiLoggingEnabled": api_logging_enabled, "logDir": str(logs_dir),
}) "logEnabled": log_enabled,
"apiLoggingEnabled": api_logging_enabled,
},
)
self.assert_file_first_line( self.assert_file_first_line(logs_dir / "geth.log", pattern="logging initialised", expected=log_enabled)
logs_dir / "geth.log",
pattern="logging initialised",
expected=log_enabled)
self.assert_file_first_line( self.assert_file_first_line(
logs_dir / "api.log", logs_dir / "api.log",
pattern='"method": "InitializeApplication"', pattern='"method": "InitializeApplication"',
expected=api_logging_enabled) expected=api_logging_enabled,
)

View File

@ -1,8 +1,7 @@
import re import re
import time
from test_cases import StatusBackend from test_cases import StatusBackend
import pytest import pytest
import os
@pytest.mark.rpc @pytest.mark.rpc
@pytest.mark.skip("waiting for status-backend to be executed on the same host/container") @pytest.mark.skip("waiting for status-backend to be executed on the same host/container")
@ -27,7 +26,10 @@ class TestLogging:
# Configure logging # Configure logging
backend_client.rpc_valid_request("wakuext_setLogLevel", [{"logLevel": "ERROR"}]) 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) # Re-login (logging settings take effect after re-login)
backend_client.logout() backend_client.logout()
@ -36,19 +38,23 @@ class TestLogging:
# Test logging # Test logging
backend_client.rpc_valid_request("wakuext_logTest") backend_client.rpc_valid_request("wakuext_logTest")
self.expect_logs(tmp_path / "geth.log", "test message", [ self.expect_logs(
r"DEBUG\s+test1\.test2", tmp_path / "geth.log",
r"INFO\s+test1\.test2", "test message",
r"INFO\s+test1\.test2\.test3", [
r"WARN\s+test1\.test2", r"DEBUG\s+test1\.test2",
r"WARN\s+test1\.test2\.test3", r"INFO\s+test1\.test2",
r"ERROR\s+test1", r"INFO\s+test1\.test2\.test3",
r"ERROR\s+test1\.test2", r"WARN\s+test1\.test2",
r"ERROR\s+test1\.test2\.test3", 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): 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() log_content = f.read()
filtered_logs = [line for line in log_content.splitlines() if filter_keyword in line] filtered_logs = [line for line in log_content.splitlines() if filter_keyword in line]

View File

@ -2,10 +2,11 @@ from time import sleep
from uuid import uuid4 from uuid import uuid4
import pytest import pytest
from test_cases import OneToOneMessageTestCase from test_cases import OneToOneMessageTestCase
from constants import DEFAULT_DISPLAY_NAME from resources.constants import DEFAULT_DISPLAY_NAME
from clients.signals import SignalType from clients.signals import SignalType
from resources.enums import MessageContentType from resources.enums import MessageContentType
@pytest.mark.rpc @pytest.mark.rpc
class TestOneToOneMessages(OneToOneMessageTestCase): class TestOneToOneMessages(OneToOneMessageTestCase):
@ -33,11 +34,15 @@ class TestOneToOneMessages(OneToOneMessageTestCase):
sleep(0.01) sleep(0.01)
for i, expected_message in enumerate(sent_messages): 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( self.validate_signal_event_against_response(
signal_event=messages_new_event, signal_event=messages_new_event,
fields_to_validate={"text": "text"}, fields_to_validate={"text": "text"},
expected_message=expected_message expected_message=expected_message,
) )
@pytest.mark.dependency(depends=["test_one_to_one_message_baseline"]) @pytest.mark.dependency(depends=["test_one_to_one_message_baseline"])
@ -73,5 +78,3 @@ class TestOneToOneMessages(OneToOneMessageTestCase):
sleep(30) sleep(30)
self.receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=message_text) self.receiver.find_signal_containing_pattern(SignalType.MESSAGES_NEW.value, event_pattern=message_text)
self.sender.wait_for_signal("messages.delivered") self.sender.wait_for_signal("messages.delivered")

View File

@ -3,10 +3,11 @@ import uuid
import pytest import pytest
from conftest import option 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 test_cases import StatusBackendTestCase
from clients.signals import SignalType from clients.signals import SignalType
@pytest.mark.rpc @pytest.mark.rpc
@pytest.mark.transaction @pytest.mark.transaction
@pytest.mark.wallet @pytest.mark.wallet
@ -19,6 +20,7 @@ class TestTransactionFromRoute(StatusBackendTestCase):
SignalType.WALLET_TRANSACTION_STATUS_CHANGED.value, SignalType.WALLET_TRANSACTION_STATUS_CHANGED.value,
SignalType.WALLET_ROUTER_TRANSACTIONS_SENT.value, SignalType.WALLET_ROUTER_TRANSACTIONS_SENT.value,
] ]
def test_tx_from_route(self): def test_tx_from_route(self):
_uuid = str(uuid.uuid4()) _uuid = str(uuid.uuid4())
@ -39,28 +41,22 @@ class TestTransactionFromRoute(StatusBackendTestCase):
"disabledFromChainIDs": [10, 42161], "disabledFromChainIDs": [10, 42161],
"disabledToChainIDs": [10, 42161], "disabledToChainIDs": [10, 42161],
"gasFeeMode": 1, "gasFeeMode": 1,
"fromLockedAmount": {} "fromLockedAmount": {},
} }
] ]
response = self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request(method, params)
routes = self.rpc_client.wait_for_signal(SignalType.WALLET_SUGGESTED_ROUTES.value) 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" method = "wallet_buildTransactionsFromRoute"
params = [ params = [{"uuid": _uuid, "slippagePercentage": 0}]
{
"uuid": _uuid,
"slippagePercentage": 0
}
]
response = self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request(method, params)
wallet_router_sign_transactions = self.rpc_client.wait_for_signal( wallet_router_sign_transactions = self.rpc_client.wait_for_signal(SignalType.WALLET_ROUTER_SIGN_TRANSACTIONS.value)
SignalType.WALLET_ROUTER_SIGN_TRANSACTIONS.value)
assert wallet_router_sign_transactions['event']['signingDetails']['signOnKeycard'] == False assert wallet_router_sign_transactions["event"]["signingDetails"]["signOnKeycard"] is False
transaction_hashes = wallet_router_sign_transactions['event']['signingDetails']['hashes'] transaction_hashes = wallet_router_sign_transactions["event"]["signingDetails"]["hashes"]
assert transaction_hashes, "Transaction hashes are empty!" assert transaction_hashes, "Transaction hashes are empty!"
@ -69,36 +65,28 @@ class TestTransactionFromRoute(StatusBackendTestCase):
for hash in transaction_hashes: for hash in transaction_hashes:
method = "wallet_signMessage" method = "wallet_signMessage"
params = [ params = [hash, user_1.address, option.password]
hash,
user_1.address,
option.password
]
response = self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request(method, params)
if response.json()["result"].startswith("0x"): result = response.json().get("result")
tx_signature = response.json()["result"][2:] assert result and result.startswith("0x"), f"Invalid transaction signature for hash {hash}: {result}"
tx_signature = result[2:]
signature = { signature = {
"r": tx_signature[:64], "r": tx_signature[:64],
"s": tx_signature[64:128], "s": tx_signature[64:128],
"v": tx_signature[128:] "v": tx_signature[128:],
} }
tx_signatures[hash] = signature tx_signatures[hash] = signature
method = "wallet_sendRouterTransactionsWithSignatures" method = "wallet_sendRouterTransactionsWithSignatures"
params = [ params = [{"uuid": _uuid, "Signatures": tx_signatures}]
{
"uuid": _uuid,
"Signatures": tx_signatures
}
]
response = self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request(method, params)
tx_status = self.rpc_client.wait_for_signal( tx_status = self.rpc_client.wait_for_signal(SignalType.WALLET_TRANSACTION_STATUS_CHANGED.value)
SignalType.WALLET_TRANSACTION_STATUS_CHANGED.value)
assert tx_status["event"]["chainId"] == 31337 assert tx_status["event"]["chainId"] == 31337
assert tx_status["event"]["status"] == "Success" assert tx_status["event"]["status"] == "Success"

View File

@ -15,7 +15,10 @@ class TestRpc(StatusBackendTestCase):
"method, params", "method, params",
[ [
("wakuext_peers", []), ("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): def test_(self, method, params):
@ -41,17 +44,11 @@ class TestRpcMessaging(StatusBackendTestCase):
# get chat public key # get chat public key
for user in self.user_1, self.user_2: for user in self.user_1, self.user_2:
response = self.rpc_client.rpc_request( response = self.rpc_client.rpc_request("accounts_getAccounts", [], _id, url=user.rpc_url)
"accounts_getAccounts", [], _id, url=user.rpc_url
)
self.rpc_client.verify_is_valid_json_rpc_response(response) self.rpc_client.verify_is_valid_json_rpc_response(response)
user.chat_public_key = next( 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, None,
) )

View File

@ -12,15 +12,22 @@ class TestProfile(StatusBackendTestCase):
[ [
("wakuext_setDisplayName", ["new valid username"]), ("wakuext_setDisplayName", ["new valid username"]),
("wakuext_setBio", ["some valid bio"]), ("wakuext_setBio", ["some valid bio"]),
("wakuext_setCustomizationColor", [{'customizationColor': 'magenta', (
'keyUid': '0xea42dd9a4e668b0b76c7a5210ca81576d51cd19cdd0f6a0c22196219dc423f29'}]), "wakuext_setCustomizationColor",
[
{
"customizationColor": "magenta",
"keyUid": "0xea42dd9a4e668b0b76c7a5210ca81576d51cd19cdd0f6a0c22196219dc423f29",
}
],
),
("wakuext_setUserStatus", [3, ""]), ("wakuext_setUserStatus", [3, ""]),
("wakuext_setSyncingOnMobileNetwork", [{"enabled": False}]), ("wakuext_setSyncingOnMobileNetwork", [{"enabled": False}]),
("wakuext_togglePeerSyncing", [{"enabled": True}]), ("wakuext_togglePeerSyncing", [{"enabled": True}]),
("wakuext_backupData", []), ("wakuext_backupData", []),
], ],
) )
def test_(self, method, params): def test_wakuext_(self, method, params):
_id = str(random.randint(1, 8888)) _id = str(random.randint(1, 8888))
self.rpc_client.rpc_valid_request(method, params, _id) self.rpc_client.rpc_valid_request(method, params, _id)
@ -32,11 +39,21 @@ class TestProfile(StatusBackendTestCase):
("settings_saveSetting", "preview-privacy?", False, True), ("settings_saveSetting", "preview-privacy?", False, True),
("settings_saveSetting", "default-sync-period", 777600, 259200), ("settings_saveSetting", "default-sync-period", 777600, 259200),
("settings_saveSetting", "appearance", 0, 1), ("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)) _id = str(random.randint(1, 8888))
logging.info("Step: check that %s is %s by default " % (setting_name, default_value)) 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", "remember-syncing-choice?", True),
("settings_saveSetting", "remote-push-notifications-enabled?", True), ("settings_saveSetting", "remote-push-notifications-enabled?", True),
("settings_saveSetting", "syncing-on-mobile-network?", True), ("settings_saveSetting", "syncing-on-mobile-network?", True),
## advanced token settings # advanced token settings
("settings_saveSetting", "wallet-set-up-passed?", True), ("settings_saveSetting", "wallet-set-up-passed?", True),
("settings_saveSetting", "opensea-enabled?", True), ("settings_saveSetting", "opensea-enabled?", True),
("settings_saveSetting", "waku-bloom-filter-mode", True), ("settings_saveSetting", "waku-bloom-filter-mode", True),
("settings_saveSetting", "webview-allow-permission-requests?", True), ("settings_saveSetting", "webview-allow-permission-requests?", True),
("settings_saveSetting", "token-group-by-community?", True), ("settings_saveSetting", "token-group-by-community?", True),
("settings_saveSetting", "display-assets-below-balance?", 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-collection?", True),
("settings_saveSetting", "collectible-group-by-community?", True), ("settings_saveSetting", "collectible-group-by-community?", True),
], ],
@ -89,7 +106,11 @@ class TestProfile(StatusBackendTestCase):
[ [
("settings_saveSetting", "send-status-updates?", False), ("settings_saveSetting", "send-status-updates?", False),
("settings_saveSetting", "link-preview-request-enabled", 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), ("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) self.rpc_client.rpc_valid_request(method, [setting_name, set_value], _id)
response = self.rpc_client.rpc_valid_request("settings_getSettings", []) response = self.rpc_client.rpc_valid_request("settings_getSettings", [])
assert setting_name not in response.json()["result"] assert setting_name not in response.json()["result"]

View File

@ -1,9 +1,9 @@
import json import json
import random import random
import wallet_utils from utils import wallet_utils
import pytest import pytest
from constants import user_1 from resources.constants import user_1
from test_cases import StatusBackendTestCase from test_cases import StatusBackendTestCase
from clients.signals import SignalType from clients.signals import SignalType
@ -11,10 +11,12 @@ EventActivityFilteringDone = "wallet-activity-filtering-done"
EventActivityFilteringUpdate = "wallet-activity-filtering-entries-updated" EventActivityFilteringUpdate = "wallet-activity-filtering-entries-updated"
EventActivitySessionUpdated = "wallet-activity-session-updated" EventActivitySessionUpdated = "wallet-activity-session-updated"
def validate_entry(entry, tx_data): def validate_entry(entry, tx_data):
assert entry["transactions"][0]["chainId"] == tx_data["tx_status"]["chainId"] assert entry["transactions"][0]["chainId"] == tx_data["tx_status"]["chainId"]
assert entry["transactions"][0]["hash"] == tx_data["tx_status"]["hash"] assert entry["transactions"][0]["hash"] == tx_data["tx_status"]["hash"]
@pytest.mark.wallet @pytest.mark.wallet
@pytest.mark.rpc @pytest.mark.rpc
class TestWalletActivitySession(StatusBackendTestCase): class TestWalletActivitySession(StatusBackendTestCase):
@ -25,64 +27,88 @@ class TestWalletActivitySession(StatusBackendTestCase):
"wallet.router.sign-transactions", "wallet.router.sign-transactions",
"wallet.router.sending-transactions-started", "wallet.router.sending-transactions-started",
"wallet.transaction.status-changed", "wallet.transaction.status-changed",
"wallet.router.transactions-sent"] "wallet.router.transactions-sent",
]
def setup_method(self): def setup_method(self):
self.request_id = str(random.randint(1, 8888)) self.request_id = str(random.randint(1, 8888))
def test_wallet_start_activity_filter_session(self): 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 # Set up a transactions for account before starting session
tx_data.append(wallet_utils.send_router_transaction(self.rpc_client)) tx_data.append(wallet_utils.send_router_transaction(self.rpc_client))
# Start activity session # Start activity session
method = "wallet_startActivityFilterSessionV2" method = "wallet_startActivityFilterSessionV2"
params = [[user_1.address], [self.network_id], params = [
{"period": {"startTimestamp": 0, "endTimestamp": 0}, "types": [], "statuses": [], [user_1.address],
"counterpartyAddresses": [], "assets": [], "collectibles": [], "filterOutAssets": False, [self.network_id],
"filterOutCollectibles": False}, 10] {
self.rpc_client.prepare_wait_for_signal("wallet", 1, lambda signal : signal["event"]["type"] == EventActivityFilteringDone) "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) 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"]) sessionID = int(response.json()["result"])
assert sessionID > 0 assert sessionID > 0
# Check response event # Check response event
assert int(event_response['requestId']) == sessionID assert int(event_response["requestId"]) == sessionID
message = json.loads(event_response['message'].replace("'", "\"")) message = json.loads(event_response["message"].replace("'", '"'))
assert int(message['errorCode']) == 1 assert int(message["errorCode"]) == 1
assert len(message['activities']) > 0 # Should have at least 1 entry assert len(message["activities"]) > 0 # Should have at least 1 entry
# First activity entry should match last sent transaction # 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 # 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)) tx_data.append(wallet_utils.send_router_transaction(self.rpc_client))
print(tx_data[-1]) 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 # Check response event
assert int(event_response['requestId']) == sessionID assert int(event_response["requestId"]) == sessionID
message = json.loads(event_response['message'].replace("'", "\"")) message = json.loads(event_response["message"].replace("'", '"'))
assert message['hasNewOnTop'] # New entries reported assert message["hasNewOnTop"] # New entries reported
# Reset activity session # Reset activity session
method = "wallet_resetActivityFilterSession" method = "wallet_resetActivityFilterSession"
params = [sessionID, 10] 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) 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 # Check response event
assert int(event_response['requestId']) == sessionID assert int(event_response["requestId"]) == sessionID
message = json.loads(event_response['message'].replace("'", "\"")) message = json.loads(event_response["message"].replace("'", '"'))
assert int(message['errorCode']) == 1 assert int(message["errorCode"]) == 1
assert len(message['activities']) > 1 # Should have at least 2 entries assert len(message["activities"]) > 1 # Should have at least 2 entries
# First activity entry should match last sent transaction # 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 # 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])

View File

@ -5,8 +5,8 @@ import jsonschema
import pytest import pytest
from conftest import option from conftest import option
from constants import user_1 from resources.constants import user_1
from test_cases import StatusBackendTestCase, TransactionTestCase, StatusDTestCase from test_cases import StatusBackendTestCase, TransactionTestCase
@pytest.mark.wallet @pytest.mark.wallet
@ -18,12 +18,12 @@ class TestTransactionRpc(TransactionTestCase):
"method, params", "method, params",
[ [
( (
"wallet_checkRecentHistoryForChainIDs", "wallet_checkRecentHistoryForChainIDs",
[[31337], ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"]], [[31337], ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"]],
), ),
( (
"wallet_getPendingTransactionsForIdentities", "wallet_getPendingTransactionsForIdentities",
[[{"chainId": None, "hash": None}]], [[{"chainId": None, "hash": None}]],
), ),
], ],
) )
@ -42,35 +42,41 @@ class TestTransactionRpc(TransactionTestCase):
self.rpc_client.verify_is_valid_json_rpc_response(response) self.rpc_client.verify_is_valid_json_rpc_response(response)
# how to create schema: # how to create schema:
# from schema_builder import CustomSchemaBuilder # from utils.schema_builder import CustomSchemaBuilder
# CustomSchemaBuilder(method).create_schema(response.json()) # 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)) jsonschema.validate(instance=response.json(), schema=json.load(schema))
@pytest.mark.parametrize( @pytest.mark.parametrize(
"method, changed_values, expected_error_code, expected_error_text", "method, changed_values, expected_error_code, expected_error_text",
[ [
( (
"transferTx_value_not_enough_balance", "transferTx_value_not_enough_balance",
{'value': '0x21e438ea8139cd35004'}, -32000, "Insufficient funds for gas", {"value": "0x21e438ea8139cd35004"},
-32000,
"Insufficient funds for gas",
), ),
( (
"transferTx_from_from_invalid_string", "transferTx_from_from_invalid_string",
{'from': 'some_invalid_address'}, -32602, "cannot unmarshal hex string without 0x prefix", {"from": "some_invalid_address"},
-32602,
"cannot unmarshal hex string without 0x prefix",
), ),
], ],
) )
def test_create_multi_transaction_validation(self, method, def test_create_multi_transaction_validation(self, method, changed_values, expected_error_code, expected_error_text):
changed_values,
expected_error_code, expected_error_text):
response = self.wallet_create_multi_transaction(**changed_values) response = self.wallet_create_multi_transaction(**changed_values)
self.rpc_client.verify_is_json_rpc_error(response) self.rpc_client.verify_is_json_rpc_error(response)
actual_error_code, actual_error_text = response.json()['error']['code'], response.json()['error']['message'] actual_error_code, actual_error_text = (
assert expected_error_code == actual_error_code, \ response.json()["error"]["code"],
f"got code: {actual_error_code} instead of expected: {expected_error_code}" response.json()["error"]["message"],
assert expected_error_text in actual_error_text, \ )
f"got error: {actual_error_text} that does not include: {expected_error_text}" 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") self.rpc_client.verify_json_schema(response.json(), "wallet_createMultiTransaction/transferTx_error")
@ -87,19 +93,69 @@ class TestRpc(StatusBackendTestCase):
("wallet_getTokenList", []), ("wallet_getTokenList", []),
("wallet_getCryptoOnRamps", []), ("wallet_getCryptoOnRamps", []),
("wallet_getCachedCurrencyFormats", []), ("wallet_getCachedCurrencyFormats", []),
("wallet_fetchPrices", (
[["WETH9", "USDC", "ZEENUS", "EUROC", "WEENUS", "XEENUS", "WETH", "ETH", "STT", "UNI", "YEENUS", "DAI"], "wallet_fetchPrices",
["usd"]]), [
[
("wallet_fetchMarketValues", "WETH9",
[["WETH9", "USDC", "ZEENUS", "EUROC", "WEENUS", "XEENUS", "WETH", "ETH", "STT", "UNI", "YEENUS", "DAI"], "USDC",
"usd"]), "ZEENUS",
("wallet_fetchTokenDetails", "EUROC",
[["WETH9", "USDC", "ZEENUS", "EUROC", "WEENUS", "XEENUS", "WETH", "ETH", "STT", "UNI", "YEENUS", "DAI"]]), "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_checkRecentHistoryForChainIDs", [[31337], [user_1.address]]),
("wallet_getWalletConnectActiveSessions", [1728995277]), ("wallet_getWalletConnectActiveSessions", [1728995277]),
("wallet_stopSuggestedRoutesAsyncCalculation", []), ("wallet_stopSuggestedRoutesAsyncCalculation", []),
] ],
) )
def test_(self, method, params): def test_(self, method, params):
_id = str(random.randint(1, 8888)) _id = str(random.randint(1, 8888))

View File

@ -3,7 +3,7 @@ import random
import pytest import pytest
from constants import user_1 from resources.constants import user_1
from test_cases import StatusBackendTestCase from test_cases import StatusBackendTestCase
@ -13,8 +13,7 @@ class TestWalletSignals(StatusBackendTestCase):
def setup_class(self): def setup_class(self):
self.await_signals.append("wallet") self.await_signals.append("wallet")
super().setup_class(self) super().setup_class()
def setup_method(self): def setup_method(self):
self.request_id = str(random.randint(1, 8888)) self.request_id = str(random.randint(1, 8888))
@ -22,26 +21,49 @@ class TestWalletSignals(StatusBackendTestCase):
@pytest.mark.skip @pytest.mark.skip
def test_wallet_get_owned_collectibles_async(self): def test_wallet_get_owned_collectibles_async(self):
method = "wallet_getOwnedCollectiblesAsync" method = "wallet_getOwnedCollectiblesAsync"
params = [0, [self.network_id, ], [user_1.address], None, 0, 25, 1, params = [
{"fetch-type": 2, "max-cache-age-seconds": 3600}] 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) self.rpc_client.rpc_valid_request(method, params, self.request_id)
signal_response = self.rpc_client.wait_for_signal("wallet", timeout=60) signal_response = self.rpc_client.wait_for_signal("wallet", timeout=60)
self.rpc_client.verify_json_schema(signal_response, method) self.rpc_client.verify_json_schema(signal_response, method)
assert signal_response['event']['type'] == "wallet-owned-collectibles-filtering-done" assert signal_response["event"]["type"] == "wallet-owned-collectibles-filtering-done"
message = json.loads(signal_response['event']['message'].replace("'", "\"")) message = json.loads(signal_response["event"]["message"].replace("'", '"'))
assert user_1.address in message['ownershipStatus'].keys() assert user_1.address in message["ownershipStatus"].keys()
@pytest.mark.skip @pytest.mark.skip
def test_wallet_filter_activity_async(self): def test_wallet_filter_activity_async(self):
method = "wallet_filterActivityAsync" method = "wallet_filterActivityAsync"
params = [1, [user_1.address], [self.network_id], params = [
{"period": {"startTimestamp": 0, "endTimestamp": 0}, "types": [], "statuses": [], 1,
"counterpartyAddresses": [], "assets": [], "collectibles": [], "filterOutAssets": False, [user_1.address],
"filterOutCollectibles": False}, 0, 50] [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) self.rpc_client.rpc_valid_request(method, params, self.request_id)
signal_response = self.rpc_client.wait_for_signal("wallet", timeout=60) signal_response = self.rpc_client.wait_for_signal("wallet", timeout=60)
self.rpc_client.verify_json_schema(signal_response, method) self.rpc_client.verify_json_schema(signal_response, method)
assert signal_response['event']['type'] == "wallet-activity-filtering-done" assert signal_response["event"]["type"] == "wallet-activity-filtering-done"
message = json.loads(signal_response['event']['message'].replace("'", "\"")) message = json.loads(signal_response["event"]["message"].replace("'", '"'))
for item in message['activities']: for item in message["activities"]:
assert user_1.address in item['sender'], item['recipient'] assert user_1.address in item["sender"], item["recipient"]

View File

View File

@ -2,19 +2,17 @@ import json
import logging import logging
import jsonschema import jsonschema
import uuid import uuid
import threading
import time
from conftest import option 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): def verify_json_schema(response, method):
with open(f"{option.base_dir}/schemas/{method}", "r") as schema: with open(f"{option.base_dir}/schemas/{method}", "r") as schema:
jsonschema.validate(instance=response, jsonschema.validate(instance=response, schema=json.load(schema))
schema=json.load(schema))
def get_suggested_routes(rpc_client, **kwargs): def get_suggested_routes(rpc_client, **kwargs):
_uuid = str(uuid.uuid4()) _uuid = str(uuid.uuid4())
amount_in = "0xde0b6b3a7640000" amount_in = "0xde0b6b3a7640000"
@ -33,47 +31,44 @@ def get_suggested_routes(rpc_client, **kwargs):
"disabledFromChainIDs": [10, 42161], "disabledFromChainIDs": [10, 42161],
"disabledToChainIDs": [10, 42161], "disabledToChainIDs": [10, 42161],
"gasFeeMode": 1, "gasFeeMode": 1,
"fromLockedAmount": {} "fromLockedAmount": {},
} }
for key, new_value in kwargs.items(): for key, new_value in kwargs.items():
if key in input_params: if key in input_params:
input_params[key] = new_value input_params[key] = new_value
else: else:
logging.info( logging.info(f"Warning: The key '{key}' does not exist in the input_params parameters and will be ignored.")
f"Warning: The key '{key}' does not exist in the input_params parameters and will be ignored.")
params = [input_params] params = [input_params]
rpc_client.prepare_wait_for_signal("wallet.suggested.routes", 1) rpc_client.prepare_wait_for_signal("wallet.suggested.routes", 1)
_ = rpc_client.rpc_valid_request(method, params) _ = rpc_client.rpc_valid_request(method, params)
routes = rpc_client.wait_for_signal("wallet.suggested.routes") 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): def build_transactions_from_route(rpc_client, uuid, **kwargs):
method = "wallet_buildTransactionsFromRoute" method = "wallet_buildTransactionsFromRoute"
build_tx_params = { build_tx_params = {"uuid": uuid, "slippagePercentage": 0}
"uuid": uuid,
"slippagePercentage": 0
}
for key, new_value in kwargs.items(): for key, new_value in kwargs.items():
if key in build_tx_params: if key in build_tx_params:
build_tx_params[key] = new_value build_tx_params[key] = new_value
else: else:
logging.info( logging.info(f"Warning: The key '{key}' does not exist in the build_tx_params parameters and will be ignored.")
f"Warning: The key '{key}' does not exist in the build_tx_params parameters and will be ignored.")
params = [build_tx_params] params = [build_tx_params]
_ = rpc_client.rpc_valid_request(method, params) _ = rpc_client.rpc_valid_request(method, params)
wallet_router_sign_transactions = rpc_client.wait_for_signal("wallet.router.sign-transactions") wallet_router_sign_transactions = rpc_client.wait_for_signal("wallet.router.sign-transactions")
assert wallet_router_sign_transactions['event']['signingDetails']['signOnKeycard'] == False assert wallet_router_sign_transactions["event"]["signingDetails"]["signOnKeycard"] is False
transaction_hashes = wallet_router_sign_transactions['event']['signingDetails']['hashes'] transaction_hashes = wallet_router_sign_transactions["event"]["signingDetails"]["hashes"]
assert transaction_hashes, "Transaction hashes are empty!" 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): def sign_messages(rpc_client, hashes):
tx_signatures = {} tx_signatures = {}
@ -81,51 +76,45 @@ def sign_messages(rpc_client, hashes):
for hash in hashes: for hash in hashes:
method = "wallet_signMessage" method = "wallet_signMessage"
params = [ params = [hash, user_1.address, option.password]
hash,
user_1.address,
option.password
]
response = rpc_client.rpc_valid_request(method, params) response = rpc_client.rpc_valid_request(method, params)
if response.json()["result"].startswith("0x"): result = response.json().get("result")
tx_signature = response.json()["result"][2:] assert result and result.startswith("0x"), f"Invalid transaction signature for hash {hash}: {result}"
tx_signature = result[2:]
signature = { signature = {
"r": tx_signature[:64], "r": tx_signature[:64],
"s": tx_signature[64:128], "s": tx_signature[64:128],
"v": tx_signature[128:] "v": tx_signature[128:],
} }
tx_signatures[hash] = signature tx_signatures[hash] = signature
return tx_signatures return tx_signatures
def send_router_transactions_with_signatures(rpc_client, uuid, tx_signatures): def send_router_transactions_with_signatures(rpc_client, uuid, tx_signatures):
method = "wallet_sendRouterTransactionsWithSignatures" method = "wallet_sendRouterTransactionsWithSignatures"
params = [ params = [{"uuid": uuid, "Signatures": tx_signatures}]
{
"uuid": uuid,
"Signatures": tx_signatures
}
]
_ = rpc_client.rpc_valid_request(method, params) _ = rpc_client.rpc_valid_request(method, params)
tx_status = rpc_client.wait_for_signal( tx_status = rpc_client.wait_for_signal("wallet.transaction.status-changed")
"wallet.transaction.status-changed")
assert tx_status["event"]["status"] == "Success" assert tx_status["event"]["status"] == "Success"
return tx_status["event"] return tx_status["event"]
def send_router_transaction(rpc_client, **kwargs): def send_router_transaction(rpc_client, **kwargs):
routes = get_suggested_routes(rpc_client, **kwargs) routes = get_suggested_routes(rpc_client, **kwargs)
build_tx = build_transactions_from_route(rpc_client, routes['Uuid']) build_tx = build_transactions_from_route(rpc_client, routes["Uuid"])
tx_signatures = sign_messages(rpc_client, build_tx['signingDetails']['hashes']) tx_signatures = sign_messages(rpc_client, build_tx["signingDetails"]["hashes"])
tx_status = send_router_transactions_with_signatures(rpc_client, routes['Uuid'], tx_signatures) tx_status = send_router_transactions_with_signatures(rpc_client, routes["Uuid"], tx_signatures)
return { return {
"routes": routes, "routes": routes,
"build_tx": build_tx, "build_tx": build_tx,
"tx_signatures": tx_signatures, "tx_signatures": tx_signatures,
"tx_status": tx_status "tx_status": tx_status,
} }