feat(接口测试): 测试计划支持禁用本地执行
--story=1009842 --user=赵勇 接口测试支持禁用本地执行 https://www.tapd.cn/55049933/s/1291450
This commit is contained in:
parent
0b8d80f49d
commit
61b82c28fd
|
@ -23,6 +23,7 @@ import io.metersphere.service.BaseProjectApplicationService;
|
||||||
import io.metersphere.service.RemakeReportService;
|
import io.metersphere.service.RemakeReportService;
|
||||||
import io.metersphere.service.SystemParameterService;
|
import io.metersphere.service.SystemParameterService;
|
||||||
import io.metersphere.utils.LoggerUtil;
|
import io.metersphere.utils.LoggerUtil;
|
||||||
|
import io.metersphere.xpack.api.service.ApiPoolDebugService;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
@ -58,11 +59,14 @@ public class JMeterService {
|
||||||
private SystemParameterService systemParameterService;
|
private SystemParameterService systemParameterService;
|
||||||
@Resource
|
@Resource
|
||||||
private BaseProjectApplicationService projectApplicationService;
|
private BaseProjectApplicationService projectApplicationService;
|
||||||
|
@Resource
|
||||||
|
private RemakeReportService remakeReportService;
|
||||||
|
@Resource
|
||||||
|
private ExecThreadPoolExecutor execThreadPoolExecutor;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
private void init() {
|
private void init() {
|
||||||
String JMETER_HOME = getJmeterHome();
|
String JMETER_HOME = getJmeterHome();
|
||||||
|
|
||||||
String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties";
|
String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties";
|
||||||
JMeterUtils.loadJMeterProperties(JMETER_PROPERTIES);
|
JMeterUtils.loadJMeterProperties(JMETER_PROPERTIES);
|
||||||
JMeterUtils.setJMeterHome(JMETER_HOME);
|
JMeterUtils.setJMeterHome(JMETER_HOME);
|
||||||
|
@ -150,8 +154,7 @@ public class JMeterService {
|
||||||
final Engine engine = EngineFactory.createApiEngine(request);
|
final Engine engine = EngineFactory.createApiEngine(request);
|
||||||
engine.start();
|
engine.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
RemakeReportService apiScenarioReportService = CommonBeanFactory.getBean(RemakeReportService.class);
|
remakeReportService.testEnded(request, e.getMessage());
|
||||||
apiScenarioReportService.testEnded(request, e.getMessage());
|
|
||||||
LoggerUtil.error("调用K8S执行请求[ " + request.getTestId() + " ]失败:", request.getReportId(), e);
|
LoggerUtil.error("调用K8S执行请求[ " + request.getTestId() + " ]失败:", request.getReportId(), e);
|
||||||
}
|
}
|
||||||
} else if ((MapUtils.isNotEmpty(request.getExtendedParameters())
|
} else if ((MapUtils.isNotEmpty(request.getExtendedParameters())
|
||||||
|
@ -166,34 +169,15 @@ public class JMeterService {
|
||||||
|
|
||||||
private synchronized void nodeDebug(JmeterRunRequestDTO request) {
|
private synchronized void nodeDebug(JmeterRunRequestDTO request) {
|
||||||
try {
|
try {
|
||||||
if (request.isDebug() && !StringUtils.equalsAny(request.getRunMode(), ApiRunMode.DEFINITION.name())) {
|
ApiPoolDebugService apiPoolDebugService = CommonBeanFactory.getBean(ApiPoolDebugService.class);
|
||||||
request.getExtendedParameters().put(ExtendedParameter.SAVE_RESULT, true);
|
if (apiPoolDebugService != null) {
|
||||||
} else if (!request.isDebug()) {
|
|
||||||
request.getExtendedParameters().put(ExtendedParameter.SAVE_RESULT, true);
|
|
||||||
}
|
|
||||||
List<TestResource> resources = GenerateHashTreeUtil.setPoolResource(request.getPoolId());
|
List<TestResource> resources = GenerateHashTreeUtil.setPoolResource(request.getPoolId());
|
||||||
String uri = null;
|
|
||||||
int index = (int) (Math.random() * resources.size());
|
|
||||||
String configuration = resources.get(index).getConfiguration();
|
|
||||||
if (StringUtils.isNotEmpty(configuration)) {
|
|
||||||
NodeDTO node = com.alibaba.fastjson.JSON.parseObject(configuration, NodeDTO.class);
|
|
||||||
uri = String.format(BASE_URL + "/jmeter/debug", node.getIp(), node.getPort());
|
|
||||||
}
|
|
||||||
if (StringUtils.isEmpty(uri)) {
|
|
||||||
LoggerUtil.info("未获取到资源池,请检查配置【系统设置-系统-测试资源池】", request.getReportId());
|
|
||||||
MSException.throwException("调用资源池执行失败,请检查资源池是否配置正常");
|
|
||||||
}
|
|
||||||
request.getExtendedParameters().put(ExtendedParameter.JMX, new MsTestPlan().getJmx(request.getHashTree()));
|
request.getExtendedParameters().put(ExtendedParameter.JMX, new MsTestPlan().getJmx(request.getHashTree()));
|
||||||
request.setHashTree(null);
|
request.setHashTree(null);
|
||||||
LoggerUtil.info("开始发送请求【 " + request.getTestId() + " 】到 " + uri + " 节点执行", request.getReportId());
|
apiPoolDebugService.run(request, resources);
|
||||||
ResponseEntity<String> result = restTemplate.postForEntity(uri, request, String.class);
|
|
||||||
if (result == null || !StringUtils.equals("SUCCESS", result.getBody())) {
|
|
||||||
LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 到" + uri + " 节点执行失败", request.getReportId());
|
|
||||||
LoggerUtil.info(result);
|
|
||||||
MSException.throwException("调用资源池执行失败,请检查资源池是否配置正常");
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
|
LoggerUtil.error(e);
|
||||||
remakeReportService.remake(request);
|
remakeReportService.remake(request);
|
||||||
LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 执行失败,进行数据回滚:", request.getReportId(), e);
|
LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 执行失败,进行数据回滚:", request.getReportId(), e);
|
||||||
MSException.throwException("调用资源池执行失败,请检查资源池是否配置正常");
|
MSException.throwException("调用资源池执行失败,请检查资源池是否配置正常");
|
||||||
|
@ -212,7 +196,6 @@ public class JMeterService {
|
||||||
}
|
}
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
LoggerUtil.info("未获取到资源池,请检查配置【系统设置-系统-测试资源池】", request.getReportId());
|
LoggerUtil.info("未获取到资源池,请检查配置【系统设置-系统-测试资源池】", request.getReportId());
|
||||||
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
|
|
||||||
remakeReportService.remake(request);
|
remakeReportService.remake(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -221,13 +204,11 @@ public class JMeterService {
|
||||||
LoggerUtil.info("开始发送请求【 " + request.getTestId() + " 】到 " + config.getUrl() + " 节点执行", request.getReportId());
|
LoggerUtil.info("开始发送请求【 " + request.getTestId() + " 】到 " + config.getUrl() + " 节点执行", request.getReportId());
|
||||||
ResponseEntity<String> result = restTemplate.postForEntity(config.getUrl(), request, String.class);
|
ResponseEntity<String> result = restTemplate.postForEntity(config.getUrl(), request, String.class);
|
||||||
if (result == null || !StringUtils.equals("SUCCESS", result.getBody())) {
|
if (result == null || !StringUtils.equals("SUCCESS", result.getBody())) {
|
||||||
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
|
|
||||||
remakeReportService.remake(request);
|
remakeReportService.remake(request);
|
||||||
LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 到" + config.getUrl() + " 节点执行失败", request.getReportId());
|
LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 到" + config.getUrl() + " 节点执行失败", request.getReportId());
|
||||||
LoggerUtil.info(result.getBody());
|
LoggerUtil.info(result.getBody());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
|
|
||||||
remakeReportService.remake(request);
|
remakeReportService.remake(request);
|
||||||
LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 执行失败,进行数据回滚:", request.getReportId(), e);
|
LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 执行失败,进行数据回滚:", request.getReportId(), e);
|
||||||
}
|
}
|
||||||
|
@ -240,7 +221,7 @@ public class JMeterService {
|
||||||
} else if (request.getHashTree() != null) {
|
} else if (request.getHashTree() != null) {
|
||||||
//解析hashTree,是否含有文件库文件
|
//解析hashTree,是否含有文件库文件
|
||||||
HashTreeUtil.initRepositoryFiles(request);
|
HashTreeUtil.initRepositoryFiles(request);
|
||||||
CommonBeanFactory.getBean(ExecThreadPoolExecutor.class).addTask(request);
|
execThreadPoolExecutor.addTask(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +256,8 @@ public class JMeterService {
|
||||||
|
|
||||||
public void verifyPool(String projectId, RunModeConfigDTO runConfig) {
|
public void verifyPool(String projectId, RunModeConfigDTO runConfig) {
|
||||||
// 检查是否禁用了本地执行
|
// 检查是否禁用了本地执行
|
||||||
if (runConfig != null && StringUtils.isEmpty(runConfig.getResourcePoolId())) {
|
if (runConfig != null && StringUtils.isEmpty(runConfig.getResourcePoolId())
|
||||||
|
&& CommonBeanFactory.getBean(ApiPoolDebugService.class) != null) {
|
||||||
BaseSystemConfigDTO configDTO = systemParameterService.getBaseInfo();
|
BaseSystemConfigDTO configDTO = systemParameterService.getBaseInfo();
|
||||||
if (StringUtils.equals(configDTO.getRunMode(), POOL)) {
|
if (StringUtils.equals(configDTO.getRunMode(), POOL)) {
|
||||||
ProjectConfig config = projectApplicationService.getProjectConfig(projectId);
|
ProjectConfig config = projectApplicationService.getProjectConfig(projectId);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package io.metersphere.api.jmeter;
|
package io.metersphere.api.jmeter;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import io.metersphere.api.dto.MsgDTO;
|
import io.metersphere.api.dto.MsgDTO;
|
||||||
import io.metersphere.commons.constants.KafkaTopicConstants;
|
import io.metersphere.commons.constants.KafkaTopicConstants;
|
||||||
|
import io.metersphere.commons.utils.JSONUtil;
|
||||||
import io.metersphere.commons.utils.NamedThreadFactory;
|
import io.metersphere.commons.utils.NamedThreadFactory;
|
||||||
import io.metersphere.commons.utils.WebSocketUtil;
|
import io.metersphere.commons.utils.WebSocketUtil;
|
||||||
import io.metersphere.service.ApiExecutionQueueService;
|
import io.metersphere.service.ApiExecutionQueueService;
|
||||||
|
@ -74,7 +74,7 @@ public class MsKafkaListener {
|
||||||
try {
|
try {
|
||||||
LoggerUtil.info("接收到执行结果:", record.key());
|
LoggerUtil.info("接收到执行结果:", record.key());
|
||||||
if (ObjectUtils.isNotEmpty(record.value()) && WebSocketUtil.has(record.key().toString())) {
|
if (ObjectUtils.isNotEmpty(record.value()) && WebSocketUtil.has(record.key().toString())) {
|
||||||
MsgDTO dto = JSON.parseObject(record.value(), MsgDTO.class);
|
MsgDTO dto = JSONUtil.parseObject(record.value(), MsgDTO.class);
|
||||||
WebSocketUtil.sendMessageSingle(dto);
|
WebSocketUtil.sendMessageSingle(dto);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -95,6 +95,7 @@ import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
|
||||||
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
|
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
|
||||||
import EnvSelectPopover from "@/business/automation/scenario/EnvSelectPopover";
|
import EnvSelectPopover from "@/business/automation/scenario/EnvSelectPopover";
|
||||||
import {getApiCaseEnvironments} from "@/api/api-test-case";
|
import {getApiCaseEnvironments} from "@/api/api-test-case";
|
||||||
|
import {hasLicense} from "metersphere-frontend/src/utils/permission";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ApiRunMode",
|
name: "ApiRunMode",
|
||||||
|
@ -149,7 +150,9 @@ export default {
|
||||||
this.runModeVisible = true;
|
this.runModeVisible = true;
|
||||||
this.getResourcePools();
|
this.getResourcePools();
|
||||||
this.getWsProjects();
|
this.getWsProjects();
|
||||||
|
if(hasLicense()) {
|
||||||
this.query();
|
this.query();
|
||||||
|
}
|
||||||
this.showPopover();
|
this.showPopover();
|
||||||
this.runConfig.environmentType = ENV_TYPE.JSON;
|
this.runConfig.environmentType = ENV_TYPE.JSON;
|
||||||
},
|
},
|
||||||
|
|
|
@ -109,6 +109,7 @@ import EnvPopover from "@/business/automation/scenario/EnvPopover";
|
||||||
import {getMaintainer, getOwnerProjects, getProjectConfig} from "@/api/project";
|
import {getMaintainer, getOwnerProjects, getProjectConfig} from "@/api/project";
|
||||||
import {getTestResourcePools} from "@/api/test-resource-pool";
|
import {getTestResourcePools} from "@/api/test-resource-pool";
|
||||||
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
|
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
|
||||||
|
import {hasLicense} from "metersphere-frontend/src/utils/permission";
|
||||||
|
|
||||||
function defaultCustomValidate() {
|
function defaultCustomValidate() {
|
||||||
return {pass: true};
|
return {pass: true};
|
||||||
|
@ -317,7 +318,9 @@ export default {
|
||||||
this.activeName = 'first';
|
this.activeName = 'first';
|
||||||
this.getResourcePools();
|
this.getResourcePools();
|
||||||
this.getWsProjects();
|
this.getWsProjects();
|
||||||
|
if(hasLicense()) {
|
||||||
this.query();
|
this.query();
|
||||||
|
}
|
||||||
this.runConfig.environmentType = ENV_TYPE.JSON;
|
this.runConfig.environmentType = ENV_TYPE.JSON;
|
||||||
},
|
},
|
||||||
findSchedule() {
|
findSchedule() {
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package io.metersphere.xpack.api.service;
|
||||||
|
|
||||||
|
import io.metersphere.base.domain.TestResource;
|
||||||
|
import io.metersphere.dto.JmeterRunRequestDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ApiPoolDebugService {
|
||||||
|
public void run(JmeterRunRequestDTO request, List<TestResource> resources);
|
||||||
|
}
|
|
@ -97,7 +97,7 @@
|
||||||
|
|
||||||
<!-- 接口测试资源池 -->
|
<!-- 接口测试资源池 -->
|
||||||
<app-manage-item :title="$t('pj.api_run_pool_title')" :prepend-span="8" :middle-span="12"
|
<app-manage-item :title="$t('pj.api_run_pool_title')" :prepend-span="8" :middle-span="12"
|
||||||
:append-span="4" v-if="isPool">
|
:append-span="4" v-if="isPool && isXpack">
|
||||||
<template #middle>
|
<template #middle>
|
||||||
<el-select v-model="config.resourcePoolId"
|
<el-select v-model="config.resourcePoolId"
|
||||||
size="mini"
|
size="mini"
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<el-input v-model="formInline.seleniumDockerUrl" :placeholder="$t('system_config.selenium_docker.url_tip')"/>
|
<el-input v-model="formInline.seleniumDockerUrl" :placeholder="$t('system_config.selenium_docker.url_tip')"/>
|
||||||
<i>({{ $t('commons.examples') }}:http://localhost:4444)</i>
|
<i>({{ $t('commons.examples') }}:http://localhost:4444)</i>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('system.api_default_run')" prop="seleniumDockerUrl">
|
<el-form-item :label="$t('system.api_default_run')" prop="runMode" v-if="hasLicense()">
|
||||||
<el-switch active-value="LOCAL" inactive-value="POOL" v-model="formInline.runMode" @change="modeChange"/>
|
<el-switch active-value="LOCAL" inactive-value="POOL" v-model="formInline.runMode" @change="modeChange"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -38,6 +38,7 @@
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import {getSystemBaseSetting, saveSystemBaseSetting} from "../../../api/system";
|
import {getSystemBaseSetting, saveSystemBaseSetting} from "../../../api/system";
|
||||||
|
import {hasLicense} from 'metersphere-frontend/src/utils/permission';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "BaseSetting",
|
name: "BaseSetting",
|
||||||
|
@ -76,6 +77,7 @@ export default {
|
||||||
this.query()
|
this.query()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
hasLicense,
|
||||||
query() {
|
query() {
|
||||||
this.loading = getSystemBaseSetting().then(res => {
|
this.loading = getSystemBaseSetting().then(res => {
|
||||||
if(!res.data.runMode) {
|
if(!res.data.runMode) {
|
||||||
|
|
|
@ -281,7 +281,9 @@ export default {
|
||||||
this.testType = testType;
|
this.testType = testType;
|
||||||
this.getResourcePools();
|
this.getResourcePools();
|
||||||
this.getWsProjects();
|
this.getWsProjects();
|
||||||
|
if(hasLicense()) {
|
||||||
this.query();
|
this.query();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
query() {
|
query() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
|
@ -292,7 +292,9 @@ export default {
|
||||||
this.getResourcePools();
|
this.getResourcePools();
|
||||||
this.getWsProjects();
|
this.getWsProjects();
|
||||||
this.showPopover();
|
this.showPopover();
|
||||||
|
if(hasLicense()) {
|
||||||
this.query();
|
this.query();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
query() {
|
query() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
|
@ -274,7 +274,9 @@ export default {
|
||||||
this.testType = testType;
|
this.testType = testType;
|
||||||
this.getResourcePools();
|
this.getResourcePools();
|
||||||
this.getWsProjects();
|
this.getWsProjects();
|
||||||
|
if(hasLicense()) {
|
||||||
this.query();
|
this.query();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
query() {
|
query() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
Loading…
Reference in New Issue