status-go/tests-functional/tests/test_cases.py

214 lines
7.0 KiB
Python

from contextlib import contextmanager
import json
import logging
import threading
import time
from collections import namedtuple
import pytest
from clients.signals import SignalClient, SignalType
from clients.status_backend import RpcClient, StatusBackend
from conftest import option
from constants import user_1, user_2, DEFAULT_DISPLAY_NAME
class StatusDTestCase:
network_id = 31337
def setup_method(self):
self.rpc_client = RpcClient(
option.rpc_url_statusd
)
class StatusBackendTestCase:
await_signals = [
SignalType.NODE_READY.value
]
def setup_class(self):
self.rpc_client = StatusBackend(await_signals=self.await_signals)
self.rpc_client.init_status_backend()
self.rpc_client.restore_account_and_login()
self.rpc_client.wait_for_signal(SignalType.NODE_READY.value)
self.network_id = 31337
class WalletTestCase(StatusBackendTestCase):
def wallet_create_multi_transaction(self, **kwargs):
method = "wallet_createMultiTransaction"
transfer_tx_data = {
"data": "",
"from": user_1.address,
"gas": "0x5BBF",
"input": "",
"maxFeePerGas": "0xbcc0f04fd",
"maxPriorityFeePerGas": "0xbcc0f04fd",
"to": user_2.address,
"type": "0x02",
"value": "0x5af3107a4000",
}
for key, new_value in kwargs.items():
if key in transfer_tx_data:
transfer_tx_data[key] = new_value
else:
logging.info(
f"Warning: The key '{key}' does not exist in the transferTx parameters and will be ignored.")
params = [
{
"fromAddress": user_1.address,
"fromAmount": "0x5af3107a4000",
"fromAsset": "ETH",
"type": 0, # MultiTransactionSend
"toAddress": user_2.address,
"toAsset": "ETH",
},
[
{
"bridgeName": "Transfer",
"chainID": 31337,
"transferTx": transfer_tx_data
}
],
f"{option.password}",
]
return self.rpc_client.rpc_request(method, params)
def send_valid_multi_transaction(self, **kwargs):
response = self.wallet_create_multi_transaction(**kwargs)
tx_hash = None
self.rpc_client.verify_is_valid_json_rpc_response(response)
try:
tx_hash = response.json(
)["result"]["hashes"][str(self.network_id)][0]
except (KeyError, json.JSONDecodeError):
raise Exception(response.content)
return tx_hash
class TransactionTestCase(WalletTestCase):
def setup_method(self):
self.tx_hash = self.send_valid_multi_transaction()
class EthRpcTestCase(WalletTestCase):
@pytest.fixture(autouse=True, scope='class')
def tx_data(self):
tx_hash = self.send_valid_multi_transaction()
self.wait_until_tx_not_pending(tx_hash)
receipt = self.get_transaction_receipt(tx_hash)
try:
block_number = receipt.json()["result"]["blockNumber"]
block_hash = receipt.json()["result"]["blockHash"]
except (KeyError, json.JSONDecodeError):
raise Exception(receipt.content)
tx_data = namedtuple("TxData", ["tx_hash", "block_number", "block_hash"])
return tx_data(tx_hash, block_number, block_hash)
def get_block_header(self, block_number):
method = "ethclient_headerByNumber"
params = [self.network_id, block_number]
return self.rpc_client.rpc_valid_request(method, params)
def get_transaction_receipt(self, tx_hash):
method = "ethclient_transactionReceipt"
params = [self.network_id, tx_hash]
return self.rpc_client.rpc_valid_request(method, params)
def wait_until_tx_not_pending(self, tx_hash, timeout=10):
method = "ethclient_transactionByHash"
params = [self.network_id, tx_hash]
response = self.rpc_client.rpc_valid_request(method, params)
start_time = time.time()
while response.json()["result"]["isPending"] == True:
time_passed = time.time() - start_time
if time_passed >= timeout:
raise TimeoutError(
f"Tx {tx_hash} is still pending after {timeout} seconds")
time.sleep(0.5)
response = self.rpc_client.rpc_valid_request(method, params)
return response.json()["result"]["tx"]
class SignalTestCase(StatusDTestCase):
await_signals = []
def setup_method(self):
super().setup_method()
self.signal_client = SignalClient(option.ws_url_statusd, self.await_signals)
websocket_thread = threading.Thread(target=self.signal_client._connect)
websocket_thread.daemon = True
websocket_thread.start()
class NetworkConditionTestCase:
@contextmanager
def add_latency(self):
pass
#TODO: To be implemented when we have docker exec capability
@contextmanager
def add_packet_loss(self):
pass
#TODO: To be implemented when we have docker exec capability
@contextmanager
def add_low_bandwith(self):
pass
#TODO: To be implemented when we have docker exec capability
@contextmanager
def node_pause(self, node):
pass
#TODO: To be implemented when we have docker exec capability
class OneToOneMessageTestCase(NetworkConditionTestCase):
def initialize_backend(self, await_signals, display_name=DEFAULT_DISPLAY_NAME, url=None):
backend = StatusBackend(await_signals=await_signals, url=url)
backend.init_status_backend()
backend.create_account_and_login(display_name=display_name)
backend.start_messenger()
return backend
def validate_event_against_response(self, event, fields_to_validate, response):
messages_in_event = event["event"]["messages"]
assert len(messages_in_event) > 0, "No messages found in the event"
response_chat = response["result"]["chats"][0]
message_id = response_chat["lastMessage"]["id"]
message = next((message for message in messages_in_event if message["id"] == message_id), None)
assert message, f"Message with ID {message_id} not found in the event"
message_mismatch = []
for response_field, event_field in fields_to_validate.items():
response_value = response_chat["lastMessage"][response_field]
event_value = message[event_field]
if response_value != event_value:
message_mismatch.append(
f"Field '{response_field}': Expected '{response_value}', Found '{event_value}'"
)
if not message_mismatch:
return
raise AssertionError(
"Some Sender RPC responses are not matching the signals received by the receiver.\n"
"Details of mismatches:\n" +
"\n".join(message_mismatch)
)