mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-09-16 19:42:36 +00:00
233 lines
8.0 KiB
Python
233 lines
8.0 KiB
Python
"""Performance and stress tests for LXMFy."""
|
|
|
|
import os
|
|
import time
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import LXMF
|
|
import psutil
|
|
import pytest
|
|
import RNS
|
|
|
|
from lxmfy import BotConfig, LXMFBot
|
|
from lxmfy.middleware import MiddlewareType
|
|
|
|
|
|
def get_memory_usage():
|
|
"""Get current memory usage in MB."""
|
|
process = psutil.Process(os.getpid())
|
|
return process.memory_info().rss / (1024 * 1024)
|
|
|
|
|
|
class TestPerformance:
|
|
"""Stress tests for LXMFy."""
|
|
|
|
@pytest.fixture
|
|
def stress_bot(self, test_config_dir):
|
|
"""Create a bot configured for stress testing."""
|
|
config = BotConfig(
|
|
name="StressBot",
|
|
test_mode=True,
|
|
storage_path=str(test_config_dir / "stress_storage"),
|
|
signature_verification_enabled=True,
|
|
require_message_signatures=False,
|
|
rate_limit=10000, # High limit for testing
|
|
cooldown=1,
|
|
cogs_enabled=False,
|
|
first_message_enabled=False, # Disable first message handling for performance tests
|
|
)
|
|
bot = LXMFBot(**config.__dict__)
|
|
# Mock some components to avoid RNS overhead in performance tests
|
|
bot.router = MagicMock()
|
|
bot.local = MagicMock()
|
|
bot.local.hash = b"local_identity_hash"
|
|
return bot
|
|
|
|
def test_message_processing_flood(self, stress_bot):
|
|
"""Flood the bot with messages to test processing throughput."""
|
|
message_count = 10000 # Increased to 10k
|
|
messages = []
|
|
|
|
processed_count = 0
|
|
|
|
def count_handler(sender, msg):
|
|
nonlocal processed_count
|
|
processed_count += 1
|
|
return True
|
|
|
|
stress_bot.message_handlers.append(count_handler)
|
|
|
|
# Pre-generate messages
|
|
for i in range(message_count):
|
|
mock_msg = MagicMock(spec=LXMF.LXMessage)
|
|
mock_msg.content = f"Stress test message {i}".encode()
|
|
mock_msg.title = f"Title {i}".encode()
|
|
mock_msg.source_hash = b"source_" + str(i % 10).encode().rjust(10, b"0")
|
|
mock_msg.destination_hash = b"local_identity_hash"
|
|
mock_msg.hash = b"hash_" + os.urandom(16)
|
|
mock_msg.fields = {}
|
|
mock_msg.signature_validated = True
|
|
messages.append(mock_msg)
|
|
|
|
start_mem = get_memory_usage()
|
|
start_time = time.time()
|
|
|
|
# Simulate receiving messages
|
|
for msg in messages:
|
|
stress_bot._message_received(msg)
|
|
|
|
duration = time.time() - start_time
|
|
end_mem = get_memory_usage()
|
|
|
|
print(f"\n[Performance] Processed {message_count} messages in {duration:.4f}s")
|
|
print(f"[Performance] Throughput: {message_count / duration:.2f} msg/s")
|
|
print(f"[Performance] Memory delta: {end_mem - start_mem:.2f} MB")
|
|
|
|
# Verify all messages were processed
|
|
assert processed_count == message_count
|
|
assert duration < 2.0 # Should be very fast in test mode
|
|
|
|
def test_signature_verification_stress(self, stress_bot):
|
|
"""Test performance of signature verification logic."""
|
|
sig_manager = stress_bot.signature_manager
|
|
identity = RNS.Identity()
|
|
sender_hash = RNS.hexrep(identity.hash, delimit=False)
|
|
|
|
# Pre-generate a signed message
|
|
mock_msg = MagicMock(spec=LXMF.LXMessage)
|
|
mock_msg.content = b"Performance test content"
|
|
mock_msg.title = b"Performance test title"
|
|
mock_msg.source_hash = identity.hash
|
|
mock_msg.destination_hash = b"dest"
|
|
mock_msg.fields = {}
|
|
mock_msg.timestamp = int(time.time())
|
|
|
|
# Our signature logic uses _canonicalize_message
|
|
signature = sig_manager.sign_message(mock_msg, identity)
|
|
|
|
iteration_count = 5000 # Increased to 5k
|
|
start_time = time.time()
|
|
|
|
# Patch where it is USED, which is lxmfy.signatures
|
|
with patch("lxmfy.signatures.RNS.Identity.recall", return_value=identity):
|
|
for _ in range(iteration_count):
|
|
sig_manager.verify_message_signature(mock_msg, signature, sender_hash)
|
|
|
|
duration = time.time() - start_time
|
|
print(
|
|
f"\n[Performance] Verified {iteration_count} signatures in {duration:.4f}s",
|
|
)
|
|
print(
|
|
f"[Performance] Avg verification time: {(duration / iteration_count) * 1000:.4f}ms",
|
|
)
|
|
|
|
assert duration < 5.0
|
|
|
|
def test_storage_extreme_load(self, stress_bot):
|
|
"""Test storage performance under heavy load."""
|
|
storage = stress_bot.storage
|
|
record_count = 10000 # Increased to 10k
|
|
|
|
start_mem = get_memory_usage()
|
|
start_time = time.time()
|
|
|
|
# Write load
|
|
for i in range(record_count):
|
|
storage.set(f"key_{i}", {"data": "value" * 10, "index": i})
|
|
|
|
write_duration = time.time() - start_time
|
|
|
|
# Read load
|
|
read_start = time.time()
|
|
for i in range(record_count):
|
|
storage.get(f"key_{i}")
|
|
read_duration = time.time() - read_start
|
|
|
|
end_mem = get_memory_usage()
|
|
|
|
print(f"\n[Performance] Storage {record_count} records:")
|
|
print(
|
|
f"[Performance] Write time: {write_duration:.4f}s ({record_count / write_duration:.2f} ops/s)",
|
|
)
|
|
print(
|
|
f"[Performance] Read time: {read_duration:.4f}s ({record_count / read_duration:.2f} ops/s)",
|
|
)
|
|
print(f"[Performance] Memory delta: {end_mem - start_mem:.2f} MB")
|
|
|
|
assert write_duration < 10.0
|
|
assert read_duration < 5.0
|
|
|
|
def test_heavy_middleware_load(self, stress_bot):
|
|
"""Test impact of multiple middlewares on message processing."""
|
|
# Add multiple dummy middlewares
|
|
for i in range(10):
|
|
|
|
def make_middleware(idx):
|
|
def mw(ctx):
|
|
ctx.data[f"mw_{idx}"] = True
|
|
return ctx
|
|
|
|
return mw
|
|
|
|
stress_bot.middleware.register(MiddlewareType.PRE_EVENT, make_middleware(i))
|
|
|
|
message_count = 500
|
|
|
|
processed_count = 0
|
|
|
|
def count_handler(sender, msg):
|
|
nonlocal processed_count
|
|
processed_count += 1
|
|
return True
|
|
|
|
stress_bot.message_handlers.append(count_handler)
|
|
|
|
start_time = time.time()
|
|
for i in range(message_count):
|
|
mock_msg = MagicMock(spec=LXMF.LXMessage)
|
|
mock_msg.content = b"middleware test"
|
|
mock_msg.source_hash = b"source"
|
|
mock_msg.destination_hash = b"local"
|
|
mock_msg.hash = b"hash_" + str(i).encode()
|
|
mock_msg.fields = {}
|
|
mock_msg.signature_validated = True
|
|
stress_bot._message_received(mock_msg)
|
|
|
|
duration = time.time() - start_time
|
|
print(
|
|
f"\n[Performance] Middleware (10 layers) x {message_count} msgs: {duration:.4f}s",
|
|
)
|
|
|
|
assert processed_count == message_count
|
|
assert duration < 2.0
|
|
|
|
def test_memory_stability_long_run(self, stress_bot):
|
|
"""Run bot for a period to check for memory leaks."""
|
|
duration_seconds = 5
|
|
start_time = time.time()
|
|
start_mem = get_memory_usage()
|
|
|
|
message_count = 0
|
|
mock_msg = MagicMock(spec=LXMF.LXMessage)
|
|
mock_msg.content = b"stability test"
|
|
mock_msg.source_hash = b"source"
|
|
mock_msg.destination_hash = b"local"
|
|
mock_msg.fields = {}
|
|
mock_msg.signature_validated = True
|
|
|
|
while time.time() - start_time < duration_seconds:
|
|
mock_msg.hash = os.urandom(16)
|
|
stress_bot._message_received(mock_msg)
|
|
message_count += 1
|
|
|
|
end_mem = get_memory_usage()
|
|
print("\n[Performance] Stability run (5s):")
|
|
print(f"[Performance] Total messages: {message_count}")
|
|
print(f"[Performance] Start memory: {start_mem:.2f} MB")
|
|
print(f"[Performance] End memory: {end_mem:.2f} MB")
|
|
print(f"[Performance] Memory delta: {end_mem - start_mem:.2f} MB")
|
|
|
|
# Stability check: Memory shouldn't grow boundlessly
|
|
# We allow some growth for caches but not massive
|
|
assert (end_mem - start_mem) < 10.0
|