VWED_server/tests/test_websocket_module.py

305 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
WebSocket模块测试
测试WebSocket内置函数的基本功能包括模拟WebSocket服务和客户端
"""
import asyncio
import json
import time
import threading
import sys
import os
from unittest.mock import Mock, AsyncMock, patch
from typing import Dict, Any, Set
# 添加项目根目录到Python路径
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(current_dir)
if parent_dir not in sys.path:
sys.path.insert(0, parent_dir)
# 导入被测试的模块
try:
from services.online_script.built_in_modules.websocket_module import VWEDWebSocketModule
from utils.logger import get_logger
except ImportError as e:
print(f"导入项目模块失败: {e}")
print("请确保从项目根目录运行此脚本")
sys.exit(1)
logger = get_logger("tests.websocket_module")
class MockWebSocket:
"""模拟WebSocket连接"""
def __init__(self, client_ip: str, client_id: str = None):
self.client = Mock()
self.client.host = client_ip
self.client_id = client_id or f"client_{client_ip.replace('.', '_')}"
self.messages = []
self.closed = False
async def send_text(self, message: str):
"""模拟发送文本消息"""
if self.closed:
raise Exception("WebSocket已关闭")
self.messages.append(message)
logger.info(f"模拟WebSocket发送消息: {message}{self.client.host}")
def close(self):
"""关闭连接"""
self.closed = True
class MockConnectionManager:
"""模拟WebSocket连接管理器"""
def __init__(self):
self.active_connections: Dict[str, Set[MockWebSocket]] = {}
self.storage_location_connections: Dict[str, Set[MockWebSocket]] = {}
def add_connection(self, task_record_id: str, websocket: MockWebSocket):
"""添加活跃连接"""
if task_record_id not in self.active_connections:
self.active_connections[task_record_id] = set()
self.active_connections[task_record_id].add(websocket)
def add_storage_connection(self, scene_id: str, websocket: MockWebSocket):
"""添加库位状态连接"""
if scene_id not in self.storage_location_connections:
self.storage_location_connections[scene_id] = set()
self.storage_location_connections[scene_id].add(websocket)
async def send_personal_message(self, message: str, websocket: MockWebSocket):
"""发送个人消息"""
await websocket.send_text(message)
class WebSocketModuleTest:
"""WebSocket模块测试类"""
def __init__(self):
self.mock_manager = MockConnectionManager()
self.module = VWEDWebSocketModule("test_script_001")
# 设置模拟管理器
self.module._manager = self.mock_manager
def setup_test_connections(self):
"""设置测试连接"""
# 创建模拟WebSocket连接
self.ws1 = MockWebSocket("192.168.1.100", "client1")
self.ws2 = MockWebSocket("192.168.1.101", "client2")
self.ws3 = MockWebSocket("192.168.1.102", "client3")
# 添加到连接管理器
self.mock_manager.add_connection("task_001", self.ws1)
self.mock_manager.add_connection("task_002", self.ws2)
self.mock_manager.add_storage_connection("scene_001", self.ws3)
logger.info("测试连接设置完成")
async def test_send_msg_by_ip(self):
"""测试根据IP发送消息"""
logger.info("=== 测试根据IP发送消息 ===")
try:
# 测试发送消息到存在的IP
self.module.send_msg_to_wsc_by_client_ip("测试消息1", "192.168.1.100")
await asyncio.sleep(0.1) # 等待异步操作完成
# 检查消息是否发送
assert len(self.ws1.messages) > 0, "消息未发送到正确的WebSocket连接"
assert "测试消息1" in self.ws1.messages, "发送的消息内容不正确"
logger.info(f"✓ 成功发送消息到IP 192.168.1.100,收到消息: {self.ws1.messages}")
# 测试发送消息到不存在的IP
try:
self.module.send_msg_to_wsc_by_client_ip("测试消息2", "192.168.1.999")
assert False, "应该抛出异常但没有抛出"
except Exception as e:
logger.info(f"✓ 正确处理不存在的IP: {e}")
except Exception as e:
logger.error(f"✗ 测试根据IP发送消息失败: {e}")
raise
async def test_send_msg_by_name(self):
"""测试根据客户端名称发送消息"""
logger.info("=== 测试根据客户端名称发送消息 ===")
try:
# 测试发送消息到存在的客户端名称
self.module.send_msg_to_wsc_by_client_name("测试消息3", "task_001")
await asyncio.sleep(0.1) # 等待异步操作完成
# 检查消息是否发送
assert len(self.ws1.messages) > 1, "消息未发送到正确的WebSocket连接"
assert "测试消息3" in self.ws1.messages, "发送的消息内容不正确"
logger.info(f"✓ 成功发送消息到客户端 task_001收到消息: {self.ws1.messages}")
# 测试发送消息到不存在的客户端名称
try:
self.module.send_msg_to_wsc_by_client_name("测试消息4", "task_999")
assert False, "应该抛出异常但没有抛出"
except Exception as e:
logger.info(f"✓ 正确处理不存在的客户端名称: {e}")
except Exception as e:
logger.error(f"✗ 测试根据客户端名称发送消息失败: {e}")
raise
def test_get_client_ips(self):
"""测试获取客户端IP列表"""
logger.info("=== 测试获取客户端IP列表 ===")
try:
client_ips = self.module.get_websocket_client_ip()
# 验证结果
expected_ips = ["192.168.1.100", "192.168.1.101", "192.168.1.102"]
for ip in expected_ips:
assert ip in client_ips, f"IP {ip} 不在返回的列表中"
logger.info(f"✓ 成功获取客户端IP列表: {client_ips}")
except Exception as e:
logger.error(f"✗ 测试获取客户端IP列表失败: {e}")
raise
def test_get_client_names(self):
"""测试获取客户端名称列表"""
logger.info("=== 测试获取客户端名称列表 ===")
try:
client_names = self.module.get_websocket_client_name()
# 验证结果
expected_names = ["task_001", "task_002", "scene_001"]
for name in expected_names:
assert name in client_names, f"客户端名称 {name} 不在返回的列表中"
logger.info(f"✓ 成功获取客户端名称列表: {client_names}")
except Exception as e:
logger.error(f"✗ 测试获取客户端名称列表失败: {e}")
raise
async def test_error_handling(self):
"""测试错误处理"""
logger.info("=== 测试错误处理 ===")
try:
# 测试WebSocket连接异常
self.ws1.close()
try:
self.module.send_msg_to_wsc_by_client_ip("测试消息5", "192.168.1.100")
await asyncio.sleep(0.1)
logger.info("✓ 处理了WebSocket连接异常")
except Exception as e:
logger.info(f"✓ 正确捕获WebSocket异常: {e}")
except Exception as e:
logger.error(f"✗ 测试错误处理失败: {e}")
raise
async def run_all_tests(self):
"""运行所有测试"""
logger.info("开始WebSocket模块测试")
try:
# 设置测试环境
self.setup_test_connections()
# 运行测试
await self.test_send_msg_by_ip()
await self.test_send_msg_by_name()
self.test_get_client_ips()
self.test_get_client_names()
await self.test_error_handling()
logger.info("✓ 所有WebSocket模块测试通过")
except Exception as e:
logger.error(f"✗ WebSocket模块测试失败: {e}")
raise
def run_mock_websocket_server():
"""运行模拟WebSocket服务器"""
logger.info("=== 启动模拟WebSocket服务器 ===")
async def mock_server():
try:
# 创建测试实例
test = WebSocketModuleTest()
# 运行测试
await test.run_all_tests()
logger.info("模拟WebSocket服务器测试完成")
except Exception as e:
logger.error(f"模拟WebSocket服务器测试失败: {e}")
raise
# 运行异步测试
asyncio.run(mock_server())
def test_websocket_integration():
"""集成测试 - 模拟完整的WebSocket通信场景"""
logger.info("=== WebSocket集成测试 ===")
async def integration_test():
# 创建测试环境
test = WebSocketModuleTest()
test.setup_test_connections()
# 模拟实际使用场景
logger.info("模拟实际使用场景...")
# 场景1广播消息给所有客户端
all_ips = test.module.get_websocket_client_ip()
for ip in all_ips:
try:
test.module.send_msg_to_wsc_by_client_ip(f"广播消息给 {ip}", ip)
await asyncio.sleep(0.05)
except Exception as e:
logger.error(f"发送广播消息失败: {e}")
# 场景2向特定任务发送状态更新
test.module.send_msg_to_wsc_by_client_name("任务状态: 执行中", "task_001")
await asyncio.sleep(0.05)
# 场景3获取连接统计信息
client_count = len(test.module.get_websocket_client_name())
logger.info(f"当前连接客户端数量: {client_count}")
logger.info("✓ WebSocket集成测试完成")
asyncio.run(integration_test())
if __name__ == "__main__":
logger.info("开始WebSocket模块完整测试")
try:
# 运行基本功能测试
run_mock_websocket_server()
# 运行集成测试
test_websocket_integration()
logger.info("✅ 所有WebSocket模块测试成功完成")
except Exception as e:
logger.error(f"❌ WebSocket模块测试失败: {e}")
raise