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)
|
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:
|
class TestDatabase:
|
||||||
"""Test-Klasse für Datenbankfunktionalität"""
|
"""Test-Klasse für Datenbankfunktionalität"""
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue