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"
|
||||
REMOVE_TC_CMD = "sudo tc qdisc del dev eth0 root"
|
||||
NUM_CONTACT_REQUESTS = int(os.getenv("NUM_CONTACT_REQUESTS", "5"))
|
||||
NUM_MESSAGES = int(os.getenv("NUM_MESSAGES", "25"))
|
||||
DELAY_BETWEEN_MESSAGES = int(os.getenv("NUM_MESSAGES", "1"))
|
||||
NUM_MESSAGES = int(os.getenv("NUM_MESSAGES", "20"))
|
||||
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):
|
||||
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)
|
||||
|
||||
websocket_thread = threading.Thread(target=self.signal_client._connect)
|
||||
|
|
|
@ -12,7 +12,7 @@ logger = get_custom_logger(__name__)
|
|||
|
||||
class TestContactRequest(StepsCommon):
|
||||
def test_contact_request_baseline(self):
|
||||
timeout_secs = 3
|
||||
timeout_secs = 5
|
||||
num_contact_requests = NUM_CONTACT_REQUESTS
|
||||
project_root = get_project_root()
|
||||
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__)
|
||||
|
||||
|
||||
class ContactRequestValidator:
|
||||
def __init__(self, response):
|
||||
self.response = response
|
||||
|
@ -16,12 +15,27 @@ class ContactRequestValidator:
|
|||
assert len(chats) > 0, "No chats found in the response"
|
||||
|
||||
chat = chats[0]
|
||||
assert chat.get("id") == expected_chat_id, f"Chat ID mismatch: Expected {expected_chat_id}"
|
||||
assert chat.get("name").startswith("0x"), "Invalid chat name format"
|
||||
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", {})
|
||||
assert last_message.get("text") == expected_text, "Message text mismatch"
|
||||
assert last_message.get("contactRequestState") == 1, "Unexpected contact request state"
|
||||
actual_text = last_message.get("text")
|
||||
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"
|
||||
|
||||
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)
|
||||
event_value = event_chat.get("lastMessage", {}).get(event_field)
|
||||
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):
|
||||
|
|
|
@ -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