Merge branch 'master' of github.com:fit2cloudrd/metersphere-server

This commit is contained in:
Captain.B 2020-08-07 17:37:45 +08:00
commit fa13003865
24 changed files with 156 additions and 40 deletions

View File

@ -49,7 +49,6 @@ public class APITestController {
return apiTestService.getApiTestByProjectId(projectId);
}
@PostMapping(value = "/schedule/update")
public void updateSchedule(@RequestBody Schedule request) {
apiTestService.updateSchedule(request);
@ -90,6 +89,11 @@ public class APITestController {
return apiTestService.run(request);
}
@PostMapping(value = "/run/independent", consumes = {"multipart/form-data"})
public String runIndependent(@RequestBody SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> files) {
return apiTestService.runIndependent(request, files);
}
@PostMapping(value = "/import", consumes = {"multipart/form-data"})
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public ApiTest testCaseImport(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart("request") ApiTestImportRequest request) {

View File

@ -10,6 +10,7 @@ public class Scenario {
private String name;
private String url;
private String environmentId;
private Boolean enableCookieShare;
private List<KeyValue> variables;
private List<KeyValue> headers;
private List<Request> requests;

View File

@ -101,7 +101,12 @@ public class APIReportService {
if (running != null) {
return running.getId();
}
ApiTestReport report = buildReport(test, triggerMode, APITestStatus.Running.name());
apiTestReportMapper.insert(report);
return report.getId();
}
public ApiTestReport buildReport(ApiTest test, String triggerMode, String status) {
ApiTestReport report = new ApiTestReport();
report.setId(UUID.randomUUID().toString());
report.setTestId(test.getId());
@ -110,11 +115,9 @@ public class APIReportService {
report.setDescription(test.getDescription());
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
report.setStatus(APITestStatus.Running.name());
report.setStatus(status);
report.setUserId(test.getUserId());
apiTestReportMapper.insert(report);
return report.getId();
return report;
}
public ApiTestReport getRunningReport(String testId) {

View File

@ -37,6 +37,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
@ -299,8 +300,8 @@ public class APITestService {
if (info.length > 1) {
provider.setVersion(info[1]);
}
provider.setService(info[0]);
provider.setServiceInterface(p);
provider.setService(p);
provider.setServiceInterface(info[0]);
Map<String, URL> services = providerService.findByService(p);
if (services != null && !services.isEmpty()) {
String[] methods = services.values().stream().findFirst().get().getParameter(CommonConstants.METHODS_KEY).split(",");
@ -314,6 +315,7 @@ public class APITestService {
}
public List<ScheduleDao> listSchedule(QueryScheduleRequest request) {
request.setEnable(true);
List<ScheduleDao> schedules = scheduleService.list(request);
List<String> resourceIds = schedules.stream()
.map(Schedule::getResourceId)
@ -327,4 +329,29 @@ public class APITestService {
}
return schedules;
}
public String runIndependent(SaveAPITestRequest request, List<MultipartFile> files) {
if (files == null || files.isEmpty()) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
}
// ApiTest test = createTest(request);
// saveFile(test.getId(), files);
MultipartFile file = files.get(0);
InputStream is = null;
try {
is = new ByteArrayInputStream(file.getBytes());
} catch (IOException e) {
LogUtil.error(e);
}
APITestResult apiTest = get(request.getId());
if (SessionUtils.getUser() == null) {
apiTest.setUserId(request.getUserId());
}
String reportId = apiReportService.create(apiTest, request.getTriggerMode());
changeStatus(request.getId(), APITestStatus.Running);
jMeterService.run(request.getId(), is);
return reportId;
}
}

View File

@ -10,6 +10,9 @@
<if test="request.workspaceId != null">
and schedule.workspace_id = #{request.workspaceId}
</if>
<if test="request.enable != null">
and schedule.enable = #{request.enable}
</if>
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">

View File

@ -420,6 +420,7 @@ public class PerformanceTestService {
}
public List<ScheduleDao> listSchedule(QueryScheduleRequest request) {
request.setEnable(true);
List<ScheduleDao> schedules = scheduleService.list(request);
List<String> resourceIds = schedules.stream()
.map(Schedule::getResourceId)

View File

@ -11,7 +11,7 @@
<template v-slot:title>{{$t('commons.project')}}</template>
<ms-recent-list :options="projectRecent"/>
<el-divider class="menu-divider"/>
<ms-show-all :index="'/api/project'"/>
<ms-show-all :index="'/api/project/all'"/>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/api/project/create'"
:title="$t('project.create')"/>
</el-submenu>
@ -20,7 +20,7 @@
<template v-slot:title>{{$t('commons.test')}}</template>
<ms-recent-list :options="testRecent"/>
<el-divider class="menu-divider"/>
<ms-show-all :index="'/api/test/list'"/>
<ms-show-all :index="'/api/test/list/all'"/>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/api/test/create'"
:title="$t('load_test.create')"/>
</el-submenu>
@ -29,7 +29,7 @@
<template v-slot:title>{{$t('commons.report')}}</template>
<ms-recent-list :options="reportRecent"/>
<el-divider class="menu-divider"/>
<ms-show-all :index="'/api/report/list'"/>
<ms-show-all :index="'/api/report/list/all'"/>
</el-submenu>
</el-menu>
</el-col>
@ -60,7 +60,7 @@
title: this.$t('project.recent'),
url: "/project/recent/5",
index: function (item) {
return '/api/' + item.id;
return '/api/test/list/' + item.id;
},
router: function (item) {
return {name: 'ApiTestList', params: {projectId: item.id, projectName: item.name}}

View File

@ -14,7 +14,7 @@
<ms-test-heatmap :values="values"/>
</el-col>
<el-col :span="12">
<ms-api-test-schedule-list :group="'API_TEST'"/>
<ms-schedule-list :group="'API_TEST'"/>
</el-col>
</el-row>
</ms-main-container>
@ -28,13 +28,13 @@
import MsApiTestRecentList from "./ApiTestRecentList";
import MsApiReportRecentList from "./ApiReportRecentList";
import MsTestHeatmap from "../../common/components/MsTestHeatmap";
import MsApiTestScheduleList from "./ApiTestScheduleList";
import MsScheduleList from "./ScheduleList";
export default {
name: "ApiTestHome",
components: {
MsApiTestScheduleList,
MsScheduleList,
MsTestHeatmap, MsApiReportRecentList, MsApiTestRecentList, MsMainContainer, MsContainer
},

View File

@ -1,7 +1,7 @@
<template>
<el-card class="table-card" v-loading="result.loading">
<template v-slot:header>
<span class="title">{{$t('commons.trigger_mode.schedule')}}</span>
<span class="title">{{$t('schedule.running_task')}}</span>
</template>
<el-table height="289" border :data="tableData" class="adjust-table table-content" @row-click="link">
<el-table-column prop="resourceName" :label="$t('schedule.test_name')" width="150" show-overflow-tooltip/>
@ -32,7 +32,7 @@
import {SCHEDULE_TYPE} from "../../../../common/js/constants";
export default {
name: "MsApiTestScheduleList",
name: "MsScheduleList",
components: {CrontabResult},
data() {
return {

View File

@ -1,5 +1,5 @@
<template>
<el-card>
<el-card class="scenario-results">
<div class="scenario-header">
<el-row :gutter="10">
<el-col :span="16">

View File

@ -157,9 +157,11 @@
saveTest() {
this.save(() => {
this.$success(this.$t('commons.save_success'));
if (this.create) {
this.$router.push({
path: '/api/test/edit?id=' + this.test.id
})
}
})
},
runTest() {

View File

@ -21,6 +21,9 @@
</div>
</template>
</el-select>
<el-form-item class="cookie-item">
<el-checkbox v-model="scenario.enableCookieShare">{{'共享 Cookie'}}</el-checkbox>
</el-form-item>
</el-form-item>
<el-tabs v-model="activeName">
@ -168,4 +171,8 @@
font-weight: 600;
}
.cookie-item {
margin-top: 15px;
}
</style>

View File

@ -1,15 +1,19 @@
<template>
<div>
<component :is="component" :is-read-only="isReadOnly" :request="request"/>
<!-- <ms-scenario-results :scenarios="content.scenarios"/>-->
</div>
</template>
<script>
import {Request, RequestFactory} from "../../model/ScenarioModel";
import MsApiHttpRequestForm from "./ApiHttpRequestForm";
import MsApiDubboRequestForm from "./ApiDubboRequestForm";
import MsScenarioResults from "../../../report/components/ScenarioResults";
export default {
name: "MsApiRequestForm",
components: {MsApiDubboRequestForm, MsApiHttpRequestForm},
components: {MsScenarioResults, MsApiDubboRequestForm, MsApiHttpRequestForm},
props: {
request: Request,
isReadOnly: {
@ -17,6 +21,12 @@
default: false
}
},
data() {
return {
reportId: "",
content:{}
}
},
computed: {
component({request: {type}}) {
let name;
@ -29,10 +39,46 @@
}
return name;
}
},
created() {
this.getReport();
},
methods: {
getReport() {
// // this.reportId = "00143d36-a58a-477e-a05a-556c1d48046c";
// if (this.reportId) {
// let url = "/api/report/get/" + this.reportId;
// this.$get(url, response => {
// let report = response.data || {};
// if (response.data) {
// // if (this.isNotRunning) {
// try {
// this.content = JSON.parse(report.content);
// } catch (e) {
// console.log(report.content)
// throw e;
// }
// // this.getFails();
// // this.loading = false;
// // }
// // else {
// // setTimeout(this.getReport, 2000)
// // }
// } else {
// this.loading = false;
// this.$error(this.$t('api_report.not_exist'));
// }
// });
// }
}
}
}
</script>
<style scoped>
.scenario-results {
margin-top: 15px;
}
</style>

View File

@ -328,6 +328,15 @@ export class HTTPSamplerArguments extends Element {
}
}
export class CookieManager extends DefaultTestElement {
constructor(testName) {
super('CookieManager', 'CookiePanel', 'CookieManager', testName);
this.collectionProp('CookieManager.cookies');
this.boolProp('CookieManager.clearEachIteration', false, false);
this.boolProp('CookieManager.controlledByThreadGroup', false, false);
}
}
export class DurationAssertion extends DefaultTestElement {
constructor(testName, duration) {
super('DurationAssertion', 'DurationAssertionGui', 'DurationAssertion', testName);

View File

@ -1,5 +1,5 @@
import {
Arguments,
Arguments, CookieManager,
DubboSample,
DurationAssertion,
Element,
@ -174,6 +174,7 @@ export class Scenario extends BaseConfig {
this.environmentId = undefined;
this.dubboConfig = undefined;
this.environment = undefined;
this.enableCookieShare = false;
this.set(options);
this.sets({variables: KeyValue, headers: KeyValue, requests: RequestFactory}, options);
@ -765,6 +766,8 @@ class JMXGenerator {
this.addScenarioHeaders(threadGroup, scenario);
this.addScenarioCookieManager(threadGroup, scenario);
scenario.requests.forEach(request => {
if (!request.isValid()) return;
let sampler;
@ -822,6 +825,12 @@ class JMXGenerator {
}
}
addScenarioCookieManager(threadGroup, scenario) {
if (scenario.enableCookieShare) {
threadGroup.put(new CookieManager(scenario.name));
}
}
addScenarioHeaders(threadGroup, scenario) {
let environment = scenario.environment;
if (environment) {

View File

@ -7,10 +7,14 @@
</span>
<el-switch :disabled="!schedule.value || isReadOnly" v-model="schedule.enable" @change="scheduleChange"/>
<ms-schedule-edit :is-read-only="isReadOnly" :schedule="schedule" :save="save" :custom-validate="customValidate" ref="scheduleEdit"/>
<crontab-result v-show="false" :ex="schedule.value" ref="crontabResult" @resultListChange="resultListChange"/>
</div>
<div>
<span :class="{'disable-character': !schedule.enable}"> {{$t('schedule.next_execution_time')}}{{this.recentList.length > 0 && schedule.enable ? this.recentList[0] : $t('schedule.not_set')}} </span>
<span>
{{$t('schedule.next_execution_time')}}
<span :class="{'disable-character': !schedule.enable}" v-if="!schedule.enable">{{$t('schedule.not_set')}}</span>
<crontab-result v-if="schedule.enable" :enable-simple-mode="true" :ex="schedule.value" ref="crontabResult"/>
</span>
</div>
</div>
</template>
@ -59,9 +63,6 @@
scheduleChange() {
this.$emit('scheduleChange');
},
resultListChange(resultList) {
this.recentList = resultList;
},
flashResultList() {
this.$refs.crontabResult.expressionChange();
}

View File

@ -1,5 +1,5 @@
<template>
<div>
<span>
<span v-if="enableSimpleMode">{{resultList && resultList.length > 0 ? resultList[0] : ''}}</span>
<div v-if="!enableSimpleMode" class="popup-result">
<p class="title">{{$t('schedule.cron.recent_run_time')}}</p>
@ -9,7 +9,7 @@
</template>
</ul>
</div>
</div>
</span>
</template>
<script>

View File

@ -14,7 +14,7 @@
methods: {
changeRoute() {
//
this.$router.push(this.index + '/all');
this.$router.replace({path: this.index, query: {type: 'all'}});
}
}
}

View File

@ -12,7 +12,7 @@
<template v-slot:title>{{$t('commons.project')}}</template>
<ms-recent-list :options="projectRecent"/>
<el-divider/>
<ms-show-all :index="'/performance/project'"/>
<ms-show-all :index="'/performance/project/all'"/>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/performance/project/create'" :title="$t('project.create')"/>
</el-submenu>
@ -21,7 +21,7 @@
<template v-slot:title>{{$t('commons.test')}}</template>
<ms-recent-list :options="testRecent"/>
<el-divider/>
<ms-show-all :index="'/performance/test'"/>
<ms-show-all :index="'/performance/test/all'"/>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/performance/test/create'" :title="$t('load_test.create')"/>
</el-submenu>
@ -30,7 +30,7 @@
<template v-slot:title>{{$t('commons.report')}}</template>
<ms-recent-list :options="reportRecent"/>
<el-divider/>
<ms-show-all :index="'/performance/report'"/>
<ms-show-all :index="'/performance/report/all'"/>
</el-submenu>
</el-menu>
</el-col>

View File

@ -14,7 +14,7 @@
<ms-test-heatmap :values="values"/>
</el-col>
<el-col :span="12">
<ms-api-test-schedule-list :group="'PERFORMANCE_TEST'"/>
<ms-schedule-list :group="'PERFORMANCE_TEST'"/>
</el-col>
</el-row>
</ms-main-container>
@ -28,12 +28,12 @@
import MsPerformanceTestRecentList from "./PerformanceTestRecentList"
import MsPerformanceReportRecentList from "./PerformanceReportRecentList"
import MsTestHeatmap from "../../common/components/MsTestHeatmap";
import MsApiTestScheduleList from "../../api/home/ApiTestScheduleList";
import MsScheduleList from "../../api/home/ScheduleList";
export default {
name: "PerformanceTestHome",
components: {
MsApiTestScheduleList,
MsScheduleList,
MsTestHeatmap,
MsMainContainer,
MsContainer,

View File

@ -13,7 +13,7 @@
<template v-slot:title>{{$t('commons.project')}}</template>
<ms-recent-list :options="projectRecent"/>
<el-divider/>
<ms-show-all :index="'/track/project'"/>
<ms-show-all :index="'/track/project/all'"/>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/track/project/create'" :title="$t('project.create')"/>
</el-submenu>
@ -22,7 +22,7 @@
<template v-slot:title>{{$t('test_track.case.test_case')}}</template>
<ms-recent-list :options="caseRecent"/>
<el-divider/>
<ms-show-all :index="'/track/case'"/>
<ms-show-all :index="'/track/case/all'"/>
<el-menu-item :index="testCaseEditPath" class="blank_item"></el-menu-item>
<el-menu-item :index="testCaseProjectPath" class="blank_item"></el-menu-item>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/track/case/create'" :title="$t('test_track.case.create_case')"/>
@ -32,7 +32,7 @@
<template v-slot:title>{{$t('test_track.plan.test_plan')}}</template>
<ms-recent-list :options="planRecent"/>
<el-divider/>
<ms-show-all :index="'/track/plan'"/>
<ms-show-all :index="'/track/plan/all'"/>
<el-menu-item :index="testPlanViewPath" class="blank_item"></el-menu-item>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/track/plan/create'" :title="$t('test_track.plan.create_plan')"/>
</el-submenu>

View File

@ -717,6 +717,7 @@ export default {
test_name: 'Test Name',
running_rule: 'Rule',
job_status: 'Status',
running_task: 'Running Task',
please_input_cron_expression: "Please Input Cron Expression",
generate_expression: "Generate Expression",
cron_expression_format_error: "Cron Expression Format Error",

View File

@ -716,6 +716,7 @@ export default {
test_name: '测试名称',
running_rule: '运行规则',
job_status: '任务状态',
running_task: '运行中的任务',
next_execution_time: "下次执行时间",
edit_timer_task: "编辑定时任务",
please_input_cron_expression: "请输入 Cron 表达式",

View File

@ -715,6 +715,7 @@ export default {
test_name: '測試名稱',
running_rule: '運行規則',
job_status: '任務狀態',
running_task: '運行中的任務',
please_input_cron_expression: "請輸入 Cron 表達式",
generate_expression: "生成表達式",
cron_expression_format_error: "Cron 表達式格式錯誤",