#!/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