feat(接口定义): 合并master 最新代码

This commit is contained in:
fit2-zhao 2020-11-27 13:59:18 +08:00
parent 22108b3048
commit 73204d7793
8 changed files with 379 additions and 401 deletions

View File

@ -7,7 +7,6 @@ import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
import io.metersphere.api.service.APITestService; import io.metersphere.api.service.APITestService;
import io.metersphere.base.domain.ApiTest; import io.metersphere.base.domain.ApiTest;
import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.RoleConstants; import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; 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.controller.request.QueryScheduleRequest;
import io.metersphere.dto.ScheduleDao; import io.metersphere.dto.ScheduleDao;
import io.metersphere.service.CheckOwnerService; import io.metersphere.service.CheckOwnerService;
import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -75,19 +76,18 @@ public class APITestController {
} }
@PostMapping(value = "/create", consumes = {"multipart/form-data"}) @PostMapping(value = "/create", consumes = {"multipart/form-data"})
public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) { public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiTestService.create(request, bodyFiles); apiTestService.create(request, file, bodyFiles);
} }
@PostMapping(value = "/create/merge", consumes = {"multipart/form-data"}) @PostMapping(value = "/create/merge", consumes = {"multipart/form-data"})
public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "selectIds") List<String> selectIds) { public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "selectIds") List<String> selectIds) {
apiTestService.mergeCreate(request, selectIds); apiTestService.mergeCreate(request, file, selectIds);
} }
@PostMapping(value = "/update", consumes = {"multipart/form-data"}) @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()); checkownerService.checkApiTestOwner(request.getId());
apiTestService.update(request, bodyFiles); apiTestService.update(request, file, bodyFiles);
} }
@PostMapping(value = "/copy") @PostMapping(value = "/copy")
@ -101,25 +101,21 @@ public class APITestController {
return apiTestService.get(testId); return apiTestService.get(testId);
} }
@PostMapping("/delete") @PostMapping("/delete")
public void delete(@RequestBody DeleteAPITestRequest request) { public void delete(@RequestBody DeleteAPITestRequest request) {
checkownerService.checkApiTestOwner(request.getId()); checkownerService.checkApiTestOwner(request.getId());
apiTestService.delete(request); apiTestService.delete(request);
} }
@PostMapping(value = "/jmx")
public String getJMX(@RequestBody SaveAPITestRequest request) {
return apiTestService.getJMX(request);
}
@PostMapping(value = "/run") @PostMapping(value = "/run")
public String run(@RequestBody SaveAPITestRequest request) { 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"}) @PostMapping(value = "/run/debug", consumes = {"multipart/form-data"})
public String runDebug(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) { public String runDebug(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
return apiTestService.runDebug(request, bodyFiles, ApiRunMode.DEBUG.name()); return apiTestService.runDebug(request, file, bodyFiles);
} }
@PostMapping(value = "/checkName") @PostMapping(value = "/checkName")
@ -140,7 +136,7 @@ public class APITestController {
@PostMapping("/list/schedule/{goPage}/{pageSize}") @PostMapping("/list/schedule/{goPage}/{pageSize}")
public List<ScheduleDao> listSchedule(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryScheduleRequest request) { 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); return apiTestService.listSchedule(request);
} }

View File

