Merge remote-tracking branch 'origin/v1.7' into v1.7

This commit is contained in:
Captain.B 2021-02-01 14:01:16 +08:00
commit 2fe9ee15a2
11 changed files with 133 additions and 30 deletions

View File

@ -272,10 +272,14 @@ public class MsHTTPSamplerProxy extends MsTestElement {
StringBuffer stringBuffer = new StringBuffer(); StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(path); stringBuffer.append(path);
stringBuffer.append("?"); stringBuffer.append("?");
this.getArguments().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).forEach(keyValue -> this.getArguments().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).forEach(keyValue -> {
stringBuffer.append(keyValue.getName()).append("=").append(keyValue.getValue() != null && keyValue.getValue().startsWith("@") ? stringBuffer.append(keyValue.getName());
ScriptEngineUtils.calculate(keyValue.getValue()) : keyValue.getValue()).append("&") if (keyValue.getValue() != null) {
); stringBuffer.append("=").append(keyValue.getValue().startsWith("@") ?
ScriptEngineUtils.calculate(keyValue.getValue()) : keyValue.getValue());
}
stringBuffer.append("&");
});
return stringBuffer.substring(0, stringBuffer.length() - 1); return stringBuffer.substring(0, stringBuffer.length() - 1);
} }

View File

@ -0,0 +1,8 @@
package io.metersphere.api.dto.parse.postman;
import lombok.Data;
@Data
public class PostmanEvent {
private String listen;
private PostmanScript script;
}

View File

@ -7,6 +7,7 @@ import java.util.List;
@Data @Data
public class PostmanItem { public class PostmanItem {
private String name; private String name;
private List<PostmanEvent> event;
private PostmanRequest request; private PostmanRequest request;
private List<PostmanItem> item; private List<PostmanItem> item;
} }

View File

@ -0,0 +1,11 @@
package io.metersphere.api.dto.parse.postman;
import lombok.Data;
import java.util.List;
@Data
public class PostmanScript {
private List<String> exec;
private String type;
}

View File

