test_: Code Migration from status-cli-tests for 1 on 1 message (#6022)
* test_: Code Migration from status-cli-tests 1_1 message test_: Code Migration from status-cli-tests 1_1 message test_: Code Migration from status-cli-tests addressing review comments test_: Code Migration from status-cli-tests 1_1 message rebase * test_: Code Migration from status-cli-tests for 1 on 1 message and added event validation * test_: Code Migration from status-cli-tests for 1 on 1 logger fix
This commit is contained in:
parent
33606e8bd9
commit
66d612cce6
|
@ -47,5 +47,6 @@ PACKET_LOSS_CMD = "sudo tc qdisc add dev eth0 root netem loss 50%"
|
||||||
LOW_BANDWIDTH_CMD = "sudo tc qdisc add dev eth0 root tbf rate 1kbit burst 1kbit"
|
LOW_BANDWIDTH_CMD = "sudo tc qdisc add dev eth0 root tbf rate 1kbit burst 1kbit"
|
||||||
REMOVE_TC_CMD = "sudo tc qdisc del dev eth0 root"
|
REMOVE_TC_CMD = "sudo tc qdisc del dev eth0 root"
|
||||||
NUM_CONTACT_REQUESTS = int(os.getenv("NUM_CONTACT_REQUESTS", "5"))
|
NUM_CONTACT_REQUESTS = int(os.getenv("NUM_CONTACT_REQUESTS", "5"))
|
||||||
NUM_MESSAGES = int(os.getenv("NUM_MESSAGES", "25"))
|
NUM_MESSAGES = int(os.getenv("NUM_MESSAGES", "20"))
|
||||||
DELAY_BETWEEN_MESSAGES = int(os.getenv("NUM_MESSAGES", "1"))
|
DELAY_BETWEEN_MESSAGES = int(os.getenv("NUM_MESSAGES", "1"))
|
||||||
|
EVENT_SIGNAL_TIMEOUT_SEC = int(os.getenv("EVENT_SIGNAL_TIMEOUT_SEC", "4"))
|
||||||
|
|
|
@ -81,7 +81,7 @@ class StatusNode:
|
||||||
|
|
||||||
def start_signal_client(self):
|
def start_signal_client(self):
|
||||||
ws_url = f"ws://localhost:{self.port}"
|
ws_url = f"ws://localhost:{self.port}"
|
||||||
await_signals = ["history.request.started", "messages.new", "history.request.completed"]
|
await_signals = ["history.request.started", "messages.new", "message.delivered", "history.request.completed"]
|
||||||
self.signal_client = SignalClient(ws_url, await_signals)
|
self.signal_client = SignalClient(ws_url, await_signals)
|
||||||
|
|
||||||
websocket_thread = threading.Thread(target=self.signal_client._connect)
|
websocket_thread = threading.Thread(target=self.signal_client._connect)
|
||||||
|
|
|
@ -12,7 +12,7 @@ logger = get_custom_logger(__name__)
|
||||||
|
|
||||||
class TestContactRequest(StepsCommon):
|
class TestContactRequest(StepsCommon):
|
||||||
def test_contact_request_baseline(self):
|
def test_contact_request_baseline(self):
|
||||||
timeout_secs = 3
|
timeout_secs = 5
|
||||||
num_contact_requests = NUM_CONTACT_REQUESTS
|
num_contact_requests = NUM_CONTACT_REQUESTS
|
||||||
project_root = get_project_root()
|
project_root = get_project_root()
|
||||||
nodes = []
|
nodes = []
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
from uuid import uuid4
|
||||||
|
import pytest
|
||||||
|
from constants import *
|
||||||
|
from src.libs.common import delay
|
||||||
|
from src.libs.custom_logger import get_custom_logger
|
||||||
|
from src.steps.common import StepsCommon
|
||||||
|
from validators.message_validator import MessageValidator
|
||||||
|
|
||||||
|
logger = get_custom_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("start_2_nodes")
|
||||||
|
class TestOneToOneMessages(StepsCommon):
|
||||||
|
def test_one_to_one_message_baseline(self):
|
||||||
|
timeout_secs = EVENT_SIGNAL_TIMEOUT_SEC
|
||||||
|
num_messages = NUM_MESSAGES
|
||||||
|
nodes = [
|
||||||
|
(self.first_node, self.second_node, "second_node_user"),
|
||||||
|
(self.second_node, self.first_node, "first_node_user")
|
||||||
|
]
|
||||||
|
messages = []
|
||||||
|
self.accept_contact_request()
|
||||||
|
|
||||||
|
missing_messages = []
|
||||||
|
|
||||||
|
for i in range(num_messages):
|
||||||
|
sending_node, receiving_node, receiving_display_name = nodes[i % 2]
|
||||||
|
result = self.send_and_wait_for_message(
|
||||||
|
sending_node, receiving_node, receiving_display_name, i, timeout_secs)
|
||||||
|
timestamp, message_text, message_id, response = result
|
||||||
|
|
||||||
|
if not response:
|
||||||
|
missing_messages.append((timestamp, message_text, message_id, sending_node.name))
|
||||||
|
else:
|
||||||
|
messages.append((timestamp, message_text, message_id, sending_node.name))
|
||||||
|
|
||||||
|
self.first_node.stop()
|
||||||
|
self.second_node.stop()
|
||||||
|
|
||||||
|
if missing_messages:
|
||||||
|
formatted_missing_messages = [
|
||||||
|
f"Timestamp: {ts}, Message: {msg}, ID: {mid}, Sender: {snd}"
|
||||||
|
for ts, msg, mid, snd in missing_messages
|
||||||
|
]
|
||||||
|
raise AssertionError(
|
||||||
|
f"{len(missing_messages)} messages out of {num_messages} were not received: "
|
||||||
|
+ "\n".join(formatted_missing_messages)
|
||||||
|
)
|
||||||
|
|
||||||
|
def send_and_wait_for_message(self, sending_node, receiving_node, display_name, index, timeout=10):
|
||||||
|
receiving_node_pubkey = receiving_node.get_pubkey(display_name)
|
||||||
|
message_text = f"message_from_{sending_node.name}_{index}"
|
||||||
|
|
||||||
|
timestamp, message_id, response = self.send_with_timestamp(
|
||||||
|
sending_node.send_message, receiving_node_pubkey, message_text
|
||||||
|
)
|
||||||
|
|
||||||
|
validator = MessageValidator(response)
|
||||||
|
validator.run_all_validations(
|
||||||
|
expected_chat_id=receiving_node_pubkey,
|
||||||
|
expected_display_name=display_name,
|
||||||
|
expected_text=message_text
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
messages_new_events = receiving_node.wait_for_complete_signal("messages.new", timeout)
|
||||||
|
receiving_node.wait_for_signal("message.delivered", timeout)
|
||||||
|
|
||||||
|
messages_new_event = None
|
||||||
|
for event in messages_new_events:
|
||||||
|
if "chats" in event.get("event", {}):
|
||||||
|
messages_new_event = event
|
||||||
|
try:
|
||||||
|
validator.validate_event_against_response(
|
||||||
|
messages_new_event,
|
||||||
|
fields_to_validate={
|
||||||
|
"text": "text",
|
||||||
|
"displayName": "displayName",
|
||||||
|
"id": "id"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
break
|
||||||
|
except AssertionError as validation_error:
|
||||||
|
logger.error(f"Validation failed for event: {messages_new_event}, Error: {validation_error}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if messages_new_event is None:
|
||||||
|
raise ValueError("No 'messages.new' event with 'chats' data found within the timeout period.")
|
||||||
|
|
||||||
|
except (TimeoutError, ValueError) as e:
|
||||||
|
logger.error(f"Signal validation failed: {str(e)}")
|
||||||
|
return timestamp, message_text, message_id, None
|
||||||
|
|
||||||
|
return timestamp, message_text, message_id, response
|
||||||
|
|
||||||
|
def test_one_to_one_message_with_latency(self):
|
||||||
|
with self.add_latency():
|
||||||
|
self.test_one_to_one_message_baseline()
|
||||||
|
|
||||||
|
def test_one_to_one_message_with_packet_loss(self):
|
||||||
|
with self.add_packet_loss():
|
||||||
|
self.test_one_to_one_message_baseline()
|
||||||
|
|
||||||
|
def test_one_to_one_message_with_low_bandwidth(self):
|
||||||
|
with self.add_low_bandwidth():
|
||||||
|
self.test_one_to_one_message_baseline()
|
||||||
|
|
||||||
|
def test_one_to_one_message_with_node_pause_30_seconds(self):
|
||||||
|
self.accept_contact_request()
|
||||||
|
with self.node_pause(self.first_node):
|
||||||
|
message = str(uuid4())
|
||||||
|
self.second_node.send_message(self.first_node_pubkey, message)
|
||||||
|
delay(30)
|
||||||
|
assert self.second_node.wait_for_signal("messages.new")
|
|
@ -2,7 +2,6 @@ from src.libs.custom_logger import get_custom_logger
|
||||||
|
|
||||||
logger = get_custom_logger(__name__)
|
logger = get_custom_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ContactRequestValidator:
|
class ContactRequestValidator:
|
||||||
def __init__(self, response):
|
def __init__(self, response):
|
||||||
self.response = response
|
self.response = response
|
||||||
|
@ -16,12 +15,27 @@ class ContactRequestValidator:
|
||||||
assert len(chats) > 0, "No chats found in the response"
|
assert len(chats) > 0, "No chats found in the response"
|
||||||
|
|
||||||
chat = chats[0]
|
chat = chats[0]
|
||||||
assert chat.get("id") == expected_chat_id, f"Chat ID mismatch: Expected {expected_chat_id}"
|
actual_chat_id = chat.get("id")
|
||||||
assert chat.get("name").startswith("0x"), "Invalid chat name format"
|
assert actual_chat_id == expected_chat_id, (
|
||||||
|
f"Chat ID mismatch: Expected '{expected_chat_id}', found '{actual_chat_id}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
actual_chat_name = chat.get("name")
|
||||||
|
assert actual_chat_name.startswith("0x"), (
|
||||||
|
f"Invalid chat name format: Expected name to start with '0x', found '{actual_chat_name}'"
|
||||||
|
)
|
||||||
|
|
||||||
last_message = chat.get("lastMessage", {})
|
last_message = chat.get("lastMessage", {})
|
||||||
assert last_message.get("text") == expected_text, "Message text mismatch"
|
actual_text = last_message.get("text")
|
||||||
assert last_message.get("contactRequestState") == 1, "Unexpected contact request state"
|
assert actual_text == expected_text, (
|
||||||
|
f"Message text mismatch: Expected '{expected_text}', found '{actual_text}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
actual_contact_request_state = last_message.get("contactRequestState")
|
||||||
|
assert actual_contact_request_state == 1, (
|
||||||
|
f"Unexpected contact request state: Expected '1', found '{actual_contact_request_state}'"
|
||||||
|
)
|
||||||
|
|
||||||
assert "compressedKey" in last_message, "Missing 'compressedKey' in last message"
|
assert "compressedKey" in last_message, "Missing 'compressedKey' in last message"
|
||||||
|
|
||||||
def validate_event_against_response(self, event, fields_to_validate):
|
def validate_event_against_response(self, event, fields_to_validate):
|
||||||
|
@ -35,7 +49,7 @@ class ContactRequestValidator:
|
||||||
response_value = response_chat.get("lastMessage", {}).get(response_field)
|
response_value = response_chat.get("lastMessage", {}).get(response_field)
|
||||||
event_value = event_chat.get("lastMessage", {}).get(event_field)
|
event_value = event_chat.get("lastMessage", {}).get(event_field)
|
||||||
assert response_value == event_value, (
|
assert response_value == event_value, (
|
||||||
f"Mismatch for '{response_field}': expected '{response_value}', got '{event_value}'"
|
f"Mismatch for '{response_field}': Expected '{response_value}', found '{event_value}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
def run_all_validations(self, expected_chat_id, expected_display_name, expected_text):
|
def run_all_validations(self, expected_chat_id, expected_display_name, expected_text):
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
from src.libs.custom_logger import get_custom_logger
|
||||||
|
|
||||||
|
logger = get_custom_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class MessageValidator:
|
||||||
|
def __init__(self, response):
|
||||||
|
self.response = response
|
||||||
|
|
||||||
|
def validate_response_structure(self):
|
||||||
|
assert self.response.get("jsonrpc") == "2.0", "Invalid JSON-RPC version"
|
||||||
|
assert "result" in self.response, "Missing 'result' in response"
|
||||||
|
|
||||||
|
def validate_chat_data(self, expected_chat_id, expected_display_name, expected_text):
|
||||||
|
chats = self.response["result"].get("chats", [])
|
||||||
|
assert len(chats) > 0, "No chats found in the response"
|
||||||
|
|
||||||
|
chat = chats[0]
|
||||||
|
actual_chat_id = chat.get("id")
|
||||||
|
assert actual_chat_id == expected_chat_id, (
|
||||||
|
f"Chat ID mismatch: Expected '{expected_chat_id}', found '{actual_chat_id}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
actual_chat_name = chat.get("name")
|
||||||
|
assert actual_chat_name.startswith("0x"), (
|
||||||
|
f"Invalid chat name format: Expected name to start with '0x', found '{actual_chat_name}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
last_message = chat.get("lastMessage", {})
|
||||||
|
actual_text = last_message.get("text")
|
||||||
|
assert actual_text == expected_text, (
|
||||||
|
f"Message text mismatch: Expected '{expected_text}', found '{actual_text}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "compressedKey" in last_message, "Missing 'compressedKey' in last message"
|
||||||
|
|
||||||
|
def validate_event_against_response(self, event, fields_to_validate):
|
||||||
|
chats_in_event = event.get("event", {}).get("chats", [])
|
||||||
|
assert len(chats_in_event) > 0, "No chats found in the event"
|
||||||
|
|
||||||
|
response_chat = self.response["result"]["chats"][0]
|
||||||
|
event_chat = chats_in_event[0]
|
||||||
|
|
||||||
|
for response_field, event_field in fields_to_validate.items():
|
||||||
|
response_value = response_chat.get("lastMessage", {}).get(response_field)
|
||||||
|
event_value = event_chat.get("lastMessage", {}).get(event_field)
|
||||||
|
assert response_value == event_value, (
|
||||||
|
f"Mismatch for '{response_field}': Expected '{response_value}', found '{event_value}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
def run_all_validations(self, expected_chat_id, expected_display_name, expected_text):
|
||||||
|
self.validate_response_structure()
|
||||||
|
self.validate_chat_data(expected_chat_id, expected_display_name, expected_text)
|
||||||
|
logger.info("All validations passed for the one-to-one message response.")
|
Loading…
Reference in New Issue