@ -47,13 +47,15 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
private final List<SampleResult> queue = new ArrayList<>(); private final List<SampleResult> queue = new ArrayList<>();
private APITestService apiTestService; private APITestService apiTestService;
private APIReportService apiReportService; private APIReportService apiReportService;
private TestPlanTestCaseService testPlanTestCaseService; private TestPlanTestCaseService testPlanTestCaseService;
private NoticeService noticeService; private NoticeService noticeService;
private MailService mailService; private MailService mailService;
private DingTaskService dingTaskService;
private WxChatTaskService wxChatTaskService;
private SystemParameterService systemParameterService;
private ApiDefinitionService apiDefinitionService; private ApiDefinitionService apiDefinitionService;
private ApiDefinitionExecResultService apiDefinitionExecResultService; private ApiDefinitionExecResultService apiDefinitionExecResultService;
@ -64,6 +66,19 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
private String debugReportId; 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 @Override
public void setupTest(BackendListenerContext context) throws Exception { public void setupTest(BackendListenerContext context) throws Exception {
setConsole(); setConsole();
@ -89,18 +104,6 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
if (mailService == null) { if (mailService == null) {
LogUtil.error("mailService is required"); 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); apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class);
if (apiDefinitionService == null) { if (apiDefinitionService == null) {
LogUtil.error("apiDefinitionService is required"); LogUtil.error("apiDefinitionService is required");
@ -109,22 +112,9 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
if (apiDefinitionExecResultService == null) { if (apiDefinitionExecResultService == null) {
LogUtil.error("apiDefinitionExecResultService is required"); LogUtil.error("apiDefinitionExecResultService is required");
} }
super.setupTest(context); 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 @Override
public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) { public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) {
@ -136,9 +126,10 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
TestResult testResult = new TestResult(); TestResult testResult = new TestResult();
testResult.setTestId(testId); testResult.setTestId(testId);
testResult.setTotal(queue.size()); testResult.setTotal(queue.size());
// 一个脚本里可能包含多个场景(MsThreadGroup)所以要区分开key: 场景Id
// 一个脚本里可能包含多个场景(ThreadGroup)所以要区分开key: 场景Id
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>(); final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
queue.forEach(result -> { queue.forEach(result -> {
// 线程名称: <场景名> <场景Index>-<请求Index>, 例如Scenario 2-1 // 线程名称: <场景名> <场景Index>-<请求Index>, 例如Scenario 2-1
String scenarioName = StringUtils.substringBeforeLast(result.getThreadName(), THREAD_SPLIT); String scenarioName = StringUtils.substringBeforeLast(result.getThreadName(), THREAD_SPLIT);
String index = StringUtils.substringAfterLast(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.addPassAssertions(requestResult.getPassAssertions());
scenarioResult.addTotalAssertions(requestResult.getTotalAssertions()); scenarioResult.addTotalAssertions(requestResult.getTotalAssertions());
}); });
testResult.getScenarios().addAll(scenarios.values()); testResult.getScenarios().addAll(scenarios.values());
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId)); testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
ApiTestReport report; ApiTestReport report = null;
if (StringUtils.equals(this.runMode, ApiRunMode.DEBUG.name())) { if (StringUtils.equals(this.runMode, ApiRunMode.DEBUG.name())) {
report = apiReportService.get(debugReportId); report = apiReportService.get(debugReportId);
apiReportService.complete(testResult, report);
} else if (StringUtils.equals(this.runMode, ApiRunMode.DELIMIT.name())) { } else if (StringUtils.equals(this.runMode, ApiRunMode.DELIMIT.name())) {
// 调试操作不需要存储结果 // 调试操作不需要存储结果
if (StringUtils.isBlank(debugReportId)) { if (StringUtils.isBlank(debugReportId)) {
@ -190,15 +181,15 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
apiDefinitionService.addResult(testResult); apiDefinitionService.addResult(testResult);
apiDefinitionExecResultService.saveApiResult(testResult); apiDefinitionExecResultService.saveApiResult(testResult);
} }
return;
} else { } else {
apiTestService.changeStatus(testId, APITestStatus.Completed); apiTestService.changeStatus(testId, APITestStatus.Completed);
report = apiReportService.getRunningReport(testResult.getTestId()); report = apiReportService.getRunningReport(testResult.getTestId());
apiReportService.complete(testResult, report);
} }
apiReportService.complete(testResult, report);
queue.clear(); queue.clear();
super.teardownTest(context); super.teardownTest(context);
TestPlanTestCaseService testPlanTestCaseService = CommonBeanFactory.getBean(TestPlanTestCaseService.class);
List<String> ids = testPlanTestCaseService.getTestPlanTestCaseIds(testResult.getTestId()); List<String> ids = testPlanTestCaseService.getTestPlanTestCaseIds(testResult.getTestId());
if (ids.size() > 0) { if (ids.size() > 0) {
try { 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())) { if (StringUtils.equals(NoticeConstants.API, report.getTriggerMode()) || StringUtils.equals(NoticeConstants.SCHEDULE, report.getTriggerMode())) {
List<String> userIds = new ArrayList<>(); List<String> userIds = new ArrayList<>();
List<MessageDetail> taskList = new ArrayList<>(); List<MessageDetail> taskList = new ArrayList<>();
@ -288,6 +284,10 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
HTTPSampleResult res = (HTTPSampleResult) result; HTTPSampleResult res = (HTTPSampleResult) result;
requestResult.setCookies(res.getCookies()); requestResult.setCookies(res.getCookies());
} }
for (SampleResult subResult : result.getSubResults()) {
requestResult.getSubRequestResults().add(getRequestResult(subResult));
}
for (SampleResult subResult : result.getSubResults()) { for (SampleResult subResult : result.getSubResults()) {
requestResult.getSubRequestResults().add(getRequestResult(subResult)); requestResult.getSubRequestResults().add(getRequestResult(subResult));
} }
@ -300,7 +300,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
responseResult.setResponseSize(result.getResponseData().length); responseResult.setResponseSize(result.getResponseData().length);
responseResult.setResponseTime(result.getTime()); responseResult.setResponseTime(result.getTime());
responseResult.setResponseMessage(result.getResponseMessage()); responseResult.setResponseMessage(result.getResponseMessage());
responseResult.setConsole(getConsole());
if (JMeterVars.get(result.hashCode()) != null) { if (JMeterVars.get(result.hashCode()) != null) {
List<String> vars = new LinkedList<>(); List<String> vars = new LinkedList<>();
JMeterVars.get(result.hashCode()).entrySet().parallelStream().reduce(vars, (first, second) -> { 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.getAssertions().add(responseAssertionResult);
} }
responseResult.setConsole(getConsole());
return requestResult; return requestResult;
} }

View File

@ -1,6 +1,6 @@
package io.metersphere.api.jmeter; 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.exception.MSException;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import io.metersphere.config.JmeterProperties; import io.metersphere.config.JmeterProperties;
@ -14,40 +14,30 @@ import org.apache.jorphan.collections.HashTree;
import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.util.List; import java.io.InputStream;
import java.lang.reflect.Field;
@Service @Service
public class JMeterService { public class JMeterService {
@Resource @Resource
private JmeterProperties jmeterProperties; private JmeterProperties jmeterProperties;
@Resource
private JMXGenerator jmxGenerator;
@PostConstruct public void run(String testId, String debugReportId, InputStream is) {
public 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);
JMeterUtils.setLocale(LocaleContextHolder.getLocale()); 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 { try {
init(); Object scriptWrapper = SaveService.loadElement(is);
HashTree testPlan = getHashTree(testId, testName, scenarios); HashTree testPlan = getHashTree(scriptWrapper);
JMeterVars.addJSR223PostProcessor(testPlan); JMeterVars.addJSR223PostProcessor(testPlan);
addBackendListener(testId, debugReportId, runMode, testPlan); addBackendListener(testId, debugReportId, ApiRunMode.DEBUG.name(), testPlan);
LocalRunner runner = new LocalRunner(testPlan); LocalRunner runner = new LocalRunner(testPlan);
runner.run(); runner.run();
} catch (Exception e) { } 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() { public String getJmeterHome() {
String home = getClass().getResource("/").getPath() + "jmeter"; String home = getClass().getResource("/").getPath() + "jmeter";
try { 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 backendListener = new BackendListener();
backendListener.setName(testId); backendListener.setName(testId);
Arguments arguments = new Arguments(); Arguments arguments = new Arguments();
arguments.addArgument(APIBackendListenerClient.TEST_ID, testId); arguments.addArgument(APIBackendListenerClient.TEST_ID, testId);
if (StringUtils.isNotBlank(runMode)) { if (StringUtils.isNotBlank(runMode)) {
arguments.addArgument("runMode", runMode); arguments.addArgument("runMode",runMode); }
}
if (StringUtils.isNotBlank(debugReportId)) { if (StringUtils.isNotBlank(debugReportId)) {
arguments.addArgument("debugReportId", debugReportId); arguments.addArgument("debugReportId", debugReportId);
} }
@ -109,5 +92,4 @@ public class JMeterService {
MSException.throwException(Translator.get("api_load_script_error")); MSException.throwException(Translator.get("api_load_script_error"));
} }
} }
} }

View File

@ -2,7 +2,6 @@ package io.metersphere.job.sechedule;
import io.metersphere.api.dto.SaveAPITestRequest; import io.metersphere.api.dto.SaveAPITestRequest;
import io.metersphere.api.service.APITestService; import io.metersphere.api.service.APITestService;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.ScheduleGroup; import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.CommonBeanFactory;
@ -14,7 +13,6 @@ import org.quartz.TriggerKey;
public class ApiTestJob extends MsScheduleJob { public class ApiTestJob extends MsScheduleJob {
private APITestService apiTestService; private APITestService apiTestService;
public ApiTestJob() { public ApiTestJob() {
apiTestService = (APITestService) CommonBeanFactory.getBean(APITestService.class); apiTestService = (APITestService) CommonBeanFactory.getBean(APITestService.class);
} }
@ -25,7 +23,7 @@ public class ApiTestJob extends MsScheduleJob {
request.setId(resourceId); request.setId(resourceId);
request.setUserId(userId); request.setUserId(userId);
request.setTriggerMode(ReportTriggerMode.SCHEDULE.name()); request.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
apiTestService.run(request, ApiRunMode.RUN.name()); apiTestService.run(request);
} }
public static JobKey getJobKey(String testId) { public static JobKey getJobKey(String testId) {

View File

@ -24,7 +24,7 @@
<!--返回结果--> <!--返回结果-->
<!-- HTTP 请求返回数据 --> <!-- HTTP 请求返回数据 -->
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p> <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> </el-card>

View File

@ -27,6 +27,10 @@
{{ $t('load_test.save_and_run') }} {{ $t('load_test.save_and_run') }}
</el-button> </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 :disabled="isReadOnly" type="warning" plain @click="cancel">{{ $t('commons.cancel') }}
</el-button> </el-button>
@ -95,339 +99,331 @@ export default {
props: ["id"], props: ["id"],
data() { data() {
return { return {
reportVisible: false, reportVisible: false,
create: false, create: false,
result: {}, result: {},
projects: [], projects: [],
change: false, change: false,
test: new Test(), test: new Test(),
isReadOnly: false, isReadOnly: false,
debugReportId: '' 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;
} }
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; watch: {
// '$route': 'init',
this.result = this.$post("/api/list/ids", {ids: updateIds}, response => { test: {
let scenarioMap = {}; handler: function () {
if (response.data) { this.change = true;
response.data.forEach(test => { },
JSON.parse(test.scenarioDefinition).forEach(options => { deep: true
let referenceId = test.id + "#" + options.id; }
scenarioMap[referenceId] = new Scenario(options); },
scenarioMap[referenceId].id = referenceId;
})
})
}
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 => { this.test.scenarioDefinition.forEach(scenario => {
if (scenario.isReference()) { if (scenario.isReference()) {
if (scenarioMap[scenario.id]) scenarios.push(scenarioMap[scenario.id]); updateIds.push(scenario.id.split("#")[0]);
} else {
scenarios.push(scenario);
} }
}) })
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({ if (updateIds.length === 0) return;
id: item.id, //
projectId: item.projectId, this.result = this.$post("/api/list/ids", {ids: updateIds}, response => {
name: item.name, let scenarioMap = {};
status: item.status, if (response.data) {
scenarioDefinition: JSON.parse(item.scenarioDefinition), response.data.forEach(test => {
schedule: item.schedule ? item.schedule : {}, JSON.parse(test.scenarioDefinition).forEach(options => {
}); let referenceId = test.id + "#" + options.id;
this.updateReference(); scenarioMap[referenceId] = new Scenario(options);
scenarioMap[referenceId].id = referenceId;
})
})
}
this.$refs.config.reset(); let scenarios = [];
} this.test.scenarioDefinition.forEach(scenario => {
}); if (scenario.isReference()) {
}, if (scenarioMap[scenario.id]) scenarios.push(scenarioMap[scenario.id]);
save(callback) { } else {
let validator = this.test.isValid(); scenarios.push(scenario);
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
}) })
} this.test.scenarioDefinition = scenarios;
// 广 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
}) })
}); },
}, getTest(id) {
saveRunTest() { this.result = this.$get("/api/get/" + id, response => {
this.change = false; if (response.data) {
if (!this.validateEnableTest()) { let item = response.data;
this.$warning(this.$t('api_test.enable_validate_tip'));
return; this.test = new Test({
} id: item.id,
this.save(() => { projectId: item.projectId,
this.$success(this.$t('commons.save_success')); name: item.name,
this.runTest(); status: item.status,
// 广 head scenarioDefinition: JSON.parse(item.scenarioDefinition),
ApiEvent.$emit(LIST_CHANGE); schedule: item.schedule ? item.schedule : {},
})
},
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);
}
});
}
}); });
this.updateReference();
this.$refs.config.reset();
} }
}); });
}); },
return bodyUploadFiles; save(callback) {
}, let validator = this.test.isValid();
validateEnableTest() { if (!validator.isValid) {
for (let scenario of this.test.scenarioDefinition) { this.$warning(this.$t(validator.info));
if (scenario.enable) { return;
for (let request of scenario.requests) { }
if (request.enable) { this.change = false;
return true; 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;
return false; },
}, resetBodyFile() {
resetBodyFile() { //
// this.test.scenarioDefinition.forEach(scenario => {
this.test.scenarioDefinition.forEach(scenario => { scenario.requests.forEach(request => {
scenario.requests.forEach(request => { if (request.body) {
if (request.body) { request.body.kvs.forEach(param => {
request.body.kvs.forEach(param => { if (param.files) {
if (param.files) { param.files.forEach(item => {
param.files.forEach(item => { if (item.file) {
if (item.file) { item.file = undefined;
item.file = undefined; }
} });
}); }
} });
}); }
} });
}); });
}); },
}, cancel() {
cancel() { this.$router.push('/api/test/list/all');
this.$router.push('/api/test/list/all'); // console.log(this.test.toJMX().xml);
}, },
createPerformance() { handleCommand(command) {
let validator = this.test.isValid(); switch (command) {
if (!validator.isValid) { case "report":
this.$warning(this.$t(validator.info)); this.$refs.reportDialog.open();
return; break;
} case "performance":
this.result = this.$post("/api/jmx", this.test, response => { this.$store.commit('setTest', {
let jmx = { projectId: this.test.projectId,
name: this.test.name + '.jmx', name: this.test.name,
xml: response.data jmx: this.test.toJMX()
}; })
this.$store.commit('setTest', { this.$router.push({
projectId: this.test.projectId, path: "/performance/test/create"
name: this.test.name, })
jmx: jmx break;
}) case "export":
this.$router.push({ downloadFile(this.test.name + ".json", this.test.export());
path: "/performance/test/create" break;
}) case "jar":
}); this.$refs.jarConfig.open();
}, break;
handleCommand(command) { case "import":
switch (command) { this.$refs.apiImport.open();
case "report": break;
this.$refs.reportDialog.open(); }
break; },
case "performance": saveCronExpression(cronExpression) {
this.createPerformance(); this.test.schedule.enable = true;
break; this.test.schedule.value = cronExpression;
case "export": this.saveSchedule();
downloadFile(this.test.name + ".json", this.test.export()); },
break; saveSchedule() {
case "jar": this.checkScheduleEdit();
this.$refs.jarConfig.open(); let param = {};
break; param = this.test.schedule;
case "import": param.resourceId = this.test.id;
this.$refs.apiImport.open(); let url = '/api/schedule/create';
break; if (param.id) {
} url = '/api/schedule/update';
}, }
saveCronExpression(cronExpression) { this.$post(url, param, () => {
this.test.schedule.enable = true; this.$success(this.$t('commons.save_success'));
this.test.schedule.value = cronExpression; this.getTest(this.test.id);
this.saveSchedule(); });
}, },
saveSchedule() { checkScheduleEdit() {
this.checkScheduleEdit(); if (this.create) {
let param = {}; this.$message(this.$t('api_test.environment.please_save_test'));
param = this.test.schedule; return false;
param.resourceId = this.test.id; }
let url = '/api/schedule/create'; return true;
if (param.id) { },
url = '/api/schedule/update'; runDebug(scenario) {
} if (this.create) {
this.$post(url, param, () => { this.$warning(this.$t('api_test.environment.please_save_test'));
this.$success(this.$t('commons.save_success')); return;
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 url = "/api/run/debug";
let runningTest = new Test(); let runningTest = new Test();
Object.assign(runningTest, this.test); Object.assign(runningTest, this.test);
let bodyFiles = this.getBodyUploadFiles(); let bodyFiles = this.getBodyUploadFiles();
runningTest.scenarioDefinition = []; runningTest.scenarioDefinition = [];
runningTest.scenarioDefinition.push(scenario); runningTest.scenarioDefinition.push(scenario);
let validator = runningTest.isValid(); let validator = runningTest.isValid();
if (!validator.isValid) { if (!validator.isValid) {
this.$warning(this.$t(validator.info)); this.$warning(this.$t(validator.info));
return; return;
} }
this.$fileUpload(url, null, bodyFiles, this.test, response => { let jmx = runningTest.toJMX();
this.debugReportId = response.data; let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
this.resetBodyFile(); 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() { created() {
this.init(); this.init();
// //
document.addEventListener('keydown', this.handleEvent) document.addEventListener('keydown', this.handleEvent)
}, },
beforeDestroy() { beforeDestroy() {
document.removeEventListener('keydown', this.handleEvent); document.removeEventListener('keydown', this.handleEvent);
}
} }
}
</script> </script>
<style scoped> <style scoped>
.test-container { .test-container {
height: calc(100vh - 155px); height: calc(100vh - 155px);
min-height: 600px; min-height: 600px;
} }
.test-name { .test-name {
width: 600px; width: 600px;
margin-left: -20px; margin-left: -20px;
margin-right: 20px; margin-right: 20px;
} }
.test-project { .test-project {
min-width: 150px; min-width: 150px;
} }
.test-container .more { .test-container .more {
margin-left: 10px; margin-left: 10px;
} }
</style> </style>

View File

@ -26,6 +26,7 @@
import MsApiScenarioConfig from "./components/ApiScenarioConfig"; import MsApiScenarioConfig from "./components/ApiScenarioConfig";
import MsApiReportStatus from "../report/ApiReportStatus"; import MsApiReportStatus from "../report/ApiReportStatus";
import MsApiReportDialog from "./ApiReportDialog"; import MsApiReportDialog from "./ApiReportDialog";
import {getUUID} from "@/common/js/utils";
import {parseEnvironment} from "./model/EnvironmentModel"; import {parseEnvironment} from "./model/EnvironmentModel";
@ -180,6 +181,9 @@
type: "application/json" 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 { return {
method: 'POST', method: 'POST',
url: url, url: url,

View File

@ -1218,13 +1218,13 @@ class JMXGenerator {
} }
envArray.forEach(item => { envArray.forEach(item => {
let targetItem = targetMap.get(item.name); let targetItem = targetMap.get(item.name);
let hasItem; let hasItem = undefined;
if (targetItem) { if (targetItem) {
hasItem = (targetItem.enable !== false); hasItem = (targetItem.enable === false ? false : true);
} else { } else {
hasItem = false; 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})); target.push(new KeyValue({name: item.name, value: item.value}));
} }
}) })
@ -1412,7 +1412,7 @@ class JMXGenerator {
let hasContentType = false; let hasContentType = false;
for (let index in request.headers) { for (let index in request.headers) {
if (request.headers.hasOwnProperty(index)) { 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; hasContentType = true;
break; break;
} }
@ -1426,7 +1426,7 @@ class JMXGenerator {
removeContentType(request) { removeContentType(request) {
for (let index in request.headers) { for (let index in request.headers) {
if (request.headers.hasOwnProperty(index)) { 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); request.headers.splice(index, 1);
break; break;
} }
@ -1524,7 +1524,7 @@ class JMXGenerator {
getResponseAssertion(regex) { getResponseAssertion(regex) {
let name = regex.description; let name = regex.description;
let type = JMX_ASSERTION_CONDITION.CONTAINS; let type = JMX_ASSERTION_CONDITION.CONTAINS; // 固定用Match自己写正则
let value = regex.expression; let value = regex.expression;
let assumeSuccess = regex.assumeSuccess; let assumeSuccess = regex.assumeSuccess;
switch (regex.subject) { switch (regex.subject) {