This commit is contained in:
wenyann 2021-03-01 15:21:32 +08:00
commit dd96caedd7
31 changed files with 412 additions and 258 deletions

View File

@ -189,7 +189,7 @@ public class MsScenario extends MsTestElement {
}
});
}
if (config != null && config.getConfig() != null && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
&& CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables())) {
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")

View File

@ -47,8 +47,10 @@ import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@ -166,7 +168,7 @@ public abstract class MsTestElement {
}
public Arguments addArguments(ParameterConfig config) {
if (config != null && config.getConfig() != null && config.getConfig().get(this.getProjectId()) != null && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
&& CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables())) {
Arguments arguments = new Arguments();
arguments.setEnabled(true);
@ -181,11 +183,14 @@ public abstract class MsTestElement {
return null;
}
protected EnvironmentConfig getEnvironmentConfig(String environmentId) {
protected Map<String, EnvironmentConfig> getEnvironmentConfig(String environmentId) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
if (environment != null && environment.getConfig() != null) {
return JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
// 单独接口执行
Map<String, EnvironmentConfig> map = new HashMap<>();
map.put(this.getProjectId(), JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class));
return map;
}
return null;
}
@ -269,7 +274,7 @@ public abstract class MsTestElement {
getFullPath(element.getParent(), path);
}
protected String getParentName(MsTestElement parent, ParameterConfig config) {
protected String getParentName(MsTestElement parent) {
if (parent != null) {
if (MsTestElementConstants.LoopController.name().equals(parent.getType())) {
MsLoopController loopController = (MsLoopController) parent;

View File

@ -30,4 +30,11 @@ public class ParameterConfig {
* 项目ID支持单接口执行
*/
private String projectId;
public boolean isEffective(String projectId) {
if (this.config != null && this.config.get(projectId) != null) {
return true;
}
return false;
}
}

View File

@ -1,19 +1,15 @@
package io.metersphere.api.dto.definition.request.auth;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.utils.CommonBeanFactory;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.protocol.http.control.AuthManager;
import org.apache.jmeter.protocol.http.control.Authorization;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
@ -66,18 +62,37 @@ public class MsAuthManager extends MsTestElement {
if (this.url != null) {
auth.setURL(this.url);
} else {
if (environment != null) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environmentWithBLOBs = environmentService.get(environment);
EnvironmentConfig envConfig = JSONObject.parseObject(environmentWithBLOBs.getConfig(), EnvironmentConfig.class);
this.url = envConfig.getHttpConfig().getProtocol() + "://" + envConfig.getHttpConfig().getSocket();
if (config != null && config.isEffective(this.getProjectId())) {
if (config.isEffective(this.getProjectId())) {
String url = config.getConfig().get(this.getProjectId()).getHttpConfig().getProtocol() + "://" + config.getConfig().get(this.getProjectId()).getHttpConfig().getSocket();
auth.setURL(url);
}
}
}
auth.setDomain(this.domain);
auth.setUser(this.username);
auth.setPass(this.password);
auth.setMechanism(AuthManager.Mechanism.DIGEST);
authManager.addAuth(auth);
tree.add(authManager);
}
public void setAuth(HashTree tree, MsAuthManager msAuthManager, HTTPSamplerProxy samplerProxy) {
try {
AuthManager authManager = new AuthManager();
authManager.setEnabled(true);
authManager.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "AuthManager");
authManager.setProperty(TestElement.TEST_CLASS, AuthManager.class.getName());
authManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("AuthPanel"));
Authorization auth = new Authorization();
auth.setURL(samplerProxy.getUrl().toString());
auth.setDomain(samplerProxy.getDomain());
auth.setUser(msAuthManager.getUsername());
auth.setPass(msAuthManager.getPassword());
auth.setMechanism(AuthManager.Mechanism.DIGEST);
authManager.addAuth(auth);
tree.add(authManager);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -36,7 +36,7 @@ public class MsJSR223Processor extends MsTestElement {
} else {
processor.setName("JSR223Processor");
}
String name = this.getParentName(this.getParent(), config);
String name = this.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
processor.setName(this.getName() + "<->" + name);
}

View File

@ -76,7 +76,7 @@ public class MsDubboSampler extends MsTestElement {
DubboSample sampler = new DubboSample();
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = this.getParentName(this.getParent(), config);
String name = this.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + "<->" + name);
}

View File

@ -8,7 +8,6 @@ import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
import io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ScriptEngineUtils;
@ -101,7 +100,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = this.getParentName(this.getParent(), config);
String name = this.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + "<->" + name);
}
@ -114,14 +113,10 @@ public class MsHTTPSamplerProxy extends MsTestElement {
sampler.setFollowRedirects(this.isFollowRedirects());
sampler.setUseKeepAlive(true);
sampler.setDoMultipart(this.isDoMultipartPost());
if (config != null && config.getConfig() != null) {
config.setConfig(config.getConfig());
} else {
if (config.getConfig() == null) {
// 单独接口执行
this.setProjectId(config.getProjectId());
Map<String, EnvironmentConfig> map = new HashMap<>();
map.put(this.getProjectId(), getEnvironmentConfig(useEnvironment));
config.setConfig(map);
config.setConfig(getEnvironmentConfig(useEnvironment));
}
// 添加环境中的公共变量
@ -130,7 +125,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
tree.add(arguments);
}
try {
if (config != null && config.getConfig() != null && config.getConfig().get(this.getProjectId()) != null) {
if (config.isEffective(this.getProjectId())) {
String url = config.getConfig().get(this.getProjectId()).getHttpConfig().getProtocol() + "://" + config.getConfig().get(this.getProjectId()).getHttpConfig().getSocket();
// 补充如果是完整URL 则用自身URL
boolean isUrl = false;
@ -219,13 +214,13 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
// 通用请求Headers
if (config != null && config.getConfig() != null && config.getConfig().get(this.getProjectId()) != null && config.getConfig().get(this.getProjectId()).getHttpConfig() != null
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getHttpConfig() != null
&& CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getHttpConfig().getHeaders())) {
setHeader(httpSamplerTree, config.getConfig().get(this.getProjectId()).getHttpConfig().getHeaders());
}
//判断是否要开启DNS
if (config != null && config.getConfig() != null && config.getConfig().get(this.getProjectId()) != null && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
&& config.getConfig().get(this.getProjectId()).getCommonConfig().isEnableHost()) {
MsDNSCacheManager.addEnvironmentVariables(httpSamplerTree, this.getName(), config.getConfig().get(this.getProjectId()));
MsDNSCacheManager.addEnvironmentDNS(httpSamplerTree, this.getName(), config.getConfig().get(this.getProjectId()));
@ -236,7 +231,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
}
if (this.authManager != null) {
this.authManager.toHashTree(tree, hashTree, config);
this.authManager.setAuth(tree, this.authManager, sampler);
}
}

View File

@ -113,7 +113,7 @@ public class MsJDBCSampler extends MsTestElement {
JDBCSampler sampler = new JDBCSampler();
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = this.getParentName(this.getParent(), config);
String name = this.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + "<->" + name);
}

View File

@ -23,9 +23,7 @@ import org.apache.jmeter.testelement.property.StringProperty;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.*;
@Data
@EqualsAndHashCode(callSuper = true)
@ -59,7 +57,7 @@ public class MsTCPSampler extends MsTestElement {
private String password = "";
@JSONField(ordinal = 33)
private String request;
// @JSONField(ordinal = 34)
// @JSONField(ordinal = 34)
// private Object requestResult;
@JSONField(ordinal = 35)
private List<KeyValue> parameters;
@ -77,7 +75,11 @@ public class MsTCPSampler extends MsTestElement {
if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) {
this.getRefElement(this);
}
// config.setConfig(getEnvironmentConfig(useEnvironment));
if (config.getConfig() == null) {
// 单独接口执行
this.setProjectId(config.getProjectId());
config.setConfig(getEnvironmentConfig(useEnvironment));
}
parseEnvironment(config.getConfig().get(this.projectId));
// 添加环境中的公共变量
@ -111,7 +113,7 @@ public class MsTCPSampler extends MsTestElement {
TCPSampler tcpSampler = new TCPSampler();
tcpSampler.setEnabled(this.isEnable());
tcpSampler.setName(this.getName());
String name = this.getParentName(this.getParent(), config);
String name = this.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
tcpSampler.setName(this.getName() + "<->" + name);
}

View File

@ -13,6 +13,7 @@ import io.metersphere.api.dto.definition.parse.ApiDefinitionImportParserFactory;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.ScheduleInfoSwaggerUrlRequest;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult;
import io.metersphere.api.dto.swaggerurl.SwaggerUrlRequest;
@ -85,6 +86,8 @@ public class ApiDefinitionService {
private ScheduleMapper scheduleMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private ApiTestEnvironmentService environmentService;
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24);
@ -427,8 +430,19 @@ public class ApiDefinitionService {
public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
FileUtils.createBodyFiles(bodyUploadIds, bodyFiles);
ParameterConfig config = new ParameterConfig();
config.setProjectId(request.getProjectId());
Map<String, EnvironmentConfig> envConfig = new HashMap<>();
Map<String, String> map = request.getEnvironmentMap();
if (map != null && map.size() > 0) {
ApiTestEnvironmentWithBLOBs environment = environmentService.get(map.get(request.getProjectId()));
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
envConfig.put(request.getProjectId(), env);
config.setConfig(envConfig);
}
HashTree hashTree = request.getTestElement().generateHashTree(config);
String runMode = ApiRunMode.DEFINITION.name();
if (StringUtils.isNotBlank(request.getType()) && StringUtils.equals(request.getType(), ApiRunMode.API_PLAN.name())) {

View File

@ -6,8 +6,8 @@
:destroy-on-close="true"
:before-close="handleClose">
<div v-for="pe in data" :key="pe.id">
<div>
<div v-loading="result.loading">
<div v-for="pe in data" :key="pe.id" style="margin-left: 20px;">
{{ getProjectName(pe.id) }}
<el-select v-model="pe['selectEnv']" placeholder="请选择环境" style="margin-left:10px; margin-top: 10px;"
size="small">
@ -29,51 +29,55 @@
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" size="small"> </el-button>
<el-button type="primary" @click="handleConfirm" size="small"> </el-button>
</span>
<el-button @click="dialogVisible = false" size="small"> </el-button>
<el-button type="primary" @click="handleConfirm" size="small"> </el-button>
</span>
<!-- 环境配置 -->
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
</el-dialog>
</template>
<script>
import {parseEnvironment} from "@/business/components/api/test/model/EnvironmentModel";
import ApiEnvironmentConfig from "@/business/components/api/definition/components/environment/ApiEnvironmentConfig";
export default {
name: "ApiScenarioEnv",
components: {ApiEnvironmentConfig},
props: {
envMap: Map,
projectIds: Set,
envMap: Map
projectList: Array
},
data() {
return {
dialogVisible: false,
projects: [],
data: [],
result: {},
projects: [],
environmentId: '',
environments: []
environments: [],
dialogVisible: false
}
},
created() {
this.getWsProjects();
},
methods: {
handleClose() {
this.dialogVisible = false;
},
init() {
this.projectIds.forEach(id => {
let item = {id: id, envs: [], selectEnv: ""};
this.data.push(item);
this.result = this.$get('/api/environment/list/' + id, res => {
let envs = res.data;
envs.forEach(environment => {
parseEnvironment(environment);
});
let item = {};
item.id = id;
item.envs = envs;
item.selectEnv = this.envMap.get(id);
this.data.push(item)
//
let temp = this.data.find(dt => dt.id === id);
temp.envs = envs;
temp.selectEnv = this.envMap.get(id);
})
})
},
@ -84,13 +88,8 @@ export default {
this.init();
}
},
getWsProjects() {
this.$get("/project/listAll", res => {
this.projects = res.data;
})
},
getProjectName(id) {
const project = this.projects.find(p => p.id === id);
const project = this.projectList.find(p => p.id === id);
return project ? project.name : "";
},
openEnvironmentConfig(projectId) {
@ -123,7 +122,7 @@ export default {
this.data.forEach(dt => {
if (!dt.selectEnv) {
sign = false;
return;
return false;
}
})
} else {
@ -137,12 +136,14 @@ export default {
return true;
},
environmentConfigClose(id) {
// todo
// todo
}
}
}
</script>
<style scoped>
.ms-scenario-button {
margin-left: 20px;
}
</style>

View File

@ -150,14 +150,14 @@
break;
}
},
list() {
list(projectId) {
let url = undefined;
if (this.isPlanModel) {
url = '/api/automation/module/list/plan/' + this.planId;
} else if (this.isRelevanceModel) {
url = "/api/automation/module/list/" + this.relevanceProjectId;
} else {
url = "/api/automation/module/list/" + this.projectId;
url = "/api/automation/module/list/" + (projectId ? projectId : this.projectId);
if (!this.projectId) {
return;
}

View File

@ -2,7 +2,7 @@
<div></div>
</template>
<script>
import {getUUID, getCurrentProjectID} from "@/common/js/utils";
import {getUUID, getCurrentProjectID, strMapToObj} from "@/common/js/utils";
import {createComponent} from "../../definition/components/jmeter/components";
export default {
@ -117,22 +117,15 @@
threadGroup.hashTree.push(this.runData);
testPlan.hashTree.push(threadGroup);
let reqObj = {id: this.reportId, reportId: this.reportId, scenarioName: this.runData.name,
scenarioId: this.runData.id, testElement: testPlan, projectId: getCurrentProjectID(), environmentMap: this.strMapToObj(map)};
scenarioId: this.runData.id, testElement: testPlan, projectId: getCurrentProjectID(), environmentMap: strMapToObj(map)};
let bodyFiles = this.getBodyUploadFiles(reqObj);
let url = "/api/automation/run/debug";
this.$fileUpload(url, null, bodyFiles, reqObj, response => {
this.runId = response.data;
this.$emit('runRefresh', {});
}, erro => {
}, error => {
});
},
strMapToObj(strMap){
let obj= Object.create(null);
for (let[k,v] of strMap) {
obj[k] = v;
}
return obj;
}
}
}
</script>

View File

@ -113,23 +113,23 @@
</el-col>
<el-col :span="7" class="ms-col-one ms-font">
<el-link type="primary" @click="handleEnv">环境配置</el-link>
<!-- <el-select v-model="currentEnvironmentId" size="small" class="ms-htt-width"-->
<!-- :placeholder="$t('api_test.definition.request.run_env')"-->
<!-- clearable>-->
<!-- <el-option v-for="(environment, index) in environments" :key="index"-->
<!-- :label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"-->
<!-- :value="environment.id"/>-->
<!-- <el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">-->
<!-- {{ $t('api_test.environment.environment_config') }}-->
<!-- </el-button>-->
<!-- <template v-slot:empty>-->
<!-- <div class="empty-environment">-->
<!-- <el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">-->
<!-- {{ $t('api_test.environment.environment_config') }}-->
<!-- </el-button>-->
<!-- </div>-->
<!-- </template>-->
<!-- </el-select>-->
<!-- <el-select v-model="currentEnvironmentId" size="small" class="ms-htt-width"-->
<!-- :placeholder="$t('api_test.definition.request.run_env')"-->
<!-- clearable>-->
<!-- <el-option v-for="(environment, index) in environments" :key="index"-->
<!-- :label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"-->
<!-- :value="environment.id"/>-->
<!-- <el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">-->
<!-- {{ $t('api_test.environment.environment_config') }}-->
<!-- </el-button>-->
<!-- <template v-slot:empty>-->
<!-- <div class="empty-environment">-->
<!-- <el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">-->
<!-- {{ $t('api_test.environment.environment_config') }}-->
<!-- </el-button>-->
<!-- </div>-->
<!-- </template>-->
<!-- </el-select>-->
</el-col>
<el-col :span="2">
@ -149,7 +149,7 @@
<span class="custom-tree-node father" slot-scope="{ node, data}" style="width: 96%">
<!-- 步骤组件-->
<ms-component-config :type="data.type" :scenario="data" :response="response" :currentScenario="currentScenario"
:currentEnvironmentId="currentEnvironmentId" :node="node" :project-list="projectList"
:currentEnvironmentId="currentEnvironmentId" :node="node" :project-list="projectList" :env-map="projectEnvMap"
@remove="remove" @copyRow="copyRow" @suggestClick="suggestClick" @refReload="reload"/>
</span>
</el-tree>
@ -186,7 +186,8 @@
<!--场景导入 -->
<scenario-relevance @save="addScenario" ref="scenarioRelevance"/>
<api-scenario-env :project-ids="projectIds" :env-map="projectEnvMap" ref="apiScenarioEnv" @setProjectEnvMap="setProjectEnvMap"/>
<api-scenario-env :project-ids="projectIds" :env-map="projectEnvMap"
ref="apiScenarioEnv" @setProjectEnvMap="setProjectEnvMap" :project-list="projectList"/>
<!-- 环境 -->
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
@ -208,47 +209,47 @@
</template>
<script>
import {API_STATUS, PRIORITY} from "../../definition/model/JsonData";
import {WORKSPACE_ID} from '@/common/js/constants';
import {
Assertions,
ConstantTimer,
Extract,
IfController,
JSR223Processor,
LoopController
} from "../../definition/model/ApiTestModel";
import {parseEnvironment} from "../../definition/model/EnvironmentModel";
import {ELEMENT_TYPE, ELEMENTS} from "./Setting";
import MsApiCustomize from "./ApiCustomize";
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig";
import MsInputTag from "./MsInputTag";
import MsRun from "./DebugRun";
import MsApiReportDetail from "../report/ApiReportDetail";
import MsVariableList from "./variable/VariableList";
import ApiImport from "../../definition/components/import/ApiImport";
import "@/common/css/material-icons.css"
import OutsideClick from "@/common/js/outside-click";
import ScenarioApiRelevance from "./api/ApiRelevance";
import ScenarioRelevance from "./api/ScenarioRelevance";
import MsComponentConfig from "./component/ComponentConfig";
import {handleCtrlSEvent} from "../../../../../common/js/utils";
import {getProject} from "@/business/components/api/automation/scenario/event";
import ApiScenarioEnv from "@/business/components/api/automation/scenario/ApiScenarioEnv";
import {API_STATUS, PRIORITY} from "../../definition/model/JsonData";
import {WORKSPACE_ID} from '@/common/js/constants';
import {
Assertions,
ConstantTimer,
Extract,
IfController,
JSR223Processor,
LoopController
} from "../../definition/model/ApiTestModel";
import {parseEnvironment} from "../../definition/model/EnvironmentModel";
import {ELEMENT_TYPE, ELEMENTS} from "./Setting";
import MsApiCustomize from "./ApiCustomize";
import {getCurrentProjectID, getUUID, objToStrMap, strMapToObj} from "@/common/js/utils";
import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig";
import MsInputTag from "./MsInputTag";
import MsRun from "./DebugRun";
import MsApiReportDetail from "../report/ApiReportDetail";
import MsVariableList from "./variable/VariableList";
import ApiImport from "../../definition/components/import/ApiImport";
import "@/common/css/material-icons.css"
import OutsideClick from "@/common/js/outside-click";
import ScenarioApiRelevance from "./api/ApiRelevance";
import ScenarioRelevance from "./api/ScenarioRelevance";
import MsComponentConfig from "./component/ComponentConfig";
import {handleCtrlSEvent} from "../../../../../common/js/utils";
import {getProject} from "@/business/components/api/automation/scenario/event";
import ApiScenarioEnv from "@/business/components/api/automation/scenario/ApiScenarioEnv";
export default {
name: "EditApiScenario",
props: {
moduleOptions: Array,
currentScenario: {},
},
components: {
ApiScenarioEnv,
MsVariableList,
ScenarioRelevance,
ScenarioApiRelevance,
ApiEnvironmentConfig,
export default {
name: "EditApiScenario",
props: {
moduleOptions: Array,
currentScenario: {},
},
components: {
ApiScenarioEnv,
MsVariableList,
ScenarioRelevance,
ScenarioApiRelevance,
ApiEnvironmentConfig,
MsApiReportDetail,
MsInputTag, MsRun,
MsApiCustomize,
@ -321,7 +322,7 @@ export default {
// this.projectEnvMap.set(projectId, projectEnv);
})
},
directives: {OutsideClick},
directives: {OutsideClick},
computed: {
buttons() {
let buttons = [
@ -543,8 +544,10 @@ export default {
}
},
showAll() {
this.operatingElements = ELEMENTS.get("ALL");
this.selectedTreeNode = undefined;
if (!this.customizeVisible) {
this.operatingElements = ELEMENTS.get("ALL");
this.selectedTreeNode = undefined;
}
//this.reload();
},
apiListImport() {
@ -901,14 +904,6 @@ export default {
}
})
},
objToStrMap(obj) {
let strMap = new Map();
for (let k of Object.keys(obj)) {
strMap.set(k, obj[k]);
}
return strMap;
},
getApiScenario() {
if (this.currentScenario.tags != undefined && !(this.currentScenario.tags instanceof Array)) {
this.currentScenario.tags = JSON.parse(this.currentScenario.tags);
@ -928,7 +923,7 @@ export default {
if (obj) {
this.currentEnvironmentId = obj.environmentId;
if (obj.environmentMap) {
this.projectEnvMap = this.objToStrMap(obj.environmentMap);
this.projectEnvMap = objToStrMap(obj.environmentMap);
} else {
//
this.projectEnvMap.set(getCurrentProjectID(), obj.environmentId);
@ -964,13 +959,6 @@ export default {
})
}
},
strMapToObj(strMap){
let obj= Object.create(null);
for (let[k,v] of strMap) {
obj[k] = v;
}
return obj;
},
setParameter() {
this.currentScenario.stepTotal = this.scenarioDefinition.length;
this.currentScenario.projectId = getCurrentProjectID();
@ -984,7 +972,7 @@ export default {
variables: this.currentScenario.variables,
headers: this.currentScenario.headers,
referenced: 'Created',
environmentMap: this.strMapToObj(this.projectEnvMap),
environmentMap: strMapToObj(this.projectEnvMap),
hashTree: this.scenarioDefinition,
projectId: this.projectId,
};

View File

@ -1,8 +1,11 @@
<template>
<relevance-dialog :title="$t('api_test.definition.api_import')" ref="relevanceDialog">
<test-case-relevance-base
@setProject="setProject"
:dialog-title="$t('api_test.definition.api_import')"
ref="baseRelevance">
<template v-slot:aside>
<ms-api-module
style="margin-top: 5px;"
@nodeSelectEvent="nodeChange"
@protocolChange="handleProtocolChange"
@refreshTable="refresh"
@ -13,6 +16,7 @@
<scenario-relevance-api-list
v-if="isApiListEnable"
:project-id="projectId"
:current-protocol="currentProtocol"
:select-node-ids="selectNodeIds"
:is-api-list-enable="isApiListEnable"
@ -21,6 +25,7 @@
<scenario-relevance-case-list
v-if="!isApiListEnable"
:project-id="projectId"
:current-protocol="currentProtocol"
:select-node-ids="selectNodeIds"
:is-api-list-enable="isApiListEnable"
@ -33,8 +38,7 @@
{{ $t('api_test.scenario.reference') }}
</el-button>
</template>
</relevance-dialog>
</test-case-relevance-base>
</template>
<script>
@ -45,10 +49,12 @@ import MsAsideContainer from "../../../../common/components/MsAsideContainer";
import MsMainContainer from "../../../../common/components/MsMainContainer";
import ScenarioRelevanceApiList from "./RelevanceApiList";
import RelevanceDialog from "../../../../track/plan/view/comonents/base/RelevanceDialog";
import TestCaseRelevanceBase from "@/business/components/track/plan/view/comonents/base/TestCaseRelevanceBase";
export default {
name: "ApiRelevance",
components: {
TestCaseRelevanceBase,
RelevanceDialog,
ScenarioRelevanceApiList,
MsMainContainer, MsAsideContainer, MsContainer, MsApiModule, ScenarioRelevanceCaseList
@ -58,67 +64,82 @@ export default {
result: {},
currentProtocol: null,
selectNodeIds: [],
moduleOptions: {},
isApiListEnable: true,
}
},
methods: {
reference() {
this.save('REF');
},
copy() {
this.save('Copy');
},
save(reference) {
if (this.isApiListEnable) {
this.$emit('save', this.$refs.apiList.selectRows, 'API', reference);
this.close();
} else {
let apiCases = this.$refs.apiCaseList.selectRows;
let ids = Array.from(apiCases).map(row => row.id);
this.result = this.$post("/api/testcase/get/request", {ids: ids}, (response) => {
apiCases.forEach((item) => {
item.request = response.data[item.id];
});
this.$emit('save', apiCases, 'CASE', reference);
this.close();
});
}
},
close() {
this.refresh();
this.$refs.relevanceDialog.close();
},
open() {
if (this.$refs.apiList) {
this.$refs.apiList.clearSelection();
}
if (this.$refs.apiCaseList) {
this.$refs.apiCaseList.clearSelection();
}
this.$refs.relevanceDialog.open();
},
isApiListEnableChange(data) {
this.isApiListEnable = data;
},
nodeChange(node, nodeIds, pNodes) {
this.selectNodeIds = nodeIds;
},
handleProtocolChange(protocol) {
this.currentProtocol = protocol;
},
setModuleOptions(data) {
this.moduleOptions = data;
},
refresh() {
if (this.isApiListEnable) {
this.$refs.apiList.initTable();
} else {
this.$refs.apiCaseList.initTable();
}
},
}
moduleOptions: {},
isApiListEnable: true,
projectId: ""
}
},
watch: {
projectId() {
this.refresh();
this.$refs.nodeTree.list(this.projectId);
}
},
methods: {
reference() {
this.save('REF');
},
copy() {
this.save('Copy');
},
save(reference) {
if (this.isApiListEnable) {
let apis = this.$refs.apiList.selectRows;
apis.forEach(api => {
api.projectId = this.projectId;
})
this.$emit('save', this.$refs.apiList.selectRows, 'API', reference);
this.$refs.baseRelevance.close();
} else {
let apiCases = this.$refs.apiCaseList.selectRows;
let ids = Array.from(apiCases).map(row => row.id);
this.result = this.$post("/api/testcase/get/request", {ids: ids}, (response) => {
apiCases.forEach((item) => {
item.request = response.data[item.id];
item.projectId = this.projectId;
});
this.$emit('save', apiCases, 'CASE', reference);
this.$refs.baseRelevance.close();
});
}
},
close() {
this.refresh();
this.$refs.relevanceDialog.close();
},
open() {
if (this.$refs.apiList) {
this.$refs.apiList.clearSelection();
}
if (this.$refs.apiCaseList) {
this.$refs.apiCaseList.clearSelection();
}
this.$refs.baseRelevance.open();
},
isApiListEnableChange(data) {
this.isApiListEnable = data;
},
nodeChange(node, nodeIds, pNodes) {
this.selectNodeIds = nodeIds;
},
handleProtocolChange(protocol) {
this.currentProtocol = protocol;
},
setModuleOptions(data) {
this.moduleOptions = data;
},
refresh() {
if (this.isApiListEnable) {
this.$refs.apiList.initTable(this.projectId);
} else {
this.$refs.apiCaseList.initTable(this.projectId);
}
},
setProject(projectId) {
this.projectId = projectId;
},
}
}
</script>
<style scoped>

View File

@ -178,18 +178,19 @@ export default {
isApiListEnableChange(data) {
this.$emit('isApiListEnableChange', data);
},
initTable() {
initTable(projectId) {
this.condition.filters = {status: ["Prepare", "Underway", "Completed"]};
this.condition.moduleIds = this.selectNodeIds;
if (this.trashEnable) {
this.condition.filters = {status: ["Trash"]};
this.condition.moduleIds = [];
}
if (this.projectId != null) {
if (projectId != null && typeof projectId === 'string') {
this.condition.projectId = projectId;
} else if (this.projectId != null) {
this.condition.projectId = this.projectId;
} else {
this.condition.projectId = getCurrentProjectID();
}
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}else{

View File

@ -164,14 +164,13 @@ export default {
isApiListEnableChange(data) {
this.$emit('isApiListEnableChange', data);
},
initTable() {
initTable(projectId) {
this.condition.status = "";
this.condition.moduleIds = this.selectNodeIds;
if (this.projectId != null) {
if (projectId != null && typeof projectId === 'string') {
this.condition.projectId = projectId;
} else if (this.projectId != null) {
this.condition.projectId = this.projectId;
} else {
this.condition.projectId = getCurrentProjectID();
}
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;

View File

@ -1,9 +1,11 @@
<template>
<test-case-relevance-base
:dialog-title="$t('api_test.automation.scenario_import')"
@setProject="setProject"
ref="baseRelevance">
<template v-slot:aside>
<ms-api-scenario-module
style="margin-top: 5px;"
@nodeSelectEvent="nodeChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"
@ -27,12 +29,9 @@
</template>
<script>
import ScenarioRelevanceCaseList from "./RelevanceCaseList";
import MsApiModule from "../../../definition/components/module/ApiModule";
import MsContainer from "../../../../common/components/MsContainer";
import MsAsideContainer from "../../../../common/components/MsAsideContainer";
import MsMainContainer from "../../../../common/components/MsMainContainer";
import ScenarioRelevanceApiList from "./RelevanceApiList";
import MsApiScenarioModule from "../ApiScenarioModule";
import MsApiScenarioList from "../ApiScenarioList";
import {getUUID} from "../../../../../../common/js/utils";
@ -63,6 +62,7 @@
watch: {
projectId() {
this.$refs.apiScenarioList.search(this.projectId);
this.$refs.nodeTree.list(this.projectId);
}
},
methods: {

View File

@ -124,6 +124,7 @@
},
languageChange(language) {
this.jsr223ProcessorData.scriptLanguage = language;
this.$emit("languageChange");
},
}
}

View File

@ -16,7 +16,7 @@
<el-tag size="mini" style="margin-left: 20px" v-if="request.referenced==='Copy'">{{ $t('commons.copy') }}</el-tag>
<el-tag size="mini" style="margin-left: 20px" v-if="request.referenced ==='REF'">{{ $t('api_test.scenario.reference') }}</el-tag>
<span style="margin-left: 20px;">{{getProjectName(request.projectId)}}</span>
<ms-run :debug="true" :reportId="reportId" :run-data="runData"
<ms-run :debug="true" :reportId="reportId" :run-data="runData" :env-map="envMap"
@runRefresh="runRefresh" ref="runTest"/>
</template>
@ -84,7 +84,8 @@
default: false,
},
currentEnvironmentId: String,
projectList: Array
projectList: Array,
envMap: Map
},
components: {
CustomizeReqInfo,
@ -103,7 +104,10 @@
if (!this.request.requestResult) {
this.request.requestResult = {responseResult: {}};
}
this.request.projectId = getCurrentProjectID();
// IDID
if (!this.request.projectId) {
this.request.projectId = getCurrentProjectID();
}
//
this.getApiInfo();
if (this.request.protocol === 'HTTP') {
@ -249,13 +253,20 @@
this.reload();
},
run() {
if (!this.currentEnvironmentId) {
this.$error(this.$t('api_test.environment.select_environment'));
return;
if (!this.envMap || this.envMap.size === 0) {
this.$warning("请在环境配置中为该步骤所属项目选择运行环境!");
return false;
} else if (this.envMap && this.envMap.size > 0) {
const env = this.envMap.get(this.request.projectId);
if (!env) {
this.$warning("请在环境配置中为该步骤所属项目选择运行环境!");
return false;
}
}
this.request.active = true;
this.loading = true;
this.runData = [];
this.runData.projectId = this.request.projectId;
this.request.useEnvironment = this.currentEnvironmentId;
this.request.customizeReq = this.isCustomizeReq;
let debugData = {

View File

@ -2,7 +2,7 @@
<div class="request-form">
<component :is="component" :scenario="scenario" :controller="scenario" :timer="scenario" :assertions="scenario" :extract="scenario" :jsr223-processor="scenario" :request="scenario" :currentScenario="currentScenario" :currentEnvironmentId="currentEnvironmentId" :node="node"
:draggable="true" :title="title" :color="titleColor" :background-color="backgroundColor" @suggestClick="suggestClick(node)" :response="response"
@remove="remove" @copyRow="copyRow" @refReload="refReload" :project-list="projectList"/>
@remove="remove" @copyRow="copyRow" @refReload="refReload" :project-list="projectList" :env-map="envMap"/>
</div>
</template>
@ -28,7 +28,8 @@
currentEnvironmentId: String,
response: {},
node: {},
projectList: Array
projectList: Array,
envMap: Map
},
data() {
return {

View File

@ -1,6 +1,6 @@
<template>
<div>
<ms-run :debug="true" :environment="currentEnvironmentId" :reportId="reportId" :run-data="debugData"
<ms-run :debug="true" :environment="envMap" :reportId="reportId" :run-data="debugData"
@runRefresh="runRefresh" ref="runTest"/>
<api-base-component
@copy="copyRow"
@ -115,6 +115,7 @@ export default {
type: Boolean,
default: false,
},
envMap: Map
},
created() {
// this.initResult();
@ -193,11 +194,6 @@ export default {
}
},
runDebug() {
/*触发执行操作*/
if (!this.currentEnvironmentId) {
this.$error(this.$t('api_test.environment.select_environment'));
return;
}
if (!this.controller.hashTree || this.controller.hashTree.length < 1) {
this.$warning("当前循环下没有请求,不能执行")
return;

View File

@ -2,7 +2,7 @@
<span></span>
</template>
<script>
import {getUUID, getBodyUploadFiles,getCurrentProjectID} from "@/common/js/utils";
import {getUUID, getBodyUploadFiles, getCurrentProjectID, strMapToObj} from "@/common/js/utils";
import ThreadGroup from "./jmeter/components/thread-group";
import TestPlan from "./jmeter/components/test-plan";
@ -14,7 +14,8 @@
debug: Boolean,
reportId: String,
runData: Array,
type: String
type: String,
envMap: Map
},
data() {
return {
@ -64,7 +65,16 @@
this.runData.forEach(item => {
threadGroup.hashTree.push(item);
})
let reqObj = {id: this.reportId, testElement: testPlan, type: this.type,projectId:getCurrentProjectID()};
let projectId = "";
// envMap
if (!this.envMap) {
projectId = getCurrentProjectID();
} else {
//
projectId = this.runData.projectId;
}
let reqObj = {id: this.reportId, testElement: testPlan, type: this.type,projectId: projectId, environmentMap: strMapToObj(this.envMap)};
let bodyFiles = getBodyUploadFiles(reqObj, this.runData);
let url = "";
if (this.debug) {
@ -76,7 +86,7 @@
this.$fileUpload(url, null, bodyFiles, reqObj, response => {
this.runId = response.data;
this.getResult();
}, erro => {
}, error => {
this.$emit('runRefresh', {});
});
}

View File

@ -44,7 +44,7 @@
<el-input size="small" v-model="assertion.desc" :placeholder="$t('api_test.request.assertions.script_name')"
class="quick-script-block"/>
<ms-jsr233-processor ref="jsr233" :is-read-only="isReadOnly" :jsr223-processor="assertion" :templates="templates"
:height="300"/>
:height="300" @languageChange="quickScript"/>
<template v-slot:footer v-if="!edit">
<ms-dialog-footer
@cancel="close"
@ -145,7 +145,7 @@
}
this.quickScript();
},
quickScript() {
beanShellOrGroovyScript() {
if (this.assertion.variable && this.assertion.operator) {
let variable = this.assertion.variable;
let operator = this.assertion.operator;
@ -184,7 +184,7 @@
script += "result = value != void && value.length() > 0;\n";
break;
}
let msg = "assertion [" + desc + "]: false;"
let msg = (operator != "is empty" && operator != "is not empty") ? "assertion [" + desc + "]: false;" : "value " + operator
script += "if (!result){\n" +
"\tmsg = \"" + msg + "\";\n" +
"\tAssertionResult.setFailureMessage(msg);\n" +
@ -197,6 +197,68 @@
}
},
pythonScript() {
if (this.assertion.variable && this.assertion.operator) {
let variable = this.assertion.variable;
let operator = this.assertion.operator;
let value = this.assertion.value || "";
let desc = "${" + variable + "} " + operator + " '" + value + "'";
let msg = "";
let script = "value = vars.get(\"" + variable + "\");\n"
switch (this.assertion.operator) {
case "==":
script += "if value != \"" + value + "\" :\n";
break;
case "!=":
script += "if value == \"" + value + "\" :\n";
break;
case "contains":
script += "if value.find(\"" + value + "\") != -1:\n";
msg = "value " + operator + " " + value + ": false;";
break;
case "not contains":
script += "if value.find(\"" + value + "\") == -1:\n";
msg = "value " + operator + " " + ": false;";
break;
case ">":
desc = "${" + variable + "} " + operator + " " + value;
script += "if value is None or int(value) < " + value + ":\n";
msg = "value " + operator + " " + value + ": false;";
break;
case "<":
desc = "${" + variable + "} " + operator + " " + value;
script += "if value is None or int(value) > " + value + ":\n";
msg = "value " + operator + " " + value + ": false;";
break;
case "is empty":
desc = "${" + variable + "} " + operator
script += "if value is not None:\n";
msg = "value " + operator + ": false;";
break;
case "is not empty":
desc = "${" + variable + "} " + operator
script += "if value is None:\n";
msg = "value " + operator + ": false;";
break;
}
script +=
"\tmsg = \" " + msg + "\";" +
"\tAssertionResult.setFailureMessage(msg);" +
"\tAssertionResult.setFailure(true);";
this.assertion.desc = desc;
this.assertion.script = script;
this.$refs.jsr233.reload();
}
},
quickScript() {
if (this.assertion.scriptLanguage == 'beanshell' || this.assertion.scriptLanguage == 'groovy' || this.assertion.scriptLanguage == 'javascript') {
this.beanShellOrGroovyScript();
} else {
this.pythonScript();
}
},
detail() {
this.visible = true;
},

View File

@ -38,7 +38,7 @@
</ms-drawer>
<!-- 执行组件 -->
<ms-run :debug="false" :environment="environment" :reportId="reportId" :run-data="runData"
<ms-run :debug="false" :environment="environment" :reportId="reportId" :run-data="runData" :env-map="envMap"
@runRefresh="runRefresh" ref="runTest"/>
<!--批量编辑-->
<ms-batch-edit ref="batchEdit" @batchEdit="batchEdit" :typeArr="typeArr" :value-arr="valueArr"/>
@ -111,6 +111,7 @@
priority: CASE_PRIORITY,
method: REQ_METHOD,
},
envMap: new Map
}
},
watch: {
@ -274,6 +275,7 @@
this.$get('/api/definition/get/' + row.request.id, response => {
row.request.path = response.data.path; // pathpath
row.request.useEnvironment = this.environment.id;
row.request.projectId = getCurrentProjectID();
this.runData.push(row.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);

View File

@ -107,14 +107,14 @@ export default {
}
},
methods: {
list() {
list(projectId) {
let url = undefined;
if (this.isPlanModel) {
url = '/api/module/list/plan/' + this.planId + '/' + this.condition.protocol;
} else if (this.isRelevanceModel) {
url = "/api/module/list/" + this.relevanceProjectId + "/" + this.condition.protocol;
} else {
url = "/api/module/list/" + this.projectId + "/" + this.condition.protocol;
url = "/api/module/list/" + (projectId ? projectId : this.projectId) + "/" + this.condition.protocol;
if (!this.projectId) {
return;
}

View File

@ -146,6 +146,9 @@
if (!this.response.body) {
this.response.body = "";
}
if(!this.response.responseResult.vars){
this.response.responseResult.vars="";
}
this.reqMessages = this.$t('api_test.request.address') + ":\n" + this.response.url + "\n" +
this.$t('api_test.scenario.headers') + ":\n" + this.response.headers + "\n" + "Cookies :\n" +
this.response.cookies + "\n" + "Bpdy:" + "\n" + this.response.body;

View File

@ -64,7 +64,7 @@
ref="caseList"/>
<!-- 执行组件 -->
<ms-run :debug="false" :environment="api.environment" :reportId="reportId" :run-data="runData"
<ms-run :debug="false" :environment="api.environment" :reportId="reportId" :run-data="runData" :env-map="envMap"
@runRefresh="runRefresh" ref="runTest"/>
</div>
@ -110,6 +110,7 @@ export default {
},
runData: [],
reportId: "",
envMap: new Map
}
},
props: {apiData: {}, currentProtocol: String, syncTabs: Array, projectId: String},

View File

@ -132,7 +132,7 @@ export default {
filterNode(value, data) {
if (!value) return true;
if (data.label) {
return data.label.indexOf(value) !== -1;
return data.label.indexOf(value.toLowerCase()) !== -1;
}
return false;
},

View File

@ -1,5 +1,5 @@
<template>
<relevance-dialog :title="$t('test_track.plan_view.relevance_test_case')" ref="relevanceDialog">
<relevance-dialog :title="dialogTitle" ref="relevanceDialog">
<template v-slot:aside>
<select-menu
@ -51,6 +51,12 @@
props: {
planId: {
type: String
},
dialogTitle: {
type: String,
default() {
return this.$t('test_track.plan_view.relevance_test_case');
}
}
},
watch: {

View File

@ -319,6 +319,7 @@ export function _getBodyUploadFiles(request, bodyUploadFiles, obj) {
}
}
}
export function handleCtrlSEvent(event, func) {
if (event.keyCode === 83 && event.ctrlKey) {
// console.log('拦截到 ctrl + s');//ctrl+s
@ -328,3 +329,22 @@ export function handleCtrlSEvent(event, func) {
return false;
}
}
export function strMapToObj(strMap) {
if (strMap) {
let obj = Object.create(null);
for (let [k, v] of strMap) {
obj[k] = v;
}
return obj;
}
return null;
}
export function objToStrMap(obj) {
let strMap = new Map();
for (let k of Object.keys(obj)) {
strMap.set(k, obj[k]);
}
return strMap;
}