自动化测试定时任务

This commit is contained in:
2025-05-28 10:45:35 +08:00
parent 0960370562
commit 426ee6aae9
5 changed files with 235 additions and 12 deletions

View File

@@ -15,6 +15,7 @@ import com.test.test.domain.qo.IDQO;
import com.test.test.service.ITestTaskLogService;
import com.test.test.service.ITestTaskResultService;
import com.test.test.service.ITestTaskService;
import com.test.test.task.TestTaskManager;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
@@ -42,6 +43,9 @@ public class TestTaskController extends BaseController {
@Resource
private ITestTaskLogService taskLogService;
@Resource
private TestTaskManager testTaskManager;
/**
* 查询定时任务列表
*/
@@ -90,9 +94,20 @@ public class TestTaskController extends BaseController {
@Log(title = "定时任务", businessType = BusinessType.INSERT)
@PostMapping("/add")
public AjaxResult add(@RequestBody TestTask testTask) {
try {
testTask.setCreateBy(getLoginUser().getUsername());
testTask.setCreateTime(DateUtils.getNowDate());
return toAjax(testTaskService.insertTestTask(testTask));
int result = testTaskService.insertTestTask(testTask);
// 如果任务状态是启用且没有被删除,则添加到定时任务管理器
if (testTask.getStatus() == 0 && "0".equals(testTask.getDelFlag())) {
testTaskManager.addNewTask(testTask);
}
return toAjax(result);
} catch (Exception e) {
return error("新增失败:" + e.getMessage());
}
}
/**
@@ -101,7 +116,23 @@ public class TestTaskController extends BaseController {
@Log(title = "定时任务", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
public AjaxResult edit(@RequestBody TestTask testTask) {
return toAjax(testTaskService.updateTestTask(testTask));
try {
// 获取原任务信息
TestTask originalTask = testTaskService.selectTestTaskById(testTask.getId()).getTask();
// 更新任务
int result = testTaskService.updateTestTask(testTask);
// 如果状态或crontab发生变化更新定时任务
if (testTask.getStatus() != originalTask.getStatus() ||
!testTask.getCrontab().equals(originalTask.getCrontab())) {
testTaskManager.updateTask(testTask);
}
return toAjax(result);
} catch (Exception e) {
return error("修改失败:" + e.getMessage());
}
}
/**
@@ -110,7 +141,14 @@ public class TestTaskController extends BaseController {
@Log(title = "定时任务", businessType = BusinessType.DELETE)
@PostMapping("/del")
public AjaxResult remove(@RequestBody IDQO qo) {
try {
// 先从定时任务管理器中移除
testTaskManager.removeTask(qo.getId());
// 再删除数据库记录
return toAjax(testTaskService.deleteTestTaskById(qo.getId()));
} catch (Exception e) {
return error("删除失败:" + e.getMessage());
}
}
/**
@@ -126,6 +164,4 @@ public class TestTaskController extends BaseController {
});
return toAjax(true);
}
}

View File

@@ -102,14 +102,40 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
// 配置 ChromeOptions
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless");
// 基本设置
options.addArguments("--headless=new"); // 使用新的无头模式
options.addArguments("--no-sandbox");
options.addArguments("--disable-dev-shm-usage");
options.addArguments("--remote-allow-origins=*");
// 禁用各种功能以提高稳定性
options.addArguments("--disable-gpu");
options.addArguments("--disable-extensions");
options.addArguments("--disable-plugins");
options.addArguments("--disable-software-rasterizer");
options.addArguments("--disable-browser-side-navigation");
options.addArguments("--disable-infobars");
options.addArguments("--disable-notifications");
// 设置窗口大小和内存限制
options.addArguments("--window-size=1920,1080");
options.addArguments("--disable-dev-shm-usage");
options.addArguments("--incognito"); // 无痕模式
// 添加性能和稳定性相关的参数
options.addArguments("--disable-background-networking");
options.addArguments("--disable-background-timer-throttling");
options.addArguments("--disable-client-side-phishing-detection");
options.addArguments("--disable-default-apps");
options.addArguments("--disable-hang-monitor");
options.addArguments("--disable-popup-blocking");
options.addArguments("--disable-prompt-on-repost");
options.addArguments("--disable-sync");
options.addArguments("--metrics-recording-only");
options.addArguments("--no-first-run");
options.addArguments("--safebrowsing-disable-auto-update");
options.addArguments("--password-store=basic");
options.addArguments("--use-mock-keychain");
// 创建 ChromeDriver
WebDriver driver = new ChromeDriver(options);

View File

@@ -0,0 +1,149 @@
package com.test.test.task;
import com.test.test.domain.TestTask;
import com.test.test.domain.qo.GroupIdQO;
import com.test.test.service.ITestTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
/**
* 定时任务管理器
* 负责调度和执行定时任务
*/
@Slf4j
@Component
public class TestTaskManager {
@Resource
private ITestTaskService testTaskService;
@Resource
private TaskScheduler taskScheduler;
@Value("${test.jmeterHomePath:/opt/apache-jmeter}")
private String jmeterHomePath;
// 用于存储正在运行的任务
private final Map<Long, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
loadTasks(); // 初始化时加载所有启用的定时任务
}
/**
* 初始加载所有启用的定时任务
*/
private void loadTasks() {
try {
GroupIdQO qo = new GroupIdQO();
List<TestTask> tasks = testTaskService.selectTestTaskList(qo);
if (tasks != null) {
tasks.stream()
.filter(task -> task != null
&& task.getStatus() != null
&& task.getStatus() == 0
&& "0".equals(task.getDelFlag()))
.forEach(this::scheduleTask);
}
} catch (Exception e) {
log.error("加载定时任务失败", e);
}
}
/**
* 更新任务
*/
public void updateTask(TestTask task) {
log.info("更新任务 {}", task.getId());
Long taskId = task.getId();
// 先取消现有任务
if (scheduledTasks.containsKey(taskId)) {
scheduledTasks.get(taskId).cancel(true);
scheduledTasks.remove(taskId);
}
// 如果任务状态是启用且没有被删除,则重新调度
if (task.getStatus() == 0 && "0".equals(task.getDelFlag())) {
log.info("启动任务:{}", task.getId());
scheduleTask(task);
}
}
/**
* 添加新任务到定时调度
*/
public void addNewTask(TestTask task) {
// 只有当任务状态是启用且没有被删除时才创建定时任务
if (task.getStatus() == 0 && "0".equals(task.getDelFlag())) {
log.info("加入定时任务:{}", task.getId());
scheduleTask(task);
}
}
/**
* 移除定时任务
*/
public void removeTask(Long taskId) {
if (scheduledTasks.containsKey(taskId)) {
scheduledTasks.get(taskId).cancel(true);
scheduledTasks.remove(taskId);
log.info("已移除定时任务: {}", taskId);
}
}
/**
* 批量移除定时任务
*/
public void removeTasks(Long[] taskIds) {
for (Long taskId : taskIds) {
removeTask(taskId);
}
}
/**
* 调度单个任务
*/
private void scheduleTask(TestTask task) {
try {
if (task.getCrontab() == null || task.getCrontab().trim().isEmpty()) {
log.error("任务 [{}] 的cron表达式为空", task.getName());
return;
}
CronTrigger trigger = new CronTrigger(task.getCrontab());
ScheduledFuture<?> future = taskScheduler.schedule(
() -> executeTask(task), trigger
);
scheduledTasks.put(task.getId(), future);
log.info("成功调度任务: {}", task.getName());
} catch (IllegalArgumentException e) {
log.error("无效的cron表达式: " + task.getCrontab(), e);
} catch (Exception e) {
log.error("调度任务时发生错误: " + task.getName(), e);
}
}
/**
* 执行单个任务
*/
private void executeTask(TestTask task) {
try {
log.info("开始执行任务: {}", task.getName());
testTaskService.executeTestTaskById(task.getId(), 1, null, jmeterHomePath, "system");
} catch (Exception e) {
log.error("执行任务 [{}] 时发生错误", task.getName(), e);
}
}
}

View File

@@ -28,7 +28,9 @@
<select id="selectTestTaskList" parameterType="GroupIdQO" resultMap="TestTaskResult">
<include refid="selectTestTaskVo"/>
<where>
<if test="groupId != null">
group_id = #{groupId}
</if>
</where>
order by create_time desc
</select>

View File

@@ -116,7 +116,7 @@ export default {
},
// 删除
hadleClickDelete(val) {
this.$modal.confirm('确认删除元素' + '').then(() => {
this.$modal.confirm('确认删除该场景' + '').then(() => {
deleteAutomation(val.id).then(res => {
if (res.code === 200) {
this.$modal.msgSuccess("删除成功");
@@ -129,13 +129,23 @@ export default {
},
// 查看
handleClickDetail(val) {
const loading = this.$loading({
lock: true,
text: '执行中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
executeAutomationData({ id: val.id }).then(res => {
loading.close();
if (res.code === 200) {
this.$modal.msgSuccess("执行成功");
} else {
this.$modal.msgSuccess("执行失败");
this.$modal.msgError("执行失败");
}
})
}).catch(err => {
loading.close();
this.$modal.msgError("执行失败");
});
},
// 分页
handleSizeChange(val) {