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:
parent
66850321ef
commit
08eee8a647
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"include": ["tests-functional"],
|
||||||
|
"venvPath": "./tests-functional", // Ensure the virtual environment (.venv) is located in ./tests-functional
|
||||||
|
"venv": ".venv"
|
||||||
|
}
|
|
@ -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.
|
|
@ -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
|
|
@ -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))
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
Loading…
Reference in New Issue