feat(接口定义): 合并master 最新代码
This commit is contained in:
parent
22108b3048
commit
73204d7793
|
@ -7,7 +7,6 @@ import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
|
|||
import io.metersphere.api.service.APITestService;
|
||||
import io.metersphere.base.domain.ApiTest;
|
||||
import io.metersphere.base.domain.Schedule;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
|
@ -15,12 +14,14 @@ import io.metersphere.commons.utils.SessionUtils;
|
|||
import io.metersphere.controller.request.QueryScheduleRequest;
|
||||
import io.metersphere.dto.ScheduleDao;
|
||||
import io.metersphere.service.CheckOwnerService;
|
||||
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -75,19 +76,18 @@ public class APITestController {
|
|||
}
|
||||
|
||||
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
|
||||
public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
apiTestService.create(request, bodyFiles);
|
||||
public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
apiTestService.create(request, file, bodyFiles);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/create/merge", consumes = {"multipart/form-data"})
|
||||
public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "selectIds") List<String> selectIds) {
|
||||
apiTestService.mergeCreate(request, selectIds);
|
||||
public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "selectIds") List<String> selectIds) {
|
||||
apiTestService.mergeCreate(request, file, selectIds);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
|
||||
public void update(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
public void update(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
checkownerService.checkApiTestOwner(request.getId());
|
||||
apiTestService.update(request, bodyFiles);
|
||||
apiTestService.update(request, file, bodyFiles);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/copy")
|
||||
|
@ -101,25 +101,21 @@ public class APITestController {
|
|||
return apiTestService.get(testId);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestBody DeleteAPITestRequest request) {
|
||||
checkownerService.checkApiTestOwner(request.getId());
|
||||
apiTestService.delete(request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/jmx")
|
||||
public String getJMX(@RequestBody SaveAPITestRequest request) {
|
||||
return apiTestService.getJMX(request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/run")
|
||||
public String run(@RequestBody SaveAPITestRequest request) {
|
||||
return apiTestService.run(request, ApiRunMode.RUN.name());
|
||||
return apiTestService.run(request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/run/debug", consumes = {"multipart/form-data"})
|
||||
public String runDebug(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
return apiTestService.runDebug(request, bodyFiles, ApiRunMode.DEBUG.name());
|
||||
public String runDebug(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
return apiTestService.runDebug(request, file, bodyFiles);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/checkName")
|
||||
|
@ -140,7 +136,7 @@ public class APITestController {
|
|||
|
||||
@PostMapping("/list/schedule/{goPage}/{pageSize}")
|
||||
public List<ScheduleDao> listSchedule(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryScheduleRequest request) {
|
||||
PageHelper.startPage(goPage, pageSize, true);
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return apiTestService.listSchedule(request);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,13 +47,15 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
private final List<SampleResult> queue = new ArrayList<>();
|
||||
|
||||
private APITestService apiTestService;
|
||||
|
||||
private APIReportService apiReportService;
|
||||
|
||||
private TestPlanTestCaseService testPlanTestCaseService;
|
||||
|
||||
private NoticeService noticeService;
|
||||
|
||||
private MailService mailService;
|
||||
private DingTaskService dingTaskService;
|
||||
private WxChatTaskService wxChatTaskService;
|
||||
private SystemParameterService systemParameterService;
|
||||
|
||||
private ApiDefinitionService apiDefinitionService;
|
||||
private ApiDefinitionExecResultService apiDefinitionExecResultService;
|
||||
|
||||
|
@ -64,6 +66,19 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
|
||||
private String debugReportId;
|
||||
|
||||
//获得控制台内容
|
||||
private PrintStream oldPrintStream = System.out;
|
||||
private ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
||||
private void setConsole() {
|
||||
System.setOut(new PrintStream(bos)); //设置新的out
|
||||
}
|
||||
|
||||
private String getConsole() {
|
||||
System.setOut(oldPrintStream);
|
||||
return bos.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupTest(BackendListenerContext context) throws Exception {
|
||||
setConsole();
|
||||
|
@ -89,18 +104,6 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
if (mailService == null) {
|
||||
LogUtil.error("mailService is required");
|
||||
}
|
||||
dingTaskService = CommonBeanFactory.getBean(DingTaskService.class);
|
||||
if (dingTaskService == null) {
|
||||
LogUtil.error("dingTaskService is required");
|
||||
}
|
||||
wxChatTaskService = CommonBeanFactory.getBean(WxChatTaskService.class);
|
||||
if (wxChatTaskService == null) {
|
||||
LogUtil.error("wxChatTaskService is required");
|
||||
}
|
||||
systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
|
||||
if (systemParameterService == null) {
|
||||
LogUtil.error("systemParameterService is required");
|
||||
}
|
||||
apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class);
|
||||
if (apiDefinitionService == null) {
|
||||
LogUtil.error("apiDefinitionService is required");
|
||||
|
@ -109,22 +112,9 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
if (apiDefinitionExecResultService == null) {
|
||||
LogUtil.error("apiDefinitionExecResultService is required");
|
||||
}
|
||||
|
||||
super.setupTest(context);
|
||||
}
|
||||
|
||||
//获得控制台内容
|
||||
private PrintStream oldPrintStream = System.out;
|
||||
private ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
||||
private void setConsole() {
|
||||
System.setOut(new PrintStream(bos)); //设置新的out
|
||||
}
|
||||
|
||||
private String getConsole() {
|
||||
System.setOut(oldPrintStream);
|
||||
return bos.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) {
|
||||
|
@ -136,9 +126,10 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
TestResult testResult = new TestResult();
|
||||
testResult.setTestId(testId);
|
||||
testResult.setTotal(queue.size());
|
||||
// 一个脚本里可能包含多个场景(MsThreadGroup),所以要区分开,key: 场景Id
|
||||
|
||||
// 一个脚本里可能包含多个场景(ThreadGroup),所以要区分开,key: 场景Id
|
||||
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
|
||||
queue.forEach(result -> {
|
||||
queue.forEach(result -> {
|
||||
// 线程名称: <场景名> <场景Index>-<请求Index>, 例如:Scenario 2-1
|
||||
String scenarioName = StringUtils.substringBeforeLast(result.getThreadName(), THREAD_SPLIT);
|
||||
String index = StringUtils.substringAfterLast(result.getThreadName(), THREAD_SPLIT);
|
||||
|
@ -176,12 +167,12 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
scenarioResult.addPassAssertions(requestResult.getPassAssertions());
|
||||
scenarioResult.addTotalAssertions(requestResult.getTotalAssertions());
|
||||
});
|
||||
|
||||
testResult.getScenarios().addAll(scenarios.values());
|
||||
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
|
||||
ApiTestReport report;
|
||||
ApiTestReport report = null;
|
||||
if (StringUtils.equals(this.runMode, ApiRunMode.DEBUG.name())) {
|
||||
report = apiReportService.get(debugReportId);
|
||||
apiReportService.complete(testResult, report);
|
||||
} else if (StringUtils.equals(this.runMode, ApiRunMode.DELIMIT.name())) {
|
||||
// 调试操作,不需要存储结果
|
||||
if (StringUtils.isBlank(debugReportId)) {
|
||||
|
@ -190,15 +181,15 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
apiDefinitionService.addResult(testResult);
|
||||
apiDefinitionExecResultService.saveApiResult(testResult);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
apiTestService.changeStatus(testId, APITestStatus.Completed);
|
||||
report = apiReportService.getRunningReport(testResult.getTestId());
|
||||
apiReportService.complete(testResult, report);
|
||||
}
|
||||
apiReportService.complete(testResult, report);
|
||||
queue.clear();
|
||||
super.teardownTest(context);
|
||||
|
||||
TestPlanTestCaseService testPlanTestCaseService = CommonBeanFactory.getBean(TestPlanTestCaseService.class);
|
||||
List<String> ids = testPlanTestCaseService.getTestPlanTestCaseIds(testResult.getTestId());
|
||||
if (ids.size() > 0) {
|
||||
try {
|
||||
|
@ -219,7 +210,12 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
|
||||
}
|
||||
|
||||
private void sendTask(ApiTestReport report, TestResult testResult) {
|
||||
private static void sendTask(ApiTestReport report, TestResult testResult) {
|
||||
NoticeService noticeService = CommonBeanFactory.getBean(NoticeService.class);
|
||||
MailService mailService = CommonBeanFactory.getBean(MailService.class);
|
||||
DingTaskService dingTaskService = CommonBeanFactory.getBean(DingTaskService.class);
|
||||
WxChatTaskService wxChatTaskService = CommonBeanFactory.getBean(WxChatTaskService.class);
|
||||
SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
|
||||
if (StringUtils.equals(NoticeConstants.API, report.getTriggerMode()) || StringUtils.equals(NoticeConstants.SCHEDULE, report.getTriggerMode())) {
|
||||
List<String> userIds = new ArrayList<>();
|
||||
List<MessageDetail> taskList = new ArrayList<>();
|
||||
|
@ -288,6 +284,10 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
HTTPSampleResult res = (HTTPSampleResult) result;
|
||||
requestResult.setCookies(res.getCookies());
|
||||
}
|
||||
|
||||
for (SampleResult subResult : result.getSubResults()) {
|
||||
requestResult.getSubRequestResults().add(getRequestResult(subResult));
|
||||
}
|
||||
for (SampleResult subResult : result.getSubResults()) {
|
||||
requestResult.getSubRequestResults().add(getRequestResult(subResult));
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
responseResult.setResponseSize(result.getResponseData().length);
|
||||
responseResult.setResponseTime(result.getTime());
|
||||
responseResult.setResponseMessage(result.getResponseMessage());
|
||||
responseResult.setConsole(getConsole());
|
||||
|
||||
if (JMeterVars.get(result.hashCode()) != null) {
|
||||
List<String> vars = new LinkedList<>();
|
||||
JMeterVars.get(result.hashCode()).entrySet().parallelStream().reduce(vars, (first, second) -> {
|
||||
|
@ -323,6 +323,8 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
}
|
||||
responseResult.getAssertions().add(responseAssertionResult);
|
||||
}
|
||||
responseResult.setConsole(getConsole());
|
||||
|
||||
return requestResult;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.metersphere.api.jmeter;
|
||||
|
||||
import io.metersphere.api.dto.scenario.Scenario;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.config.JmeterProperties;
|
||||
|
@ -14,40 +14,30 @@ import org.apache.jorphan.collections.HashTree;
|
|||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
@Service
|
||||
public class JMeterService {
|
||||
|
||||
@Resource
|
||||
private JmeterProperties jmeterProperties;
|
||||
@Resource
|
||||
private JMXGenerator jmxGenerator;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
public void run(String testId, String debugReportId, InputStream is) {
|
||||
String JMETER_HOME = getJmeterHome();
|
||||
|
||||
String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties";
|
||||
JMeterUtils.loadJMeterProperties(JMETER_PROPERTIES);
|
||||
JMeterUtils.setJMeterHome(JMETER_HOME);
|
||||
JMeterUtils.setLocale(LocaleContextHolder.getLocale());
|
||||
}
|
||||
|
||||
public HashTree getHashTree(String testId, String testName, List<Scenario> scenarios) {
|
||||
return jmxGenerator.parse(testId, testName, scenarios);
|
||||
}
|
||||
|
||||
public void run(String testId, String testName, List<Scenario> scenarios, String debugReportId, String runMode) {
|
||||
try {
|
||||
init();
|
||||
HashTree testPlan = getHashTree(testId, testName, scenarios);
|
||||
Object scriptWrapper = SaveService.loadElement(is);
|
||||
HashTree testPlan = getHashTree(scriptWrapper);
|
||||
JMeterVars.addJSR223PostProcessor(testPlan);
|
||||
addBackendListener(testId, debugReportId, runMode, testPlan);
|
||||
addBackendListener(testId, debugReportId, ApiRunMode.DEBUG.name(), testPlan);
|
||||
LocalRunner runner = new LocalRunner(testPlan);
|
||||
runner.run();
|
||||
} catch (Exception e) {
|
||||
|
@ -56,18 +46,6 @@ public class JMeterService {
|
|||
}
|
||||
}
|
||||
|
||||
public String getJMX(HashTree hashTree) {
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
SaveService.saveTree(hashTree, baos);
|
||||
LogUtil.debug(baos.toString());
|
||||
return baos.toString();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.warn("HashTree error, can't log jmx content");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getJmeterHome() {
|
||||
String home = getClass().getResource("/").getPath() + "jmeter";
|
||||
try {
|
||||
|
@ -82,14 +60,19 @@ public class JMeterService {
|
|||
}
|
||||
}
|
||||
|
||||
private void addBackendListener(String testId, String debugReportId, String runMode, HashTree testPlan) {
|
||||
private HashTree getHashTree(Object scriptWrapper) throws Exception {
|
||||
Field field = scriptWrapper.getClass().getDeclaredField("testPlan");
|
||||
field.setAccessible(true);
|
||||
return (HashTree) field.get(scriptWrapper);
|
||||
}
|
||||
|
||||
private void addBackendListener(String testId, String debugReportId,String runMode, HashTree testPlan) {
|
||||
BackendListener backendListener = new BackendListener();
|
||||
backendListener.setName(testId);
|
||||
Arguments arguments = new Arguments();
|
||||
arguments.addArgument(APIBackendListenerClient.TEST_ID, testId);
|
||||
if (StringUtils.isNotBlank(runMode)) {
|
||||
arguments.addArgument("runMode", runMode);
|
||||
}
|
||||
arguments.addArgument("runMode",runMode); }
|
||||
if (StringUtils.isNotBlank(debugReportId)) {
|
||||
arguments.addArgument("debugReportId", debugReportId);
|
||||
}
|
||||
|
@ -109,5 +92,4 @@ public class JMeterService {
|
|||
MSException.throwException(Translator.get("api_load_script_error"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package io.metersphere.job.sechedule;
|
|||
|
||||
import io.metersphere.api.dto.SaveAPITestRequest;
|
||||
import io.metersphere.api.service.APITestService;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.constants.ReportTriggerMode;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
|
@ -14,7 +13,6 @@ import org.quartz.TriggerKey;
|
|||
public class ApiTestJob extends MsScheduleJob {
|
||||
|
||||
private APITestService apiTestService;
|
||||
|
||||
public ApiTestJob() {
|
||||
apiTestService = (APITestService) CommonBeanFactory.getBean(APITestService.class);
|
||||
}
|
||||
|
@ -25,7 +23,7 @@ public class ApiTestJob extends MsScheduleJob {
|
|||
request.setId(resourceId);
|
||||
request.setUserId(userId);
|
||||
request.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
|
||||
apiTestService.run(request, ApiRunMode.RUN.name());
|
||||
apiTestService.run(request);
|
||||
}
|
||||
|
||||
public static JobKey getJobKey(String testId) {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<!--返回结果-->
|
||||
<!-- HTTP 请求返回数据 -->
|
||||
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
|
||||
<ms-request-result-tail :response="responseData" ref="runResult"/>
|
||||
<ms-request-result-tail :response="responseData" :currentProtocol="currentProtocol" ref="runResult"/>
|
||||
|
||||
</el-card>
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
{{ $t('load_test.save_and_run') }}
|
||||
</el-button>
|
||||
|
||||
<!-- <el-button :disabled="isReadOnly" type="primary" plain v-if="isShowRun" @click="runTest">-->
|
||||
<!-- {{$t('api_test.run')}}-->
|
||||
<!-- </el-button>-->
|
||||
|
||||
<el-button :disabled="isReadOnly" type="warning" plain @click="cancel">{{ $t('commons.cancel') }}
|
||||
</el-button>
|
||||
|
||||
|
@ -95,339 +99,331 @@ export default {
|
|||
|
||||
props: ["id"],
|
||||
|
||||
data() {
|
||||
return {
|
||||
reportVisible: false,
|
||||
create: false,
|
||||
result: {},
|
||||
projects: [],
|
||||
change: false,
|
||||
test: new Test(),
|
||||
isReadOnly: false,
|
||||
debugReportId: ''
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route': 'init',
|
||||
test: {
|
||||
handler: function () {
|
||||
this.change = true;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
init() {
|
||||
let projectId;
|
||||
|
||||
this.isReadOnly = !checkoutTestManagerOrTestUser();
|
||||
|
||||
if (this.id) {
|
||||
this.create = false;
|
||||
this.getTest(this.id);
|
||||
} else {
|
||||
this.create = true;
|
||||
this.test = new Test();
|
||||
if (this.$refs.config) {
|
||||
this.$refs.config.reset();
|
||||
}
|
||||
// 仅创建时获取选择的项目
|
||||
projectId = this.$store.state.common.projectId;
|
||||
data() {
|
||||
return {
|
||||
reportVisible: false,
|
||||
create: false,
|
||||
result: {},
|
||||
projects: [],
|
||||
change: false,
|
||||
test: new Test(),
|
||||
isReadOnly: false,
|
||||
debugReportId: ''
|
||||
}
|
||||
this.result = this.$get("/project/listAll", response => {
|
||||
this.projects = response.data;
|
||||
// 等待项目列表加载完
|
||||
if (projectId) this.test.projectId = projectId;
|
||||
})
|
||||
},
|
||||
updateReference() {
|
||||
let updateIds = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
if (scenario.isReference()) {
|
||||
updateIds.push(scenario.id.split("#")[0]);
|
||||
}
|
||||
})
|
||||
|
||||
if (updateIds.length === 0) return;
|
||||
// 更新引用场景
|
||||
this.result = this.$post("/api/list/ids", {ids: updateIds}, response => {
|
||||
let scenarioMap = {};
|
||||
if (response.data) {
|
||||
response.data.forEach(test => {
|
||||
JSON.parse(test.scenarioDefinition).forEach(options => {
|
||||
let referenceId = test.id + "#" + options.id;
|
||||
scenarioMap[referenceId] = new Scenario(options);
|
||||
scenarioMap[referenceId].id = referenceId;
|
||||
})
|
||||
})
|
||||
}
|
||||
watch: {
|
||||
'$route': 'init',
|
||||
test: {
|
||||
handler: function () {
|
||||
this.change = true;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
|
||||
let scenarios = [];
|
||||
methods: {
|
||||
init() {
|
||||
let projectId;
|
||||
|
||||
this.isReadOnly = !checkoutTestManagerOrTestUser();
|
||||
|
||||
if (this.id) {
|
||||
this.create = false;
|
||||
this.getTest(this.id);
|
||||
} else {
|
||||
this.create = true;
|
||||
this.test = new Test();
|
||||
if (this.$refs.config) {
|
||||
this.$refs.config.reset();
|
||||
}
|
||||
// 仅创建时获取选择的项目
|
||||
projectId = this.$store.state.common.projectId;
|
||||
}
|
||||
this.result = this.$get("/project/listAll", response => {
|
||||
this.projects = response.data;
|
||||
// 等待项目列表加载完
|
||||
if (projectId) this.test.projectId = projectId;
|
||||
})
|
||||
},
|
||||
updateReference() {
|
||||
let updateIds = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
if (scenario.isReference()) {
|
||||
if (scenarioMap[scenario.id]) scenarios.push(scenarioMap[scenario.id]);
|
||||
} else {
|
||||
scenarios.push(scenario);
|
||||
updateIds.push(scenario.id.split("#")[0]);
|
||||
}
|
||||
})
|
||||
this.test.scenarioDefinition = scenarios;
|
||||
})
|
||||
},
|
||||
getTest(id) {
|
||||
this.result = this.$get("/api/get/" + id, response => {
|
||||
if (response.data) {
|
||||
let item = response.data;
|
||||
|
||||
this.test = new Test({
|
||||
id: item.id,
|
||||
projectId: item.projectId,
|
||||
name: item.name,
|
||||
status: item.status,
|
||||
scenarioDefinition: JSON.parse(item.scenarioDefinition),
|
||||
schedule: item.schedule ? item.schedule : {},
|
||||
});
|
||||
this.updateReference();
|
||||
if (updateIds.length === 0) return;
|
||||
// 更新引用场景
|
||||
this.result = this.$post("/api/list/ids", {ids: updateIds}, response => {
|
||||
let scenarioMap = {};
|
||||
if (response.data) {
|
||||
response.data.forEach(test => {
|
||||
JSON.parse(test.scenarioDefinition).forEach(options => {
|
||||
let referenceId = test.id + "#" + options.id;
|
||||
scenarioMap[referenceId] = new Scenario(options);
|
||||
scenarioMap[referenceId].id = referenceId;
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.$refs.config.reset();
|
||||
}
|
||||
});
|
||||
},
|
||||
save(callback) {
|
||||
let validator = this.test.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
}
|
||||
this.change = false;
|
||||
let bodyFiles = this.getBodyUploadFiles();
|
||||
let url = this.create ? "/api/create" : "/api/update";
|
||||
this.result = this.$fileUpload(url, null, bodyFiles, this.test, () => {
|
||||
if (callback) callback();
|
||||
this.create = false;
|
||||
this.resetBodyFile();
|
||||
});
|
||||
},
|
||||
saveTest() {
|
||||
this.save(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
if (this.create) {
|
||||
this.$router.push({
|
||||
path: '/api/test/edit?id=' + this.test.id
|
||||
let scenarios = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
if (scenario.isReference()) {
|
||||
if (scenarioMap[scenario.id]) scenarios.push(scenarioMap[scenario.id]);
|
||||
} else {
|
||||
scenarios.push(scenario);
|
||||
}
|
||||
})
|
||||
}
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
})
|
||||
},
|
||||
runTest() {
|
||||
this.test.triggerMode = 'MANUAL';
|
||||
this.result = this.$post("/api/run", this.test, (response) => {
|
||||
this.$success(this.$t('api_test.running'));
|
||||
this.$router.push({
|
||||
path: '/api/report/view/' + response.data
|
||||
this.test.scenarioDefinition = scenarios;
|
||||
})
|
||||
});
|
||||
},
|
||||
saveRunTest() {
|
||||
this.change = false;
|
||||
if (!this.validateEnableTest()) {
|
||||
this.$warning(this.$t('api_test.enable_validate_tip'));
|
||||
return;
|
||||
}
|
||||
this.save(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.runTest();
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
})
|
||||
},
|
||||
getBodyUploadFiles() {
|
||||
let bodyUploadFiles = [];
|
||||
this.test.bodyUploadIds = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
scenario.requests.forEach(request => {
|
||||
if (request.body) {
|
||||
request.body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
let fileId = getUUID().substring(0, 8);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
this.test.bodyUploadIds.push(fileId);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
getTest(id) {
|
||||
this.result = this.$get("/api/get/" + id, response => {
|
||||
if (response.data) {
|
||||
let item = response.data;
|
||||
|
||||
this.test = new Test({
|
||||
id: item.id,
|
||||
projectId: item.projectId,
|
||||
name: item.name,
|
||||
status: item.status,
|
||||
scenarioDefinition: JSON.parse(item.scenarioDefinition),
|
||||
schedule: item.schedule ? item.schedule : {},
|
||||
});
|
||||
this.updateReference();
|
||||
|
||||
this.$refs.config.reset();
|
||||
}
|
||||
});
|
||||
});
|
||||
return bodyUploadFiles;
|
||||
},
|
||||
validateEnableTest() {
|
||||
for (let scenario of this.test.scenarioDefinition) {
|
||||
if (scenario.enable) {
|
||||
for (let request of scenario.requests) {
|
||||
if (request.enable) {
|
||||
return true;
|
||||
},
|
||||
save(callback) {
|
||||
let validator = this.test.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
}
|
||||
this.change = false;
|
||||
let bodyFiles = this.getBodyUploadFiles();
|
||||
let url = this.create ? "/api/create" : "/api/update";
|
||||
let jmx = this.test.toJMX();
|
||||
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
|
||||
let file = new File([blob], jmx.name);
|
||||
this.result = this.$fileUpload(url, file, bodyFiles, this.test, () => {
|
||||
if (callback) callback();
|
||||
this.create = false;
|
||||
this.resetBodyFile();
|
||||
});
|
||||
},
|
||||
saveTest() {
|
||||
this.save(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
if (this.create) {
|
||||
this.$router.push({
|
||||
path: '/api/test/edit?id=' + this.test.id
|
||||
})
|
||||
}
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
})
|
||||
},
|
||||
runTest() {
|
||||
this.result = this.$post("/api/run", {id: this.test.id, triggerMode: 'MANUAL'}, (response) => {
|
||||
this.$success(this.$t('api_test.running'));
|
||||
this.$router.push({
|
||||
path: '/api/report/view/' + response.data
|
||||
})
|
||||
});
|
||||
},
|
||||
saveRunTest() {
|
||||
this.change = false;
|
||||
if (!this.validateEnableTest()) {
|
||||
this.$warning(this.$t('api_test.enable_validate_tip'));
|
||||
return;
|
||||
}
|
||||
this.save(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.runTest();
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
})
|
||||
},
|
||||
getBodyUploadFiles() {
|
||||
let bodyUploadFiles = [];
|
||||
this.test.bodyUploadIds = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
scenario.requests.forEach(request => {
|
||||
if (request.body) {
|
||||
request.body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
let fileId = getUUID().substring(0, 8);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
this.test.bodyUploadIds.push(fileId);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return bodyUploadFiles;
|
||||
},
|
||||
validateEnableTest() {
|
||||
for (let scenario of this.test.scenarioDefinition) {
|
||||
if (scenario.enable) {
|
||||
for (let request of scenario.requests) {
|
||||
if (request.enable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
resetBodyFile() {
|
||||
//下次保存不再上传已传文件
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
scenario.requests.forEach(request => {
|
||||
if (request.body) {
|
||||
request.body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
item.file = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
},
|
||||
resetBodyFile() {
|
||||
//下次保存不再上传已传文件
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
scenario.requests.forEach(request => {
|
||||
if (request.body) {
|
||||
request.body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
item.file = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
cancel() {
|
||||
this.$router.push('/api/test/list/all');
|
||||
},
|
||||
createPerformance() {
|
||||
let validator = this.test.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
}
|
||||
this.result = this.$post("/api/jmx", this.test, response => {
|
||||
let jmx = {
|
||||
name: this.test.name + '.jmx',
|
||||
xml: response.data
|
||||
};
|
||||
this.$store.commit('setTest', {
|
||||
projectId: this.test.projectId,
|
||||
name: this.test.name,
|
||||
jmx: jmx
|
||||
})
|
||||
this.$router.push({
|
||||
path: "/performance/test/create"
|
||||
})
|
||||
});
|
||||
},
|
||||
handleCommand(command) {
|
||||
switch (command) {
|
||||
case "report":
|
||||
this.$refs.reportDialog.open();
|
||||
break;
|
||||
case "performance":
|
||||
this.createPerformance();
|
||||
break;
|
||||
case "export":
|
||||
downloadFile(this.test.name + ".json", this.test.export());
|
||||
break;
|
||||
case "jar":
|
||||
this.$refs.jarConfig.open();
|
||||
break;
|
||||
case "import":
|
||||
this.$refs.apiImport.open();
|
||||
break;
|
||||
}
|
||||
},
|
||||
saveCronExpression(cronExpression) {
|
||||
this.test.schedule.enable = true;
|
||||
this.test.schedule.value = cronExpression;
|
||||
this.saveSchedule();
|
||||
},
|
||||
saveSchedule() {
|
||||
this.checkScheduleEdit();
|
||||
let param = {};
|
||||
param = this.test.schedule;
|
||||
param.resourceId = this.test.id;
|
||||
let url = '/api/schedule/create';
|
||||
if (param.id) {
|
||||
url = '/api/schedule/update';
|
||||
}
|
||||
this.$post(url, param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.getTest(this.test.id);
|
||||
});
|
||||
},
|
||||
checkScheduleEdit() {
|
||||
if (this.create) {
|
||||
this.$message(this.$t('api_test.environment.please_save_test'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
runDebug(scenario) {
|
||||
if (this.create) {
|
||||
this.$warning(this.$t('api_test.environment.please_save_test'));
|
||||
return;
|
||||
}
|
||||
},
|
||||
cancel() {
|
||||
this.$router.push('/api/test/list/all');
|
||||
// console.log(this.test.toJMX().xml);
|
||||
},
|
||||
handleCommand(command) {
|
||||
switch (command) {
|
||||
case "report":
|
||||
this.$refs.reportDialog.open();
|
||||
break;
|
||||
case "performance":
|
||||
this.$store.commit('setTest', {
|
||||
projectId: this.test.projectId,
|
||||
name: this.test.name,
|
||||
jmx: this.test.toJMX()
|
||||
})
|
||||
this.$router.push({
|
||||
path: "/performance/test/create"
|
||||
})
|
||||
break;
|
||||
case "export":
|
||||
downloadFile(this.test.name + ".json", this.test.export());
|
||||
break;
|
||||
case "jar":
|
||||
this.$refs.jarConfig.open();
|
||||
break;
|
||||
case "import":
|
||||
this.$refs.apiImport.open();
|
||||
break;
|
||||
}
|
||||
},
|
||||
saveCronExpression(cronExpression) {
|
||||
this.test.schedule.enable = true;
|
||||
this.test.schedule.value = cronExpression;
|
||||
this.saveSchedule();
|
||||
},
|
||||
saveSchedule() {
|
||||
this.checkScheduleEdit();
|
||||
let param = {};
|
||||
param = this.test.schedule;
|
||||
param.resourceId = this.test.id;
|
||||
let url = '/api/schedule/create';
|
||||
if (param.id) {
|
||||
url = '/api/schedule/update';
|
||||
}
|
||||
this.$post(url, param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.getTest(this.test.id);
|
||||
});
|
||||
},
|
||||
checkScheduleEdit() {
|
||||
if (this.create) {
|
||||
this.$message(this.$t('api_test.environment.please_save_test'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
runDebug(scenario) {
|
||||
if (this.create) {
|
||||
this.$warning(this.$t('api_test.environment.please_save_test'));
|
||||
return;
|
||||
}
|
||||
|
||||
let url = "/api/run/debug";
|
||||
let runningTest = new Test();
|
||||
Object.assign(runningTest, this.test);
|
||||
let bodyFiles = this.getBodyUploadFiles();
|
||||
runningTest.scenarioDefinition = [];
|
||||
runningTest.scenarioDefinition.push(scenario);
|
||||
let validator = runningTest.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
}
|
||||
let url = "/api/run/debug";
|
||||
let runningTest = new Test();
|
||||
Object.assign(runningTest, this.test);
|
||||
let bodyFiles = this.getBodyUploadFiles();
|
||||
runningTest.scenarioDefinition = [];
|
||||
runningTest.scenarioDefinition.push(scenario);
|
||||
let validator = runningTest.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
}
|
||||
|
||||
this.$fileUpload(url, null, bodyFiles, this.test, response => {
|
||||
this.debugReportId = response.data;
|
||||
this.resetBodyFile();
|
||||
});
|
||||
let jmx = runningTest.toJMX();
|
||||
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
|
||||
let file = new File([blob], jmx.name);
|
||||
this.$fileUpload(url, file, bodyFiles, this.test, response => {
|
||||
this.debugReportId = response.data;
|
||||
this.resetBodyFile();
|
||||
});
|
||||
},
|
||||
handleEvent(event) {
|
||||
if (event.keyCode === 83 && event.ctrlKey) {
|
||||
// console.log('拦截到 ctrl + s');//ctrl+s
|
||||
this.saveTest();
|
||||
event.preventDefault();
|
||||
event.returnValue = false;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
handleEvent(event) {
|
||||
if (event.keyCode === 83 && event.ctrlKey) {
|
||||
console.log('拦截到 ctrl + s');//ctrl+s
|
||||
this.saveTest();
|
||||
event.preventDefault();
|
||||
event.returnValue = false;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.init();
|
||||
//
|
||||
document.addEventListener('keydown', this.handleEvent)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.handleEvent);
|
||||
created() {
|
||||
this.init();
|
||||
//
|
||||
document.addEventListener('keydown', this.handleEvent)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.handleEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.test-container {
|
||||
height: calc(100vh - 155px);
|
||||
min-height: 600px;
|
||||
}
|
||||
.test-container {
|
||||
height: calc(100vh - 155px);
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.test-name {
|
||||
width: 600px;
|
||||
margin-left: -20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.test-name {
|
||||
width: 600px;
|
||||
margin-left: -20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.test-project {
|
||||
min-width: 150px;
|
||||
}
|
||||
.test-project {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.test-container .more {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.test-container .more {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
|
||||
import MsApiReportStatus from "../report/ApiReportStatus";
|
||||
import MsApiReportDialog from "./ApiReportDialog";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
import {parseEnvironment} from "./model/EnvironmentModel";
|
||||
|
||||
|
||||
|
@ -180,6 +181,9 @@
|
|||
type: "application/json"
|
||||
}));
|
||||
|
||||
let jmx = this.test.toJMX();
|
||||
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
|
||||
formData.append("file", new File([blob], jmx.name));
|
||||
return {
|
||||
method: 'POST',
|
||||
url: url,
|
||||
|
|
|
@ -1218,13 +1218,13 @@ class JMXGenerator {
|
|||
}
|
||||
envArray.forEach(item => {
|
||||
let targetItem = targetMap.get(item.name);
|
||||
let hasItem;
|
||||
let hasItem = undefined;
|
||||
if (targetItem) {
|
||||
hasItem = (targetItem.enable !== false);
|
||||
hasItem = (targetItem.enable === false ? false : true);
|
||||
} else {
|
||||
hasItem = false;
|
||||
}
|
||||
if (item.enable !== false && item.name && !hasItem) {
|
||||
if (item.enable != false && item.name && !hasItem) {
|
||||
target.push(new KeyValue({name: item.name, value: item.value}));
|
||||
}
|
||||
})
|
||||
|
@ -1412,7 +1412,7 @@ class JMXGenerator {
|
|||
let hasContentType = false;
|
||||
for (let index in request.headers) {
|
||||
if (request.headers.hasOwnProperty(index)) {
|
||||
if (request.headers[index].name === 'Content-Type' && request.headers[index].enable !== false) {
|
||||
if (request.headers[index].name === 'Content-Type' && request.headers[index].enable != false) {
|
||||
hasContentType = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1426,7 +1426,7 @@ class JMXGenerator {
|
|||
removeContentType(request) {
|
||||
for (let index in request.headers) {
|
||||
if (request.headers.hasOwnProperty(index)) {
|
||||
if (request.headers[index].name === 'Content-Type' && request.headers[index].enable !== false) {
|
||||
if (request.headers[index].name === 'Content-Type' && request.headers[index].enable != false) {
|
||||
request.headers.splice(index, 1);
|
||||
break;
|
||||
}
|
||||
|
@ -1524,7 +1524,7 @@ class JMXGenerator {
|
|||
|
||||
getResponseAssertion(regex) {
|
||||
let name = regex.description;
|
||||
let type = JMX_ASSERTION_CONDITION.CONTAINS;
|
||||
let type = JMX_ASSERTION_CONDITION.CONTAINS; // 固定用Match,自己写正则
|
||||
let value = regex.expression;
|
||||
let assumeSuccess = regex.assumeSuccess;
|
||||
switch (regex.subject) {
|
||||
|
|
Loading…
Reference in New Issue