test_: run functional tests on host (no container) (#6159)

* test_: run on host
This commit is contained in:
Anton Danchenko 2024-12-12 13:45:21 +01:00 committed by GitHub
parent ef177c1c63
commit 1795620df0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 199 additions and 149 deletions

View File

@ -30,6 +30,7 @@ LABEL source="https://github.com/status-im/status-go"
LABEL description="status-go is an underlying part of Status - a browser, messenger, and gateway to a decentralized world." LABEL description="status-go is an underlying part of Status - a browser, messenger, and gateway to a decentralized world."
RUN apk add --no-cache ca-certificates bash libgcc libstdc++ curl RUN apk add --no-cache ca-certificates bash libgcc libstdc++ curl
RUN mkdir -p /usr/status-user && chmod -R 777 /usr/status-user
RUN mkdir -p /static/keys RUN mkdir -p /static/keys
RUN mkdir -p /static/configs RUN mkdir -p /static/configs

View File

@ -26,15 +26,35 @@ mkdir -p "${test_results_path}"
all_compose_files="-f ${root_path}/docker-compose.anvil.yml -f ${root_path}/docker-compose.test.status-go.yml" all_compose_files="-f ${root_path}/docker-compose.anvil.yml -f ${root_path}/docker-compose.test.status-go.yml"
project_name="status-go-func-tests-$(date +%s)" project_name="status-go-func-tests-$(date +%s)"
export STATUS_BACKEND_COUNT=10
export STATUS_BACKEND_URLS=$(eval echo http://${project_name}-status-backend-{1..${STATUS_BACKEND_COUNT}}:3333 | tr ' ' ,) export STATUS_BACKEND_URLS=$(eval echo http://${project_name}-status-backend-{1..${STATUS_BACKEND_COUNT}}:3333 | tr ' ' ,)
# Run functional tests # Remove orphans
echo -e "${GRN}Running tests${RST}, HEAD: $(git rev-parse HEAD)" docker ps -a --filter "name=status-go-func-tests-*-status-backend-*" --filter "status=exited" -q | xargs -r docker rm
docker compose -p ${project_name} ${all_compose_files} up -d --build --scale status-backend=${STATUS_BACKEND_COUNT} --remove-orphans
echo -e "${GRN}Running tests-rpc${RST}" # Follow the logs, wait for them to finish # Run docker
docker compose -p ${project_name} ${all_compose_files} logs -f tests-rpc > "${root_path}/tests-rpc.log" echo -e "${GRN}Running tests${RST}, HEAD: $(git rev-parse HEAD)"
docker compose -p ${project_name} ${all_compose_files} up -d --build --remove-orphans
# Set up virtual environment
venv_path="${root_path}/.venv"
if [[ -d "${venv_path}" ]]; then
echo -e "${GRN}Using existing virtual environment${RST}"
else
echo -e "${GRN}Creating new virtual environment${RST}"
python3 -m venv "${venv_path}"
fi
source "${venv_path}/bin/activate"
# Upgrade pip and install requirements
echo -e "${GRN}Installing dependencies${RST}"
pip install --upgrade pip
pip install -r "${root_path}/requirements.txt"
# Run functional tests
pytest -m rpc --docker_project_name=${project_name} --codecov_dir=${binary_coverage_reports_path} --junitxml=${test_results_path}/report.xml
exit_code=$?
# Stop containers # Stop containers
echo -e "${GRN}Stopping docker containers${RST}" echo -e "${GRN}Stopping docker containers${RST}"
@ -45,9 +65,6 @@ echo -e "${GRN}Saving logs${RST}"
docker compose -p ${project_name} ${all_compose_files} logs status-go > "${root_path}/statusd.log" docker compose -p ${project_name} ${all_compose_files} logs status-go > "${root_path}/statusd.log"
docker compose -p ${project_name} ${all_compose_files} logs status-backend > "${root_path}/status-backend.log" docker compose -p ${project_name} ${all_compose_files} logs status-backend > "${root_path}/status-backend.log"
# Retrieve exit code
exit_code=$(docker inspect ${project_name}-tests-rpc-1 -f '{{.State.ExitCode}}');
# Cleanup containers # Cleanup containers
echo -e "${GRN}Removing docker containers${RST}" echo -e "${GRN}Removing docker containers${RST}"
docker compose -p ${project_name} ${all_compose_files} down docker compose -p ${project_name} ${all_compose_files} down

View File

@ -25,12 +25,13 @@ Functional tests for status-go
* Status-im contracts will be deployed to the network * Status-im contracts will be deployed to the network
### Run tests ### Run tests
- In `./tests-functional` run `docker compose -f docker-compose.anvil.yml -f docker-compose.test.status-go.yml -f docker-compose.status-go.local.yml up --build --scale status-backend=10 --remove-orphans`, as result: - In `./tests-functional` run `docker compose -f docker-compose.anvil.yml -f docker-compose.test.status-go.yml -f docker-compose.status-go.local.yml up --build --remove-orphans`, as result:
* a container with [status-go as daemon](https://github.com/status-im/status-go/issues/5175) will be created with APIModules exposed on `0.0.0.0:3333` * a container with [status-backend](https://github.com/status-im/status-go/pull/5847) will be created with endpoint exposed on `0.0.0.0:3333`
* status-go will use [anvil](https://book.getfoundry.sh/reference/anvil/) as RPCURL with ChainID 31337 * status-go will use [anvil](https://book.getfoundry.sh/reference/anvil/) as RPCURL with ChainID 31337
* all Status-im contracts will be deployed to the network * Status-im contracts will be deployed to the network
* In `./tests-functional/tests` directory run `pytest -m wallet` * In `./tests-functional/tests` directory run `pytest -m rpc`
* To run tests against binary run `pytest -m <your mark> --url=http:<binary_url>:<binary_port> --user_dir=/<path>`
## Implementation details ## Implementation details

View File

@ -4,23 +4,31 @@ import time
import random import random
import threading import threading
import requests import requests
from tenacity import retry, stop_after_delay, wait_fixed import docker
import os
from tenacity import retry, stop_after_delay, wait_fixed
from clients.signals import SignalClient 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 from constants import user_1, DEFAULT_DISPLAY_NAME, USER_DIR
class StatusBackend(RpcClient, SignalClient): class StatusBackend(RpcClient, SignalClient):
def __init__(self, await_signals=[], url=None): def __init__(self, await_signals=[]):
try:
url = url if url else random.choice(option.status_backend_urls) if option.status_backend_url:
except IndexError: url = option.status_backend_url
raise Exception("Not enough status-backend containers, please add more") else:
option.status_backend_urls.remove(url) self.docker_client = docker.from_env()
host_port = random.choice(option.status_backend_port_range)
self.container = self._start_container(host_port)
url = f"http://127.0.0.1:{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")
@ -29,14 +37,70 @@ class StatusBackend(RpcClient, SignalClient):
RpcClient.__init__(self, self.rpc_url) RpcClient.__init__(self, self.rpc_url)
SignalClient.__init__(self, self.ws_url, await_signals) SignalClient.__init__(self, self.ws_url, await_signals)
self._health_check()
websocket_thread = threading.Thread(target=self._connect) websocket_thread = threading.Thread(target=self._connect)
websocket_thread.daemon = True websocket_thread.daemon = True
websocket_thread.start() websocket_thread.start()
def _start_container(self, host_port):
docker_project_name = option.docker_project_name
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
image_name = f"{docker_project_name}-status-backend:latest"
container_name = f"{docker_project_name}-status-backend-{timestamp}"
coverage_path = option.codecov_dir if option.codecov_dir else os.path.abspath("./coverage/binary")
container_args = {
"image": image_name,
"detach": True,
"name": container_name,
"labels": {"com.docker.compose.project": docker_project_name},
"entrypoint": [
"status-backend",
"--address", "0.0.0.0:3333",
],
"ports": {"3333/tcp": host_port},
"environment": {
"GOCOVERDIR": "/coverage/binary",
},
"volumes": {
coverage_path: {
"bind": "/coverage/binary",
"mode": "rw",
}
},
}
if "FUNCTIONAL_TESTS_DOCKER_UID" in os.environ:
container_args["user"] = os.environ["FUNCTIONAL_TESTS_DOCKER_UID"]
container = self.docker_client.containers.run(**container_args)
network = self.docker_client.networks.get(
f"{docker_project_name}_default")
network.connect(container)
option.status_backend_containers.append(container.id)
return container
def _health_check(self):
start_time = time.time()
while True:
try:
self.api_valid_request(method="Fleets", data=[])
break
except Exception as e:
if time.time() - start_time > 20:
raise Exception(e)
time.sleep(1)
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(f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}") logging.info(
f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}")
response = requests.post(url, json=data) response = requests.post(url, json=data)
logging.info(f"Got response: {response.content}") logging.info(f"Got response: {response.content}")
return response return response
@ -46,7 +110,8 @@ class StatusBackend(RpcClient, SignalClient):
assert response.content assert response.content
logging.info(f"Got response: {response.content}") logging.info(f"Got response: {response.content}")
try: try:
assert not response.json()["error"] error = response.json()["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}")
@ -58,7 +123,7 @@ class StatusBackend(RpcClient, SignalClient):
self.verify_is_valid_api_response(response) self.verify_is_valid_api_response(response)
return response return response
def init_status_backend(self, data_dir="/"): def init_status_backend(self, data_dir=USER_DIR):
method = "InitializeApplication" method = "InitializeApplication"
data = { data = {
"dataDir": data_dir, "dataDir": data_dir,
@ -68,7 +133,7 @@ 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="/", 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,
@ -81,7 +146,7 @@ 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="/",display_name=DEFAULT_DISPLAY_NAME, user=user_1, def restore_account_and_login(self, data_dir=USER_DIR, display_name=DEFAULT_DISPLAY_NAME, user=user_1,
network_id=31337): network_id=31337):
method = "RestoreAccountAndLogin" method = "RestoreAccountAndLogin"
data = { data = {
@ -136,7 +201,8 @@ class StatusBackend(RpcClient, SignalClient):
return return
except AssertionError: except AssertionError:
time.sleep(3) time.sleep(3)
raise TimeoutError(f"RPC client was not started after {timeout} seconds") raise TimeoutError(
f"RPC client was not started after {timeout} seconds")
@retry(stop=stop_after_delay(10), wait=wait_fixed(0.5), reraise=True) @retry(stop=stop_after_delay(10), wait=wait_fixed(0.5), reraise=True)
def start_messenger(self, params=[]): def start_messenger(self, params=[]):
@ -173,7 +239,8 @@ 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(f"Public key not found for display name: {display_name}") raise ValueError(
f"Public key not found for display name: {display_name}")
def send_contact_request(self, params=[]): def send_contact_request(self, params=[]):
method = "wakuext_sendContactRequest" method = "wakuext_sendContactRequest"

View File

@ -1,32 +1,16 @@
import os import os
import threading import docker
from dataclasses import dataclass
import pytest as pytest import pytest as pytest
from dataclasses import dataclass
def pytest_addoption(parser): def pytest_addoption(parser):
parser.addoption( parser.addoption(
"--rpc_url_statusd", "--status_backend_url",
action="store", action="store",
help="", help="",
default="http://0.0.0.0:3333", default=None,
)
parser.addoption(
"--ws_url_statusd",
action="store",
help="",
default="ws://0.0.0.0:8354",
)
parser.addoption(
"--status_backend_urls",
action="store",
help="",
default=[
f"http://0.0.0.0:{3314 + i}" for i in range(
int(os.getenv("STATUS_BACKEND_COUNT", 10))
)
],
) )
parser.addoption( parser.addoption(
"--anvil_url", "--anvil_url",
@ -40,6 +24,24 @@ def pytest_addoption(parser):
help="", help="",
default="Strong12345", default="Strong12345",
) )
parser.addoption(
"--docker_project_name",
action="store",
help="",
default="tests-functional",
)
parser.addoption(
"--codecov_dir",
action="store",
help="",
default=None,
)
parser.addoption(
"--user_dir",
action="store",
help="",
default=None,
)
@dataclass @dataclass
class Option: class Option:
@ -52,6 +54,24 @@ option = Option()
def pytest_configure(config): def pytest_configure(config):
global option global option
option = config.option option = config.option
if type(option.status_backend_urls) is str:
option.status_backend_urls = option.status_backend_urls.split(",") executor_number = int(os.getenv('EXECUTOR_NUMBER', 5))
base_port = 7000
range_size = 100
start_port = base_port + (executor_number * range_size)
option.status_backend_port_range = list(range(start_port, start_port + range_size - 1))
option.status_backend_containers = []
option.base_dir = os.path.dirname(os.path.abspath(__file__)) option.base_dir = os.path.dirname(os.path.abspath(__file__))
def pytest_unconfigure():
docker_client = docker.from_env()
for container_id in option.status_backend_containers:
try:
container = docker_client.containers.get(container_id)
container.stop(timeout=30)
container.remove()
except Exception as e:
print(e)

View File

@ -1,4 +1,5 @@
from dataclasses import dataclass from dataclasses import dataclass
from conftest import option
import os import os
@ -26,4 +27,5 @@ 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"

View File

@ -2,10 +2,6 @@ services:
anvil: anvil:
ports: ports:
- 8545:8545 - 8545:8545
status-go:
ports:
- 3333:3333
- 8354:8354
status-backend: status-backend:
ports: ports:
- 3314-3324:3333 - 3314-3324:3333

View File

@ -1,32 +1,4 @@
services: services:
status-go:
user: ${FUNCTIONAL_TESTS_DOCKER_UID}
build:
context: ../
dockerfile: _assets/build/Dockerfile
args:
build_tags: gowaku_no_rln,enable_private_api
build_target: statusd
build_flags: -cover
entrypoint: [
"statusd",
"-c", "/static/configs/config.json",
"--server", "0.0.0.0:8354",
"--seed-phrase", "test test test test test test test test test test test junk",
"--password", "Strong12345",
"--dir", "/tmp/status-go-data", # Keep in sync with `config.json/DataDir` value. Later this arg will not be needed.
]
healthcheck:
test: ["CMD-SHELL", "curl -X POST --data '{\"jsonrpc\":\"2.0\",\"method\":\"net_version\",\"params\":[],\"id\":1}' -H 'Content-Type: application/json' http://0.0.0.0:3333 || exit 1"]
interval: 5s
timeout: 2s
retries: 120
environment:
GOCOVERDIR: "/coverage/binary"
volumes:
- ./coverage/binary:/coverage/binary
stop_signal: SIGINT
status-backend: status-backend:
user: ${INTEGRATION_TESTS_DOCKER_UID} user: ${INTEGRATION_TESTS_DOCKER_UID}
build: build:
@ -50,27 +22,3 @@ services:
volumes: volumes:
- ./coverage/binary:/coverage/binary - ./coverage/binary:/coverage/binary
stop_signal: SIGINT stop_signal: SIGINT
tests-rpc:
user: ${FUNCTIONAL_TESTS_DOCKER_UID}
depends_on:
status-go:
condition: service_healthy
status-backend:
condition: service_healthy
deploy-communities-contracts:
condition: service_completed_successfully
build:
context: .
dockerfile: Dockerfile.tests-rpc
entrypoint: [
"pytest",
"-m", "rpc",
"--anvil_url=http://anvil:8545",
"--rpc_url_statusd=http://status-go:3333",
"--status_backend_urls=${STATUS_BACKEND_URLS}",
"--ws_url_statusd=ws://status-go:8354",
"--junitxml=/tests-rpc/reports/report.xml"
]
volumes:
- .:/tests-rpc

View File

@ -6,3 +6,4 @@ genson~=1.2.2
websocket-client~=1.4.2 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

View File

@ -179,8 +179,8 @@ class NetworkConditionTestCase:
class OneToOneMessageTestCase(NetworkConditionTestCase): class OneToOneMessageTestCase(NetworkConditionTestCase):
def initialize_backend(self, await_signals, display_name=DEFAULT_DISPLAY_NAME, url=None): def initialize_backend(self, await_signals, display_name=DEFAULT_DISPLAY_NAME):
backend = StatusBackend(await_signals=await_signals, url=url) backend = StatusBackend(await_signals=await_signals)
backend.init_status_backend() backend.init_status_backend()
backend.create_account_and_login(display_name=display_name) backend.create_account_and_login(display_name=display_name)
backend.start_messenger() backend.start_messenger()

View File

@ -4,21 +4,21 @@ import pytest
from conftest import option from conftest import option
from constants import user_1, user_2 from constants import user_1, user_2
from test_cases import SignalTestCase 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
class TestTransactionFromRoute(SignalTestCase): class TestTransactionFromRoute(StatusBackendTestCase):
await_signals = [ await_signals = [
SignalType.NODE_LOGIN.value,
SignalType.WALLET_SUGGESTED_ROUTES.value, SignalType.WALLET_SUGGESTED_ROUTES.value,
SignalType.WALLET_ROUTER_SIGN_TRANSACTIONS.value, SignalType.WALLET_ROUTER_SIGN_TRANSACTIONS.value,
SignalType.WALLET_ROUTER_SENDING_TRANSACTIONS_STARTED.value, SignalType.WALLET_ROUTER_SENDING_TRANSACTIONS_STARTED.value,
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())
@ -44,7 +44,7 @@ class TestTransactionFromRoute(SignalTestCase):
] ]
response = self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request(method, params)
routes = self.signal_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"
@ -56,7 +56,7 @@ class TestTransactionFromRoute(SignalTestCase):
] ]
response = self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request(method, params)
wallet_router_sign_transactions = self.signal_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'] == False
@ -97,19 +97,18 @@ class TestTransactionFromRoute(SignalTestCase):
] ]
response = self.rpc_client.rpc_valid_request(method, params) response = self.rpc_client.rpc_valid_request(method, params)
tx_status = self.signal_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"
tx_hash = tx_status["event"]["hash"] tx_hash = tx_status["event"]["hash"]
method = "eth_getTransactionByHash" method = "ethclient_transactionByHash"
params = [tx_hash] params = [self.network_id, tx_hash]
response = self.rpc_client.rpc_valid_request(method, params, url=option.anvil_url) response = self.rpc_client.rpc_valid_request(method, params)
tx_details = response.json()["result"] tx_details = response.json()["result"]["tx"]
assert tx_details["value"] == amount_in assert tx_details["value"] == amount_in
assert tx_details["to"].upper() == user_2.address.upper() assert tx_details["to"].upper() == user_2.address.upper()
assert tx_details["from"].upper() == user_1.address.upper()

View File

@ -1,14 +1,11 @@
import json import json
import random import random
import wallet_utils
import pytest import pytest
from constants import user_1 from constants import user_1
from test_cases import SignalTestCase from test_cases import StatusBackendTestCase
from clients.signals import SignalType
import wallet_utils
import logging
EventActivityFilteringDone = "wallet-activity-filtering-done" EventActivityFilteringDone = "wallet-activity-filtering-done"
EventActivityFilteringUpdate = "wallet-activity-filtering-entries-updated" EventActivityFilteringUpdate = "wallet-activity-filtering-entries-updated"
@ -20,8 +17,10 @@ def validate_entry(entry, tx_data):
@pytest.mark.wallet @pytest.mark.wallet
@pytest.mark.rpc @pytest.mark.rpc
class TestWalletActivitySession(SignalTestCase): class TestWalletActivitySession(StatusBackendTestCase):
await_signals = ["wallet", await_signals = [
SignalType.NODE_LOGIN.value,
"wallet",
"wallet.suggested.routes", "wallet.suggested.routes",
"wallet.router.sign-transactions", "wallet.router.sign-transactions",
"wallet.router.sending-transactions-started", "wallet.router.sending-transactions-started",
@ -29,13 +28,12 @@ class TestWalletActivitySession(SignalTestCase):
"wallet.router.transactions-sent"] "wallet.router.transactions-sent"]
def setup_method(self): def setup_method(self):
super().setup_method()
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, self.signal_client)) tx_data.append(wallet_utils.send_router_transaction(self.rpc_client))
# Start activity session # Start activity session
method = "wallet_startActivityFilterSessionV2" method = "wallet_startActivityFilterSessionV2"
@ -43,9 +41,9 @@ class TestWalletActivitySession(SignalTestCase):
{"period": {"startTimestamp": 0, "endTimestamp": 0}, "types": [], "statuses": [], {"period": {"startTimestamp": 0, "endTimestamp": 0}, "types": [], "statuses": [],
"counterpartyAddresses": [], "assets": [], "collectibles": [], "filterOutAssets": False, "counterpartyAddresses": [], "assets": [], "collectibles": [], "filterOutAssets": False,
"filterOutCollectibles": False}, 10] "filterOutCollectibles": False}, 10]
self.signal_client.prepare_wait_for_signal("wallet", 1, lambda signal : signal["event"]["type"] == EventActivityFilteringDone) 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.signal_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"])
@ -60,10 +58,10 @@ class TestWalletActivitySession(SignalTestCase):
validate_entry(message['activities'][0], tx_data[-1]) validate_entry(message['activities'][0], tx_data[-1])
# Trigger new transaction # Trigger new transaction
self.signal_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, self.signal_client)) tx_data.append(wallet_utils.send_router_transaction(self.rpc_client))
print(tx_data[-1]) print(tx_data[-1])
event_response = self.signal_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
@ -73,9 +71,9 @@ class TestWalletActivitySession(SignalTestCase):
# Reset activity session # Reset activity session
method = "wallet_resetActivityFilterSession" method = "wallet_resetActivityFilterSession"
params = [sessionID, 10] params = [sessionID, 10]
self.signal_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.signal_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

