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."
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/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"
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 ' ' ,)
# Run functional tests
echo -e "${GRN}Running tests${RST}, HEAD: $(git rev-parse HEAD)"
docker compose -p ${project_name} ${all_compose_files} up -d --build --scale status-backend=${STATUS_BACKEND_COUNT} --remove-orphans
# Remove orphans
docker ps -a --filter "name=status-go-func-tests-*-status-backend-*" --filter "status=exited" -q | xargs -r docker rm
echo -e "${GRN}Running tests-rpc${RST}" # Follow the logs, wait for them to finish
docker compose -p ${project_name} ${all_compose_files} logs -f tests-rpc > "${root_path}/tests-rpc.log"
# Run docker
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
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-backend > "${root_path}/status-backend.log"
# Retrieve exit code
exit_code=$(docker inspect ${project_name}-tests-rpc-1 -f '{{.State.ExitCode}}');
# Cleanup containers
echo -e "${GRN}Removing docker containers${RST}"
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
### 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:
* 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`
- 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-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
* 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

View File

@ -4,23 +4,31 @@ import time
import random
import threading
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.rpc import RpcClient
from datetime import datetime
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):
def __init__(self, await_signals=[], url=None):
try:
url = url if url else random.choice(option.status_backend_urls)
except IndexError:
raise Exception("Not enough status-backend containers, please add more")
option.status_backend_urls.remove(url)
def __init__(self, await_signals=[]):
if option.status_backend_url:
url = option.status_backend_url
else:
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.ws_url = f"{url}".replace("http", "ws")
@ -29,14 +37,70 @@ class StatusBackend(RpcClient, SignalClient):
RpcClient.__init__(self, self.rpc_url)
SignalClient.__init__(self, self.ws_url, await_signals)
self._health_check()
websocket_thread = threading.Thread(target=self._connect)
websocket_thread.daemon = True
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):
url = url if url else self.api_url
url = f"{url}/{method}"
logging.info(f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}")
logging.info(
f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}")
response = requests.post(url, json=data)
logging.info(f"Got response: {response.content}")
return response
@ -46,7 +110,8 @@ class StatusBackend(RpcClient, SignalClient):
assert response.content
logging.info(f"Got response: {response.content}")
try:
assert not response.json()["error"]
error = response.json()["error"]
assert not error, f"Error: {error}"
except json.JSONDecodeError:
raise AssertionError(
f"Invalid JSON in response: {response.content}")
@ -58,7 +123,7 @@ class StatusBackend(RpcClient, SignalClient):
self.verify_is_valid_api_response(response)
return response
def init_status_backend(self, data_dir="/"):
def init_status_backend(self, data_dir=USER_DIR):
method = "InitializeApplication"
data = {
"dataDir": data_dir,
@ -68,7 +133,7 @@ class StatusBackend(RpcClient, SignalClient):
}
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"
data = {
"rootDataDir": data_dir,
@ -81,7 +146,7 @@ class StatusBackend(RpcClient, SignalClient):
}
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):
method = "RestoreAccountAndLogin"
data = {
@ -136,7 +201,8 @@ class StatusBackend(RpcClient, SignalClient):
return
except AssertionError:
time.sleep(3)
raise TimeoutError(f"RPC client was not started after {timeout} seconds")
raise TimeoutError(
f"RPC client was not started after {timeout} seconds")
@retry(stop=stop_after_delay(10), wait=wait_fixed(0.5), reraise=True)
def start_messenger(self, params=[]):
@ -173,7 +239,8 @@ class StatusBackend(RpcClient, SignalClient):
for account in accounts:
if account.get("name") == display_name:
return account.get("public-key")
raise ValueError(f"Public key not found for display name: {display_name}")
raise ValueError(
f"Public key not found for display name: {display_name}")
def send_contact_request(self, params=[]):
method = "wakuext_sendContactRequest"

View File

@ -1,32 +1,16 @@
import os
import threading
from dataclasses import dataclass
import docker
import pytest as pytest
from dataclasses import dataclass
def pytest_addoption(parser):
parser.addoption(
"--rpc_url_statusd",
"--status_backend_url",
action="store",
help="",
default="http://0.0.0.0:3333",
)
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))
)
],
default=None,
)
parser.addoption(
"--anvil_url",
@ -40,6 +24,24 @@ def pytest_addoption(parser):
help="",
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
class Option:
@ -52,6 +54,24 @@ option = Option()
def pytest_configure(config):
global 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__))
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 conftest import option
import os
@ -26,4 +27,5 @@ DEFAULT_DISPLAY_NAME = "Mr_Meeseeks"
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "../"))
TESTS_DIR = os.path.join(PROJECT_ROOT, "tests-functional")
SIGNALS_DIR = os.path.join(TESTS_DIR, "signals")
LOG_SIGNALS_TO_FILE = False # used for debugging purposes
LOG_SIGNALS_TO_FILE = False # used for debugging purposes
USER_DIR = option.user_dir if option.user_dir else "/usr/status-user"

View File

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

View File

@ -1,32 +1,4 @@
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:
user: ${INTEGRATION_TESTS_DOCKER_UID}
build:
@ -50,27 +22,3 @@ services:
volumes:
- ./coverage/binary:/coverage/binary
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
tenacity~=9.0.0
pytest-dependency~=0.6.0
docker==7.1.0

View File

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

View File

@ -4,21 +4,21 @@ import pytest
from conftest import option
from constants import user_1, user_2
from test_cases import SignalTestCase
from test_cases import StatusBackendTestCase
from clients.signals import SignalType
@pytest.mark.rpc
@pytest.mark.transaction
@pytest.mark.wallet
class TestTransactionFromRoute(SignalTestCase):
class TestTransactionFromRoute(StatusBackendTestCase):
await_signals = [
SignalType.NODE_LOGIN.value,
SignalType.WALLET_SUGGESTED_ROUTES.value,
SignalType.WALLET_ROUTER_SIGN_TRANSACTIONS.value,
SignalType.WALLET_ROUTER_SENDING_TRANSACTIONS_STARTED.value,
SignalType.WALLET_TRANSACTION_STATUS_CHANGED.value,
SignalType.WALLET_ROUTER_TRANSACTIONS_SENT.value,
]
def test_tx_from_route(self):
_uuid = str(uuid.uuid4())
@ -44,7 +44,7 @@ class TestTransactionFromRoute(SignalTestCase):
]
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
method = "wallet_buildTransactionsFromRoute"
@ -56,7 +56,7 @@ class TestTransactionFromRoute(SignalTestCase):
]
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)
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)
tx_status = self.signal_client.wait_for_signal(
tx_status = self.rpc_client.wait_for_signal(
SignalType.WALLET_TRANSACTION_STATUS_CHANGED.value)
assert tx_status["event"]["chainId"] == 31337
assert tx_status["event"]["status"] == "Success"
tx_hash = tx_status["event"]["hash"]
method = "eth_getTransactionByHash"
params = [tx_hash]
method = "ethclient_transactionByHash"
params = [self.network_id, tx_hash]
response = self.rpc_client.rpc_valid_request(method, params, url=option.anvil_url)
tx_details = response.json()["result"]
response = self.rpc_client.rpc_valid_request(method, params)
tx_details = response.json()["result"]["tx"]
assert tx_details["value"] == amount_in
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 random
import wallet_utils
import pytest
from constants import user_1
from test_cases import SignalTestCase
import wallet_utils
import logging
from test_cases import StatusBackendTestCase
from clients.signals import SignalType
EventActivityFilteringDone = "wallet-activity-filtering-done"
EventActivityFilteringUpdate = "wallet-activity-filtering-entries-updated"
@ -20,8 +17,10 @@ def validate_entry(entry, tx_data):
@pytest.mark.wallet
@pytest.mark.rpc
class TestWalletActivitySession(SignalTestCase):
await_signals = ["wallet",
class TestWalletActivitySession(StatusBackendTestCase):
await_signals = [
SignalType.NODE_LOGIN.value,
"wallet",
"wallet.suggested.routes",
"wallet.router.sign-transactions",
"wallet.router.sending-transactions-started",
@ -29,13 +28,12 @@ class TestWalletActivitySession(SignalTestCase):
"wallet.router.transactions-sent"]
def setup_method(self):
super().setup_method()
self.request_id = str(random.randint(1, 8888))
def test_wallet_start_activity_filter_session(self):
tx_data = [] # (routes, build_tx, tx_signatures, tx_status)
# 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
method = "wallet_startActivityFilterSessionV2"
@ -43,9 +41,9 @@ class TestWalletActivitySession(SignalTestCase):
{"period": {"startTimestamp": 0, "endTimestamp": 0}, "types": [], "statuses": [],
"counterpartyAddresses": [], "assets": [], "collectibles": [], "filterOutAssets": False,
"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)
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
sessionID = int(response.json()["result"])
@ -60,10 +58,10 @@ class TestWalletActivitySession(SignalTestCase):
validate_entry(message['activities'][0], tx_data[-1])
# Trigger new transaction
self.signal_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))
self.rpc_client.prepare_wait_for_signal("wallet", 1, lambda signal : signal["event"]["type"] == EventActivitySessionUpdated and signal['event']['requestId'] == sessionID)
tx_data.append(wallet_utils.send_router_transaction(self.rpc_client))
print(tx_data[-1])
event_response = self.signal_client.wait_for_signal("wallet", timeout=10)['event']
event_response = self.rpc_client.wait_for_signal("wallet", timeout=10)['event']
# Check response event
assert int(event_response['requestId']) == sessionID
@ -73,9 +71,9 @@ class TestWalletActivitySession(SignalTestCase):
# Reset activity session
method = "wallet_resetActivityFilterSession"
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)
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
assert int(event_response['requestId']) == sessionID

View File

@ -15,7 +15,7 @@ def verify_json_schema(response, method):
jsonschema.validate(instance=response,
schema=json.load(schema))
def get_suggested_routes(rpc_client, signal_client, **kwargs):
def get_suggested_routes(rpc_client, **kwargs):
_uuid = str(uuid.uuid4())
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.")
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)
routes = signal_client.wait_for_signal("wallet.suggested.routes")
routes = rpc_client.wait_for_signal("wallet.suggested.routes")
assert routes['event']['Uuid'] == _uuid
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"
build_tx_params = {
"uuid": uuid,
@ -66,7 +66,7 @@ def build_transactions_from_route(rpc_client, signal_client, uuid, **kwargs):
params = [build_tx_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
transaction_hashes = wallet_router_sign_transactions['event']['signingDetails']['hashes']
@ -101,7 +101,7 @@ def sign_messages(rpc_client, hashes):
tx_signatures[hash] = signature
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"
params = [
{
@ -111,18 +111,18 @@ def send_router_transactions_with_signatures(rpc_client, signal_client, uuid, tx
]
_ = 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")
assert tx_status["event"]["status"] == "Success"
return tx_status["event"]
def send_router_transaction(rpc_client, signal_client, **kwargs):
routes = get_suggested_routes(rpc_client, signal_client, **kwargs)
build_tx = build_transactions_from_route(rpc_client, signal_client, routes['Uuid'])
def send_router_transaction(rpc_client, **kwargs):
routes = get_suggested_routes(rpc_client, **kwargs)
build_tx = build_transactions_from_route(rpc_client, routes['Uuid'])
tx_signatures = sign_messages(rpc_client, build_tx['signingDetails']['hashes'])
tx_status = send_router_transactions_with_signatures(rpc_client, signal_client, routes['Uuid'], tx_signatures)
tx_status = send_router_transactions_with_signatures(rpc_client, routes['Uuid'], tx_signatures)
return {
"routes": routes,
"build_tx": build_tx,