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/signals
tests-functional/*.log
pyrightconfig.json
.venv

View File

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

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
* 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
- 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:
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))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,7 +13,6 @@ class TestAppGeneral(StatusBackendTestCase):
"method, params",
[
("appgeneral_getCurrencies", []),
],
)
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.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):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

View File

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