From 5be71901bbea23f5bb220a1fbd8168e940b7d181 Mon Sep 17 00:00:00 2001 From: Jan Felix Wiebe Date: Wed, 9 Jul 2025 22:28:39 +0200 Subject: [PATCH] added test cases for multiple connected clients --- backend/test_automated.py | 379 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) diff --git a/backend/test_automated.py b/backend/test_automated.py index 8986519..b875562 100644 --- a/backend/test_automated.py +++ b/backend/test_automated.py @@ -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"""