#!/usr/bin/env python # -*- coding: utf-8 -*- """ 脚本集成测试 测试从创建项目、编辑脚本到VWED任务调度的完整流程 """ import asyncio import json import sys import os from pathlib import Path # 添加项目根目录到 Python 路径 sys.path.insert(0, str(Path(__file__).parent.parent)) from services.online_script.script_file_service import get_file_service from services.online_script.script_engine_service import get_script_engine from services.online_script.script_task_integration import get_task_integration from services.online_script.script_registry_service import get_global_registry from utils.logger import get_logger logger = get_logger("test.script_integration") class ScriptIntegrationTest: """脚本集成测试类""" def __init__(self): self.file_service = get_file_service() self.script_engine = get_script_engine() self.task_integration = get_task_integration() self.registry = get_global_registry() # 测试数据 self.test_project_id = None self.test_file_id = None self.test_script_id = None async def run_full_test(self): """运行完整的集成测试""" try: logger.info("=== 开始脚本集成测试 ===") # 第1步:创建测试项目 await self.test_create_project() # 第2步:创建测试脚本文件 await self.test_create_script_file() # 第3步:编辑脚本内容 await self.test_update_script_content() # 第4步:启动脚本服务 await self.test_start_script_service() # 第5步:测试脚本函数调用 await self.test_execute_script_function() # 第6步:测试VWED任务集成 await self.test_vwed_task_integration() # 第7步:测试API接口调用 await self.test_dynamic_api_routes() # 第8步:获取注册中心状态 await self.test_registry_status() # 第9步:停止脚本服务 await self.test_stop_script_service() logger.info("=== 脚本集成测试完成 ===") except Exception as e: logger.error(f"集成测试失败: {e}", exc_info=True) raise async def test_create_project(self): """测试创建项目""" logger.info("测试1: 创建脚本项目") result = await self.file_service.create_project( project_name="测试项目_集成测试", description="用于集成测试的项目", created_by="test_user" ) assert result["success"], f"创建项目失败: {result.get('error')}" self.test_project_id = result["project"]["id"] logger.info(f"✓ 项目创建成功,ID: {self.test_project_id}") async def test_create_script_file(self): """测试创建脚本文件""" logger.info("测试2: 创建脚本文件") # 初始的简单脚本内容 initial_content = '''def boot(): """脚本启动函数""" VWED.log.sync_info("测试脚本启动中...") # 这里会在后续步骤中添加更多功能 VWED.log.sync_info("测试脚本启动完成") ''' result = await self.file_service.create_file( project_id=self.test_project_id, file_name="test_integration.py", file_path="test_integration.py", content=initial_content, file_type="python", created_by="test_user" ) assert result["success"], f"创建文件失败: {result.get('error')}" self.test_file_id = result["file"]["id"] logger.info(f"✓ 脚本文件创建成功,ID: {self.test_file_id}") async def test_update_script_content(self): """测试更新脚本内容""" logger.info("测试3: 编辑脚本内容") # 完整的测试脚本内容 updated_content = '''def boot(): """脚本启动函数 - 注册各种服务""" VWED.log.sync_info("集成测试脚本启动中...") # 注册API接口 setup_api_routes() # 注册自定义函数 setup_functions() # 注册事件监听器 setup_events() # 注册定时任务 setup_timers() VWED.log.sync_info("集成测试脚本服务注册完成") def setup_api_routes(): """设置API接口""" @VWED.api.get("/test/hello", description="测试问候接口") def hello_api(request_data): name = request_data["query_params"].get("name", "World") VWED.log.sync_info(f"API调用: hello_api, name={name}") return { "message": f"Hello, {name}!", "timestamp": VWED.util.now(), "script_id": VWED.get_script_id() } @VWED.api.post("/test/calculate", description="测试计算接口") def calculate_api(request_data): data = request_data["body"] a = data.get("a", 0) b = data.get("b", 0) operation = data.get("operation", "add") if operation == "add": result = a + b elif operation == "subtract": result = a - b elif operation == "multiply": result = a * b elif operation == "divide": result = a / b if b != 0 else "Error: Division by zero" else: result = "Error: Unknown operation" VWED.log.sync_info(f"API计算: {a} {operation} {b} = {result}") return { "operation": operation, "operand_a": a, "operand_b": b, "result": result, "timestamp": VWED.util.now() } def setup_functions(): """设置自定义函数""" @VWED.function.register("test_add", description="测试加法函数") def test_add(args): """供VWED任务调用的加法函数""" a = args.get("a", 0) b = args.get("b", 0) result = a + b VWED.log.sync_info(f"函数调用: test_add({a}, {b}) = {result}") return { "result": result, "operation": "addition", "inputs": {"a": a, "b": b} } @VWED.function.register("test_process_data", description="测试数据处理函数") def test_process_data(args): """数据处理测试函数""" data_list = args.get("data", []) process_type = args.get("type", "count") if process_type == "count": result = len(data_list) elif process_type == "sum": result = sum(data_list) if all(isinstance(x, (int, float)) for x in data_list) else "Error: Non-numeric data" elif process_type == "filter_positive": result = [x for x in data_list if isinstance(x, (int, float)) and x > 0] else: result = data_list VWED.log.sync_info(f"数据处理: type={process_type}, input_size={len(data_list)}, result={result}") return { "processed_data": result, "process_type": process_type, "input_size": len(data_list) } @VWED.function.register("test_async_task", description="测试异步任务函数") async def test_async_task(args): """异步任务测试函数""" task_name = args.get("task_name", "default_task") delay = args.get("delay", 1) await VWED.log.info(f"异步任务开始: {task_name}, 延迟: {delay}秒") await VWED.util.async_sleep(delay) await VWED.log.info(f"异步任务完成: {task_name}") return { "task_name": task_name, "delay_seconds": delay, "completed": True, "completion_time": VWED.util.now() } def setup_events(): """设置事件监听器""" @VWED.event.listen("test_event") def on_test_event(event_data): VWED.log.sync_info(f"接收到测试事件: {event_data}") # 存储事件计数 event_count = VWED.data.get("event_count", 0) VWED.data.set("event_count", event_count + 1) @VWED.event.listen("task_completed", priority=1) def on_task_completed(event_data): task_id = event_data.get("task_id", "unknown") VWED.log.sync_info(f"任务完成通知: {task_id}") # 记录完成的任务 completed_tasks = VWED.data.get("completed_tasks", []) completed_tasks.append({ "task_id": task_id, "completed_at": VWED.util.now() }) VWED.data.set("completed_tasks", completed_tasks) def setup_timers(): """设置定时任务""" @VWED.timer.interval(30) # 每30秒执行一次 def heartbeat_timer(): heartbeat_count = VWED.data.get("heartbeat_count", 0) VWED.data.set("heartbeat_count", heartbeat_count + 1) VWED.log.sync_info(f"心跳检测 #{heartbeat_count + 1}") @VWED.timer.once(delay=5) # 5秒后执行一次 def initialization_timer(): VWED.log.sync_info("初始化任务执行") VWED.data.set("initialized", True) VWED.data.set("init_time", VWED.util.now()) # 辅助函数 def get_test_statistics(): """获取测试统计信息""" return { "event_count": VWED.data.get("event_count", 0), "heartbeat_count": VWED.data.get("heartbeat_count", 0), "completed_tasks": len(VWED.data.get("completed_tasks", [])), "initialized": VWED.data.get("initialized", False), "init_time": VWED.data.get("init_time", None) } ''' result = await self.file_service.update_file_content( file_id=self.test_file_id, content=updated_content, updated_by="test_user" ) assert result["success"], f"更新文件内容失败: {result.get('error')}" logger.info("✓ 脚本内容更新成功,已添加完整的测试功能") async def test_start_script_service(self): """测试启动脚本服务""" logger.info("测试4: 启动脚本服务") # 构建脚本路径 script_path = f"projects/测试项目_集成测试/test_integration.py" result = await self.script_engine.start_script_service( script_path=script_path, start_params={"test_mode": True} ) assert result["success"], f"启动脚本服务失败: {result.get('error')}" self.test_script_id = result["script_id"] logger.info(f"✓ 脚本服务启动成功,Script ID: {self.test_script_id}") logger.info(f" - 注册的接口数: {result['registrations']['apis']}") logger.info(f" - 注册的函数数: {result['registrations']['functions']}") logger.info(f" - 注册的事件数: {result['registrations']['events']}") logger.info(f" - 注册的定时器数: {result['registrations']['timers']}") async def test_execute_script_function(self): """测试执行脚本函数""" logger.info("测试5: 执行脚本函数") # 测试同步函数 result1 = await self.script_engine.execute_script_function( script_id=self.test_script_id, function_name="test_add", function_args={"a": 15, "b": 25} ) assert result1["success"], f"执行test_add函数失败: {result1.get('error')}" assert result1["result"]["result"] == 40, "加法函数计算结果错误" logger.info(f"✓ 同步函数test_add执行成功: 15 + 25 = {result1['result']['result']}") # 测试数据处理函数 result2 = await self.script_engine.execute_script_function( script_id=self.test_script_id, function_name="test_process_data", function_args={"data": [1, 2, 3, -1, 4, -2, 5], "type": "filter_positive"} ) assert result2["success"], f"执行test_process_data函数失败: {result2.get('error')}" expected_result = [1, 2, 3, 4, 5] assert result2["result"]["processed_data"] == expected_result, "数据过滤结果错误" logger.info(f"✓ 数据处理函数执行成功: 过滤出正数 {expected_result}") # 测试异步函数 result3 = await self.script_engine.execute_script_function( script_id=self.test_script_id, function_name="test_async_task", function_args={"task_name": "integration_test", "delay": 0.5} ) assert result3["success"], f"执行test_async_task函数失败: {result3.get('error')}" assert result3["result"]["completed"] == True, "异步任务未正确完成" logger.info(f"✓ 异步函数test_async_task执行成功") async def test_vwed_task_integration(self): """测试VWED任务系统集成""" logger.info("测试6: VWED任务系统集成") # 获取可用的脚本函数列表 available_functions = await self.task_integration.get_available_functions() assert len(available_functions) > 0, "没有可用的脚本函数" function_names = [func["function_name"] for func in available_functions] assert "test_add" in function_names, "test_add函数未在可用函数列表中" assert "test_process_data" in function_names, "test_process_data函数未在可用函数列表中" logger.info(f"✓ 可用脚本函数: {function_names}") # 模拟从VWED任务中调用脚本函数 task_context = { "task_id": "test_task_001", "instance_id": "test_instance_001", "block_id": "script_block_001" } result = await self.task_integration.execute_script_function_from_task( function_name="test_add", function_args={"a": 100, "b": 200}, task_context=task_context ) assert result["success"], f"从任务调用脚本函数失败: {result.get('error')}" assert result["result"]["result"] == 300, "任务调用脚本函数计算结果错误" logger.info(f"✓ VWED任务调用脚本函数成功: 100 + 200 = {result['result']['result']}") async def test_dynamic_api_routes(self): """测试动态API路由(模拟)""" logger.info("测试7: 动态API路由测试") # 获取注册的API路由信息 registrations = self.registry.get_all_registrations() api_routes = registrations.get("api_routes", {}) # 检查是否注册了预期的API路由 expected_routes = ["GET:/test/hello", "POST:/test/calculate"] for route_key in expected_routes: assert route_key in api_routes, f"API路由 {route_key} 未注册" route_info = api_routes[route_key] assert route_info["script_id"] == self.test_script_id, f"路由 {route_key} 的script_id不匹配" logger.info(f"✓ 动态API路由注册成功: {list(api_routes.keys())}") # 这里可以进一步测试实际的HTTP请求(需要启动FastAPI服务器) # 由于是集成测试,我们主要验证注册是否正确 async def test_registry_status(self): """测试获取注册中心状态""" logger.info("测试8: 获取注册中心状态") registrations = self.registry.get_all_registrations() # 验证注册信息 assert len(registrations["api_routes"]) >= 2, "API路由注册数量不足" assert len(registrations["registered_functions"]) >= 3, "函数注册数量不足" assert len(registrations["event_listeners"]) >= 1, "事件监听器注册数量不足" assert len(registrations["active_scripts"]) >= 1, "活跃脚本数量不足" logger.info("✓ 注册中心状态检查通过") logger.info(f" - API路由数: {len(registrations['api_routes'])}") logger.info(f" - 注册函数数: {len(registrations['registered_functions'])}") logger.info(f" - 事件监听器数: {len(registrations['event_listeners'])}") logger.info(f" - 活跃脚本数: {len(registrations['active_scripts'])}") async def test_stop_script_service(self): """测试停止脚本服务""" logger.info("测试9: 停止脚本服务") result = await self.script_engine.stop_script_service(self.test_script_id) assert result["success"], f"停止脚本服务失败: {result.get('error')}" logger.info("✓ 脚本服务停止成功") # 验证注册项已被清理 running_scripts = self.script_engine.get_running_scripts() script_ids = [s["script_id"] for s in running_scripts] assert self.test_script_id not in script_ids, "脚本服务未正确停止" logger.info("✓ 脚本注册项清理完成") async def main(): """主测试函数""" try: # 创建测试实例 test = ScriptIntegrationTest() # 运行完整的集成测试 await test.run_full_test() print("\n" + "="*60) print("🎉 脚本集成测试全部通过!") print("="*60) print("测试覆盖的功能:") print("✓ 项目和文件管理") print("✓ 脚本内容编辑") print("✓ 脚本服务启动和停止") print("✓ API接口动态注册") print("✓ 自定义函数注册和调用") print("✓ 事件系统和定时任务") print("✓ VWED任务系统集成") print("✓ 注册中心状态管理") print("="*60) return True except Exception as e: print("\n" + "="*60) print("❌ 脚本集成测试失败!") print("="*60) print(f"错误信息: {e}") logger.error(f"集成测试失败: {e}", exc_info=True) print("="*60) return False if __name__ == "__main__": # 运行测试 success = asyncio.run(main()) sys.exit(0 if success else 1)