feat(测试计划): 测试计划不再强制关联用例时选择环境
--story=1012486 --user=宋天阳 【货车之家】接口场景包含跨项目步骤时取消跨项目环境必选&测试计划关联接口、UI测试时取消运行环境必选 https://www.tapd.cn/55049933/s/1401625
This commit is contained in:
parent
eed243d40c
commit
dd92feeba2
|
@ -287,8 +287,16 @@ public class ApiExecuteService {
|
||||||
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
|
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
|
||||||
example.createCriteria().andTestPlanIdEqualTo(request.getTestPlanId()).andApiCaseIdEqualTo(request.getCaseId());
|
example.createCriteria().andTestPlanIdEqualTo(request.getTestPlanId()).andApiCaseIdEqualTo(request.getCaseId());
|
||||||
List<TestPlanApiCase> list = testPlanApiCaseMapper.selectByExample(example);
|
List<TestPlanApiCase> list = testPlanApiCaseMapper.selectByExample(example);
|
||||||
|
if (CollectionUtils.isNotEmpty(list)) {
|
||||||
request.setEnvironmentId(list.get(0).getEnvironmentId());
|
request.setEnvironmentId(list.get(0).getEnvironmentId());
|
||||||
element.setName(list.get(0).getId());
|
element.setName(list.get(0).getId());
|
||||||
|
} else {
|
||||||
|
TestPlanApiCase apiCase = testPlanApiCaseMapper.selectByPrimaryKey(request.getCaseId());
|
||||||
|
if (apiCase != null) {
|
||||||
|
request.setEnvironmentId(apiCase.getEnvironmentId());
|
||||||
|
element.setName(request.getCaseId());
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
element.setName(request.getCaseId());
|
element.setName(request.getCaseId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,7 @@ import io.metersphere.base.mapper.ext.BaseApiExecutionQueueMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
|
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper;
|
import io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper;
|
||||||
import io.metersphere.base.mapper.plan.ext.ExtTestPlanApiCaseMapper;
|
import io.metersphere.base.mapper.plan.ext.ExtTestPlanApiCaseMapper;
|
||||||
import io.metersphere.commons.constants.ApiRunMode;
|
import io.metersphere.commons.constants.*;
|
||||||
import io.metersphere.commons.constants.CommonConstants;
|
|
||||||
import io.metersphere.commons.constants.KafkaTopicConstants;
|
|
||||||
import io.metersphere.commons.constants.TestPlanReportStatus;
|
|
||||||
import io.metersphere.commons.enums.ApiReportStatus;
|
import io.metersphere.commons.enums.ApiReportStatus;
|
||||||
import io.metersphere.commons.utils.BeanUtils;
|
import io.metersphere.commons.utils.BeanUtils;
|
||||||
import io.metersphere.commons.utils.JSON;
|
import io.metersphere.commons.utils.JSON;
|
||||||
|
@ -89,9 +86,11 @@ public class ApiExecutionQueueService {
|
||||||
Map<String, String> detailMap = new HashMap<>();
|
Map<String, String> detailMap = new HashMap<>();
|
||||||
List<ApiExecutionQueueDetail> queueDetails = new LinkedList<>();
|
List<ApiExecutionQueueDetail> queueDetails = new LinkedList<>();
|
||||||
// 初始化API/用例队列
|
// 初始化API/用例队列
|
||||||
|
String redisLockType = TestPlanExecuteCaseType.SCENARIO.name();
|
||||||
if (StringUtils.equalsAnyIgnoreCase(type, ApiRunMode.DEFINITION.name(), ApiRunMode.API_PLAN.name())) {
|
if (StringUtils.equalsAnyIgnoreCase(type, ApiRunMode.DEFINITION.name(), ApiRunMode.API_PLAN.name())) {
|
||||||
Map<String, ApiDefinitionExecResult> runMap = (Map<String, ApiDefinitionExecResult>) runObj;
|
Map<String, ApiDefinitionExecResult> runMap = (Map<String, ApiDefinitionExecResult>) runObj;
|
||||||
initApi(runMap, resQueue, config, detailMap, queueDetails);
|
initApi(runMap, resQueue, config, detailMap, queueDetails);
|
||||||
|
redisLockType = TestPlanExecuteCaseType.API_CASE.name();
|
||||||
}
|
}
|
||||||
// 初始化场景
|
// 初始化场景
|
||||||
else {
|
else {
|
||||||
|
@ -101,11 +100,16 @@ public class ApiExecutionQueueService {
|
||||||
if (CollectionUtils.isNotEmpty(queueDetails)) {
|
if (CollectionUtils.isNotEmpty(queueDetails)) {
|
||||||
extApiExecutionQueueMapper.sqlInsert(queueDetails);
|
extApiExecutionQueueMapper.sqlInsert(queueDetails);
|
||||||
}
|
}
|
||||||
|
//redis移除key (执行测试计划时会添加key)
|
||||||
|
redisTemplateService.unlock(reportId, redisLockType, reportId);
|
||||||
resQueue.setDetailMap(detailMap);
|
resQueue.setDetailMap(detailMap);
|
||||||
LoggerUtil.info("报告【" + type + "】生成执行链结束", reportId);
|
LoggerUtil.info("报告【" + type + "】生成执行链结束", reportId);
|
||||||
return resQueue;
|
return resQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplateService redisTemplateService;
|
||||||
|
|
||||||
private void initScenario(Map<String, RunModeDataDTO> runMap, DBTestQueue resQueue, RunModeConfigDTO config, Map<String, String> detailMap, List<ApiExecutionQueueDetail> queueDetails) {
|
private void initScenario(Map<String, RunModeDataDTO> runMap, DBTestQueue resQueue, RunModeConfigDTO config, Map<String, String> detailMap, List<ApiExecutionQueueDetail> queueDetails) {
|
||||||
final int[] sort = {0};
|
final int[] sort = {0};
|
||||||
runMap.forEach((k, v) -> {
|
runMap.forEach((k, v) -> {
|
||||||
|
|
|
@ -846,9 +846,8 @@ public class MockConfigService {
|
||||||
if (project != null) {
|
if (project != null) {
|
||||||
RequestMockParams requestMockParams = MockApiUtils.genRequestMockParamsFromHttpRequest(request, true);
|
RequestMockParams requestMockParams = MockApiUtils.genRequestMockParamsFromHttpRequest(request, true);
|
||||||
String urlSuffix = this.getUrlSuffix(project.getSystemId(), request);
|
String urlSuffix = this.getUrlSuffix(project.getSystemId(), request);
|
||||||
LogUtil.info("Mock urlSuffix:{}", urlSuffix);
|
LogUtil.info("Mock [" + url + "] Header:{}", requestHeaderMap);
|
||||||
LogUtil.info("Mock requestHeaderMap:{}", requestHeaderMap);
|
LogUtil.info("Mock [" + url + "] request:{}", JSON.toJSONString(requestMockParams));
|
||||||
LogUtil.info("Mock requestMockParams:{}", JSON.toJSONString(requestMockParams));
|
|
||||||
List<ApiDefinitionWithBLOBs> qualifiedApiList = apiDefinitionService.preparedUrl(project.getId(), method, urlSuffix, requestHeaderMap.get(MockApiHeaders.MOCK_API_RESOURCE_ID));
|
List<ApiDefinitionWithBLOBs> qualifiedApiList = apiDefinitionService.preparedUrl(project.getId(), method, urlSuffix, requestHeaderMap.get(MockApiHeaders.MOCK_API_RESOURCE_ID));
|
||||||
for (ApiDefinitionWithBLOBs api : qualifiedApiList) {
|
for (ApiDefinitionWithBLOBs api : qualifiedApiList) {
|
||||||
if (StringUtils.isEmpty(returnStr)) {
|
if (StringUtils.isEmpty(returnStr)) {
|
||||||
|
@ -872,6 +871,7 @@ public class MockConfigService {
|
||||||
response.setStatus(404);
|
response.setStatus(404);
|
||||||
returnStr = Translator.get("mock_warning");
|
returnStr = Translator.get("mock_warning");
|
||||||
}
|
}
|
||||||
|
LogUtil.info("Mock [" + url + "] response:{}", returnStr);
|
||||||
return returnStr;
|
return returnStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -883,9 +883,8 @@ public class MockConfigService {
|
||||||
RequestMockParams requestMockParams = MockApiUtils.genRequestMockParamsFromHttpRequest(request, false);
|
RequestMockParams requestMockParams = MockApiUtils.genRequestMockParamsFromHttpRequest(request, false);
|
||||||
|
|
||||||
String urlSuffix = this.getUrlSuffix(project.getSystemId(), request);
|
String urlSuffix = this.getUrlSuffix(project.getSystemId(), request);
|
||||||
LogUtil.info("Mock urlSuffix:{}", urlSuffix);
|
LogUtil.info("Mock [" + url + "] Header:{}", requestHeaderMap);
|
||||||
LogUtil.info("Mock requestHeaderMap:{}", requestHeaderMap);
|
LogUtil.info("Mock [" + url + "] request:{}", JSON.toJSONString(requestMockParams));
|
||||||
LogUtil.info("Mock requestMockParams:{}", JSON.toJSONString(requestMockParams));
|
|
||||||
List<ApiDefinitionWithBLOBs> qualifiedApiList = apiDefinitionService.preparedUrl(project.getId(), method, urlSuffix, requestHeaderMap.get(MockApiHeaders.MOCK_API_RESOURCE_ID));
|
List<ApiDefinitionWithBLOBs> qualifiedApiList = apiDefinitionService.preparedUrl(project.getId(), method, urlSuffix, requestHeaderMap.get(MockApiHeaders.MOCK_API_RESOURCE_ID));
|
||||||
/*
|
/*
|
||||||
GET/DELETE 这种通过url穿参数的接口,在接口路径相同的情况下可能会出现这样的情况:
|
GET/DELETE 这种通过url穿参数的接口,在接口路径相同的情况下可能会出现这样的情况:
|
||||||
|
@ -919,6 +918,7 @@ public class MockConfigService {
|
||||||
response.setStatus(404);
|
response.setStatus(404);
|
||||||
returnStr = Translator.get("mock_warning");
|
returnStr = Translator.get("mock_warning");
|
||||||
}
|
}
|
||||||
|
LogUtil.info("Mock [" + url + "] response:{}", returnStr);
|
||||||
return returnStr;
|
return returnStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,4 +99,10 @@ public class RedisTemplateService {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void unlock(String testPlanReportId, String key, String value) {
|
||||||
|
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||||
|
RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
|
||||||
|
this.redisTemplate.execute(redisScript, Collections.singletonList(StringUtils.join(testPlanReportId, key)), new Object[]{value});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
v-xpack
|
v-xpack
|
||||||
:project-id="projectId"
|
:project-id="projectId"
|
||||||
:default-version="currentVersion"
|
:default-version="currentVersion"
|
||||||
@changeVersion="currentVersionChange" />
|
@changeVersion="currentVersionChange"/>
|
||||||
</template>
|
</template>
|
||||||
</scenario-relevance-api-list>
|
</scenario-relevance-api-list>
|
||||||
|
|
||||||
|
@ -53,15 +53,15 @@
|
||||||
v-xpack
|
v-xpack
|
||||||
:project-id="projectId"
|
:project-id="projectId"
|
||||||
:default-version="currentVersion"
|
:default-version="currentVersion"
|
||||||
@changeVersion="currentVersionChange" />
|
@changeVersion="currentVersionChange"/>
|
||||||
</template>
|
</template>
|
||||||
</scenario-relevance-case-list>
|
</scenario-relevance-case-list>
|
||||||
|
|
||||||
<template v-slot:headerBtn>
|
<template v-slot:headerBtn>
|
||||||
<!-- 显示数量 -->
|
<!-- 显示数量 -->
|
||||||
<table-select-count-bar :count="selectCounts" style="float: left; margin: 5px" />
|
<table-select-count-bar :count="selectCounts" style="float: left; margin: 5px"/>
|
||||||
|
|
||||||
<el-button size="mini" icon="el-icon-refresh" @click="refreshData" />
|
<el-button size="mini" icon="el-icon-refresh" @click="refreshData"/>
|
||||||
<el-button type="primary" @click="copy" :loading="buttonIsWorking" @keydown.enter.native.prevent size="mini">
|
<el-button type="primary" @click="copy" :loading="buttonIsWorking" @keydown.enter.native.prevent size="mini">
|
||||||
{{ $t('commons.copy') }}
|
{{ $t('commons.copy') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
@ -79,9 +79,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getApiCaseWithBLOBs } from '@/api/api-test-case';
|
import {getApiCaseWithBLOBs} from '@/api/api-test-case';
|
||||||
import { apiListBatch } from '@/api/definition';
|
import {apiListBatch} from '@/api/definition';
|
||||||
import { getProjectVersions } from '@/api/xpack';
|
import {getProjectVersions} from '@/api/xpack';
|
||||||
import ScenarioRelevanceCaseList from './RelevanceCaseList';
|
import ScenarioRelevanceCaseList from './RelevanceCaseList';
|
||||||
import MsApiModule from '../../../definition/components/module/ApiModule';
|
import MsApiModule from '../../../definition/components/module/ApiModule';
|
||||||
import MsContainer from 'metersphere-frontend/src/components/MsContainer';
|
import MsContainer from 'metersphere-frontend/src/components/MsContainer';
|
||||||
|
@ -90,9 +90,9 @@ import MsMainContainer from 'metersphere-frontend/src/components/MsMainContainer
|
||||||
import ScenarioRelevanceApiList from './RelevanceApiList';
|
import ScenarioRelevanceApiList from './RelevanceApiList';
|
||||||
import RelevanceDialog from '@/business/commons/RelevanceDialog';
|
import RelevanceDialog from '@/business/commons/RelevanceDialog';
|
||||||
import TestCaseRelevanceBase from '@/business/commons/TestCaseRelevanceBase';
|
import TestCaseRelevanceBase from '@/business/commons/TestCaseRelevanceBase';
|
||||||
import { hasLicense } from 'metersphere-frontend/src/utils/permission';
|
import {hasLicense} from 'metersphere-frontend/src/utils/permission';
|
||||||
import TableSelectCountBar from '@/business/automation/scenario/api/TableSelectCountBar';
|
import TableSelectCountBar from '@/business/automation/scenario/api/TableSelectCountBar';
|
||||||
import { operationConfirm } from 'metersphere-frontend/src/utils';
|
import {operationConfirm} from 'metersphere-frontend/src/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ApiRelevance',
|
name: 'ApiRelevance',
|
||||||
|
@ -260,11 +260,11 @@ export default {
|
||||||
this.versionFilters = response.data
|
this.versionFilters = response.data
|
||||||
.filter((u) => u.id === currentVersion)
|
.filter((u) => u.id === currentVersion)
|
||||||
.map((u) => {
|
.map((u) => {
|
||||||
return { text: u.name, value: u.id };
|
return {text: u.name, value: u.id};
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.versionFilters = response.data.map((u) => {
|
this.versionFilters = response.data.map((u) => {
|
||||||
return { text: u.name, value: u.id };
|
return {text: u.name, value: u.id};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
@setModuleOptions="setModuleOptions"
|
@setModuleOptions="setModuleOptions"
|
||||||
:is-read-only="true"
|
:is-read-only="true"
|
||||||
:is-relevance="true"
|
:is-relevance="true"
|
||||||
ref="nodeTree" />
|
ref="nodeTree"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<relevance-api-list
|
<relevance-api-list
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
:is-script="isScript"
|
:is-script="isScript"
|
||||||
:plan-id="planId"
|
:plan-id="planId"
|
||||||
@isApiListEnableChange="isApiListEnableChange"
|
@isApiListEnableChange="isApiListEnableChange"
|
||||||
ref="apiList" />
|
ref="apiList"/>
|
||||||
|
|
||||||
<relevance-case-list
|
<relevance-case-list
|
||||||
v-if="!isApiListEnable"
|
v-if="!isApiListEnable"
|
||||||
|
@ -40,19 +40,19 @@
|
||||||
:is-script="isScript"
|
:is-script="isScript"
|
||||||
:plan-id="planId"
|
:plan-id="planId"
|
||||||
@isApiListEnableChange="isApiListEnableChange"
|
@isApiListEnableChange="isApiListEnableChange"
|
||||||
ref="apiCaseList" />
|
ref="apiCaseList"/>
|
||||||
</test-case-relevance-base>
|
</test-case-relevance-base>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getApiCaseWithBLOBs } from '@/api/api-test-case';
|
import {getApiCaseWithBLOBs} from '@/api/api-test-case';
|
||||||
import { apiListBatch } from '@/api/definition';
|
import {apiListBatch} from '@/api/definition';
|
||||||
import RelevanceCaseList from '@/business/automation/scenario/api/RelevanceCaseList';
|
import RelevanceCaseList from '@/business/automation/scenario/api/RelevanceCaseList';
|
||||||
import RelevanceApiList from '@/business/automation/scenario/api/RelevanceApiList';
|
import RelevanceApiList from '@/business/automation/scenario/api/RelevanceApiList';
|
||||||
import MsApiModule from '@/business/definition/components/module/ApiModule';
|
import MsApiModule from '@/business/definition/components/module/ApiModule';
|
||||||
import { getEnvironmentById } from 'metersphere-frontend/src/api/environment';
|
import {getEnvironmentById} from 'metersphere-frontend/src/api/environment';
|
||||||
import TestCaseRelevanceBase from '@/business/commons/TestCaseRelevanceBase';
|
import TestCaseRelevanceBase from '@/business/commons/TestCaseRelevanceBase';
|
||||||
import { parseEnvironment } from '@/business/environment/model/EnvironmentModel';
|
import {parseEnvironment} from '@/business/environment/model/EnvironmentModel';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ApiFuncRelevance',
|
name: 'ApiFuncRelevance',
|
||||||
|
@ -75,7 +75,7 @@ export default {
|
||||||
condition: {},
|
condition: {},
|
||||||
currentRow: {},
|
currentRow: {},
|
||||||
projectId: '',
|
projectId: '',
|
||||||
options: [{ value: 'HTTP', name: 'HTTP' }],
|
options: [{value: 'HTTP', name: 'HTTP'}],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|
|
@ -737,6 +737,7 @@ const message = {
|
||||||
batch_add_to_ws: "Add to environment group in bulk",
|
batch_add_to_ws: "Add to environment group in bulk",
|
||||||
choice_conflict: "one project chooses a corresponding environment!",
|
choice_conflict: "one project chooses a corresponding environment!",
|
||||||
env_list: "Environment List",
|
env_list: "Environment List",
|
||||||
|
case_env: "Case environment",
|
||||||
confirm: "Confirm",
|
confirm: "Confirm",
|
||||||
please_select_env_for_current_scenario:
|
please_select_env_for_current_scenario:
|
||||||
"please select env for current scenario",
|
"please select env for current scenario",
|
||||||
|
|
|
@ -725,6 +725,7 @@ const message = {
|
||||||
batch_add_to_ws: "批量添加到环境组",
|
batch_add_to_ws: "批量添加到环境组",
|
||||||
choice_conflict: "环境选择冲突,一个项目选择一个对应环境!",
|
choice_conflict: "环境选择冲突,一个项目选择一个对应环境!",
|
||||||
env_list: "环境列表",
|
env_list: "环境列表",
|
||||||
|
case_env: "用例环境",
|
||||||
confirm: "确 定",
|
confirm: "确 定",
|
||||||
please_select_env_for_current_scenario: "请为当前场景选择一个运行环境!",
|
please_select_env_for_current_scenario: "请为当前场景选择一个运行环境!",
|
||||||
please_select_env_for_current_plan: "请为当前测试计划选择一个运行环境!",
|
please_select_env_for_current_plan: "请为当前测试计划选择一个运行环境!",
|
||||||
|
|
|
@ -724,6 +724,7 @@ const message = {
|
||||||
batch_add_to_ws: "批量添加到環境組",
|
batch_add_to_ws: "批量添加到環境組",
|
||||||
choice_conflict: "環境選擇沖突,一個項目選擇一個對應環境!",
|
choice_conflict: "環境選擇沖突,一個項目選擇一個對應環境!",
|
||||||
env_list: "環境列表",
|
env_list: "環境列表",
|
||||||
|
case_env: "用例環境",
|
||||||
confirm: "確 定",
|
confirm: "確 定",
|
||||||
please_select_env_for_current_scenario: "請為當前場景選擇一個運行環境!",
|
please_select_env_for_current_scenario: "請為當前場景選擇一個運行環境!",
|
||||||
please_select_env_for_current_plan: "請為當前测试计划選擇一個運行環境!",
|
please_select_env_for_current_plan: "請為當前测试计划選擇一個運行環境!",
|
||||||
|
|
|
@ -155,7 +155,11 @@ export const JMETER_FUNC = [
|
||||||
{type: "Information", name: "${__machineIP}", description: "get the local machine IP address"},
|
{type: "Information", name: "${__machineIP}", description: "get the local machine IP address"},
|
||||||
{type: "Information", name: "${__machineName}", description: "get the local machine name"},
|
{type: "Information", name: "${__machineName}", description: "get the local machine name"},
|
||||||
{type: "Information", name: "${__time}", description: "return current time in various formats"},
|
{type: "Information", name: "${__time}", description: "return current time in various formats"},
|
||||||
{type: "Information", name: "${__timeShift}", description: "return a date in various formats with the specified amount of seconds/minutes/hours/days added"},
|
{
|
||||||
|
type: "Information",
|
||||||
|
name: "${__timeShift}",
|
||||||
|
description: "return a date in various formats with the specified amount of seconds/minutes/hours/days added"
|
||||||
|
},
|
||||||
{type: "Information", name: "${__log}", description: "log (or display) a message (and return the value)"},
|
{type: "Information", name: "${__log}", description: "log (or display) a message (and return the value)"},
|
||||||
{type: "Information", name: "${__logn}", description: "log (or display) a message (empty return value)"},
|
{type: "Information", name: "${__logn}", description: "log (or display) a message (empty return value)"},
|
||||||
{type: "Input", name: "${__StringFromFile}", description: "read a line from a file"},
|
{type: "Input", name: "${__StringFromFile}", description: "read a line from a file"},
|
||||||
|
@ -164,13 +168,21 @@ export const JMETER_FUNC = [
|
||||||
{type: "Input", name: "${__XPath}", description: "Use an XPath expression to read from a file"},
|
{type: "Input", name: "${__XPath}", description: "Use an XPath expression to read from a file"},
|
||||||
{type: "Input", name: "${__StringToFile}", description: "write a string to a file"},
|
{type: "Input", name: "${__StringToFile}", description: "write a string to a file"},
|
||||||
{type: "Calculation", name: "${__counter}", description: "generate an incrementing number"},
|
{type: "Calculation", name: "${__counter}", description: "generate an incrementing number"},
|
||||||
{type: "Formatting", name: "${__dateTimeConvert}", description: "Convert a date or time from source to target format"},
|
{
|
||||||
|
type: "Formatting",
|
||||||
|
name: "${__dateTimeConvert}",
|
||||||
|
description: "Convert a date or time from source to target format"
|
||||||
|
},
|
||||||
{type: "Calculation", name: "${__digest}", description: "Generate a digest (SHA-1, SHA-256, MD5...)"},
|
{type: "Calculation", name: "${__digest}", description: "Generate a digest (SHA-1, SHA-256, MD5...)"},
|
||||||
{type: "Calculation", name: "${__intSum}", description: "add int numbers"},
|
{type: "Calculation", name: "${__intSum}", description: "add int numbers"},
|
||||||
{type: "Calculation", name: "${__longSum}", description: "add long numbers"},
|
{type: "Calculation", name: "${__longSum}", description: "add long numbers"},
|
||||||
{type: "Calculation", name: "${__Random}", description: "generate a random number"},
|
{type: "Calculation", name: "${__Random}", description: "generate a random number"},
|
||||||
{type: "Calculation", name: "${__RandomDate}", description: "generate random date within a specific date range"},
|
{type: "Calculation", name: "${__RandomDate}", description: "generate random date within a specific date range"},
|
||||||
{type: "Calculation", name: "${__RandomFromMultipleVars}", description: "extracts an element from the values of a set of variables separated by |"},
|
{
|
||||||
|
type: "Calculation",
|
||||||
|
name: "${__RandomFromMultipleVars}",
|
||||||
|
description: "extracts an element from the values of a set of variables separated by |"
|
||||||
|
},
|
||||||
{type: "Calculation", name: "${__RandomString}", description: "generate a random string"},
|
{type: "Calculation", name: "${__RandomString}", description: "generate a random string"},
|
||||||
{type: "Calculation", name: "${__UUID}", description: "generate a random type 4 UUID"},
|
{type: "Calculation", name: "${__UUID}", description: "generate a random type 4 UUID"},
|
||||||
{type: "Scripting", name: "${__groovy}", description: "run an Apache Groovy script"},
|
{type: "Scripting", name: "${__groovy}", description: "run an Apache Groovy script"},
|
||||||
|
@ -196,7 +208,11 @@ export const JMETER_FUNC = [
|
||||||
{type: "String", name: "${__unescape}", description: "Process strings containing Java escapes (e.g. \n & \t)"},
|
{type: "String", name: "${__unescape}", description: "Process strings containing Java escapes (e.g. \n & \t)"},
|
||||||
{type: "String", name: "${__unescapeHtml}", description: "Decode HTML-encoded strings"},
|
{type: "String", name: "${__unescapeHtml}", description: "Decode HTML-encoded strings"},
|
||||||
{type: "String", name: "${__urldecode}", description: "Decode a application/x-www-form-urlencoded string"},
|
{type: "String", name: "${__urldecode}", description: "Decode a application/x-www-form-urlencoded string"},
|
||||||
{type: "String", name: "${__urlencode}", description: "Encode a string to a application/x-www-form-urlencoded string"},
|
{
|
||||||
|
type: "String",
|
||||||
|
name: "${__urlencode}",
|
||||||
|
description: "Encode a string to a application/x-www-form-urlencoded string"
|
||||||
|
},
|
||||||
{type: "String", name: "${__TestPlanName}", description: "Return name of current test plan"},
|
{type: "String", name: "${__TestPlanName}", description: "Return name of current test plan"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -212,13 +228,14 @@ export const CONFIG_TYPE = {
|
||||||
ABNORMAL: "ABNORMAL"
|
ABNORMAL: "ABNORMAL"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WORKSTATION={
|
export const WORKSTATION = {
|
||||||
UPCOMING:"upcoming",
|
UPCOMING: "upcoming",
|
||||||
FOCUS:"focus",
|
FOCUS: "focus",
|
||||||
NODE:"node"
|
NODE: "node"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ENV_TYPE = {
|
export const ENV_TYPE = {
|
||||||
|
DEFAULT: "DEFAULT",
|
||||||
JSON: "JSON",
|
JSON: "JSON",
|
||||||
GROUP: "GROUP"
|
GROUP: "GROUP"
|
||||||
}
|
}
|
||||||
|
@ -295,15 +312,71 @@ export const TASK_DATA = [
|
||||||
name: "track",
|
name: "track",
|
||||||
title: "side_task.test_tracking.title",
|
title: "side_task.test_tracking.title",
|
||||||
percentage: 14,
|
percentage: 14,
|
||||||
permission: ['PROJECT_MANAGER:READ', 'WORKSPACE_PROJECT_MANAGER:READ','PROJECT_TRACK_CASE:READ+CREATE','PROJECT_TRACK_REVIEW:READ+CREATE','PROJECT_TRACK_REVIEW:READ+COMMENT','PROJECT_TRACK_PLAN:READ+CREATE','PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL','PROJECT_TRACK_ISSUE:READ+CREATE','PROJECT_TRACK_CASE:READ+BATCH_ADD_PUBLIC'],
|
permission: ['PROJECT_MANAGER:READ', 'WORKSPACE_PROJECT_MANAGER:READ', 'PROJECT_TRACK_CASE:READ+CREATE', 'PROJECT_TRACK_REVIEW:READ+CREATE', 'PROJECT_TRACK_REVIEW:READ+COMMENT', 'PROJECT_TRACK_PLAN:READ+CREATE', 'PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL', 'PROJECT_TRACK_ISSUE:READ+CREATE', 'PROJECT_TRACK_CASE:READ+BATCH_ADD_PUBLIC'],
|
||||||
taskData: [
|
taskData: [
|
||||||
{ id: 1, name: "side_task.test_tracking.task_1", status: 1, permission: ['PROJECT_MANAGER:READ', 'WORKSPACE_PROJECT_MANAGER:READ'], api: [''], path: '/setting/project/:type', url: "" },
|
{
|
||||||
{ id: 2, name: "side_task.test_tracking.task_2", status: 0, permission: ['PROJECT_TRACK_CASE:READ+CREATE'], api: ["/test/case/add"], path: '/track/case/all', url: "/assets/guide/track/task-2.gif" },
|
id: 1,
|
||||||
{ id: 3, name: "side_task.test_tracking.task_3", status: 0, permission: ['PROJECT_TRACK_REVIEW:READ+CREATE'], api: ["/test/case/review/save"], path: '/track/review/all', url: "/assets/guide/track/task-3.gif" },
|
name: "side_task.test_tracking.task_1",
|
||||||
{ id: 4, name: "side_task.test_tracking.task_4", status: 0, permission: ['PROJECT_TRACK_REVIEW:READ+COMMENT'], api: ["/test/case/comment/save"], path: '/track/review/all', url: "/assets/guide/track/task-4.gif" },
|
status: 1,
|
||||||
{ id: 5, name: "side_task.test_tracking.task_5", status: 0, permission: ['PROJECT_TRACK_PLAN:READ+CREATE'], api: ["/test/plan/add"], path: '/track/plan/all', url: "/assets/guide/track/task-5.gif" },
|
permission: ['PROJECT_MANAGER:READ', 'WORKSPACE_PROJECT_MANAGER:READ'],
|
||||||
{ id: 6, name: "side_task.test_tracking.task_6", status: 0, permission: ['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL'], api: ["/test/plan/relevance"], path: '/track/plan/all', url: "/assets/guide/track/task-6.gif" },
|
api: [''],
|
||||||
{ id: 7, name: "side_task.test_tracking.task_7", status: 0, permission: ['PROJECT_TRACK_ISSUE:READ+CREATE','PROJECT_TRACK_CASE:READ+BATCH_ADD_PUBLIC'], api: ["issues/add","test/case/issues/relate"], path: '/track/issue', url: "/assets/guide/track/task-7.gif" },
|
path: '/setting/project/:type',
|
||||||
|
url: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "side_task.test_tracking.task_2",
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_TRACK_CASE:READ+CREATE'],
|
||||||
|
api: ["/test/case/add"],
|
||||||
|
path: '/track/case/all',
|
||||||
|
url: "/assets/guide/track/task-2.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "side_task.test_tracking.task_3",
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_TRACK_REVIEW:READ+CREATE'],
|
||||||
|
api: ["/test/case/review/save"],
|
||||||
|
path: '/track/review/all',
|
||||||
|
url: "/assets/guide/track/task-3.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: "side_task.test_tracking.task_4",
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_TRACK_REVIEW:READ+COMMENT'],
|
||||||
|
api: ["/test/case/comment/save"],
|
||||||
|
path: '/track/review/all',
|
||||||
|
url: "/assets/guide/track/task-4.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: "side_task.test_tracking.task_5",
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_TRACK_PLAN:READ+CREATE'],
|
||||||
|
api: ["/test/plan/add"],
|
||||||
|
path: '/track/plan/all',
|
||||||
|
url: "/assets/guide/track/task-5.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: "side_task.test_tracking.task_6",
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL'],
|
||||||
|
api: ["/test/plan/relevance"],
|
||||||
|
path: '/track/plan/all',
|
||||||
|
url: "/assets/guide/track/task-6.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: "side_task.test_tracking.task_7",
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_TRACK_ISSUE:READ+CREATE', 'PROJECT_TRACK_CASE:READ+BATCH_ADD_PUBLIC'],
|
||||||
|
api: ["issues/add", "test/case/issues/relate"],
|
||||||
|
path: '/track/issue',
|
||||||
|
url: "/assets/guide/track/task-7.gif"
|
||||||
|
},
|
||||||
],
|
],
|
||||||
rate: 1,
|
rate: 1,
|
||||||
status: 0
|
status: 0
|
||||||
|
@ -313,15 +386,71 @@ export const TASK_DATA = [
|
||||||
name: "api",
|
name: "api",
|
||||||
title: 'side_task.api_test.title',
|
title: 'side_task.api_test.title',
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
permission: ['PROJECT_API_DEFINITION:READ+CREATE_API','PROJECT_API_DEFINITION:READ+IMPORT_API','PROJECT_API_DEFINITION:READ+DEBUG','PROJECT_API_DEFINITION:READ+CREATE_CASE','PROJECT_API_DEFINITION:READ','PROJECT_API_SCENARIO:READ+CREATE','PROJECT_API_SCENARIO:READ+SCHEDULE'],
|
permission: ['PROJECT_API_DEFINITION:READ+CREATE_API', 'PROJECT_API_DEFINITION:READ+IMPORT_API', 'PROJECT_API_DEFINITION:READ+DEBUG', 'PROJECT_API_DEFINITION:READ+CREATE_CASE', 'PROJECT_API_DEFINITION:READ', 'PROJECT_API_SCENARIO:READ+CREATE', 'PROJECT_API_SCENARIO:READ+SCHEDULE'],
|
||||||
taskData: [
|
taskData: [
|
||||||
{id: 1, name: "side_task.api_test.task_1", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ+CREATE_API'], api: ["/api/definition/create"], url: "/assets/guide/api/task-1.gif" },
|
{
|
||||||
{id: 2, name: "side_task.api_test.task_2", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ+IMPORT_API'], api: ["/api/definition/import"], url: "/assets/guide/api/task-2.gif" },
|
id: 1,
|
||||||
{id: 3, name: "side_task.api_test.task_3", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ+DEBUG'], api: ["/api/definition/run/debug"], url: "/assets/guide/api/task-3.gif" },
|
name: "side_task.api_test.task_1",
|
||||||
{id: 4, name: "side_task.api_test.task_4", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ+CREATE_CASE'], api: ["/api/testcase/create"], url: "/assets/guide/api/task-4.gif" },
|
status: 0,
|
||||||
{id: 5, name: "side_task.api_test.task_5", status: 0, path: '/api/definition', permission: ['PROJECT_API_DEFINITION:READ'], api: ["/share/generate/api/document"], url: "/assets/guide/api/task-5.gif" },
|
path: '/api/definition',
|
||||||
{id: 6, name: "side_task.api_test.task_6", status: 0, path: '/api/automation', permission: ['PROJECT_API_SCENARIO:READ+CREATE'], api: ["/api/automation/create"], url: "/assets/guide/api/task-6.gif" },
|
permission: ['PROJECT_API_DEFINITION:READ+CREATE_API'],
|
||||||
{id: 7, name: "side_task.api_test.task_7", status: 0, path: '/api/automation', permission: ['PROJECT_API_SCENARIO:READ+SCHEDULE'], api: ["/api/automation/schedule/create"], url: "/assets/guide/api/task-7.gif" },
|
api: ["/api/definition/create"],
|
||||||
|
url: "/assets/guide/api/task-1.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "side_task.api_test.task_2",
|
||||||
|
status: 0,
|
||||||
|
path: '/api/definition',
|
||||||
|
permission: ['PROJECT_API_DEFINITION:READ+IMPORT_API'],
|
||||||
|
api: ["/api/definition/import"],
|
||||||
|
url: "/assets/guide/api/task-2.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "side_task.api_test.task_3",
|
||||||
|
status: 0,
|
||||||
|
path: '/api/definition',
|
||||||
|
permission: ['PROJECT_API_DEFINITION:READ+DEBUG'],
|
||||||
|
api: ["/api/definition/run/debug"],
|
||||||
|
url: "/assets/guide/api/task-3.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: "side_task.api_test.task_4",
|
||||||
|
status: 0,
|
||||||
|
path: '/api/definition',
|
||||||
|
permission: ['PROJECT_API_DEFINITION:READ+CREATE_CASE'],
|
||||||
|
api: ["/api/testcase/create"],
|
||||||
|
url: "/assets/guide/api/task-4.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: "side_task.api_test.task_5",
|
||||||
|
status: 0,
|
||||||
|
path: '/api/definition',
|
||||||
|
permission: ['PROJECT_API_DEFINITION:READ'],
|
||||||
|
api: ["/share/generate/api/document"],
|
||||||
|
url: "/assets/guide/api/task-5.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: "side_task.api_test.task_6",
|
||||||
|
status: 0,
|
||||||
|
path: '/api/automation',
|
||||||
|
permission: ['PROJECT_API_SCENARIO:READ+CREATE'],
|
||||||
|
api: ["/api/automation/create"],
|
||||||
|
url: "/assets/guide/api/task-6.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: "side_task.api_test.task_7",
|
||||||
|
status: 0,
|
||||||
|
path: '/api/automation',
|
||||||
|
permission: ['PROJECT_API_SCENARIO:READ+SCHEDULE'],
|
||||||
|
api: ["/api/automation/schedule/create"],
|
||||||
|
url: "/assets/guide/api/task-7.gif"
|
||||||
|
},
|
||||||
],
|
],
|
||||||
rate: 0,
|
rate: 0,
|
||||||
status: 0
|
status: 0
|
||||||
|
@ -331,10 +460,26 @@ export const TASK_DATA = [
|
||||||
name: "performance",
|
name: "performance",
|
||||||
title: 'side_task.performance_test.title',
|
title: 'side_task.performance_test.title',
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
permission: ['PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE',"PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH",'PROJECT_PERFORMANCE_REPORT:READ'],
|
permission: ['PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE', "PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH", 'PROJECT_PERFORMANCE_REPORT:READ'],
|
||||||
taskData: [
|
taskData: [
|
||||||
{id: 1, name: 'side_task.performance_test.task_1', status: 0, path: '/performance/test/all', permission: ['PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE',"PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH"], api: ["/performance/save"], url: "/assets/guide/performance/task-1.gif" },
|
{
|
||||||
{id: 2, name: 'side_task.performance_test.task_2', status: 0, path: '/performance/report/all', permission: ['PROJECT_PERFORMANCE_REPORT:READ'], api: ["/share/generate/expired"], url: "/assets/guide/performance/task-2.gif" },
|
id: 1,
|
||||||
|
name: 'side_task.performance_test.task_1',
|
||||||
|
status: 0,
|
||||||
|
path: '/performance/test/all',
|
||||||
|
permission: ['PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE', "PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH"],
|
||||||
|
api: ["/performance/save"],
|
||||||
|
url: "/assets/guide/performance/task-1.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'side_task.performance_test.task_2',
|
||||||
|
status: 0,
|
||||||
|
path: '/performance/report/all',
|
||||||
|
permission: ['PROJECT_PERFORMANCE_REPORT:READ'],
|
||||||
|
api: ["/share/generate/expired"],
|
||||||
|
url: "/assets/guide/performance/task-2.gif"
|
||||||
|
},
|
||||||
],
|
],
|
||||||
rate: 0,
|
rate: 0,
|
||||||
status: 0
|
status: 0
|
||||||
|
@ -344,11 +489,35 @@ export const TASK_DATA = [
|
||||||
name: "project",
|
name: "project",
|
||||||
title: 'side_task.project_setting.title',
|
title: 'side_task.project_setting.title',
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
permission: ['WORKSPACE_PROJECT_MANAGER:READ+CREATE','PROJECT_USER:READ+CREATE','PROJECT_ENVIRONMENT:READ+CREATE'],
|
permission: ['WORKSPACE_PROJECT_MANAGER:READ+CREATE', 'PROJECT_USER:READ+CREATE', 'PROJECT_ENVIRONMENT:READ+CREATE'],
|
||||||
taskData: [
|
taskData: [
|
||||||
{id: 1, name: 'side_task.project_setting.task_1', status: 0, permission: ['WORKSPACE_PROJECT_MANAGER:READ+CREATE'], api: ["/project/add"], path: '/setting/project/:type', url: "/assets/guide/project/task-1.gif" },
|
{
|
||||||
{id: 2, name: 'side_task.project_setting.task_2', status: 0, permission: ['PROJECT_USER:READ+CREATE'], api: ["/project/member/add","/setting/user/project/member/add"], path: '/project/member', url: "/assets/guide/project/task-2.gif" },
|
id: 1,
|
||||||
{id: 3, name: 'side_task.project_setting.task_3', status: 0, permission: ['PROJECT_ENVIRONMENT:READ+CREATE'], api: ["/environment/add"], path: '/project/env', url: "/assets/guide/project/task-3.gif" },
|
name: 'side_task.project_setting.task_1',
|
||||||
|
status: 0,
|
||||||
|
permission: ['WORKSPACE_PROJECT_MANAGER:READ+CREATE'],
|
||||||
|
api: ["/project/add"],
|
||||||
|
path: '/setting/project/:type',
|
||||||
|
url: "/assets/guide/project/task-1.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'side_task.project_setting.task_2',
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_USER:READ+CREATE'],
|
||||||
|
api: ["/project/member/add", "/setting/user/project/member/add"],
|
||||||
|
path: '/project/member',
|
||||||
|
url: "/assets/guide/project/task-2.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'side_task.project_setting.task_3',
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_ENVIRONMENT:READ+CREATE'],
|
||||||
|
api: ["/environment/add"],
|
||||||
|
path: '/project/env',
|
||||||
|
url: "/assets/guide/project/task-3.gif"
|
||||||
|
},
|
||||||
],
|
],
|
||||||
rate: 0,
|
rate: 0,
|
||||||
status: 0
|
status: 0
|
||||||
|
@ -358,11 +527,35 @@ export const TASK_DATA = [
|
||||||
name: "ui",
|
name: "ui",
|
||||||
title: 'side_task.ui_test.title',
|
title: 'side_task.ui_test.title',
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
permission: ['PROJECT_UI_ELEMENT:READ+CREATE','PROJECT_UI_SCENARIO:READ+CREATE','PROJECT_UI_SCENARIO:READ+RUN','PROJECT_UI_SCENARIO:READ+DEBUG'],
|
permission: ['PROJECT_UI_ELEMENT:READ+CREATE', 'PROJECT_UI_SCENARIO:READ+CREATE', 'PROJECT_UI_SCENARIO:READ+RUN', 'PROJECT_UI_SCENARIO:READ+DEBUG'],
|
||||||
taskData: [
|
taskData: [
|
||||||
{id: 1, name: 'side_task.ui_test.task_1', status: 0, permission: ['PROJECT_UI_ELEMENT:READ+CREATE'], api: ["/ui/element/add"], path: '/ui/element', url: "/assets/guide/ui/task-1.gif" },
|
{
|
||||||
{id: 2, name: 'side_task.ui_test.task_2', status: 0, permission: ['PROJECT_UI_SCENARIO:READ+CREATE'], api: ["/ui/automation/create"], path: '/ui/automation', url: "/assets/guide/ui/task-2.gif" },
|
id: 1,
|
||||||
{id: 2, name: 'side_task.ui_test.task_3', status: 0, permission: ['PROJECT_UI_SCENARIO:READ+RUN','PROJECT_UI_SCENARIO:READ+DEBUG'], api: ["/ui/automation/run/debug"], path: '/ui/automation', url: "/assets/guide/ui/task-3.gif" },
|
name: 'side_task.ui_test.task_1',
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_UI_ELEMENT:READ+CREATE'],
|
||||||
|
api: ["/ui/element/add"],
|
||||||
|
path: '/ui/element',
|
||||||
|
url: "/assets/guide/ui/task-1.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'side_task.ui_test.task_2',
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_UI_SCENARIO:READ+CREATE'],
|
||||||
|
api: ["/ui/automation/create"],
|
||||||
|
path: '/ui/automation',
|
||||||
|
url: "/assets/guide/ui/task-2.gif"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'side_task.ui_test.task_3',
|
||||||
|
status: 0,
|
||||||
|
permission: ['PROJECT_UI_SCENARIO:READ+RUN', 'PROJECT_UI_SCENARIO:READ+DEBUG'],
|
||||||
|
api: ["/ui/automation/run/debug"],
|
||||||
|
path: '/ui/automation',
|
||||||
|
url: "/assets/guide/ui/task-3.gif"
|
||||||
|
},
|
||||||
],
|
],
|
||||||
rate: 0,
|
rate: 0,
|
||||||
status: 0
|
status: 0
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package io.metersphere.commons.constants;
|
||||||
|
|
||||||
|
public enum TestPlanExecuteCaseType {
|
||||||
|
API_CASE, SCENARIO, UI_SCENARIO, LOAD_CASE
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
package io.metersphere.service;
|
||||||
|
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.utils.LoggerUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||||
|
import org.springframework.data.redis.core.script.RedisScript;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class RedisTemplateService {
|
||||||
|
public static final long TIME_OUT = 480;
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
public boolean setIfAbsent(String key, String value) {
|
||||||
|
try {
|
||||||
|
return redisTemplate.opsForValue().setIfAbsent(key, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LoggerUtil.error(key, e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(String key) {
|
||||||
|
try {
|
||||||
|
return redisTemplate.opsForValue().get(key);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LoggerUtil.error(key, e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete(String key) {
|
||||||
|
try {
|
||||||
|
return redisTemplate.delete(key);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LoggerUtil.error(key, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加锁
|
||||||
|
*/
|
||||||
|
public boolean lock(String testPlanReportId, String key, String value) {
|
||||||
|
Boolean hasReport = redisTemplate.opsForValue().setIfAbsent(
|
||||||
|
StringUtils.join(testPlanReportId, key),
|
||||||
|
value,
|
||||||
|
TIME_OUT,
|
||||||
|
TimeUnit.MINUTES);
|
||||||
|
if (Boolean.FALSE.equals(hasReport)) {
|
||||||
|
redisTemplate.opsForValue().setIfPresent(
|
||||||
|
StringUtils.join(testPlanReportId, key),
|
||||||
|
value,
|
||||||
|
TIME_OUT,
|
||||||
|
TimeUnit.MINUTES);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(String testPlanReportId, String key, String reportId) {
|
||||||
|
try {
|
||||||
|
Object value = redisTemplate.opsForValue().get(StringUtils.join(testPlanReportId, key));
|
||||||
|
return ObjectUtils.isNotEmpty(value) && StringUtils.equals(reportId, String.valueOf(value));
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解锁
|
||||||
|
*/
|
||||||
|
public boolean unlock(String testPlanReportId, String key, String value) {
|
||||||
|
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||||
|
RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
|
||||||
|
Long result = redisTemplate.execute(redisScript, Collections.singletonList(StringUtils.join(testPlanReportId, key)), value);
|
||||||
|
if (Objects.equals(1L, result)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import io.metersphere.base.mapper.ApiExecutionQueueMapper;
|
||||||
import io.metersphere.base.mapper.TestPlanLoadCaseMapper;
|
import io.metersphere.base.mapper.TestPlanLoadCaseMapper;
|
||||||
import io.metersphere.base.mapper.ext.BaseApiExecutionQueueMapper;
|
import io.metersphere.base.mapper.ext.BaseApiExecutionQueueMapper;
|
||||||
import io.metersphere.commons.constants.KafkaTopicConstants;
|
import io.metersphere.commons.constants.KafkaTopicConstants;
|
||||||
|
import io.metersphere.commons.constants.TestPlanExecuteCaseType;
|
||||||
import io.metersphere.commons.constants.TestPlanLoadCaseStatus;
|
import io.metersphere.commons.constants.TestPlanLoadCaseStatus;
|
||||||
import io.metersphere.commons.constants.TriggerMode;
|
import io.metersphere.commons.constants.TriggerMode;
|
||||||
import io.metersphere.commons.utils.BeanUtils;
|
import io.metersphere.commons.utils.BeanUtils;
|
||||||
|
@ -14,6 +15,7 @@ import io.metersphere.constants.RunModeConstants;
|
||||||
import io.metersphere.dto.RunModeConfigDTO;
|
import io.metersphere.dto.RunModeConfigDTO;
|
||||||
import io.metersphere.plan.exec.queue.DBTestQueue;
|
import io.metersphere.plan.exec.queue.DBTestQueue;
|
||||||
import io.metersphere.request.RunTestPlanRequest;
|
import io.metersphere.request.RunTestPlanRequest;
|
||||||
|
import io.metersphere.service.RedisTemplateService;
|
||||||
import io.metersphere.utils.LoggerUtil;
|
import io.metersphere.utils.LoggerUtil;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -175,13 +177,16 @@ public class PerfQueueService {
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplateService redisTemplateService;
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
public DBTestQueue add(Object runObj, String poolId, String reportId, String reportType, String runMode, RunModeConfigDTO config) {
|
public DBTestQueue add(Object runObj, String poolId, String testPlanReportId, String reportType, String runMode, RunModeConfigDTO config) {
|
||||||
LoggerUtil.info("报告【" + reportId + "】开始生成执行链");
|
LoggerUtil.info("报告【" + testPlanReportId + "】开始生成执行链");
|
||||||
if (config.getEnvMap() == null) {
|
if (config.getEnvMap() == null) {
|
||||||
config.setEnvMap(new LinkedHashMap<>());
|
config.setEnvMap(new LinkedHashMap<>());
|
||||||
}
|
}
|
||||||
ApiExecutionQueue executionQueue = getApiExecutionQueue(poolId, reportId, reportType, runMode, config);
|
ApiExecutionQueue executionQueue = getApiExecutionQueue(poolId, testPlanReportId, reportType, runMode, config);
|
||||||
queueMapper.insert(executionQueue);
|
queueMapper.insert(executionQueue);
|
||||||
DBTestQueue resQueue = new DBTestQueue();
|
DBTestQueue resQueue = new DBTestQueue();
|
||||||
BeanUtils.copyBean(resQueue, executionQueue);
|
BeanUtils.copyBean(resQueue, executionQueue);
|
||||||
|
@ -196,7 +201,9 @@ public class PerfQueueService {
|
||||||
extApiExecutionQueueMapper.sqlInsert(queueDetails);
|
extApiExecutionQueueMapper.sqlInsert(queueDetails);
|
||||||
}
|
}
|
||||||
resQueue.setDetailMap(detailMap);
|
resQueue.setDetailMap(detailMap);
|
||||||
LoggerUtil.info("报告【" + reportId + "】生成执行链结束");
|
LoggerUtil.info("报告【" + testPlanReportId + "】生成执行链结束");
|
||||||
|
//移除Redis中的标志
|
||||||
|
redisTemplateService.unlock(testPlanReportId, TestPlanExecuteCaseType.LOAD_CASE.name(), testPlanReportId);
|
||||||
return resQueue;
|
return resQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +214,7 @@ public class PerfQueueService {
|
||||||
executionQueue.setPoolId(poolId);
|
executionQueue.setPoolId(poolId);
|
||||||
executionQueue.setFailure(config.isOnSampleError());
|
executionQueue.setFailure(config.isOnSampleError());
|
||||||
executionQueue.setReportId(reportId);
|
executionQueue.setReportId(reportId);
|
||||||
executionQueue.setReportType(StringUtils.isNotEmpty(reportType) ? reportType : RunModeConstants.INDEPENDENCE.toString());
|
executionQueue.setReportType(TestPlanExecuteCaseType.LOAD_CASE.name());
|
||||||
executionQueue.setRunMode(runMode);
|
executionQueue.setRunMode(runMode);
|
||||||
return executionQueue;
|
return executionQueue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import io.metersphere.base.mapper.ApiExecutionQueueMapper;
|
||||||
import io.metersphere.commons.constants.KafkaTopicConstants;
|
import io.metersphere.commons.constants.KafkaTopicConstants;
|
||||||
import io.metersphere.plan.service.AutomationCaseExecOverService;
|
import io.metersphere.plan.service.AutomationCaseExecOverService;
|
||||||
import io.metersphere.plan.service.TestPlanReportService;
|
import io.metersphere.plan.service.TestPlanReportService;
|
||||||
|
import io.metersphere.service.RedisTemplateService;
|
||||||
import io.metersphere.utils.LoggerUtil;
|
import io.metersphere.utils.LoggerUtil;
|
||||||
import io.metersphere.utils.NamedThreadFactory;
|
import io.metersphere.utils.NamedThreadFactory;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -28,6 +29,8 @@ public class ExecReportListener {
|
||||||
@Resource
|
@Resource
|
||||||
private TestPlanReportService testPlanReportService;
|
private TestPlanReportService testPlanReportService;
|
||||||
@Resource
|
@Resource
|
||||||
|
private RedisTemplateService redisTemplateService;
|
||||||
|
@Resource
|
||||||
private AutomationCaseExecOverService automationCaseExecOverService;
|
private AutomationCaseExecOverService automationCaseExecOverService;
|
||||||
|
|
||||||
// 线程池维护线程的最少数量
|
// 线程池维护线程的最少数量
|
||||||
|
@ -57,6 +60,7 @@ public class ExecReportListener {
|
||||||
task.setApiExecutionQueueDetailMapper(executionQueueDetailMapper);
|
task.setApiExecutionQueueDetailMapper(executionQueueDetailMapper);
|
||||||
task.setAutomationCaseExecOverService(automationCaseExecOverService);
|
task.setAutomationCaseExecOverService(automationCaseExecOverService);
|
||||||
task.setTestPlanReportService(testPlanReportService);
|
task.setTestPlanReportService(testPlanReportService);
|
||||||
|
task.setRedisTemplateService(redisTemplateService);
|
||||||
task.setRecord(item);
|
task.setRecord(item);
|
||||||
threadPool.execute(task);
|
threadPool.execute(task);
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,14 +5,16 @@ import io.metersphere.base.domain.ApiExecutionQueueDetailExample;
|
||||||
import io.metersphere.base.domain.ApiExecutionQueueExample;
|
import io.metersphere.base.domain.ApiExecutionQueueExample;
|
||||||
import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper;
|
import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper;
|
||||||
import io.metersphere.base.mapper.ApiExecutionQueueMapper;
|
import io.metersphere.base.mapper.ApiExecutionQueueMapper;
|
||||||
|
import io.metersphere.commons.constants.TestPlanExecuteCaseType;
|
||||||
import io.metersphere.commons.constants.TestPlanReportStatus;
|
import io.metersphere.commons.constants.TestPlanReportStatus;
|
||||||
import io.metersphere.plan.service.AutomationCaseExecOverService;
|
import io.metersphere.plan.service.AutomationCaseExecOverService;
|
||||||
import io.metersphere.plan.service.TestPlanReportService;
|
import io.metersphere.plan.service.TestPlanReportService;
|
||||||
|
import io.metersphere.service.RedisTemplateService;
|
||||||
import io.metersphere.utils.LoggerUtil;
|
import io.metersphere.utils.LoggerUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -25,7 +27,7 @@ public class ExecReportListenerTask implements Runnable {
|
||||||
private ApiExecutionQueueDetailMapper apiExecutionQueueDetailMapper;
|
private ApiExecutionQueueDetailMapper apiExecutionQueueDetailMapper;
|
||||||
private TestPlanReportService testPlanReportService;
|
private TestPlanReportService testPlanReportService;
|
||||||
private AutomationCaseExecOverService automationCaseExecOverService;
|
private AutomationCaseExecOverService automationCaseExecOverService;
|
||||||
|
private RedisTemplateService redisTemplateService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -50,15 +52,15 @@ public class ExecReportListenerTask implements Runnable {
|
||||||
ApiExecutionQueueExample executionQueueExample = new ApiExecutionQueueExample();
|
ApiExecutionQueueExample executionQueueExample = new ApiExecutionQueueExample();
|
||||||
executionQueueExample.createCriteria().andReportIdEqualTo(testPlanReportId);
|
executionQueueExample.createCriteria().andReportIdEqualTo(testPlanReportId);
|
||||||
List<ApiExecutionQueue> queues = apiExecutionQueueMapper.selectByExample(executionQueueExample);
|
List<ApiExecutionQueue> queues = apiExecutionQueueMapper.selectByExample(executionQueueExample);
|
||||||
if (CollectionUtils.isEmpty(queues)) {
|
if (CollectionUtils.isEmpty(queues) && this.isTestPlanIsEmptyInRedis(testPlanReportId)) {
|
||||||
LoggerUtil.info("Normal execution completes, update test plan report status:" + testPlanReportId);
|
LoggerUtil.info("Normal execution completes, update test plan report status:" + testPlanReportId);
|
||||||
testPlanReportService.testPlanExecuteOver(testPlanReportId, TestPlanReportStatus.COMPLETED.name());
|
testPlanReportService.testPlanExecuteOver(testPlanReportId, TestPlanReportStatus.COMPLETED.name());
|
||||||
} else {
|
} else if (CollectionUtils.isNotEmpty(queues)) {
|
||||||
List<String> ids = queues.stream().map(ApiExecutionQueue::getId).collect(Collectors.toList());
|
List<String> ids = queues.stream().map(ApiExecutionQueue::getId).collect(Collectors.toList());
|
||||||
ApiExecutionQueueDetailExample detailExample = new ApiExecutionQueueDetailExample();
|
ApiExecutionQueueDetailExample detailExample = new ApiExecutionQueueDetailExample();
|
||||||
detailExample.createCriteria().andQueueIdIn(ids);
|
detailExample.createCriteria().andQueueIdIn(ids);
|
||||||
long count = apiExecutionQueueDetailMapper.countByExample(detailExample);
|
long count = apiExecutionQueueDetailMapper.countByExample(detailExample);
|
||||||
if (count == 0) {
|
if (count == 0 && this.isTestPlanIsEmptyInRedis(testPlanReportId)) {
|
||||||
LoggerUtil.info("Normal execution completes, update test plan report status:" + testPlanReportId);
|
LoggerUtil.info("Normal execution completes, update test plan report status:" + testPlanReportId);
|
||||||
testPlanReportService.testPlanExecuteOver(testPlanReportId, TestPlanReportStatus.COMPLETED.name());
|
testPlanReportService.testPlanExecuteOver(testPlanReportId, TestPlanReportStatus.COMPLETED.name());
|
||||||
LoggerUtil.info("Clear Queue:" + ids);
|
LoggerUtil.info("Clear Queue:" + ids);
|
||||||
|
@ -68,4 +70,15 @@ public class ExecReportListenerTask implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试计划执行时会将运行标志放入redis中。当测试计划执行队列入库后,会将redis中的标志清除。
|
||||||
|
*/
|
||||||
|
private boolean isTestPlanIsEmptyInRedis(String testPlanReportId) {
|
||||||
|
Object scenarioObj = redisTemplateService.get(testPlanReportId + TestPlanExecuteCaseType.SCENARIO);
|
||||||
|
Object apiCaseObj = redisTemplateService.get(testPlanReportId + TestPlanExecuteCaseType.API_CASE);
|
||||||
|
Object uiObj = redisTemplateService.get(testPlanReportId + TestPlanExecuteCaseType.UI_SCENARIO);
|
||||||
|
Object loadObj = redisTemplateService.get(testPlanReportId + TestPlanExecuteCaseType.LOAD_CASE);
|
||||||
|
return ObjectUtils.isEmpty(scenarioObj) && ObjectUtils.isEmpty(apiCaseObj) && ObjectUtils.isEmpty(uiObj) && ObjectUtils.isEmpty(loadObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,221 +0,0 @@
|
||||||
package io.metersphere.plan.service;
|
|
||||||
|
|
||||||
import io.metersphere.base.domain.TestPlanWithBLOBs;
|
|
||||||
import io.metersphere.base.mapper.TestPlanMapper;
|
|
||||||
import io.metersphere.commons.exception.MSException;
|
|
||||||
import io.metersphere.commons.utils.JSON;
|
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
|
||||||
import io.metersphere.constants.RunModeConstants;
|
|
||||||
import io.metersphere.dto.*;
|
|
||||||
import io.metersphere.i18n.Translator;
|
|
||||||
import io.metersphere.plan.dto.ExecutionWay;
|
|
||||||
import io.metersphere.plan.request.api.TestPlanRunRequest;
|
|
||||||
import io.metersphere.plan.service.remote.api.PlanTestPlanApiCaseService;
|
|
||||||
import io.metersphere.plan.service.remote.api.PlanTestPlanScenarioCaseService;
|
|
||||||
import io.metersphere.plan.service.remote.performance.PerfExecService;
|
|
||||||
import io.metersphere.plan.service.remote.ui.PlanTestPlanUiScenarioCaseService;
|
|
||||||
import io.metersphere.plan.utils.TestPlanRequestUtil;
|
|
||||||
import io.metersphere.utils.LoggerUtil;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.apache.commons.collections.MapUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Transactional
|
|
||||||
public class TestPlanExecuteService {
|
|
||||||
@Resource
|
|
||||||
@Lazy
|
|
||||||
private TestPlanService testPlanService;
|
|
||||||
@Resource
|
|
||||||
private TestPlanReportService testPlanReportService;
|
|
||||||
@Resource
|
|
||||||
private PlanTestPlanApiCaseService planTestPlanApiCaseService;
|
|
||||||
@Resource
|
|
||||||
private PlanTestPlanScenarioCaseService planTestPlanScenarioCaseService;
|
|
||||||
@Resource
|
|
||||||
private PerfExecService perfExecService;
|
|
||||||
@Resource
|
|
||||||
private PlanTestPlanUiScenarioCaseService planTestPlanUiScenarioCaseService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private TestPlanMapper testPlanMapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行测试计划流程是会调用其它服务的执行方法,并通过kafka传递信息给test-track服务来判断测试计划是否执行结束
|
|
||||||
* 执行方法采用单独的事务控制,执行完了就提交,让测试报告以及包括执行内容的数据及时入库
|
|
||||||
*/
|
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
|
||||||
public String runTestPlan(String testPlanId, String projectId, String userId, String triggerMode, String planReportId, String executionWay, String apiRunConfig) {
|
|
||||||
// 校验测试计划是否在执行中
|
|
||||||
if (testPlanService.checkTestPlanIsRunning(testPlanId)) {
|
|
||||||
LogUtil.info("当前测试计划正在执行中,请稍后再试", testPlanId);
|
|
||||||
MSException.throwException(Translator.get("test_plan_run_message"));
|
|
||||||
}
|
|
||||||
RunModeConfigDTO runModeConfig = null;
|
|
||||||
try {
|
|
||||||
runModeConfig = JSON.parseObject(apiRunConfig, RunModeConfigDTO.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e);
|
|
||||||
}
|
|
||||||
if (runModeConfig == null) {
|
|
||||||
runModeConfig = this.buildRunModeConfigDTO();
|
|
||||||
}
|
|
||||||
|
|
||||||
//环境参数为空时,依据测试计划保存的环境执行
|
|
||||||
if (((StringUtils.equals("GROUP", runModeConfig.getEnvironmentType()) && StringUtils.isBlank(runModeConfig.getEnvironmentGroupId()))
|
|
||||||
|| (!StringUtils.equals("GROUP", runModeConfig.getEnvironmentType()) && MapUtils.isEmpty(runModeConfig.getEnvMap()) && MapUtils.isEmpty(runModeConfig.getTestPlanDefaultEnvMap())))
|
|
||||||
&& !StringUtils.equals(executionWay, ExecutionWay.RUN.name())) {
|
|
||||||
TestPlanWithBLOBs testPlanWithBLOBs = testPlanMapper.selectByPrimaryKey(testPlanId);
|
|
||||||
if (StringUtils.isNotEmpty(testPlanWithBLOBs.getRunModeConfig())) {
|
|
||||||
try {
|
|
||||||
Map json = JSON.parseMap(testPlanWithBLOBs.getRunModeConfig());
|
|
||||||
TestPlanRequestUtil.changeStringToBoolean(json);
|
|
||||||
TestPlanRunRequest testPlanRunRequest = JSON.parseObject(JSON.toJSONString(json), TestPlanRunRequest.class);
|
|
||||||
if (testPlanRunRequest != null) {
|
|
||||||
String envType = testPlanRunRequest.getEnvironmentType();
|
|
||||||
Map<String, String> envMap = testPlanRunRequest.getEnvMap();
|
|
||||||
String environmentGroupId = testPlanRunRequest.getEnvironmentGroupId();
|
|
||||||
runModeConfig = testPlanService.getRunModeConfigDTO(testPlanRunRequest, envType, envMap, environmentGroupId, testPlanId);
|
|
||||||
runModeConfig.setTestPlanDefaultEnvMap(testPlanRunRequest.getTestPlanDefaultEnvMap());
|
|
||||||
if (!testPlanRunRequest.isRunWithinResourcePool()) {
|
|
||||||
runModeConfig.setResourcePoolId(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error("获取测试计划保存的环境信息出错!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (planReportId == null) {
|
|
||||||
planReportId = UUID.randomUUID().toString();
|
|
||||||
}
|
|
||||||
if (testPlanService.haveExecCase(testPlanId, true)) {
|
|
||||||
testPlanService.verifyPool(projectId, runModeConfig);
|
|
||||||
}
|
|
||||||
//创建测试报告,然后返回的ID重新赋值为resourceID,作为后续的参数
|
|
||||||
TestPlanScheduleReportInfoDTO reportInfoDTO = testPlanService.genTestPlanReport(planReportId, testPlanId, userId, triggerMode, runModeConfig);
|
|
||||||
|
|
||||||
LoggerUtil.info("预生成测试计划报告【" + reportInfoDTO.getTestPlanReport() != null ? reportInfoDTO.getTestPlanReport().getName() : StringUtils.EMPTY + "】计划报告ID[" + planReportId + "]");
|
|
||||||
|
|
||||||
List<TestPlanApiDTO> apiTestCases = null;
|
|
||||||
List<TestPlanScenarioDTO> scenarioCases = null;
|
|
||||||
List<TestPlanUiScenarioDTO> uiScenarios = null;
|
|
||||||
Map<String, String> loadCaseReportMap = null;
|
|
||||||
if (MapUtils.isNotEmpty(reportInfoDTO.getApiTestCaseDataMap())) {
|
|
||||||
try {
|
|
||||||
apiTestCases = planTestPlanApiCaseService.getFailureListByIds(reportInfoDTO.getApiTestCaseDataMap().keySet());
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error("测试计划执行查询接口用例失败!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (MapUtils.isNotEmpty(reportInfoDTO.getPlanScenarioIdMap())) {
|
|
||||||
try {
|
|
||||||
scenarioCases = planTestPlanScenarioCaseService.getFailureListByIds(reportInfoDTO.getPlanScenarioIdMap().keySet());
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error("测试计划执行查询场景用例失败!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (MapUtils.isNotEmpty(reportInfoDTO.getUiScenarioIdMap())) {
|
|
||||||
try {
|
|
||||||
uiScenarios = planTestPlanUiScenarioCaseService.getFailureListByIds(reportInfoDTO.getUiScenarioIdMap().keySet());
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error("测试计划执行查询UI用例失败!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boolean haveApiCaseExec = false, haveScenarioCaseExec = false, haveLoadCaseExec = false, haveUICaseExec = false;
|
|
||||||
if (CollectionUtils.isNotEmpty(apiTestCases)) {
|
|
||||||
//执行接口案例任务
|
|
||||||
LoggerUtil.info("开始执行测试计划接口用例 " + planReportId);
|
|
||||||
try {
|
|
||||||
Map<String, String> apiCaseReportMap = testPlanService.executeApiTestCase(triggerMode, planReportId, userId, testPlanId, runModeConfig);
|
|
||||||
if (MapUtils.isNotEmpty(apiCaseReportMap)) {
|
|
||||||
haveApiCaseExec = true;
|
|
||||||
for (TestPlanApiDTO dto : apiTestCases) {
|
|
||||||
dto.setReportId(apiCaseReportMap.get(dto.getId()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
apiTestCases = null;
|
|
||||||
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划接口用例失败! ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isNotEmpty(scenarioCases)) {
|
|
||||||
//执行场景执行任务
|
|
||||||
LoggerUtil.info("开始执行测试计划场景用例 " + planReportId);
|
|
||||||
try {
|
|
||||||
Map<String, String> scenarioReportMap = testPlanService.executeScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getPlanScenarioIdMap());
|
|
||||||
if (MapUtils.isNotEmpty(scenarioReportMap)) {
|
|
||||||
haveScenarioCaseExec = true;
|
|
||||||
List<TestPlanScenarioDTO> removeDTO = new ArrayList<>();
|
|
||||||
for (TestPlanScenarioDTO dto : scenarioCases) {
|
|
||||||
if (scenarioReportMap.containsKey(dto.getId())) {
|
|
||||||
dto.setReportId(scenarioReportMap.get(dto.getId()));
|
|
||||||
} else {
|
|
||||||
removeDTO.add(dto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isNotEmpty(removeDTO)) {
|
|
||||||
scenarioCases.removeAll(removeDTO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
scenarioCases = null;
|
|
||||||
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划场景用例失败! ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MapUtils.isNotEmpty(reportInfoDTO.getPerformanceIdMap())) {
|
|
||||||
//执行性能测试任务
|
|
||||||
LoggerUtil.info("开始执行测试计划性能用例 " + planReportId);
|
|
||||||
try {
|
|
||||||
loadCaseReportMap = perfExecService.executeLoadCase(planReportId, runModeConfig, testPlanService.transformationPerfTriggerMode(triggerMode), reportInfoDTO.getPerformanceIdMap());
|
|
||||||
if (MapUtils.isNotEmpty(loadCaseReportMap)) {
|
|
||||||
haveLoadCaseExec = true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划性能用例失败! ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(uiScenarios)) {
|
|
||||||
//执行UI场景执行任务
|
|
||||||
LoggerUtil.info("开始执行测试计划 UI 场景用例 " + planReportId);
|
|
||||||
try {
|
|
||||||
Map<String, String> uiScenarioReportMap = testPlanService.executeUiScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getUiScenarioIdMap());
|
|
||||||
if (MapUtils.isNotEmpty(uiScenarioReportMap)) {
|
|
||||||
haveUICaseExec = true;
|
|
||||||
for (TestPlanUiScenarioDTO dto : uiScenarios) {
|
|
||||||
dto.setReportId(uiScenarioReportMap.get(dto.getId()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
uiScenarios = null;
|
|
||||||
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划 UI 用例失败! ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LoggerUtil.info("开始生成测试计划报告内容 " + planReportId);
|
|
||||||
testPlanReportService.createTestPlanReportContentReportIds(planReportId, apiTestCases, scenarioCases, uiScenarios, loadCaseReportMap);
|
|
||||||
if (!haveApiCaseExec && !haveScenarioCaseExec && !haveLoadCaseExec && !haveUICaseExec) {
|
|
||||||
//如果没有执行的自动化用例,调用结束测试计划的方法。 因为方法中包含着测试计划执行队列的处理逻辑。
|
|
||||||
testPlanReportService.testPlanUnExecute(reportInfoDTO.getTestPlanReport());
|
|
||||||
}
|
|
||||||
return planReportId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RunModeConfigDTO buildRunModeConfigDTO() {
|
|
||||||
RunModeConfigDTO runModeConfig = new RunModeConfigDTO();
|
|
||||||
runModeConfig.setMode(RunModeConstants.SERIAL.name());
|
|
||||||
runModeConfig.setReportType("iddReport");
|
|
||||||
runModeConfig.setEnvMap(new HashMap<>());
|
|
||||||
runModeConfig.setOnSampleError(false);
|
|
||||||
return runModeConfig;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -49,6 +49,7 @@ import org.apache.ibatis.session.SqlSession;
|
||||||
import org.apache.ibatis.session.SqlSessionFactory;
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
import org.mybatis.spring.SqlSessionUtils;
|
import org.mybatis.spring.SqlSessionUtils;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@ -622,6 +623,7 @@ public class TestPlanReportService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
public void testPlanUnExecute(TestPlanReport testPlanReport) {
|
public void testPlanUnExecute(TestPlanReport testPlanReport) {
|
||||||
if (testPlanReport != null && !StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.COMPLETED.name())) {
|
if (testPlanReport != null && !StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.COMPLETED.name())) {
|
||||||
testPlanReport.setIsApiCaseExecuting(false);
|
testPlanReport.setIsApiCaseExecuting(false);
|
||||||
|
|
|
@ -40,6 +40,7 @@ import io.metersphere.plan.request.performance.LoadPlanReportDTO;
|
||||||
import io.metersphere.plan.request.ui.RunUiScenarioRequest;
|
import io.metersphere.plan.request.ui.RunUiScenarioRequest;
|
||||||
import io.metersphere.plan.request.ui.TestPlanUiExecuteReportDTO;
|
import io.metersphere.plan.request.ui.TestPlanUiExecuteReportDTO;
|
||||||
import io.metersphere.plan.request.ui.UiPlanReportRequest;
|
import io.metersphere.plan.request.ui.UiPlanReportRequest;
|
||||||
|
import io.metersphere.plan.service.execute.TestPlanExecuteService;
|
||||||
import io.metersphere.plan.service.remote.api.PlanApiAutomationService;
|
import io.metersphere.plan.service.remote.api.PlanApiAutomationService;
|
||||||
import io.metersphere.plan.service.remote.api.PlanTestPlanApiCaseService;
|
import io.metersphere.plan.service.remote.api.PlanTestPlanApiCaseService;
|
||||||
import io.metersphere.plan.service.remote.api.PlanTestPlanScenarioCaseService;
|
import io.metersphere.plan.service.remote.api.PlanTestPlanScenarioCaseService;
|
||||||
|
@ -495,6 +496,22 @@ public class TestPlanService {
|
||||||
request.setProjectId(request.getProjectId());
|
request.setProjectId(request.getProjectId());
|
||||||
}
|
}
|
||||||
List<TestPlanDTOWithMetric> testPlanList = extTestPlanMapper.list(request);
|
List<TestPlanDTOWithMetric> testPlanList = extTestPlanMapper.list(request);
|
||||||
|
|
||||||
|
//统计测试计划的测试用例数
|
||||||
|
List<String> testPlanIdList = testPlanList.stream().map(TestPlanDTOWithMetric::getId).collect(Collectors.toList());
|
||||||
|
Map<String, ParamsDTO> planTestCaseCountMap = extTestPlanMapper.testPlanTestCaseCount(testPlanIdList);
|
||||||
|
Map<String, ParamsDTO> planApiCaseMap = extTestPlanMapper.testPlanApiCaseCount(testPlanIdList);
|
||||||
|
Map<String, ParamsDTO> planApiScenarioMap = extTestPlanMapper.testPlanApiScenarioCount(testPlanIdList);
|
||||||
|
Map<String, ParamsDTO> planUiScenarioMap = extTestPlanMapper.testPlanUiScenarioCount(testPlanIdList);
|
||||||
|
Map<String, ParamsDTO> planLoadCaseMap = extTestPlanMapper.testPlanLoadCaseCount(testPlanIdList);
|
||||||
|
for (TestPlanDTOWithMetric testPlanMetric : testPlanList) {
|
||||||
|
testPlanMetric.setTestPlanTestCaseCount(planTestCaseCountMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planTestCaseCountMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planTestCaseCountMap.get(testPlanMetric.getId()).getValue()));
|
||||||
|
testPlanMetric.setTestPlanApiCaseCount(planApiCaseMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planApiCaseMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planApiCaseMap.get(testPlanMetric.getId()).getValue()));
|
||||||
|
testPlanMetric.setTestPlanApiScenarioCount(planApiScenarioMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planApiScenarioMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planApiScenarioMap.get(testPlanMetric.getId()).getValue()));
|
||||||
|
testPlanMetric.setTestPlanUiScenarioCount(planUiScenarioMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planUiScenarioMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planUiScenarioMap.get(testPlanMetric.getId()).getValue()));
|
||||||
|
testPlanMetric.setTestPlanLoadCaseCount(planLoadCaseMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planLoadCaseMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planLoadCaseMap.get(testPlanMetric.getId()).getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(testPlanList)) {
|
if (CollectionUtils.isNotEmpty(testPlanList)) {
|
||||||
List<String> changeToFinishedIds = new ArrayList<>();
|
List<String> changeToFinishedIds = new ArrayList<>();
|
||||||
//检查定时任务的设置
|
//检查定时任务的设置
|
||||||
|
@ -556,17 +573,7 @@ public class TestPlanService {
|
||||||
|
|
||||||
public List<TestPlanDTOWithMetric> selectTestPlanMetricById(List<String> idList) {
|
public List<TestPlanDTOWithMetric> selectTestPlanMetricById(List<String> idList) {
|
||||||
List<TestPlanDTOWithMetric> testPlanMetricList = this.calcTestPlanRateByIdList(idList);
|
List<TestPlanDTOWithMetric> testPlanMetricList = this.calcTestPlanRateByIdList(idList);
|
||||||
Map<String, ParamsDTO> planTestCaseCountMap = extTestPlanMapper.testPlanTestCaseCount(idList);
|
|
||||||
Map<String, ParamsDTO> planApiCaseMap = extTestPlanMapper.testPlanApiCaseCount(idList);
|
|
||||||
Map<String, ParamsDTO> planApiScenarioMap = extTestPlanMapper.testPlanApiScenarioCount(idList);
|
|
||||||
Map<String, ParamsDTO> planUiScenarioMap = extTestPlanMapper.testPlanUiScenarioCount(idList);
|
|
||||||
Map<String, ParamsDTO> planLoadCaseMap = extTestPlanMapper.testPlanLoadCaseCount(idList);
|
|
||||||
for (TestPlanDTOWithMetric testPlanMetric : testPlanMetricList) {
|
for (TestPlanDTOWithMetric testPlanMetric : testPlanMetricList) {
|
||||||
testPlanMetric.setTestPlanTestCaseCount(planTestCaseCountMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planTestCaseCountMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planTestCaseCountMap.get(testPlanMetric.getId()).getValue()));
|
|
||||||
testPlanMetric.setTestPlanApiCaseCount(planApiCaseMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planApiCaseMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planApiCaseMap.get(testPlanMetric.getId()).getValue()));
|
|
||||||
testPlanMetric.setTestPlanApiScenarioCount(planApiScenarioMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planApiScenarioMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planApiScenarioMap.get(testPlanMetric.getId()).getValue()));
|
|
||||||
testPlanMetric.setTestPlanUiScenarioCount(planUiScenarioMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planUiScenarioMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planUiScenarioMap.get(testPlanMetric.getId()).getValue()));
|
|
||||||
testPlanMetric.setTestPlanLoadCaseCount(planLoadCaseMap.get(testPlanMetric.getId()) == null ? 0 : Integer.parseInt(planLoadCaseMap.get(testPlanMetric.getId()).getValue() == null ? "0" : planLoadCaseMap.get(testPlanMetric.getId()).getValue()));
|
|
||||||
List<User> followUsers = this.getPlanFollow(testPlanMetric.getId());
|
List<User> followUsers = this.getPlanFollow(testPlanMetric.getId());
|
||||||
testPlanMetric.setFollowUsers(followUsers);
|
testPlanMetric.setFollowUsers(followUsers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,352 @@
|
||||||
|
package io.metersphere.plan.service.execute;
|
||||||
|
|
||||||
|
import com.esotericsoftware.minlog.Log;
|
||||||
|
import io.metersphere.base.domain.TestPlanReport;
|
||||||
|
import io.metersphere.base.domain.TestPlanWithBLOBs;
|
||||||
|
import io.metersphere.base.mapper.TestPlanMapper;
|
||||||
|
import io.metersphere.commons.constants.TestPlanExecuteCaseType;
|
||||||
|
import io.metersphere.commons.exception.MSException;
|
||||||
|
import io.metersphere.commons.utils.JSON;
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.constants.RunModeConstants;
|
||||||
|
import io.metersphere.dto.*;
|
||||||
|
import io.metersphere.i18n.Translator;
|
||||||
|
import io.metersphere.plan.dto.ExecutionWay;
|
||||||
|
import io.metersphere.plan.request.api.TestPlanRunRequest;
|
||||||
|
import io.metersphere.plan.service.TestPlanReportService;
|
||||||
|
import io.metersphere.plan.service.TestPlanService;
|
||||||
|
import io.metersphere.plan.service.remote.api.PlanTestPlanApiCaseService;
|
||||||
|
import io.metersphere.plan.service.remote.api.PlanTestPlanScenarioCaseService;
|
||||||
|
import io.metersphere.plan.service.remote.performance.PerfExecService;
|
||||||
|
import io.metersphere.plan.service.remote.ui.PlanTestPlanUiScenarioCaseService;
|
||||||
|
import io.metersphere.plan.utils.TestPlanRequestUtil;
|
||||||
|
import io.metersphere.service.RedisTemplateService;
|
||||||
|
import io.metersphere.utils.LoggerUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class TestPlanExecuteService {
|
||||||
|
@Resource
|
||||||
|
@Lazy
|
||||||
|
private TestPlanService testPlanService;
|
||||||
|
@Resource
|
||||||
|
private TestPlanReportService testPlanReportService;
|
||||||
|
@Resource
|
||||||
|
private PlanTestPlanApiCaseService planTestPlanApiCaseService;
|
||||||
|
@Resource
|
||||||
|
private PlanTestPlanScenarioCaseService planTestPlanScenarioCaseService;
|
||||||
|
@Resource
|
||||||
|
private PerfExecService perfExecService;
|
||||||
|
@Resource
|
||||||
|
private PlanTestPlanUiScenarioCaseService planTestPlanUiScenarioCaseService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TestPlanMapper testPlanMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplateService redisTemplateService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行测试计划流程是会调用其它服务的执行方法,并通过kafka传递信息给test-track服务来判断测试计划是否执行结束
|
||||||
|
* 执行方法采用单独的事务控制,执行完了就提交,让测试报告以及包括执行内容的数据及时入库
|
||||||
|
*/
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||||
|
public String runTestPlan(String testPlanId, String projectId, String userId, String triggerMode, String planReportId, String executionWay, String apiRunConfig) {
|
||||||
|
//获取运行模式
|
||||||
|
RunModeConfigDTO runModeConfig = this.getRunModeConfig(apiRunConfig, executionWay, testPlanId);
|
||||||
|
if (StringUtils.isEmpty(planReportId)) {
|
||||||
|
planReportId = UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
TestPlanReport testPlanReport = null;
|
||||||
|
try {
|
||||||
|
this.checkTestPlanCanRunning(testPlanId, projectId, runModeConfig);
|
||||||
|
//创建测试报告,然后返回的ID重新赋值为resourceID,作为后续的参数
|
||||||
|
TestPlanScheduleReportInfoDTO reportInfoDTO = testPlanService.genTestPlanReport(planReportId, testPlanId, userId, triggerMode, runModeConfig);
|
||||||
|
testPlanReport = reportInfoDTO.getTestPlanReport();
|
||||||
|
LoggerUtil.info("预生成测试计划报告【" + (reportInfoDTO.getTestPlanReport() != null ? reportInfoDTO.getTestPlanReport().getName() : StringUtils.EMPTY) + "】计划报告ID[" + planReportId + "]");
|
||||||
|
this.execute(reportInfoDTO, runModeConfig, triggerMode, projectId, userId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//如果执行失败,要保证执行队列是否不被影响
|
||||||
|
if (testPlanReport == null) {
|
||||||
|
testPlanReport = new TestPlanReport();
|
||||||
|
testPlanReport.setId(planReportId);
|
||||||
|
}
|
||||||
|
testPlanReportService.testPlanUnExecute(testPlanReport);
|
||||||
|
Log.error("执行测试计划失败!", e);
|
||||||
|
}
|
||||||
|
return planReportId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkTestPlanCanRunning(String testPlanId, String projectId, RunModeConfigDTO runModeConfig) throws Exception {
|
||||||
|
|
||||||
|
// 校验测试计划是否在执行中
|
||||||
|
if (testPlanService.checkTestPlanIsRunning(testPlanId)) {
|
||||||
|
|
||||||
|
LogUtil.info("当前测试计划正在执行中,请稍后再试", testPlanId);
|
||||||
|
MSException.throwException(Translator.get("test_plan_run_message"));
|
||||||
|
}
|
||||||
|
//检查执行资源池
|
||||||
|
if (testPlanService.haveExecCase(testPlanId, true)) {
|
||||||
|
testPlanService.verifyPool(projectId, runModeConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void execute(TestPlanScheduleReportInfoDTO reportInfoDTO, RunModeConfigDTO runModeConfig, String triggerMode, String projectId, String executeUser) throws Exception {
|
||||||
|
CaseExecuteResult caseExecuteResult = new CaseExecuteResult();
|
||||||
|
|
||||||
|
CountDownLatch countDownLatch = this.countDownExecute(reportInfoDTO, caseExecuteResult, runModeConfig, triggerMode, projectId, executeUser);
|
||||||
|
countDownLatch.await();
|
||||||
|
LoggerUtil.info("开始生成测试计划报告内容 " + reportInfoDTO.getTestPlanReport().getId());
|
||||||
|
testPlanReportService.createTestPlanReportContentReportIds(reportInfoDTO.getTestPlanReport().getId(),
|
||||||
|
caseExecuteResult.getApiCaseDTO(), caseExecuteResult.getScenarioCases(), caseExecuteResult.getUiScenarios(), caseExecuteResult.getLoadCaseReportMap());
|
||||||
|
if (!caseExecuteResult.isExecuting()) {
|
||||||
|
MSException.throwException("测试计划执行失败,不存在可执行的用例!报告ID:[" + reportInfoDTO.getTestPlanReport().getTestPlanId() + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CountDownLatch countDownExecute(TestPlanScheduleReportInfoDTO reportInfoDTO, CaseExecuteResult caseExecuteResult, RunModeConfigDTO runModeConfig, String triggerMode, String projectId, String executeUser) {
|
||||||
|
CountDownLatch countDownLatch = new CountDownLatch(4);
|
||||||
|
try {
|
||||||
|
this.executeApiCase(caseExecuteResult, reportInfoDTO.getApiTestCaseDataMap(), triggerMode,
|
||||||
|
reportInfoDTO.getTestPlanReport().getId(), reportInfoDTO.getTestPlanReport().getTestPlanId(), executeUser, runModeConfig);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.executeScenarioCase(caseExecuteResult, reportInfoDTO.getPlanScenarioIdMap(), triggerMode,
|
||||||
|
reportInfoDTO.getTestPlanReport().getId(), reportInfoDTO.getTestPlanReport().getTestPlanId(), projectId, executeUser, runModeConfig);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.executeUiCase(caseExecuteResult, reportInfoDTO.getUiScenarioIdMap(), triggerMode,
|
||||||
|
reportInfoDTO.getTestPlanReport().getId(), reportInfoDTO.getTestPlanReport().getTestPlanId(), projectId, executeUser, runModeConfig);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.executeLoadCase(caseExecuteResult, reportInfoDTO.getPerformanceIdMap(), triggerMode,
|
||||||
|
reportInfoDTO.getTestPlanReport().getId(), runModeConfig);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
return countDownLatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeApiCase(CaseExecuteResult executeResult, Map<String, String> executeCase, String triggerMode, String testPlanReportId, String testPlanId, String executeUser, RunModeConfigDTO runModeConfig) {
|
||||||
|
boolean executing = false;
|
||||||
|
List<TestPlanApiDTO> apiTestCases = null;
|
||||||
|
if (MapUtils.isNotEmpty(executeCase)) {
|
||||||
|
try {
|
||||||
|
apiTestCases = planTestPlanApiCaseService.getFailureListByIds(executeCase.keySet());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error("测试计划执行查询接口用例失败!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(apiTestCases)) {
|
||||||
|
//执行接口案例任务
|
||||||
|
LoggerUtil.info("开始执行测试计划接口用例 " + testPlanReportId);
|
||||||
|
try {
|
||||||
|
redisTemplateService.lock(testPlanReportId, TestPlanExecuteCaseType.API_CASE.name(), testPlanReportId);
|
||||||
|
Map<String, String> apiCaseReportMap = testPlanService.executeApiTestCase(triggerMode, testPlanReportId, executeUser, testPlanId, runModeConfig);
|
||||||
|
if (MapUtils.isNotEmpty(apiCaseReportMap)) {
|
||||||
|
executing = true;
|
||||||
|
for (TestPlanApiDTO dto : apiTestCases) {
|
||||||
|
dto.setReportId(apiCaseReportMap.get(dto.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
redisTemplateService.unlock(testPlanReportId, TestPlanExecuteCaseType.API_CASE.name(), testPlanReportId);
|
||||||
|
apiTestCases = null;
|
||||||
|
LoggerUtil.info("测试报告" + testPlanReportId + "本次执行测试计划接口用例失败! ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
executeResult.setApiCaseExecuting(executing);
|
||||||
|
executeResult.setApiCaseDTO(apiTestCases);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeScenarioCase(CaseExecuteResult executeResult, Map<String, String> executeCase, String triggerMode, String testPlanReportId, String testPlanId, String projectId, String executeUser, RunModeConfigDTO runModeConfig) {
|
||||||
|
boolean executing = false;
|
||||||
|
List<TestPlanScenarioDTO> scenarioCases = null;
|
||||||
|
if (MapUtils.isNotEmpty(executeCase)) {
|
||||||
|
try {
|
||||||
|
scenarioCases = planTestPlanScenarioCaseService.getFailureListByIds(executeCase.keySet());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error("测试计划执行查询场景用例失败!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CollectionUtils.isNotEmpty(scenarioCases)) {
|
||||||
|
//执行场景执行任务
|
||||||
|
LoggerUtil.info("开始执行测试计划场景用例 " + testPlanReportId);
|
||||||
|
try {
|
||||||
|
|
||||||
|
redisTemplateService.lock(testPlanReportId, TestPlanExecuteCaseType.SCENARIO.name(), testPlanReportId);
|
||||||
|
Map<String, String> scenarioReportMap = testPlanService.executeScenarioCase(testPlanReportId, testPlanId, projectId, runModeConfig, triggerMode, executeUser, executeCase);
|
||||||
|
if (MapUtils.isNotEmpty(scenarioReportMap)) {
|
||||||
|
executing = true;
|
||||||
|
List<TestPlanScenarioDTO> removeDTO = new ArrayList<>();
|
||||||
|
for (TestPlanScenarioDTO dto : scenarioCases) {
|
||||||
|
if (scenarioReportMap.containsKey(dto.getId())) {
|
||||||
|
dto.setReportId(scenarioReportMap.get(dto.getId()));
|
||||||
|
} else {
|
||||||
|
removeDTO.add(dto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(removeDTO)) {
|
||||||
|
scenarioCases.removeAll(removeDTO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
redisTemplateService.unlock(testPlanReportId, TestPlanExecuteCaseType.SCENARIO.name(), testPlanReportId);
|
||||||
|
scenarioCases = null;
|
||||||
|
LoggerUtil.info("测试报告" + testPlanReportId + "本次执行测试计划场景用例失败! ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
executeResult.setScenarioCases(scenarioCases);
|
||||||
|
executeResult.setScenarioExecuting(executing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeUiCase(CaseExecuteResult executeResult, Map<String, String> executeCase, String triggerMode, String testPlanReportId, String testPlanId, String projectId, String executeUser, RunModeConfigDTO runModeConfig) {
|
||||||
|
boolean executing = false;
|
||||||
|
List<TestPlanUiScenarioDTO> uiScenarios = null;
|
||||||
|
if (MapUtils.isNotEmpty(executeCase)) {
|
||||||
|
try {
|
||||||
|
uiScenarios = planTestPlanUiScenarioCaseService.getFailureListByIds(executeCase.keySet());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error("测试计划执行查询UI用例失败!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(uiScenarios)) {
|
||||||
|
//执行UI场景执行任务
|
||||||
|
LoggerUtil.info("开始执行测试计划 UI 场景用例 " + testPlanReportId);
|
||||||
|
try {
|
||||||
|
redisTemplateService.lock(testPlanReportId, TestPlanExecuteCaseType.UI_SCENARIO.name(), testPlanReportId);
|
||||||
|
Map<String, String> uiScenarioReportMap = testPlanService.executeUiScenarioCase(testPlanReportId, testPlanId, projectId, runModeConfig, triggerMode, executeUser, executeCase);
|
||||||
|
if (MapUtils.isNotEmpty(uiScenarioReportMap)) {
|
||||||
|
executing = true;
|
||||||
|
for (TestPlanUiScenarioDTO dto : uiScenarios) {
|
||||||
|
dto.setReportId(uiScenarioReportMap.get(dto.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
redisTemplateService.unlock(testPlanReportId, TestPlanExecuteCaseType.UI_SCENARIO.name(), testPlanReportId);
|
||||||
|
uiScenarios = null;
|
||||||
|
LoggerUtil.info("测试报告" + testPlanReportId + "本次执行测试计划 UI 用例失败! ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
executeResult.setUiScenarios(uiScenarios);
|
||||||
|
executeResult.setUiScenarioExecuting(executing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeLoadCase(CaseExecuteResult executeResult, Map<String, String> executeCase, String triggerMode, String testPlanReportId, RunModeConfigDTO runModeConfig) {
|
||||||
|
boolean executing = false;
|
||||||
|
|
||||||
|
Map<String, String> loadCaseReportMap = null;
|
||||||
|
|
||||||
|
if (MapUtils.isNotEmpty(executeCase)) {
|
||||||
|
//执行性能测试任务
|
||||||
|
LoggerUtil.info("开始执行测试计划性能用例 " + testPlanReportId);
|
||||||
|
try {
|
||||||
|
redisTemplateService.lock(testPlanReportId, TestPlanExecuteCaseType.LOAD_CASE.name(), testPlanReportId);
|
||||||
|
loadCaseReportMap = perfExecService.executeLoadCase(testPlanReportId, runModeConfig, testPlanService.transformationPerfTriggerMode(triggerMode), executeCase);
|
||||||
|
if (MapUtils.isNotEmpty(loadCaseReportMap)) {
|
||||||
|
executing = true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
redisTemplateService.unlock(testPlanReportId, TestPlanExecuteCaseType.LOAD_CASE.name(), testPlanReportId);
|
||||||
|
LoggerUtil.info("测试报告" + testPlanReportId + "本次执行测试计划性能用例失败! ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
executeResult.setLoadCaseReportMap(loadCaseReportMap);
|
||||||
|
executeResult.setLoadCaseExecuting(executing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RunModeConfigDTO getRunModeConfig(String apiRunConfig, String executionWay, String testPlanId) {
|
||||||
|
RunModeConfigDTO runModeConfig = null;
|
||||||
|
try {
|
||||||
|
runModeConfig = JSON.parseObject(apiRunConfig, RunModeConfigDTO.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
}
|
||||||
|
if (runModeConfig == null) {
|
||||||
|
runModeConfig = this.buildRunModeConfigDTO();
|
||||||
|
}
|
||||||
|
|
||||||
|
//环境参数为空时,依据测试计划保存的环境执行
|
||||||
|
if (((StringUtils.equals("GROUP", runModeConfig.getEnvironmentType()) && StringUtils.isBlank(runModeConfig.getEnvironmentGroupId()))
|
||||||
|
|| (!StringUtils.equals("GROUP", runModeConfig.getEnvironmentType()) && MapUtils.isEmpty(runModeConfig.getEnvMap()) && MapUtils.isEmpty(runModeConfig.getTestPlanDefaultEnvMap())))
|
||||||
|
&& !StringUtils.equals(executionWay, ExecutionWay.RUN.name())) {
|
||||||
|
TestPlanWithBLOBs testPlanWithBLOBs = testPlanMapper.selectByPrimaryKey(testPlanId);
|
||||||
|
if (StringUtils.isNotEmpty(testPlanWithBLOBs.getRunModeConfig())) {
|
||||||
|
try {
|
||||||
|
Map json = JSON.parseMap(testPlanWithBLOBs.getRunModeConfig());
|
||||||
|
TestPlanRequestUtil.changeStringToBoolean(json);
|
||||||
|
TestPlanRunRequest testPlanRunRequest = JSON.parseObject(JSON.toJSONString(json), TestPlanRunRequest.class);
|
||||||
|
if (testPlanRunRequest != null) {
|
||||||
|
String envType = testPlanRunRequest.getEnvironmentType();
|
||||||
|
Map<String, String> envMap = testPlanRunRequest.getEnvMap();
|
||||||
|
String environmentGroupId = testPlanRunRequest.getEnvironmentGroupId();
|
||||||
|
runModeConfig = testPlanService.getRunModeConfigDTO(testPlanRunRequest, envType, envMap, environmentGroupId, testPlanId);
|
||||||
|
runModeConfig.setTestPlanDefaultEnvMap(testPlanRunRequest.getTestPlanDefaultEnvMap());
|
||||||
|
if (!testPlanRunRequest.isRunWithinResourcePool()) {
|
||||||
|
runModeConfig.setResourcePoolId(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error("获取测试计划保存的环境信息出错!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return runModeConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RunModeConfigDTO buildRunModeConfigDTO() {
|
||||||
|
RunModeConfigDTO runModeConfig = new RunModeConfigDTO();
|
||||||
|
runModeConfig.setMode(RunModeConstants.SERIAL.name());
|
||||||
|
runModeConfig.setReportType("iddReport");
|
||||||
|
runModeConfig.setEnvMap(new HashMap<>());
|
||||||
|
runModeConfig.setOnSampleError(false);
|
||||||
|
return runModeConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
class CaseExecuteResult {
|
||||||
|
private boolean apiCaseExecuting;
|
||||||
|
private boolean scenarioExecuting;
|
||||||
|
private boolean uiScenarioExecuting;
|
||||||
|
private boolean loadCaseExecuting;
|
||||||
|
|
||||||
|
|
||||||
|
private List<TestPlanApiDTO> apiCaseDTO;
|
||||||
|
private List<TestPlanScenarioDTO> scenarioCases;
|
||||||
|
private List<TestPlanUiScenarioDTO> uiScenarios;
|
||||||
|
private Map<String, String> loadCaseReportMap;
|
||||||
|
|
||||||
|
public boolean isExecuting() {
|
||||||
|
return apiCaseExecuting || scenarioExecuting || uiScenarioExecuting || loadCaseExecuting;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
@close="close"
|
@close="close"
|
||||||
:visible.sync="runModeVisible"
|
:visible.sync="runModeVisible"
|
||||||
>
|
>
|
||||||
|
|
||||||
<div class="env-container">
|
<div class="env-container">
|
||||||
<div>
|
<div>
|
||||||
<div>{{ $t("commons.environment") }}:</div>
|
<div>{{ $t("commons.environment") }}:</div>
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
:project-env-map="projectEnvListMap"
|
:project-env-map="projectEnvListMap"
|
||||||
:environment-type.sync="runConfig.environmentType"
|
:environment-type.sync="runConfig.environmentType"
|
||||||
:has-option-group="true"
|
:has-option-group="true"
|
||||||
|
:is-env-saved="isEnvSaved"
|
||||||
:group-id="runConfig.environmentGroupId"
|
:group-id="runConfig.environmentGroupId"
|
||||||
@setProjectEnvMap="setProjectEnvMap"
|
@setProjectEnvMap="setProjectEnvMap"
|
||||||
@setDefaultEnv="setDefaultEnv"
|
@setDefaultEnv="setDefaultEnv"
|
||||||
|
@ -59,13 +61,12 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="mode-row">{{ $t("run_mode.other_config") }}:</div>
|
<div class="mode-row">{{ $t("run_mode.other_config") }}:</div>
|
||||||
<div>
|
<div>
|
||||||
<!-- 串行 -->
|
<!-- 资源池 -->
|
||||||
<div
|
<div
|
||||||
class="mode-row"
|
class="mode-row"
|
||||||
v-if="
|
v-if="
|
||||||
runConfig.mode === 'serial' &&
|
|
||||||
testType === 'API' &&
|
testType === 'API' &&
|
||||||
haveOtherExecCase
|
(haveOtherExecCase && !haveUICase)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<span>{{ $t("run_mode.run_with_resource_pool") }}: </span>
|
<span>{{ $t("run_mode.run_with_resource_pool") }}: </span>
|
||||||
|
@ -83,31 +84,6 @@
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<!-- 并行 -->
|
|
||||||
<div
|
|
||||||
class="mode-row"
|
|
||||||
v-if="
|
|
||||||
runConfig.mode === 'parallel' &&
|
|
||||||
testType === 'API' &&
|
|
||||||
haveOtherExecCase
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<span>{{ $t("run_mode.run_with_resource_pool") }}: </span>
|
|
||||||
<el-select
|
|
||||||
v-model="runConfig.resourcePoolId"
|
|
||||||
size="mini"
|
|
||||||
style="width: 100%; margin-top: 8px"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in resourcePools"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.name"
|
|
||||||
:disabled="!item.api"
|
|
||||||
:value="item.id"
|
|
||||||
>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 失败重试 -->
|
<!-- 失败重试 -->
|
||||||
<div class="mode-row">
|
<div class="mode-row">
|
||||||
|
@ -124,7 +100,7 @@
|
||||||
class="el-icon-question"
|
class="el-icon-question"
|
||||||
style="cursor: pointer"
|
style="cursor: pointer"
|
||||||
/> </el-tooltip
|
/> </el-tooltip
|
||||||
><br />
|
><br/>
|
||||||
<span>
|
<span>
|
||||||
{{ $t("run_mode.retry") }}
|
{{ $t("run_mode.retry") }}
|
||||||
<el-input-number
|
<el-input-number
|
||||||
|
@ -164,7 +140,8 @@
|
||||||
<el-button @click="close">{{ $t("commons.cancel") }}</el-button>
|
<el-button @click="close">{{ $t("commons.cancel") }}</el-button>
|
||||||
<el-dropdown @command="handleCommand" style="margin-left: 5px">
|
<el-dropdown @command="handleCommand" style="margin-left: 5px">
|
||||||
<el-button type="primary">
|
<el-button type="primary">
|
||||||
{{ $t("api_test.run")
|
{{
|
||||||
|
$t("api_test.run")
|
||||||
}}<i class="el-icon-arrow-down el-icon--right"></i>
|
}}<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
@ -180,7 +157,7 @@
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</div>
|
</div>
|
||||||
<ms-dialog-footer v-else @cancel="close" @confirm="handleRunBatch" />
|
<ms-dialog-footer v-else @cancel="close" @confirm="handleRunBatch"/>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
@ -220,7 +197,7 @@ export default {
|
||||||
btnStyle: {
|
btnStyle: {
|
||||||
width: "260px",
|
width: "260px",
|
||||||
},
|
},
|
||||||
result: { loading: false },
|
result: {loading: false},
|
||||||
runModeVisible: false,
|
runModeVisible: false,
|
||||||
testType: null,
|
testType: null,
|
||||||
resourcePools: [],
|
resourcePools: [],
|
||||||
|
@ -233,7 +210,7 @@ export default {
|
||||||
resourcePoolId: null,
|
resourcePoolId: null,
|
||||||
envMap: new Map(),
|
envMap: new Map(),
|
||||||
environmentGroupId: "",
|
environmentGroupId: "",
|
||||||
environmentType: ENV_TYPE.JSON,
|
environmentType: ENV_TYPE.DEFAULT,
|
||||||
retryEnable: false,
|
retryEnable: false,
|
||||||
retryNum: 1,
|
retryNum: 1,
|
||||||
browser: "CHROME",
|
browser: "CHROME",
|
||||||
|
@ -241,6 +218,8 @@ export default {
|
||||||
},
|
},
|
||||||
projectList: [],
|
projectList: [],
|
||||||
projectIds: new Set(),
|
projectIds: new Set(),
|
||||||
|
//环境是否保存过。未保存过的话展示的是”用例环境“
|
||||||
|
isEnvSaved: true,
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
value: "confirmAndRun",
|
value: "confirmAndRun",
|
||||||
|
@ -279,6 +258,7 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
//是否有其他用例(性能测试除外)
|
||||||
haveOtherExecCase: {
|
haveOtherExecCase: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
|
@ -289,11 +269,22 @@ export default {
|
||||||
this.defaultEnvMap = {};
|
this.defaultEnvMap = {};
|
||||||
if (runModeConfig) {
|
if (runModeConfig) {
|
||||||
this.runConfig = JSON.parse(runModeConfig);
|
this.runConfig = JSON.parse(runModeConfig);
|
||||||
|
if (!this.runConfig.envMap || JSON.stringify(this.runConfig.envMap) === "{}") {
|
||||||
|
this.isEnvSaved = false;
|
||||||
|
this.runConfig.environmentType = ENV_TYPE.DEFAULT;
|
||||||
|
} else {
|
||||||
|
this.isEnvSaved = true;
|
||||||
|
this.runConfig.environmentType = ENV_TYPE.JSON;
|
||||||
|
}
|
||||||
this.runConfig.envMap = new Map();
|
this.runConfig.envMap = new Map();
|
||||||
this.runConfig.testPlanDefaultEnvMap = {};
|
this.runConfig.testPlanDefaultEnvMap = {};
|
||||||
this.runConfig.onSampleError =
|
this.runConfig.onSampleError =
|
||||||
this.runConfig.onSampleError === "true" ||
|
this.runConfig.onSampleError === "true" ||
|
||||||
this.runConfig.onSampleError === true;
|
this.runConfig.onSampleError === true;
|
||||||
|
} else {
|
||||||
|
this.isEnvSaved = false;
|
||||||
|
//没保存过运行配置的测试计划,运行环境类型为default
|
||||||
|
this.runConfig.environmentType = ENV_TYPE.DEFAULT;
|
||||||
}
|
}
|
||||||
this.runModeVisible = true;
|
this.runModeVisible = true;
|
||||||
this.testType = testType;
|
this.testType = testType;
|
||||||
|
@ -408,7 +399,7 @@ export default {
|
||||||
this.$refs.envSelectPopover.open();
|
this.$refs.envSelectPopover.open();
|
||||||
});
|
});
|
||||||
} else if (this.type === "plan") {
|
} else if (this.type === "plan") {
|
||||||
param = { id: this.planId };
|
param = {id: this.planId};
|
||||||
getPlanCaseEnv(param).then((res) => {
|
getPlanCaseEnv(param).then((res) => {
|
||||||
let data = res.data;
|
let data = res.data;
|
||||||
if (data) {
|
if (data) {
|
||||||
|
@ -418,7 +409,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.projectIds.size === 0) {
|
if (this.projectIds.size === 0) {
|
||||||
param = { id: this.planId };
|
param = {id: this.planId};
|
||||||
getPlanCaseProjectIds(param).then((res) => {
|
getPlanCaseProjectIds(param).then((res) => {
|
||||||
let data = res.data;
|
let data = res.data;
|
||||||
if (data) {
|
if (data) {
|
||||||
|
@ -459,11 +450,12 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.env-container{
|
.env-container {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding-bottom: 1px;
|
padding-bottom: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-container .title {
|
.env-container .title {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
|
@ -486,6 +478,7 @@ export default {
|
||||||
.radio-change:deep(.el-radio__input.is-checked + .el-radio__label) {
|
.radio-change:deep(.el-radio__input.is-checked + .el-radio__label) {
|
||||||
color: #606266 !important;
|
color: #606266 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-change:deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
|
.radio-change:deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
|
||||||
color: #606266 !important;
|
color: #606266 !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,23 +75,24 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<crontab-result :ex="form.cronValue" ref="crontabResult" />
|
<crontab-result :ex="form.cronValue" ref="crontabResult"/>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
|
<div v-if="haveUICase || haveOtherExecCase">
|
||||||
<div class="el-step__icon is-text" style="margin-right: 10px">
|
<div class="el-step__icon is-text" style="margin-right: 10px">
|
||||||
<div class="el-step__icon-inner">2</div>
|
<div class="el-step__icon-inner">2</div>
|
||||||
</div>
|
</div>
|
||||||
<span>{{ $t("load_test.runtime_config") }}</span>
|
<span>{{ $t("load_test.runtime_config") }}</span>
|
||||||
<div class="ms-mode-div">
|
<div class="ms-mode-div">
|
||||||
<span class="ms-mode-span">{{ $t("run_mode.title") }}:</span>
|
<span class="ms-mode-span">{{ $t("run_mode.title") }}:</span>
|
||||||
<el-radio-group v-model="runConfig.mode" @change="changeMode">
|
<el-radio-group v-if="haveUICase || haveOtherExecCase" v-model="runConfig.mode" @change="changeMode">
|
||||||
<el-radio label="serial">{{ $t("run_mode.serial") }}</el-radio>
|
<el-radio label="serial">{{ $t("run_mode.serial") }}</el-radio>
|
||||||
<el-radio label="parallel"
|
<el-radio label="parallel"
|
||||||
>{{ $t("run_mode.parallel") }}
|
>{{ $t("run_mode.parallel") }}
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 10px">
|
<div v-if="haveUICase" style="margin-top: 10px">
|
||||||
<span class="ms-mode-span">{{ $t("浏览器") }}:</span>
|
<span class="ms-mode-span">{{ $t("浏览器") }}:</span>
|
||||||
<el-select
|
<el-select
|
||||||
size="mini"
|
size="mini"
|
||||||
|
@ -106,7 +107,7 @@
|
||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-mode-div" v-if="runConfig.mode === 'serial'">
|
<div class="ms-mode-div" v-if="(haveUICase || haveOtherExecCase) && runConfig.mode === 'serial'">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="3">
|
<el-col :span="3">
|
||||||
<span class="ms-mode-span"
|
<span class="ms-mode-span"
|
||||||
|
@ -114,8 +115,8 @@
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="18">
|
<el-col :span="18">
|
||||||
<div v-if="testType === 'API'">
|
<div v-if="haveOtherExecCase && testType === 'API'">
|
||||||
<sapn>{{ $t("run_mode.run_with_resource_pool") }}: </sapn>
|
<sapn>{{ $t("run_mode.run_with_resource_pool") }}:</sapn>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="runConfig.resourcePoolId"
|
v-model="runConfig.resourcePoolId"
|
||||||
size="mini"
|
size="mini"
|
||||||
|
@ -132,7 +133,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-mode-div" v-if="runConfig.mode === 'parallel'">
|
<div class="ms-mode-div" v-if="(haveUICase || haveOtherExecCase) && runConfig.mode === 'parallel'">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="3">
|
<el-col :span="3">
|
||||||
<span class="ms-mode-span"
|
<span class="ms-mode-span"
|
||||||
|
@ -140,7 +141,7 @@
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="18">
|
<el-col :span="18">
|
||||||
<div v-if="testType === 'API'">
|
<div v-if="haveOtherExecCase && testType === 'API'">
|
||||||
<span>
|
<span>
|
||||||
{{ $t("run_mode.run_with_resource_pool") }} :
|
{{ $t("run_mode.run_with_resource_pool") }} :
|
||||||
</span>
|
</span>
|
||||||
|
@ -180,7 +181,7 @@
|
||||||
<div slot="content">
|
<div slot="content">
|
||||||
{{ $t("run_mode.retry_message") }}
|
{{ $t("run_mode.retry_message") }}
|
||||||
</div>
|
</div>
|
||||||
<i class="el-icon-question" style="cursor: pointer" />
|
<i class="el-icon-question" style="cursor: pointer"/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<span>
|
<span>
|
||||||
{{ $t("run_mode.retry") }}
|
{{ $t("run_mode.retry") }}
|
||||||
|
@ -209,7 +210,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div v-if="haveUICase">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="3"> </el-col>
|
<el-col :span="3"> </el-col>
|
||||||
<el-col :span="18">
|
<el-col :span="18">
|
||||||
|
@ -221,7 +222,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
width="60%"
|
width="60%"
|
||||||
:title="$t('schedule.generate_expression')"
|
:title="$t('schedule.generate_expression')"
|
||||||
|
@ -250,21 +251,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {getCurrentProjectID, getCurrentUser, getCurrentWorkspaceId,} from "metersphere-frontend/src/utils/token";
|
||||||
getCurrentProjectID,
|
import {listenGoBack, removeGoBackListener,} from "metersphere-frontend/src/utils";
|
||||||
getCurrentUser,
|
|
||||||
getCurrentWorkspaceId,
|
|
||||||
} from "metersphere-frontend/src/utils/token";
|
|
||||||
import {
|
|
||||||
listenGoBack,
|
|
||||||
removeGoBackListener,
|
|
||||||
} from "metersphere-frontend/src/utils";
|
|
||||||
import Crontab from "metersphere-frontend/src/components/cron/Crontab";
|
import Crontab from "metersphere-frontend/src/components/cron/Crontab";
|
||||||
import CrontabResult from "metersphere-frontend/src/components/cron/CrontabResult";
|
import CrontabResult from "metersphere-frontend/src/components/cron/CrontabResult";
|
||||||
import { cronValidate } from "metersphere-frontend/src/utils/cron";
|
import {cronValidate} from "metersphere-frontend/src/utils/cron";
|
||||||
import MsScheduleNotification from "./ScheduleNotification";
|
import MsScheduleNotification from "./ScheduleNotification";
|
||||||
import ScheduleSwitch from "./ScheduleSwitch";
|
import ScheduleSwitch from "./ScheduleSwitch";
|
||||||
import { ENV_TYPE } from "metersphere-frontend/src/utils/constants";
|
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
|
||||||
import MxNotification from "metersphere-frontend/src/components/MxNoticeTemplate";
|
import MxNotification from "metersphere-frontend/src/components/MxNoticeTemplate";
|
||||||
import {
|
import {
|
||||||
createSchedule,
|
createSchedule,
|
||||||
|
@ -272,14 +266,13 @@ import {
|
||||||
updateSchedule,
|
updateSchedule,
|
||||||
updateScheduleEnableByPrimyKey,
|
updateScheduleEnableByPrimyKey,
|
||||||
} from "@/api/remote/plan/test-plan";
|
} from "@/api/remote/plan/test-plan";
|
||||||
import { saveNotice } from "@/api/notice";
|
import {saveNotice} from "@/api/notice";
|
||||||
import { getProjectMember } from "@/api/user";
|
import {getProjectMember} from "@/api/user";
|
||||||
import { getQuotaValidResourcePools } from "@/api/remote/resource-pool";
|
import {getQuotaValidResourcePools} from "@/api/remote/resource-pool";
|
||||||
import { getProjectConfig } from "@/api/project";
|
import {getProjectConfig} from "@/api/project";
|
||||||
import { getSystemBaseSetting } from "metersphere-frontend/src/api/system";
|
|
||||||
|
|
||||||
function defaultCustomValidate() {
|
function defaultCustomValidate() {
|
||||||
return { pass: true };
|
return {pass: true};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -308,6 +301,11 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
//是否有其他用例(性能测试除外)
|
||||||
|
haveOtherExecCase: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -351,7 +349,7 @@ export default {
|
||||||
activeName: "first",
|
activeName: "first",
|
||||||
rules: {
|
rules: {
|
||||||
cronValue: [
|
cronValue: [
|
||||||
{ required: true, validator: validateCron, trigger: "blur" },
|
{required: true, validator: validateCron, trigger: "blur"},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
resourcePools: [],
|
resourcePools: [],
|
||||||
|
@ -382,7 +380,7 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async checkPool(){
|
async checkPool() {
|
||||||
let hasPool = false;
|
let hasPool = false;
|
||||||
this.resourcePools.forEach(item => {
|
this.resourcePools.forEach(item => {
|
||||||
if (item.id === this.runConfig.resourcePoolId) {
|
if (item.id === this.runConfig.resourcePoolId) {
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
<span @click.stop="clickt = 'stop'">
|
<span @click.stop="clickt = 'stop'">
|
||||||
<el-dropdown class="test-case-status" @command="statusChange">
|
<el-dropdown class="test-case-status" @command="statusChange">
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
<plan-status-table-item :value="scope.row.status" />
|
<plan-status-table-item :value="scope.row.status"/>
|
||||||
</span>
|
</span>
|
||||||
<el-dropdown-menu slot="dropdown" chang>
|
<el-dropdown-menu slot="dropdown" chang>
|
||||||
<el-dropdown-item
|
<el-dropdown-item
|
||||||
|
@ -122,8 +122,9 @@
|
||||||
<span v-if="scope.row.scheduleStatus === 'OPEN'">
|
<span v-if="scope.row.scheduleStatus === 'OPEN'">
|
||||||
<el-tooltip placement="bottom-start" effect="light">
|
<el-tooltip placement="bottom-start" effect="light">
|
||||||
<div slot="content">
|
<div slot="content">
|
||||||
{{ $t("home.table.run_rule") }}: {{ scope.row.scheduleCorn
|
{{ $t("home.table.run_rule") }}: {{
|
||||||
}}<br />
|
scope.row.scheduleCorn
|
||||||
|
}}<br/>
|
||||||
{{ $t("test_track.plan.next_run_time") }}:<span>{{
|
{{ $t("test_track.plan.next_run_time") }}:<span>{{
|
||||||
scope.row.scheduleExecuteTime | datetimeFormat
|
scope.row.scheduleExecuteTime | datetimeFormat
|
||||||
}}</span>
|
}}</span>
|
||||||
|
@ -196,7 +197,7 @@
|
||||||
v-if="scope.row.isMetricLoadOver"
|
v-if="scope.row.isMetricLoadOver"
|
||||||
:percentage="scope.row.testRate ? scope.row.testRate : 0"
|
:percentage="scope.row.testRate ? scope.row.testRate : 0"
|
||||||
></el-progress>
|
></el-progress>
|
||||||
<i v-else class="el-icon-loading" />
|
<i v-else class="el-icon-loading"/>
|
||||||
</template>
|
</template>
|
||||||
</ms-table-column>
|
</ms-table-column>
|
||||||
<ms-table-column
|
<ms-table-column
|
||||||
|
@ -208,7 +209,7 @@
|
||||||
>
|
>
|
||||||
</ms-table-column>
|
</ms-table-column>
|
||||||
|
|
||||||
<ms-tags-column :field="item" :fields-width="fieldsWidth" />
|
<ms-tags-column :field="item" :fields-width="fieldsWidth"/>
|
||||||
|
|
||||||
<ms-table-column
|
<ms-table-column
|
||||||
prop="testPlanTestCaseCount"
|
prop="testPlanTestCaseCount"
|
||||||
|
@ -261,7 +262,7 @@
|
||||||
<span v-if="scope.row.isMetricLoadOver">{{
|
<span v-if="scope.row.isMetricLoadOver">{{
|
||||||
scope.row.passRate
|
scope.row.passRate
|
||||||
}}</span>
|
}}</span>
|
||||||
<i v-else class="el-icon-loading" />
|
<i v-else class="el-icon-loading"/>
|
||||||
</template>
|
</template>
|
||||||
</ms-table-column>
|
</ms-table-column>
|
||||||
<ms-table-column
|
<ms-table-column
|
||||||
|
@ -424,6 +425,7 @@
|
||||||
:plan-case-ids="[]"
|
:plan-case-ids="[]"
|
||||||
:type="'plan'"
|
:type="'plan'"
|
||||||
:have-u-i-case="haveUICase"
|
:have-u-i-case="haveUICase"
|
||||||
|
:have-other-exec-case="haveOtherExecCase"
|
||||||
/>
|
/>
|
||||||
<ms-test-plan-schedule-batch-switch
|
<ms-test-plan-schedule-batch-switch
|
||||||
ref="scheduleBatchSwitch"
|
ref="scheduleBatchSwitch"
|
||||||
|
@ -439,8 +441,8 @@
|
||||||
:have-u-i-case="haveUICase"
|
:have-u-i-case="haveUICase"
|
||||||
:have-other-exec-case="haveOtherExecCase"
|
:have-other-exec-case="haveOtherExecCase"
|
||||||
/>
|
/>
|
||||||
<test-plan-report-review ref="testCaseReportView" />
|
<test-plan-report-review ref="testCaseReportView"/>
|
||||||
<ms-task-center ref="taskCenter" :show-menu="false" />
|
<ms-task-center ref="taskCenter" :show-menu="false"/>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:visible.sync="showExecute"
|
:visible.sync="showExecute"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
|
@ -454,10 +456,10 @@
|
||||||
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
|
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br/>
|
||||||
<span>注:运行模式仅对测试计划间有效</span>
|
<span>注:运行模式仅对测试计划间有效</span>
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<ms-dialog-footer @cancel="closeExecute" @confirm="handleRunBatch" />
|
<ms-dialog-footer @cancel="closeExecute" @confirm="handleRunBatch"/>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
@ -487,7 +489,7 @@ import HeaderLabelOperate from "metersphere-frontend/src/components/head/HeaderL
|
||||||
import MsTag from "metersphere-frontend/src/components/MsTag";
|
import MsTag from "metersphere-frontend/src/components/MsTag";
|
||||||
import MsTestPlanScheduleMaintain from "@/business/plan/components/ScheduleMaintain";
|
import MsTestPlanScheduleMaintain from "@/business/plan/components/ScheduleMaintain";
|
||||||
import {getCurrentProjectID, getCurrentUser, getCurrentUserId,} from "metersphere-frontend/src/utils/token";
|
import {getCurrentProjectID, getCurrentUser, getCurrentUserId,} from "metersphere-frontend/src/utils/token";
|
||||||
import {hasLicense, hasPermission,} from "metersphere-frontend/src/utils/permission";
|
import {hasPermission,} from "metersphere-frontend/src/utils/permission";
|
||||||
import {operationConfirm} from "metersphere-frontend/src/utils";
|
import {operationConfirm} from "metersphere-frontend/src/utils";
|
||||||
import MsTestPlanRunModeWithEnv from "@/business/plan/common/TestPlanRunModeWithEnv";
|
import MsTestPlanRunModeWithEnv from "@/business/plan/common/TestPlanRunModeWithEnv";
|
||||||
import MsTaskCenter from "metersphere-frontend/src/components/task/TaskCenter";
|
import MsTaskCenter from "metersphere-frontend/src/components/task/TaskCenter";
|
||||||
|
@ -500,8 +502,6 @@ import {
|
||||||
testPlanEditFollows,
|
testPlanEditFollows,
|
||||||
testPlanEditRunConfig,
|
testPlanEditRunConfig,
|
||||||
testPlanGetEnableScheduleCount,
|
testPlanGetEnableScheduleCount,
|
||||||
testPlanHaveExecCase,
|
|
||||||
testPlanHaveUiCase,
|
|
||||||
testPlanList,
|
testPlanList,
|
||||||
testPlanMetric,
|
testPlanMetric,
|
||||||
testPlanRun,
|
testPlanRun,
|
||||||
|
@ -583,17 +583,17 @@ export default {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
stageFilters: [
|
stageFilters: [
|
||||||
{ text: this.$t("test_track.plan.smoke_test"), value: "smoke" },
|
{text: this.$t("test_track.plan.smoke_test"), value: "smoke"},
|
||||||
{ text: this.$t("test_track.plan.system_test"), value: "system" },
|
{text: this.$t("test_track.plan.system_test"), value: "system"},
|
||||||
{
|
{
|
||||||
text: this.$t("test_track.plan.regression_test"),
|
text: this.$t("test_track.plan.regression_test"),
|
||||||
value: "regression",
|
value: "regression",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
scheduleFilters: [
|
scheduleFilters: [
|
||||||
{ text: this.$t("test_track.plan.schedule_enabled"), value: "OPEN" },
|
{text: this.$t("test_track.plan.schedule_enabled"), value: "OPEN"},
|
||||||
{ text: this.$t("test_track.issue.status_closed"), value: "SHUT" },
|
{text: this.$t("test_track.issue.status_closed"), value: "SHUT"},
|
||||||
{ text: this.$t("schedule.not_set"), value: "NOTSET" },
|
{text: this.$t("schedule.not_set"), value: "NOTSET"},
|
||||||
],
|
],
|
||||||
currentPlanId: "",
|
currentPlanId: "",
|
||||||
stageOption: [],
|
stageOption: [],
|
||||||
|
@ -634,7 +634,7 @@ export default {
|
||||||
batchExecuteType: "serial",
|
batchExecuteType: "serial",
|
||||||
//是否有UI执行用例
|
//是否有UI执行用例
|
||||||
haveUICase: false,
|
haveUICase: false,
|
||||||
//是否有API/性能执行用例
|
//是否有API执行用例
|
||||||
haveOtherExecCase: false,
|
haveOtherExecCase: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -709,7 +709,7 @@ export default {
|
||||||
this.condition.projectId = getCurrentProjectID();
|
this.condition.projectId = getCurrentProjectID();
|
||||||
this.cardLoading = true;
|
this.cardLoading = true;
|
||||||
testPlanList(
|
testPlanList(
|
||||||
{ pageNum: this.currentPage, pageSize: this.pageSize },
|
{pageNum: this.currentPage, pageSize: this.pageSize},
|
||||||
this.condition
|
this.condition
|
||||||
).then((response) => {
|
).then((response) => {
|
||||||
this.cardLoading = false;
|
this.cardLoading = false;
|
||||||
|
@ -763,31 +763,6 @@ export default {
|
||||||
this.$set(item, "passed", metricData.passed);
|
this.$set(item, "passed", metricData.passed);
|
||||||
this.$set(item, "tested", metricData.tested);
|
this.$set(item, "tested", metricData.tested);
|
||||||
this.$set(item, "total", metricData.total);
|
this.$set(item, "total", metricData.total);
|
||||||
this.$set(
|
|
||||||
item,
|
|
||||||
"testPlanTestCaseCount",
|
|
||||||
metricData.testPlanTestCaseCount
|
|
||||||
);
|
|
||||||
this.$set(
|
|
||||||
item,
|
|
||||||
"testPlanApiCaseCount",
|
|
||||||
metricData.testPlanApiCaseCount
|
|
||||||
);
|
|
||||||
this.$set(
|
|
||||||
item,
|
|
||||||
"testPlanApiScenarioCount",
|
|
||||||
metricData.testPlanApiScenarioCount
|
|
||||||
);
|
|
||||||
this.$set(
|
|
||||||
item,
|
|
||||||
"testPlanUiScenarioCount",
|
|
||||||
metricData.testPlanUiScenarioCount
|
|
||||||
);
|
|
||||||
this.$set(
|
|
||||||
item,
|
|
||||||
"testPlanLoadCaseCount",
|
|
||||||
metricData.testPlanLoadCaseCount
|
|
||||||
);
|
|
||||||
if (metricData.followUsers) {
|
if (metricData.followUsers) {
|
||||||
let data = metricData.followUsers;
|
let data = metricData.followUsers;
|
||||||
let follow = "";
|
let follow = "";
|
||||||
|
@ -820,7 +795,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
resetTestPlanRow(item) {
|
resetTestPlanRow(item) {
|
||||||
if (!isMetricLoadOver) {
|
if (!item.isMetricLoadOver) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$set(item, "isMetricLoadOver", true);
|
this.$set(item, "isMetricLoadOver", true);
|
||||||
|
@ -834,11 +809,6 @@ export default {
|
||||||
this.$set(item, "passed", 0);
|
this.$set(item, "passed", 0);
|
||||||
this.$set(item, "tested", 0);
|
this.$set(item, "tested", 0);
|
||||||
this.$set(item, "total", 0);
|
this.$set(item, "total", 0);
|
||||||
this.$set(item, "testPlanTestCaseCount", 0);
|
|
||||||
this.$set(item, "testPlanApiCaseCount", 0);
|
|
||||||
this.$set(item, "testPlanApiScenarioCount", 0);
|
|
||||||
this.$set(item, "testPlanUiScenarioCount", 0);
|
|
||||||
this.$set(item, "testPlanLoadCaseCount", 0);
|
|
||||||
},
|
},
|
||||||
copyData(status) {
|
copyData(status) {
|
||||||
return JSON.parse(JSON.stringify(this.dataMap.get(status)));
|
return JSON.parse(JSON.stringify(this.dataMap.get(status)));
|
||||||
|
@ -928,7 +898,7 @@ export default {
|
||||||
handleRunBatch() {
|
handleRunBatch() {
|
||||||
this.showExecute = false;
|
this.showExecute = false;
|
||||||
let mode = this.batchExecuteType;
|
let mode = this.batchExecuteType;
|
||||||
let param = { mode };
|
let param = {mode};
|
||||||
const ids = [];
|
const ids = [];
|
||||||
if (this.condition.selectAll) {
|
if (this.condition.selectAll) {
|
||||||
param.isAll = true;
|
param.isAll = true;
|
||||||
|
@ -1049,8 +1019,19 @@ export default {
|
||||||
this.$refs.testCaseReportView.open(plan);
|
this.$refs.testCaseReportView.open(plan);
|
||||||
},
|
},
|
||||||
async scheduleTask(row) {
|
async scheduleTask(row) {
|
||||||
|
this.haveUICase = false;
|
||||||
|
this.haveOtherExecCase = false;
|
||||||
|
|
||||||
row.redirectFrom = "testPlan";
|
row.redirectFrom = "testPlan";
|
||||||
this.currentPlanId = row.id;
|
this.currentPlanId = row.id;
|
||||||
|
|
||||||
|
this.haveUICase = row.testPlanUiScenarioCount > 0;
|
||||||
|
let haveApiCase = row.testPlanApiCaseCount > 0;
|
||||||
|
let haveScenarioCase = row.testPlanApiScenarioCount > 0;
|
||||||
|
if (haveApiCase || haveScenarioCase) {
|
||||||
|
this.haveOtherExecCase = true;
|
||||||
|
}
|
||||||
|
|
||||||
this.$refs.scheduleMaintain.open(row);
|
this.$refs.scheduleMaintain.open(row);
|
||||||
},
|
},
|
||||||
saveSortField(key, orders) {
|
saveSortField(key, orders) {
|
||||||
|
@ -1074,18 +1055,27 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleRun(row) {
|
handleRun(row) {
|
||||||
|
this.haveUICase = false;
|
||||||
|
this.haveOtherExecCase = false;
|
||||||
|
|
||||||
this.currentPlanId = row.id;
|
this.currentPlanId = row.id;
|
||||||
this.haveUIScenario().then(() => {
|
let haveApiCase = row.testPlanApiCaseCount > 0;
|
||||||
testPlanHaveExecCase(row.id).then(async (res) => {
|
let haveScenarioCase = row.testPlanApiScenarioCount > 0;
|
||||||
this.haveOtherExecCase = res.data;
|
let haveLoadCase = row.testPlanLoadCaseCount > 0;
|
||||||
|
this.haveUICase = row.testPlanUiScenarioCount > 0;
|
||||||
|
|
||||||
|
if (!this.haveUICase && !haveApiCase && !haveScenarioCase && haveLoadCase) {
|
||||||
|
//只有性能测试,则直接执行
|
||||||
|
this.$refs.runMode.handleCommand("run");
|
||||||
|
} else if (haveApiCase || haveScenarioCase || this.haveUICase) {
|
||||||
|
this.haveOtherExecCase = true;
|
||||||
//因为ui没有资源池,这里必须分离两个变量
|
//因为ui没有资源池,这里必须分离两个变量
|
||||||
if (this.haveOtherExecCase || this.haveUICase) {
|
|
||||||
this.$refs.runMode.open("API", row.runModeConfig);
|
this.$refs.runMode.open("API", row.runModeConfig);
|
||||||
} else {
|
} else {
|
||||||
|
//没有可执行的资源,则直接跳转到计划里
|
||||||
this.$router.push("/track/plan/view/" + row.id);
|
this.$router.push("/track/plan/view/" + row.id);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
_handleRun(config) {
|
_handleRun(config) {
|
||||||
let defaultPlanEnvMap = config.testPlanDefaultEnvMap;
|
let defaultPlanEnvMap = config.testPlanDefaultEnvMap;
|
||||||
|
@ -1183,18 +1173,18 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
haveUIScenario() {
|
// haveUIScenario() {
|
||||||
if (hasLicense()) {
|
// if (hasLicense()) {
|
||||||
return new Promise((resolve) => {
|
// return new Promise((resolve) => {
|
||||||
testPlanHaveUiCase(this.currentPlanId).then((r) => {
|
// testPlanHaveUiCase(this.currentPlanId).then((r) => {
|
||||||
this.haveUICase = r.data;
|
// this.haveUICase = r.data;
|
||||||
resolve();
|
// resolve();
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
return new Promise((resolve) => resolve());
|
// return new Promise((resolve) => resolve());
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<!-- {{ JSON.stringify(eventData) }}-->
|
||||||
<el-radio-group
|
<el-radio-group
|
||||||
v-model="radio"
|
v-model="radio"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@change="radioChange"
|
@change="radioChange"
|
||||||
class="radio-change"
|
class="radio-change"
|
||||||
>
|
>
|
||||||
|
<el-radio v-show="!isEnvSaved" :label="ENV_TYPE.DEFAULT">{{
|
||||||
|
$t("workspace.env_group.case_env")
|
||||||
|
}}
|
||||||
|
</el-radio>
|
||||||
<el-radio :label="ENV_TYPE.JSON">{{
|
<el-radio :label="ENV_TYPE.JSON">{{
|
||||||
$t("workspace.env_group.env_list")
|
$t("workspace.env_group.env_list")
|
||||||
}}</el-radio>
|
}}
|
||||||
|
</el-radio>
|
||||||
<el-radio :label="ENV_TYPE.GROUP" v-if="showEnvGroup"
|
<el-radio :label="ENV_TYPE.GROUP" v-if="showEnvGroup"
|
||||||
>{{ $t("workspace.env_group.name")
|
>{{
|
||||||
|
$t("workspace.env_group.name")
|
||||||
}}<i class="el-icon-tickets mode-span" @click="viewGroup"></i
|
}}<i class="el-icon-tickets mode-span" @click="viewGroup"></i
|
||||||
></el-radio>
|
></el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
|
@ -37,7 +44,7 @@
|
||||||
/>
|
/>
|
||||||
<span class="project-name" :title="getProjectName(pe.id)">
|
<span class="project-name" :title="getProjectName(pe.id)">
|
||||||
{{ getProjectName(pe.id) }} </span
|
{{ getProjectName(pe.id) }} </span
|
||||||
><br />
|
><br/>
|
||||||
<div v-if="pe.expendStatus === 'open'">
|
<div v-if="pe.expendStatus === 'open'">
|
||||||
<el-radio-group
|
<el-radio-group
|
||||||
v-model="pe.envRadio"
|
v-model="pe.envRadio"
|
||||||
|
@ -47,10 +54,12 @@
|
||||||
>
|
>
|
||||||
<el-radio label="DEFAULT_ENV" style="margin-top: 7px">{{
|
<el-radio label="DEFAULT_ENV" style="margin-top: 7px">{{
|
||||||
$t("api_test.environment.default_environment")
|
$t("api_test.environment.default_environment")
|
||||||
}}</el-radio>
|
}}
|
||||||
|
</el-radio>
|
||||||
<el-radio label="CUSTOMIZE_ENV" style="margin-top: 7px">{{
|
<el-radio label="CUSTOMIZE_ENV" style="margin-top: 7px">{{
|
||||||
$t("api_test.environment.choose_new_environment")
|
$t("api_test.environment.choose_new_environment")
|
||||||
}}</el-radio>
|
}}
|
||||||
|
</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<el-tag
|
<el-tag
|
||||||
v-show="!pe.showEnvSelect"
|
v-show="!pe.showEnvSelect"
|
||||||
|
@ -58,7 +67,8 @@
|
||||||
:key="index"
|
:key="index"
|
||||||
size="mini"
|
size="mini"
|
||||||
style="margin-left: 0; margin-right: 2px; margin-top: 8px"
|
style="margin-left: 0; margin-right: 2px; margin-top: 8px"
|
||||||
>{{ itemName }}</el-tag
|
>{{ itemName }}
|
||||||
|
</el-tag
|
||||||
>
|
>
|
||||||
<el-select
|
<el-select
|
||||||
v-show="pe.showEnvSelect"
|
v-show="pe.showEnvSelect"
|
||||||
|
@ -141,19 +151,16 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ENV_TYPE } from "metersphere-frontend/src/utils/constants";
|
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
|
||||||
import {
|
import {environmentGetALL, getEnvironmentOptions,} from "metersphere-frontend/src/api/environment";
|
||||||
environmentGetALL,
|
|
||||||
getEnvironmentOptions,
|
|
||||||
} from "metersphere-frontend/src/api/environment";
|
|
||||||
import MsTag from "metersphere-frontend/src/components/MsTag";
|
import MsTag from "metersphere-frontend/src/components/MsTag";
|
||||||
import EnvironmentGroup from "@/business/plan/env/EnvironmentGroupList";
|
import EnvironmentGroup from "@/business/plan/env/EnvironmentGroupList";
|
||||||
import { getEnvironmentByProjectId } from "@/api/remote/api/api-environment";
|
import {getEnvironmentByProjectId} from "@/api/remote/api/api-environment";
|
||||||
import { parseEnvironment } from "metersphere-frontend/src/model/EnvironmentModel";
|
import {parseEnvironment} from "metersphere-frontend/src/model/EnvironmentModel";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "EnvSelectPopover",
|
name: "EnvSelectPopover",
|
||||||
components: { MsTag, EnvironmentGroup },
|
components: {MsTag, EnvironmentGroup},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
radio: this.environmentType,
|
radio: this.environmentType,
|
||||||
|
@ -189,6 +196,11 @@ export default {
|
||||||
},
|
},
|
||||||
projectIds: Set,
|
projectIds: Set,
|
||||||
projectList: Array,
|
projectList: Array,
|
||||||
|
//环境是否保存过
|
||||||
|
isEnvSaved: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
projectEnvMap: Object,
|
projectEnvMap: Object,
|
||||||
envMap: Map,
|
envMap: Map,
|
||||||
environmentType: String,
|
environmentType: String,
|
||||||
|
@ -233,7 +245,7 @@ export default {
|
||||||
this.groups = data ? data : [];
|
this.groups = data ? data : [];
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
getEnvironmentOptions({ projectIds: [...this.projectIds] }).then(
|
getEnvironmentOptions({projectIds: [...this.projectIds]}).then(
|
||||||
(res) => {
|
(res) => {
|
||||||
let groups = res.data;
|
let groups = res.data;
|
||||||
this.disabledGroups = groups.filter(
|
this.disabledGroups = groups.filter(
|
||||||
|
|
|
@ -75,18 +75,12 @@
|
||||||
<script>
|
<script>
|
||||||
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
|
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
|
||||||
import MxVersionSelect from "metersphere-frontend/src/components/version/MxVersionSelect";
|
import MxVersionSelect from "metersphere-frontend/src/components/version/MxVersionSelect";
|
||||||
import {
|
import {apiDefinitionListBatch, apiDefinitionRelevance,} from "@/api/remote/api/api-definition";
|
||||||
apiDefinitionListBatch,
|
import {apiTestCaseListBlobs, apiTestCaseRelevance,} from "@/api/remote/api/api-case";
|
||||||
apiDefinitionRelevance,
|
|
||||||
} from "@/api/remote/api/api-definition";
|
|
||||||
import {
|
|
||||||
apiTestCaseListBlobs,
|
|
||||||
apiTestCaseRelevance,
|
|
||||||
} from "@/api/remote/api/api-case";
|
|
||||||
import RelevanceApiList from "@/business/plan/view/comonents/api/RelevanceApiList";
|
import RelevanceApiList from "@/business/plan/view/comonents/api/RelevanceApiList";
|
||||||
import RelevanceCaseList from "@/business/plan/view/comonents/api/RelevanceCaseList";
|
import RelevanceCaseList from "@/business/plan/view/comonents/api/RelevanceCaseList";
|
||||||
import MsApiModule from "@/business/plan/view/comonents/api/module/ApiModule";
|
import MsApiModule from "@/business/plan/view/comonents/api/module/ApiModule";
|
||||||
import { getVersionFilters } from "@/business/utils/sdk-utils";
|
import {getVersionFilters} from "@/business/utils/sdk-utils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TestCaseApiRelevance",
|
name: "TestCaseApiRelevance",
|
||||||
|
@ -244,13 +238,6 @@ export default {
|
||||||
|
|
||||||
postRelevance(relevanceList, environmentId, selectIds, protocol) {
|
postRelevance(relevanceList, environmentId, selectIds, protocol) {
|
||||||
let param = {};
|
let param = {};
|
||||||
if (protocol !== "DUBBO") {
|
|
||||||
if (!environmentId) {
|
|
||||||
this.isSaving = false;
|
|
||||||
this.$warning(this.$t("api_test.environment.select_environment"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (selectIds.length < 1) {
|
if (selectIds.length < 1) {
|
||||||
this.isSaving = false;
|
this.isSaving = false;
|
||||||
this.$warning(this.$t("test_track.plan_view.please_choose_test_case"));
|
this.$warning(this.$t("test_track.plan_view.please_choose_test_case"));
|
||||||
|
|
|
@ -35,15 +35,10 @@
|
||||||
<script>
|
<script>
|
||||||
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
|
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
|
||||||
import RelevanceScenarioList from "./RelevanceScenarioList";
|
import RelevanceScenarioList from "./RelevanceScenarioList";
|
||||||
import { ENV_TYPE } from "metersphere-frontend/src/utils/constants";
|
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
|
||||||
import {
|
import {getCurrentProjectID, getVersionFilters, hasLicense, strMapToObj,} from "@/business/utils/sdk-utils";
|
||||||
getCurrentProjectID,
|
import {testPlanAutoCheck} from "@/api/remote/plan/test-plan";
|
||||||
hasLicense,
|
import {scenarioRelevance} from "@/api/remote/plan/test-plan-scenario";
|
||||||
strMapToObj,
|
|
||||||
} from "@/business/utils/sdk-utils";
|
|
||||||
import { getVersionFilters } from "@/business/utils/sdk-utils";
|
|
||||||
import { testPlanAutoCheck } from "@/api/remote/plan/test-plan";
|
|
||||||
import { scenarioRelevance } from "@/api/remote/plan/test-plan-scenario";
|
|
||||||
import MsApiScenarioModule from "@/business/plan/view/comonents/api/module/ApiScenarioModule";
|
import MsApiScenarioModule from "@/business/plan/view/comonents/api/module/ApiScenarioModule";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -137,11 +132,6 @@ export default {
|
||||||
},
|
},
|
||||||
async saveCaseRelevance() {
|
async saveCaseRelevance() {
|
||||||
this.isSaving = true;
|
this.isSaving = true;
|
||||||
const sign = await this.$refs.apiScenarioList.checkEnv();
|
|
||||||
if (!sign) {
|
|
||||||
this.isSaving = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let selectIds = [];
|
let selectIds = [];
|
||||||
let selectRows = this.$refs.apiScenarioList.selectRows;
|
let selectRows = this.$refs.apiScenarioList.selectRows;
|
||||||
const envMap = this.$refs.apiScenarioList.projectEnvMap;
|
const envMap = this.$refs.apiScenarioList.projectEnvMap;
|
||||||
|
@ -157,15 +147,7 @@ export default {
|
||||||
selectRows.forEach((row) => {
|
selectRows.forEach((row) => {
|
||||||
selectIds.push(row.id);
|
selectIds.push(row.id);
|
||||||
});
|
});
|
||||||
if (envType === ENV_TYPE.JSON && (!envMap || envMap.size < 1)) {
|
|
||||||
this.isSaving = false;
|
|
||||||
this.$warning(this.$t("api_test.environment.select_environment"));
|
|
||||||
return false;
|
|
||||||
} else if (envType === ENV_TYPE.GROUP && !envGroupId) {
|
|
||||||
this.isSaving = false;
|
|
||||||
this.$warning(this.$t("api_test.environment.select_environment"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let param = {};
|
let param = {};
|
||||||
param.planId = this.planId;
|
param.planId = this.planId;
|
||||||
param.mapping = strMapToObj(map);
|
param.mapping = strMapToObj(map);
|
||||||
|
|
|
@ -91,14 +91,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import NodeTree from "metersphere-frontend/src/components/module/MsNodeTree";
|
import NodeTree from "metersphere-frontend/src/components/module/MsNodeTree";
|
||||||
import MsTestPlanCommonComponent from "../base/TestPlanCommonComponent";
|
import MsTestPlanCommonComponent from "../base/TestPlanCommonComponent";
|
||||||
import TestPlanApiCaseList from "./TestPlanApiCaseList";
|
import TestPlanApiCaseList from "./TestPlanApiCaseList";
|
||||||
import TestCaseApiRelevance from "./TestCaseApiRelevance";
|
import TestCaseApiRelevance from "./TestCaseApiRelevance";
|
||||||
import MsTestPlanApiScenarioList from "./TestPlanApiScenarioList";
|
import MsTestPlanApiScenarioList from "./TestPlanApiScenarioList";
|
||||||
import TestCaseScenarioRelevance from "./TestCaseScenarioRelevance";
|
import TestCaseScenarioRelevance from "./TestCaseScenarioRelevance";
|
||||||
import MsApiModule from "@/business/plan/view/comonents/api/module/ApiModule";
|
import MsApiModule from "@/business/plan/view/comonents/api/module/ApiModule";
|
||||||
import MsApiScenarioModule from "@/business/plan/view/comonents/api/module/ApiScenarioModule";
|
import MsApiScenarioModule from "@/business/plan/view/comonents/api/module/ApiScenarioModule";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TestPlanApi",
|
name: "TestPlanApi",
|
||||||
|
@ -140,19 +140,19 @@ export default {
|
||||||
this.selectNodeIds = [];
|
this.selectNodeIds = [];
|
||||||
this.moduleOptions = {};
|
this.moduleOptions = {};
|
||||||
},
|
},
|
||||||
redirectCharType(){
|
redirectCharType() {
|
||||||
if(this.redirectCharType=='scenario'){
|
if (this.redirectCharType == 'scenario') {
|
||||||
this.model = 'scenario';
|
this.model = 'scenario';
|
||||||
}else{
|
} else {
|
||||||
this.model = 'api';
|
this.model = 'api';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
checkRedirectCharType(){
|
checkRedirectCharType() {
|
||||||
if(this.redirectCharType=='scenario'){
|
if (this.redirectCharType == 'scenario') {
|
||||||
this.model = 'scenario';
|
this.model = 'scenario';
|
||||||
}else{
|
} else {
|
||||||
this.model = 'api';
|
this.model = 'api';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -124,6 +124,9 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.initProtocol();
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'condition.filterText'() {
|
'condition.filterText'() {
|
||||||
this.filter();
|
this.filter();
|
||||||
|
|
|
@ -34,13 +34,13 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
|
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
|
||||||
import { strMapToObj } from "metersphere-frontend/src/utils";
|
import {strMapToObj} from "metersphere-frontend/src/utils";
|
||||||
import { ENV_TYPE } from "metersphere-frontend/src/utils/constants";
|
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
|
||||||
import RelevanceUiScenarioList from "@/business/plan/view/comonents/ui/RelevanceUiScenarioList";
|
import RelevanceUiScenarioList from "@/business/plan/view/comonents/ui/RelevanceUiScenarioList";
|
||||||
import { testPlanAutoCheck } from "@/api/remote/plan/test-plan";
|
import {testPlanAutoCheck} from "@/api/remote/plan/test-plan";
|
||||||
import { testPlanUiScenarioRelevanceListIds } from "@/api/remote/ui/test-plan-ui-scenario-case";
|
import {testPlanUiScenarioRelevanceListIds} from "@/api/remote/ui/test-plan-ui-scenario-case";
|
||||||
import UiScenarioModule from "@/business/plan/view/comonents/ui/UiScenarioModule";
|
import UiScenarioModule from "@/business/plan/view/comonents/ui/UiScenarioModule";
|
||||||
import { uiAutomationRelevance } from "@/api/remote/ui/api-scenario";
|
import {uiAutomationRelevance} from "@/api/remote/ui/api-scenario";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TestCaseUiScenarioRelevance",
|
name: "TestCaseUiScenarioRelevance",
|
||||||
|
@ -163,12 +163,6 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!envMap || envMap.size == 0) {
|
|
||||||
this.isSaving = false;
|
|
||||||
this.$warning(this.$t("api_test.environment.select_environment"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let param = {};
|
let param = {};
|
||||||
param.planId = this.planId;
|
param.planId = this.planId;
|
||||||
param.mapping = strMapToObj(map);
|
param.mapping = strMapToObj(map);
|
||||||
|
|
Loading…
Reference in New Issue