View File

@ -15,7 +15,7 @@ def verify_json_schema(response, method):
jsonschema.validate(instance=response, jsonschema.validate(instance=response,
schema=json.load(schema)) schema=json.load(schema))
def get_suggested_routes(rpc_client, signal_client, **kwargs): def get_suggested_routes(rpc_client, **kwargs):
_uuid = str(uuid.uuid4()) _uuid = str(uuid.uuid4())
amount_in = "0xde0b6b3a7640000" amount_in = "0xde0b6b3a7640000"
@ -43,15 +43,15 @@ def get_suggested_routes(rpc_client, signal_client, **kwargs):
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]
signal_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 = signal_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, signal_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, "uuid": uuid,
@ -66,7 +66,7 @@ def build_transactions_from_route(rpc_client, signal_client, uuid, **kwargs):
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 = signal_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'] == False
transaction_hashes = wallet_router_sign_transactions['event']['signingDetails']['hashes'] transaction_hashes = wallet_router_sign_transactions['event']['signingDetails']['hashes']
@ -101,7 +101,7 @@ def sign_messages(rpc_client, hashes):
tx_signatures[hash] = signature tx_signatures[hash] = signature
return tx_signatures return tx_signatures
def send_router_transactions_with_signatures(rpc_client, signal_client, uuid, tx_signatures): def send_router_transactions_with_signatures(rpc_client, uuid, tx_signatures):
method = "wallet_sendRouterTransactionsWithSignatures" method = "wallet_sendRouterTransactionsWithSignatures"
params = [ params = [
{ {
@ -111,18 +111,18 @@ def send_router_transactions_with_signatures(rpc_client, signal_client, uuid, tx
] ]
_ = rpc_client.rpc_valid_request(method, params) _ = rpc_client.rpc_valid_request(method, params)
tx_status = signal_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, signal_client, **kwargs): def send_router_transaction(rpc_client, **kwargs):
routes = get_suggested_routes(rpc_client, signal_client, **kwargs) routes = get_suggested_routes(rpc_client, **kwargs)
build_tx = build_transactions_from_route(rpc_client, signal_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, signal_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,