@ -57,7 +57,7 @@ public class KeyValue {
} }
public boolean isValid() { public boolean isValid() {
return ((StringUtils.isNotBlank(name) && StringUtils.isNotBlank(value)) || "JSON-SCHEMA".equals(type)) && !StringUtils.equalsIgnoreCase(type, "file"); return (StringUtils.isNotBlank(name) || "JSON-SCHEMA".equals(type)) && !StringUtils.equalsIgnoreCase(type, "file");
} }
public boolean isFile() { public boolean isFile() {

View File

@ -13,6 +13,7 @@ import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.service.ApiModuleService; import io.metersphere.api.service.ApiModuleService;
import io.metersphere.base.domain.ApiModule; import io.metersphere.base.domain.ApiModule;
import io.metersphere.commons.constants.ApiImportPlatform;
import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
@ -34,6 +35,7 @@ public class MsParser extends ApiImportAbstractParser {
if (testObject.get("projectName") != null) { if (testObject.get("projectName") != null) {
return parseMsFormat(testStr, request); return parseMsFormat(testStr, request);
} else { } else {
request.setPlatform(ApiImportPlatform.Plugin.name());
return parsePluginFormat(testObject, request); return parsePluginFormat(testObject, request);
} }
} }

View File

@ -5,6 +5,8 @@ import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.ApiDefinitionResult; import io.metersphere.api.dto.definition.ApiDefinitionResult;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.parse.postman.*; import io.metersphere.api.dto.parse.postman.*;
import io.metersphere.api.dto.scenario.Body; import io.metersphere.api.dto.scenario.Body;
@ -12,11 +14,14 @@ import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.base.domain.ApiModule; import io.metersphere.base.domain.ApiModule;
import io.metersphere.commons.constants.MsRequestBodyType; import io.metersphere.commons.constants.MsRequestBodyType;
import io.metersphere.commons.constants.PostmanRequestBodyMode; import io.metersphere.commons.constants.PostmanRequestBodyMode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
public class PostmanParser extends ApiImportAbstractParser { public class PostmanParser extends ApiImportAbstractParser {
@ -75,10 +80,37 @@ public class PostmanParser extends ApiImportAbstractParser {
request.setArguments(parseKeyValue(url.getQuery())); request.setArguments(parseKeyValue(url.getQuery()));
request.setHeaders(parseKeyValue(requestDesc.getHeader())); request.setHeaders(parseKeyValue(requestDesc.getHeader()));
addBodyHeader(request); addBodyHeader(request);
addPreScript(request, requestItem.getEvent());
apiDefinition.setRequest(JSON.toJSONString(request)); apiDefinition.setRequest(JSON.toJSONString(request));
return apiDefinition; return apiDefinition;
} }
private void addPreScript(MsHTTPSamplerProxy request, List<PostmanEvent> event) {
if (CollectionUtils.isNotEmpty(event)) {
StringBuilder scriptStr = new StringBuilder();
event = event.stream()
.filter(item -> item.getScript() != null)
.collect(Collectors.toList());
event.forEach(item -> {
PostmanScript script = item.getScript();
List<String> exec = script.getExec();
if (CollectionUtils.isNotEmpty(exec)) {
exec.forEach(col -> {
scriptStr.append(col + "/n");
});
}
});
if (StringUtils.isNotBlank(scriptStr)) {
MsJSR223PreProcessor jsr223PreProcessor = new MsJSR223PreProcessor();
jsr223PreProcessor.setScriptLanguage("javascript");
jsr223PreProcessor.setScript(scriptStr.toString());
LinkedList<MsTestElement> hashTree = new LinkedList<>();
hashTree.add(jsr223PreProcessor);
request.setHashTree(hashTree);
}
}
}
private List<KeyValue> parseKeyValue(List<PostmanKeyValue> postmanKeyValues) { private List<KeyValue> parseKeyValue(List<PostmanKeyValue> postmanKeyValues) {
if (postmanKeyValues == null) { if (postmanKeyValues == null) {
return null; return null;

View File

@ -10,6 +10,7 @@ import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.definition.*; import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.request.ScheduleInfoSwaggerUrlRequest; import io.metersphere.api.dto.definition.request.ScheduleInfoSwaggerUrlRequest;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult; import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult;
import io.metersphere.api.dto.swaggerurl.SwaggerUrlRequest; import io.metersphere.api.dto.swaggerurl.SwaggerUrlRequest;
@ -21,10 +22,7 @@ import io.metersphere.api.parse.ApiImportParserFactory;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*; import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.*;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.constants.ScheduleType;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*; import io.metersphere.commons.utils.*;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
@ -300,7 +298,7 @@ public class ApiDefinitionService {
} }
} }
private ApiDefinition importCreate(ApiDefinitionResult request, ApiDefinitionMapper batchMapper, ApiTestImportRequest apiTestImportRequest) { private ApiDefinition importCreate(ApiDefinitionResult request, ApiDefinitionMapper batchMapper, ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest) {
SaveApiDefinitionRequest saveReq = new SaveApiDefinitionRequest(); SaveApiDefinitionRequest saveReq = new SaveApiDefinitionRequest();
BeanUtils.copyBean(saveReq, request); BeanUtils.copyBean(saveReq, request);
final ApiDefinitionWithBLOBs apiDefinition = new ApiDefinitionWithBLOBs(); final ApiDefinitionWithBLOBs apiDefinition = new ApiDefinitionWithBLOBs();
@ -317,30 +315,72 @@ public class ApiDefinitionService {
List<ApiDefinition> sameRequest = getSameRequest(saveReq); List<ApiDefinition> sameRequest = getSameRequest(saveReq);
if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) { if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) {
if (CollectionUtils.isEmpty(sameRequest)) { _importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, apiTestImportRequest);
batchMapper.insert(apiDefinition);
} else {
//如果存在则修改
apiDefinition.setId(sameRequest.get(0).getId());
apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition);
}
} else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) { } else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) {
if (CollectionUtils.isEmpty(sameRequest)) { if (CollectionUtils.isEmpty(sameRequest)) {
//postman 可能含有前置脚本接口定义去掉脚本
String requestStr = setImportHashTree(apiDefinition);
batchMapper.insert(apiDefinition); batchMapper.insert(apiDefinition);
apiDefinition.setRequest(requestStr);
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, true);
} }
} else { } else {
if (CollectionUtils.isEmpty(sameRequest)) { _importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, apiTestImportRequest);
batchMapper.insert(apiDefinition);
} else {
//如果存在则修改
apiDefinition.setId(sameRequest.get(0).getId());
apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition);
}
} }
return apiDefinition; return apiDefinition;
} }
private void _importCreate(List<ApiDefinition> sameRequest, ApiDefinitionMapper batchMapper, ApiDefinitionWithBLOBs apiDefinition,
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest) {
if (CollectionUtils.isEmpty(sameRequest)) {
String request = setImportHashTree(apiDefinition);
batchMapper.insert(apiDefinition);
apiDefinition.setRequest(request);
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, true);
} else {
//如果存在则修改
apiDefinition.setId(sameRequest.get(0).getId());
String request = setImportHashTree(apiDefinition);
apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition);
apiDefinition.setRequest(request);
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, false);
}
}
private String setImportHashTree(ApiDefinitionWithBLOBs apiDefinition) {
String request = apiDefinition.getRequest();
MsHTTPSamplerProxy msHTTPSamplerProxy = JSONObject.parseObject(request, MsHTTPSamplerProxy.class);
msHTTPSamplerProxy.setHashTree(null);
apiDefinition.setRequest(JSONObject.toJSONString(msHTTPSamplerProxy));
return request;
}
/**
* 导入是插件或者postman时创建用例
* postman考虑是否有前置脚本
*/
private void importApiCase(ApiDefinitionWithBLOBs apiDefinition, ApiTestCaseMapper apiTestCaseMapper,
ApiTestImportRequest apiTestImportRequest, Boolean isInsert) {
try {
if (StringUtils.equalsAnyIgnoreCase(apiTestImportRequest.getPlatform(), ApiImportPlatform.Plugin.name(), ApiImportPlatform.Postman.name())) {
ApiTestCaseWithBLOBs apiTestCase = new ApiTestCaseWithBLOBs();
BeanUtils.copyBean(apiTestCase, apiDefinition);
apiTestCase.setId(UUID.randomUUID().toString());
apiTestCase.setApiDefinitionId(apiDefinition.getId());
apiTestCase.setCreateTime(System.currentTimeMillis());
apiTestCase.setUpdateTime(System.currentTimeMillis());
apiTestCase.setCreateUserId(SessionUtils.getUserId());
apiTestCase.setUpdateUserId(SessionUtils.getUserId());
apiTestCase.setPriority("P0");
if (!isInsert) {
apiTestCase.setName(apiTestCase.getName() + "_" + apiTestCase.getId().substring(0, 5));
}
apiTestCaseMapper.insert(apiTestCase);
}
} catch (Exception e) {
LogUtil.error("导入创建用例异常", e);
}
}
private void deleteFileByTestId(String apiId) { private void deleteFileByTestId(String apiId) {
ApiTestFileExample apiTestFileExample = new ApiTestFileExample(); ApiTestFileExample apiTestFileExample = new ApiTestFileExample();
@ -457,6 +497,7 @@ public class ApiDefinitionService {
private void importApi(ApiTestImportRequest request, ApiDefinitionImport apiImport) { private void importApi(ApiTestImportRequest request, ApiDefinitionImport apiImport) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionMapper batchMapper = sqlSession.getMapper(ApiDefinitionMapper.class); ApiDefinitionMapper batchMapper = sqlSession.getMapper(ApiDefinitionMapper.class);
ApiTestCaseMapper apiTestCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
List<ApiDefinitionResult> data = apiImport.getData(); List<ApiDefinitionResult> data = apiImport.getData();
int num = 0; int num = 0;
if (!CollectionUtils.isEmpty(data) && data.get(0) != null && data.get(0).getProjectId() != null) { if (!CollectionUtils.isEmpty(data) && data.get(0) != null && data.get(0).getProjectId() != null) {
@ -468,7 +509,7 @@ public class ApiDefinitionService {
item.setName(item.getName().substring(0, 255)); item.setName(item.getName().substring(0, 255));
} }
item.setNum(num++); item.setNum(num++);
importCreate(item, batchMapper, request); importCreate(item, batchMapper, apiTestCaseMapper, request);
if (i % 300 == 0) { if (i % 300 == 0) {
sqlSession.flushStatements(); sqlSession.flushStatements();
} }

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants; package io.metersphere.commons.constants;
public enum ApiImportPlatform { public enum ApiImportPlatform {
Metersphere, Postman, Swagger2 Metersphere, Postman, Swagger2, Plugin
} }

View File

@ -37,6 +37,7 @@
<el-button size="mini" icon="el-icon-delete" type="danger" circle @click="remove"/> <el-button size="mini" icon="el-icon-delete" type="danger" circle @click="remove"/>
</el-tooltip> </el-tooltip>
</div> </div>
</div> </div>
<div class="header"> <div class="header">
<fieldset :disabled="data.disabled" class="ms-fieldset"> <fieldset :disabled="data.disabled" class="ms-fieldset">

View File

@ -31,19 +31,21 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="num" label="ID" show-overflow-tooltip> <el-table-column prop="num" label="ID" min-width="120px" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<el-tooltip content="编辑"> <el-tooltip content="编辑">
<a style="cursor:pointer" @click="handleTestCase(scope.row)"> {{ scope.row.num }} </a> <a style="cursor:pointer" @click="handleTestCase(scope.row)"> {{ scope.row.num }} </a>
</el-tooltip> </el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="name" :label="$t('test_track.case.name')" show-overflow-tooltip/>
<el-table-column prop="name" min-width="160px" :label="$t('test_track.case.name')" show-overflow-tooltip/>
<el-table-column <el-table-column
prop="priority" prop="priority"
:filters="priorityFilters" :filters="priorityFilters"
column-key="priority" column-key="priority"
min-width="120px"
:label="$t('test_track.case.priority')" :label="$t('test_track.case.priority')"
show-overflow-tooltip> show-overflow-tooltip>
<template v-slot:default="scope"> <template v-slot:default="scope">
@ -54,10 +56,11 @@
<el-table-column <el-table-column
sortable="custom" sortable="custom"
prop="path" prop="path"
min-width="180px"
:label="$t('api_test.definition.api_path')" :label="$t('api_test.definition.api_path')"
show-overflow-tooltip/> show-overflow-tooltip/>
<el-table-column prop="tags" :label="$t('commons.tag')"> <el-table-column prop="tags" min-width="120px" :label="$t('commons.tag')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<div v-for="(itemName,index) in scope.row.tags" :key="index"> <div v-for="(itemName,index) in scope.row.tags" :key="index">
<ms-tag type="success" effect="plain" :content="itemName"/> <ms-tag type="success" effect="plain" :content="itemName"/>