added test cases for multiple connected clients
This commit is contained in:
parent
87310d77f0
commit
5be71901bb
1 changed files with 379 additions and 0 deletions
|
@ -590,6 +590,385 @@ class TestWebSocket:
|
|||
websocket_manager.disconnect(mock_ws)
|
||||
|
||||
|
||||
class TestWebSocketMultiClient:
|
||||
"""Test-Klasse für Multi-Client WebSocket-Funktionalität"""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_multiple_clients_receive_order_created(self):
|
||||
"""Test dass alle verbundenen Clients order_created Nachrichten erhalten"""
|
||||
from websocket_manager import websocket_manager
|
||||
from database import db
|
||||
from models import Drink, DrinkType, MateType
|
||||
|
||||
# Erstelle mehrere Test-WebSockets
|
||||
class MockWebSocket:
|
||||
def __init__(self, client_id):
|
||||
self.client_id = client_id
|
||||
self.messages = []
|
||||
self.closed = False
|
||||
|
||||
async def accept(self):
|
||||
pass
|
||||
|
||||
async def send_text(self, message):
|
||||
self.messages.append(message)
|
||||
|
||||
async def receive_text(self):
|
||||
return "ping"
|
||||
|
||||
async def close(self):
|
||||
self.closed = True
|
||||
|
||||
# Verbinde mehrere Mock-WebSockets
|
||||
mock_ws1 = MockWebSocket("client1")
|
||||
mock_ws2 = MockWebSocket("client2")
|
||||
mock_ws3 = MockWebSocket("client3")
|
||||
|
||||
await websocket_manager.connect(mock_ws1)
|
||||
await websocket_manager.connect(mock_ws2)
|
||||
await websocket_manager.connect(mock_ws3)
|
||||
|
||||
assert len(websocket_manager.active_connections) == 3
|
||||
|
||||
# Erstelle eine neue Bestellung (sollte an alle Clients broadcasten)
|
||||
drinks = [
|
||||
Drink(
|
||||
drink_type=DrinkType.TSCHUNK,
|
||||
mate_type=MateType.CLUB_MATE,
|
||||
quantity=2,
|
||||
notes="Multi-Client Test"
|
||||
)
|
||||
]
|
||||
|
||||
order = await db.create_order(drinks)
|
||||
|
||||
# Prüfe, dass alle Clients die order_created Nachricht erhalten haben
|
||||
for mock_ws in [mock_ws1, mock_ws2, mock_ws3]:
|
||||
assert len(mock_ws.messages) >= 1
|
||||
|
||||
# Finde die "order_created" Nachricht
|
||||
order_created_found = False
|
||||
for message in mock_ws.messages:
|
||||
try:
|
||||
data = json.loads(message)
|
||||
if data.get("type") == "order_created":
|
||||
order_created_found = True
|
||||
assert data["order"]["id"] == order.id
|
||||
assert "timestamp" in data
|
||||
break
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
assert order_created_found, f"Client {mock_ws.client_id} hat keine order_created Nachricht erhalten"
|
||||
|
||||
# Cleanup
|
||||
await db.delete_order(order.id)
|
||||
websocket_manager.disconnect(mock_ws1)
|
||||
websocket_manager.disconnect(mock_ws2)
|
||||
websocket_manager.disconnect(mock_ws3)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_multiple_clients_receive_order_deleted(self):
|
||||
"""Test dass alle verbundenen Clients order_deleted Nachrichten erhalten"""
|
||||
from websocket_manager import websocket_manager
|
||||
from database import db
|
||||
from models import Drink, DrinkType, MateType
|
||||
|
||||
# Erstelle mehrere Test-WebSockets
|
||||
class MockWebSocket:
|
||||
def __init__(self, client_id):
|
||||
self.client_id = client_id
|
||||
self.messages = []
|
||||
self.closed = False
|
||||
|
||||
async def accept(self):
|
||||
pass
|
||||
|
||||
async def send_text(self, message):
|
||||
self.messages.append(message)
|
||||
|
||||
async def receive_text(self):
|
||||
return "ping"
|
||||
|
||||
async def close(self):
|
||||
self.closed = True
|
||||
|
||||
# Verbinde mehrere Mock-WebSockets
|
||||
mock_ws1 = MockWebSocket("client1")
|
||||
mock_ws2 = MockWebSocket("client2")
|
||||
|
||||
await websocket_manager.connect(mock_ws1)
|
||||
await websocket_manager.connect(mock_ws2)
|
||||
|
||||
# Erstelle zuerst eine Bestellung
|
||||
drinks = [
|
||||
Drink(
|
||||
drink_type=DrinkType.VIRGIN_TSCHUNK,
|
||||
mate_type=MateType.FLORA_MATE,
|
||||
quantity=1,
|
||||
notes="Delete Test"
|
||||
)
|
||||
]
|
||||
|
||||
order = await db.create_order(drinks)
|
||||
order_id = order.id
|
||||
|
||||
# Lösche die Bestellung (sollte an alle Clients broadcasten)
|
||||
success = await db.delete_order(order_id)
|
||||
assert success is True
|
||||
|
||||
# Prüfe, dass alle Clients die order_deleted Nachricht erhalten haben
|
||||
for mock_ws in [mock_ws1, mock_ws2]:
|
||||
assert len(mock_ws.messages) >= 2 # Mindestens create + delete
|
||||
|
||||
# Finde die "order_deleted" Nachricht
|
||||
order_deleted_found = False
|
||||
for message in mock_ws.messages:
|
||||
try:
|
||||
data = json.loads(message)
|
||||
if data.get("type") == "order_deleted":
|
||||
order_deleted_found = True
|
||||
assert data["order_id"] == order_id
|
||||
assert "timestamp" in data
|
||||
break
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
assert order_deleted_found, f"Client {mock_ws.client_id} hat keine order_deleted Nachricht erhalten"
|
||||
|
||||
# Cleanup
|
||||
websocket_manager.disconnect(mock_ws1)
|
||||
websocket_manager.disconnect(mock_ws2)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_client_disconnection_handling(self):
|
||||
"""Test dass getrennte Clients keine weiteren Nachrichten erhalten"""
|
||||
from websocket_manager import websocket_manager
|
||||
from database import db
|
||||
from models import Drink, DrinkType, MateType
|
||||
|
||||
# Erstelle Test-WebSockets
|
||||
class MockWebSocket:
|
||||
def __init__(self, client_id):
|
||||
self.client_id = client_id
|
||||
self.messages = []
|
||||
self.closed = False
|
||||
|
||||
async def accept(self):
|
||||
pass
|
||||
|
||||
async def send_text(self, message):
|
||||
if not self.closed:
|
||||
self.messages.append(message)
|
||||
|
||||
async def receive_text(self):
|
||||
return "ping"
|
||||
|
||||
async def close(self):
|
||||
self.closed = True
|
||||
|
||||
# Verbinde WebSockets
|
||||
mock_ws1 = MockWebSocket("client1")
|
||||
mock_ws2 = MockWebSocket("client2")
|
||||
|
||||
await websocket_manager.connect(mock_ws1)
|
||||
await websocket_manager.connect(mock_ws2)
|
||||
|
||||
# Trenne ersten Client
|
||||
websocket_manager.disconnect(mock_ws1)
|
||||
assert len(websocket_manager.active_connections) == 1
|
||||
|
||||
# Erstelle eine Bestellung (sollte nur an client2 gehen)
|
||||
drinks = [
|
||||
Drink(
|
||||
drink_type=DrinkType.TSCHUNK_HANNOVER_MISCHE,
|
||||
mate_type=MateType.CLUB_MATE,
|
||||
quantity=1
|
||||
)
|
||||
]
|
||||
|
||||
order = await db.create_order(drinks)
|
||||
|
||||
# Prüfe, dass nur client2 die Nachricht erhalten hat
|
||||
assert len(mock_ws1.messages) == 0 # Getrennter Client sollte keine Nachrichten erhalten
|
||||
assert len(mock_ws2.messages) >= 1 # Verbundener Client sollte Nachricht erhalten
|
||||
|
||||
# Prüfe, dass client2 die order_created Nachricht erhalten hat
|
||||
order_created_found = False
|
||||
for message in mock_ws2.messages:
|
||||
try:
|
||||
data = json.loads(message)
|
||||
if data.get("type") == "order_created":
|
||||
order_created_found = True
|
||||
assert data["order"]["id"] == order.id
|
||||
break
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
assert order_created_found, "Verbundener Client hat keine order_created Nachricht erhalten"
|
||||
|
||||
# Cleanup
|
||||
await db.delete_order(order.id)
|
||||
websocket_manager.disconnect(mock_ws2)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_concurrent_client_operations(self):
|
||||
"""Test gleichzeitige Operationen mit mehreren Clients"""
|
||||
from websocket_manager import websocket_manager
|
||||
from database import db
|
||||
from models import Drink, DrinkType, MateType
|
||||
import asyncio
|
||||
|
||||
# Erstelle Test-WebSockets
|
||||
class MockWebSocket:
|
||||
def __init__(self, client_id):
|
||||
self.client_id = client_id
|
||||
self.messages = []
|
||||
self.closed = False
|
||||
|
||||
async def accept(self):
|
||||
pass
|
||||
|
||||
async def send_text(self, message):
|
||||
self.messages.append(message)
|
||||
|
||||
async def receive_text(self):
|
||||
return "ping"
|
||||
|
||||
async def close(self):
|
||||
self.closed = True
|
||||
|
||||
# Verbinde mehrere WebSockets
|
||||
clients = []
|
||||
for i in range(5):
|
||||
client = MockWebSocket(f"client{i}")
|
||||
await websocket_manager.connect(client)
|
||||
clients.append(client)
|
||||
|
||||
assert len(websocket_manager.active_connections) == 5
|
||||
|
||||
# Erstelle mehrere Bestellungen schnell hintereinander
|
||||
orders = []
|
||||
for i in range(3):
|
||||
drinks = [
|
||||
Drink(
|
||||
drink_type=DrinkType.TSCHUNK,
|
||||
mate_type=MateType.CLUB_MATE,
|
||||
quantity=i + 1,
|
||||
notes=f"Concurrent Test {i + 1}"
|
||||
)
|
||||
]
|
||||
order = await db.create_order(drinks)
|
||||
orders.append(order)
|
||||
await asyncio.sleep(0.05) # Kurze Pause
|
||||
|
||||
# Prüfe, dass alle Clients alle Nachrichten erhalten haben
|
||||
for client in clients:
|
||||
# Jeder Client sollte mindestens 3 order_created Nachrichten erhalten haben
|
||||
order_created_count = 0
|
||||
for message in client.messages:
|
||||
try:
|
||||
data = json.loads(message)
|
||||
if data.get("type") == "order_created":
|
||||
order_created_count += 1
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
assert order_created_count >= 3, f"Client {client.client_id} hat nicht alle Nachrichten erhalten: {order_created_count}/3"
|
||||
|
||||
# Lösche alle Bestellungen
|
||||
for order in orders:
|
||||
await db.delete_order(order.id)
|
||||
|
||||
# Prüfe, dass alle Clients die delete-Nachrichten erhalten haben
|
||||
for client in clients:
|
||||
order_deleted_count = 0
|
||||
for message in client.messages:
|
||||
try:
|
||||
data = json.loads(message)
|
||||
if data.get("type") == "order_deleted":
|
||||
order_deleted_count += 1
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
assert order_deleted_count >= 3, f"Client {client.client_id} hat nicht alle delete-Nachrichten erhalten: {order_deleted_count}/3"
|
||||
|
||||
# Cleanup
|
||||
for client in clients:
|
||||
websocket_manager.disconnect(client)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_websocket_message_format_consistency(self):
|
||||
"""Test dass alle WebSocket-Nachrichten konsistentes Format haben"""
|
||||
from websocket_manager import websocket_manager
|
||||
from database import db
|
||||
from models import Drink, DrinkType, MateType
|
||||
|
||||
# Erstelle Test-WebSocket
|
||||
class MockWebSocket:
|
||||
def __init__(self):
|
||||
self.messages = []
|
||||
self.closed = False
|
||||
|
||||
async def accept(self):
|
||||
pass
|
||||
|
||||
async def send_text(self, message):
|
||||
self.messages.append(message)
|
||||
|
||||
async def receive_text(self):
|
||||
return "ping"
|
||||
|
||||
async def close(self):
|
||||
self.closed = True
|
||||
|
||||
mock_ws = MockWebSocket()
|
||||
await websocket_manager.connect(mock_ws)
|
||||
|
||||
# Erstelle und lösche eine Bestellung
|
||||
drinks = [
|
||||
Drink(
|
||||
drink_type=DrinkType.TSCHUNK,
|
||||
mate_type=MateType.CLUB_MATE,
|
||||
quantity=1
|
||||
)
|
||||
]
|
||||
|
||||
order = await db.create_order(drinks)
|
||||
order_id = order.id
|
||||
|
||||
await db.delete_order(order_id)
|
||||
|
||||
# Prüfe Nachrichtenformat
|
||||
for message in mock_ws.messages:
|
||||
try:
|
||||
data = json.loads(message)
|
||||
|
||||
# Alle Nachrichten sollten diese Felder haben
|
||||
assert "type" in data
|
||||
assert "timestamp" in data
|
||||
|
||||
# Prüfe spezifische Nachrichtentypen
|
||||
if data["type"] == "order_created":
|
||||
assert "order" in data
|
||||
assert "id" in data["order"]
|
||||
assert "order_date" in data["order"]
|
||||
assert "drinks" in data["order"]
|
||||
|
||||
elif data["type"] == "order_deleted":
|
||||
assert "order_id" in data
|
||||
|
||||
elif data["type"] == "all_orders":
|
||||
assert "orders" in data
|
||||
assert isinstance(data["orders"], list)
|
||||
|
||||
except json.JSONDecodeError:
|
||||
assert False, f"Ungültiges JSON-Format: {message}"
|
||||
|
||||
# Cleanup
|
||||
websocket_manager.disconnect(mock_ws)
|
||||
|
||||
|
||||
class TestDatabase:
|
||||
"""Test-Klasse für Datenbankfunktionalität"""
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue