为API和UI测试活动引入心跳机制,以增强Temporal任务的健壮性
This commit is contained in:
parent
fa70f376f4
commit
c50d6f1771
@ -2,6 +2,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import asyncio
|
||||||
|
|
||||||
from temporalio import activity
|
from temporalio import activity
|
||||||
|
|
||||||
@ -15,6 +16,20 @@ from utils import upload_file_to_s3, scalar_map_to_dict
|
|||||||
|
|
||||||
|
|
||||||
class TestActivities:
|
class TestActivities:
|
||||||
|
|
||||||
|
async def _heartbeat_task(self, interval_seconds=30):
|
||||||
|
"""心跳任务,定期发送心跳信号"""
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
await asyncio.sleep(interval_seconds)
|
||||||
|
activity.heartbeat()
|
||||||
|
activity.logger.debug("Activity heartbeat sent")
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
activity.logger.debug("Heartbeat task cancelled")
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
activity.logger.warning(f"Failed to send heartbeat: {e}")
|
||||||
|
|
||||||
@activity.defn(name="run_api_test")
|
@activity.defn(name="run_api_test")
|
||||||
async def run_api_test(self, req: pb.ApiTestRequest) -> pb.ApiTestResult:
|
async def run_api_test(self, req: pb.ApiTestRequest) -> pb.ApiTestResult:
|
||||||
"""执行API测试的Temporal Activity实现"""
|
"""执行API测试的Temporal Activity实现"""
|
||||||
@ -23,7 +38,13 @@ class TestActivities:
|
|||||||
result = pb.ApiTestResult()
|
result = pb.ApiTestResult()
|
||||||
result.base_result.test_case_id = req.test_case_id
|
result.base_result.test_case_id = req.test_case_id
|
||||||
|
|
||||||
|
# 启动心跳任务
|
||||||
|
heartbeat_task = asyncio.create_task(self._heartbeat_task())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# 发送初始心跳
|
||||||
|
activity.heartbeat()
|
||||||
|
|
||||||
# 调用实际的API测试逻辑
|
# 调用实际的API测试逻辑
|
||||||
api_test_success, actual_status, response_body, log_output = execute_api_test_case(
|
api_test_success, actual_status, response_body, log_output = execute_api_test_case(
|
||||||
req.test_case_id, req.endpoint, req.http_method, scalar_map_to_dict(req.headers), req.request_body,
|
req.test_case_id, req.endpoint, req.http_method, scalar_map_to_dict(req.headers), req.request_body,
|
||||||
@ -41,11 +62,17 @@ class TestActivities:
|
|||||||
result.base_result.success = False
|
result.base_result.success = False
|
||||||
result.base_result.message = f"API Test Error: {e}"
|
result.base_result.message = f"API Test Error: {e}"
|
||||||
result.base_result.error_details = str(e)
|
result.base_result.error_details = str(e)
|
||||||
|
finally:
|
||||||
|
# 取消心跳任务
|
||||||
|
heartbeat_task.cancel()
|
||||||
|
try:
|
||||||
|
await heartbeat_task
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
|
||||||
result.base_result.duration_seconds = time.time() - start_time
|
result.base_result.duration_seconds = time.time() - start_time
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@activity.defn(name="run_ui_test")
|
@activity.defn(name="run_ui_test")
|
||||||
async def run_ui_test(self, req: pb.UiTestRequest) -> pb.UiTestResult:
|
async def run_ui_test(self, req: pb.UiTestRequest) -> pb.UiTestResult:
|
||||||
"""执行UI测试的Temporal Activity实现"""
|
"""执行UI测试的Temporal Activity实现"""
|
||||||
@ -54,7 +81,13 @@ class TestActivities:
|
|||||||
result = pb.UiTestResult()
|
result = pb.UiTestResult()
|
||||||
result.base_result.test_case_id = req.test_case_id
|
result.base_result.test_case_id = req.test_case_id
|
||||||
|
|
||||||
|
# 启动心跳任务
|
||||||
|
heartbeat_task = asyncio.create_task(self._heartbeat_task())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# 发送初始心跳
|
||||||
|
activity.heartbeat()
|
||||||
|
|
||||||
# 调用实际的UI测试逻辑,返回本地文件路径
|
# 调用实际的UI测试逻辑,返回本地文件路径
|
||||||
ui_test_success, log_output, screenshot_path, html_report_path = await execute_ui_test_case(
|
ui_test_success, log_output, screenshot_path, html_report_path = await execute_ui_test_case(
|
||||||
req.test_case_id, req.url_path, req.browser_type, req.headless, scalar_map_to_dict(req.user_data)
|
req.test_case_id, req.url_path, req.browser_type, req.headless, scalar_map_to_dict(req.user_data)
|
||||||
@ -66,9 +99,14 @@ class TestActivities:
|
|||||||
|
|
||||||
# 上传截图和报告到对象存储,并返回URL
|
# 上传截图和报告到对象存储,并返回URL
|
||||||
if screenshot_path and os.path.exists(screenshot_path):
|
if screenshot_path and os.path.exists(screenshot_path):
|
||||||
|
# 在长时间操作前发送心跳
|
||||||
|
activity.heartbeat()
|
||||||
result.screenshot_url = await upload_file_to_s3(screenshot_path, f"screenshots/{req.test_case_id}.png")
|
result.screenshot_url = await upload_file_to_s3(screenshot_path, f"screenshots/{req.test_case_id}.png")
|
||||||
os.remove(screenshot_path) # 清理本地文件
|
os.remove(screenshot_path) # 清理本地文件
|
||||||
|
|
||||||
if html_report_path and os.path.exists(html_report_path):
|
if html_report_path and os.path.exists(html_report_path):
|
||||||
|
# 在长时间操作前发送心跳
|
||||||
|
activity.heartbeat()
|
||||||
result.html_report_url = await upload_file_to_s3(html_report_path, f"reports/{req.test_case_id}.html")
|
result.html_report_url = await upload_file_to_s3(html_report_path, f"reports/{req.test_case_id}.html")
|
||||||
os.remove(html_report_path) # 清理本地文件
|
os.remove(html_report_path) # 清理本地文件
|
||||||
|
|
||||||
@ -77,6 +115,13 @@ class TestActivities:
|
|||||||
result.base_result.success = False
|
result.base_result.success = False
|
||||||
result.base_result.message = f"UI Test Error: {e}"
|
result.base_result.message = f"UI Test Error: {e}"
|
||||||
result.base_result.error_details = str(e)
|
result.base_result.error_details = str(e)
|
||||||
|
finally:
|
||||||
|
# 取消心跳任务
|
||||||
|
heartbeat_task.cancel()
|
||||||
|
try:
|
||||||
|
await heartbeat_task
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
|
||||||
result.base_result.duration_seconds = time.time() - start_time
|
result.base_result.duration_seconds = time.time() - start_time
|
||||||
return result
|
return result
|
Loading…
Reference in New Issue
Block a user