VWED_server/tests/test_script_integration.py

489 lines
18 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 -*-
"""
脚本集成测试
测试从创建项目、编辑脚本到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.script_file_service import get_file_service
from services.script_engine_service import get_script_engine
from services.script_task_integration import get_task_integration
from services.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)