1e3dc11d59
feat(test-suite): 新增测试套件模块,包含API测试客户端和测试配置 fix(api): 修复数据库实体和仓库的删除操作返回值 style(api): 统一数据库表名和字段命名 perf(api): 添加缓存注解提升配置查询性能 test(api): 添加H2测试数据库配置支持 chore: 清理旧的测试文件和脚本
191 lines
6.4 KiB
Python
191 lines
6.4 KiB
Python
"""
|
|
WebSocket实时通信测试用例
|
|
"""
|
|
|
|
import pytest
|
|
import asyncio
|
|
import json
|
|
import os
|
|
from websockets.client import connect
|
|
from websockets.exceptions import ConnectionClosed
|
|
|
|
|
|
@pytest.mark.websocket
|
|
@pytest.mark.regression
|
|
class TestWebSocket:
|
|
"""WebSocket实时通信测试类"""
|
|
|
|
@pytest.fixture
|
|
def websocket_url(self):
|
|
"""WebSocket连接URL"""
|
|
api_base_url = os.getenv("API_BASE_URL", "http://localhost:8084")
|
|
ws_url = api_base_url.replace("http://", "ws://")
|
|
return f"{ws_url}/ws"
|
|
|
|
@pytest.fixture
|
|
async def websocket_connection(self, websocket_url):
|
|
"""WebSocket连接fixture"""
|
|
async with connect(websocket_url) as websocket:
|
|
yield websocket
|
|
|
|
@pytest.fixture
|
|
async def authenticated_websocket(self, websocket_url, authenticated_client):
|
|
"""带认证的WebSocket连接"""
|
|
token = authenticated_client.headers.get("Authorization")
|
|
url_with_token = f"{websocket_url}?token={token.replace('Bearer ', '')}"
|
|
|
|
async with connect(url_with_token) as websocket:
|
|
yield websocket
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_connection(self, websocket_url):
|
|
"""测试WebSocket连接建立"""
|
|
try:
|
|
async with connect(websocket_url) as websocket:
|
|
assert websocket.open
|
|
except ConnectionRefusedError:
|
|
pytest.skip("WebSocket服务未启动")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_ping_pong(self, websocket_connection):
|
|
"""测试WebSocket心跳机制"""
|
|
ping_message = {
|
|
"type": "ping",
|
|
"timestamp": 1234567890
|
|
}
|
|
|
|
await websocket_connection.send(json.dumps(ping_message))
|
|
|
|
response = await asyncio.wait_for(websocket_connection.recv(), timeout=5.0)
|
|
pong_message = json.loads(response)
|
|
|
|
assert pong_message["type"] == "pong"
|
|
assert "timestamp" in pong_message
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_subscribe(self, websocket_connection):
|
|
"""测试WebSocket订阅"""
|
|
subscribe_message = {
|
|
"type": "subscribe",
|
|
"channel": "notifications"
|
|
}
|
|
|
|
await websocket_connection.send(json.dumps(subscribe_message))
|
|
|
|
response = await asyncio.wait_for(websocket_connection.recv(), timeout=5.0)
|
|
message = json.loads(response)
|
|
|
|
assert message["type"] in ["subscribe_ack", "pong"]
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_multiple_messages(self, websocket_connection):
|
|
"""测试WebSocket多消息处理"""
|
|
messages = [
|
|
{"type": "ping"},
|
|
{"type": "subscribe", "channel": "test"},
|
|
{"type": "ping"}
|
|
]
|
|
|
|
responses = []
|
|
for msg in messages:
|
|
await websocket_connection.send(json.dumps(msg))
|
|
try:
|
|
response = await asyncio.wait_for(websocket_connection.recv(), timeout=2.0)
|
|
responses.append(json.loads(response))
|
|
except asyncio.TimeoutError:
|
|
pass
|
|
|
|
assert len(responses) >= 2
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_invalid_message(self, websocket_connection):
|
|
"""测试WebSocket无效消息处理"""
|
|
invalid_messages = [
|
|
"invalid json",
|
|
"",
|
|
json.dumps({"type": "unknown_type"}),
|
|
json.dumps({})
|
|
]
|
|
|
|
for msg in invalid_messages:
|
|
try:
|
|
await websocket_connection.send(msg)
|
|
await asyncio.sleep(0.5)
|
|
except Exception:
|
|
pass
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_connection_close(self, websocket_url):
|
|
"""测试WebSocket连接关闭"""
|
|
async with connect(websocket_url) as websocket:
|
|
assert websocket.open
|
|
await websocket.close()
|
|
assert not websocket.open
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_timeout(self, websocket_url):
|
|
"""测试WebSocket超时"""
|
|
try:
|
|
async with connect(websocket_url, ping_timeout=2.0) as websocket:
|
|
await asyncio.sleep(3.0)
|
|
except (ConnectionClosed, asyncio.TimeoutError):
|
|
pass
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_concurrent_connections(self, websocket_url):
|
|
"""测试WebSocket并发连接"""
|
|
async def create_connection():
|
|
try:
|
|
async with connect(websocket_url) as websocket:
|
|
await websocket.send(json.dumps({"type": "ping"}))
|
|
await asyncio.wait_for(websocket_connection.recv(), timeout=2.0)
|
|
except Exception:
|
|
pass
|
|
|
|
connections = [create_connection() for _ in range(5)]
|
|
await asyncio.gather(*connections, return_exceptions=True)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_large_message(self, websocket_connection):
|
|
"""测试WebSocket大消息处理"""
|
|
large_data = "x" * 10000
|
|
message = {
|
|
"type": "test",
|
|
"data": large_data
|
|
}
|
|
|
|
await websocket_connection.send(json.dumps(message))
|
|
|
|
try:
|
|
response = await asyncio.wait_for(websocket_connection.recv(), timeout=5.0)
|
|
assert response
|
|
except asyncio.TimeoutError:
|
|
pass
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_reconnect(self, websocket_url):
|
|
"""测试WebSocket重连"""
|
|
for i in range(3):
|
|
try:
|
|
async with connect(websocket_url) as websocket:
|
|
await websocket.send(json.dumps({"type": "ping"}))
|
|
response = await asyncio.wait_for(websocket.recv(), timeout=2.0)
|
|
assert response
|
|
except Exception:
|
|
pass
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_unicode_message(self, websocket_connection):
|
|
"""测试WebSocket Unicode消息"""
|
|
unicode_message = {
|
|
"type": "test",
|
|
"content": "测试中文🎉🚀"
|
|
}
|
|
|
|
await websocket_connection.send(json.dumps(unicode_message))
|
|
|
|
try:
|
|
response = await asyncio.wait_for(websocket_connection.recv(), timeout=2.0)
|
|
assert response
|
|
except asyncio.TimeoutError:
|
|
pass |