diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml new file mode 100644 index 0000000000..c0e5ac9812 --- /dev/null +++ b/.github/workflows/build-push.yml @@ -0,0 +1,58 @@ +name: Build Docker Image and Push + +on: + push: + branches: + - main + - v1* + pull_request: + branches: + - main + - v1* + +jobs: + build_push: + runs-on: ubuntu-latest + name: Build Docker Image and Push + steps: + - uses: actions/checkout@v2 + - name: Inject slug/short variables + uses: rlespinasse/github-slug-action@v3.x + - name: Cache node modules + uses: actions/cache@v2 + env: + cache-name: cache-node-modules + with: + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Cache local Maven repository + uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file + + - name: Build with Maven + run: mvn -B package --file pom.xml + + - name: Push to Docker Hub + uses: docker/build-push-action@v1 + with: + username: metersphere + password: ${{ secrets.DOCKER_HUB_TOKEN }} + repository: metersphere/metersphere + tag_with_ref: true + build_args: MS_VERSION=${{ env.GITHUB_REF_SLUG }}-${{ env.GITHUB_SHA_SHORT }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 8e0a6e24fa..5dc3c7e4d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM registry.fit2cloud.com/metersphere/fabric8-java-alpine-openjdk8-jre +FROM metersphere/fabric8-java-alpine-openjdk8-jre MAINTAINER FIT2CLOUD diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java index 06706fcdd7..2bf62c351b 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java @@ -1,6 +1,5 @@ package io.metersphere.api.dto.definition.request.sampler; -import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONType; @@ -9,7 +8,6 @@ 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.api.dto.scenario.request.BodyFile; import io.metersphere.api.service.ApiTestEnvironmentService; import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs; import io.metersphere.commons.utils.CommonBeanFactory; @@ -23,16 +21,13 @@ import org.apache.jmeter.protocol.http.control.Header; import org.apache.jmeter.protocol.http.control.HeaderManager; import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy; import org.apache.jmeter.protocol.http.util.HTTPArgument; -import org.apache.jmeter.protocol.http.util.HTTPFileArg; import org.apache.jmeter.save.SaveService; import org.apache.jmeter.testelement.TestElement; import org.apache.jorphan.collections.HashTree; import java.net.URL; import java.net.URLDecoder; -import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; @Data @EqualsAndHashCode(callSuper = true) @@ -142,39 +137,11 @@ public class MsHTTPSamplerProxy extends MsTestElement { if (CollectionUtils.isNotEmpty(this.getArguments())) { sampler.setArguments(httpArguments(this.getArguments())); } + // 请求体 if (!StringUtils.equals(this.getMethod(), "GET")) { - List body = new ArrayList<>(); - if (this.getBody().isKV() || this.getBody().isBinary()) { - body = this.getBody().getKvs().stream().filter(KeyValue::isValid).collect(Collectors.toList()); - HTTPFileArg[] httpFileArgs = httpFileArgs(); - // 文件上传 - if (httpFileArgs.length > 0) { - sampler.setHTTPFiles(httpFileArgs()); - sampler.setDoMultipart(true); - } - } else if (this.getBody().isJson()) { - KeyValue keyValue = new KeyValue("", JSON.toJSONString(this.getBody().getJson())); - keyValue.setEnable(true); - keyValue.setEncode(false); - body.add(keyValue); - } else { - if (StringUtils.isNotBlank(this.getBody().getRaw())) { - sampler.setPostBodyRaw(true); - KeyValue keyValue = new KeyValue("", this.getBody().getRaw()); - keyValue.setEnable(true); - keyValue.setEncode(false); - body.add(keyValue); - } - if (StringUtils.isNotBlank(this.getBody().getXml())) { - sampler.setPostBodyRaw(true); - KeyValue keyValue = new KeyValue("", this.getBody().getXml()); - keyValue.setEnable(true); - keyValue.setEncode(false); - body.add(keyValue); - } - } - sampler.setArguments(httpArguments(body)); + List bodyParams = this.body.getBodyParams(sampler, this.getId()); + sampler.setArguments(httpArguments(bodyParams)); } final HashTree httpSamplerTree = tree.add(sampler); @@ -225,29 +192,6 @@ public class MsHTTPSamplerProxy extends MsTestElement { return arguments; } - private void setFileArg(List list, List files, KeyValue keyValue) { - final String BODY_FILE_DIR = "/opt/metersphere/data/body"; - if (files != null) { - files.forEach(file -> { - String paramName = keyValue.getName() == null ? this.getId() : keyValue.getName(); - String path = BODY_FILE_DIR + '/' + file.getId() + '_' + file.getName(); - String mimetype = keyValue.getContentType(); - list.add(new HTTPFileArg(path, paramName, mimetype)); - }); - } - } - - private HTTPFileArg[] httpFileArgs() { - List list = new ArrayList<>(); - this.getBody().getKvs().stream().filter(KeyValue::isFile).filter(KeyValue::isEnable).forEach(keyValue -> { - setFileArg(list, keyValue.getFiles(), keyValue); - }); - this.getBody().getBinary().stream().filter(KeyValue::isFile).filter(KeyValue::isEnable).forEach(keyValue -> { - setFileArg(list, keyValue.getFiles(), keyValue); - }); - return list.toArray(new HTTPFileArg[0]); - } - public void setHeader(HashTree tree) { HeaderManager headerManager = new HeaderManager(); headerManager.setEnabled(true); diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/Body.java b/backend/src/main/java/io/metersphere/api/dto/scenario/Body.java index cbf9a73ea3..fc0e0f7fa3 100644 --- a/backend/src/main/java/io/metersphere/api/dto/scenario/Body.java +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/Body.java @@ -1,27 +1,30 @@ package io.metersphere.api.dto.scenario; +import io.metersphere.api.dto.scenario.request.BodyFile; import lombok.Data; import org.apache.commons.lang3.StringUtils; +import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy; +import org.apache.jmeter.protocol.http.util.HTTPFileArg; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; @Data public class Body { private String type; private String raw; private String format; - private List fromUrlencoded; private List kvs; private List binary; - private Object json; - private String xml; - private final static String KV = "KeyValue"; - private final static String FORM_DATA = "Form Data"; - private final static String RAW = "Raw"; - private final static String BINARY = "BINARY"; - private final static String JSON = "JSON"; - private final static String XML = "XML"; + public final static String KV = "KeyValue"; + public final static String FORM_DATA = "Form Data"; + public final static String WWW_FROM = "WWW_FORM"; + public final static String RAW = "Raw"; + public final static String BINARY = "BINARY"; + public final static String JSON = "JSON"; + public final static String XML = "XML"; public boolean isValid() { if (this.isKV()) { @@ -32,7 +35,55 @@ public class Body { } public boolean isKV() { - return StringUtils.equals(type, KV); + if (StringUtils.equals(type, FORM_DATA) || StringUtils.equals(type, WWW_FROM) + || StringUtils.equals(type, BINARY)) { + return true; + } else return false; + } + + public List getBodyParams(HTTPSamplerProxy sampler, String requestId) { + List body = new ArrayList<>(); + if (this.isKV() || this.isBinary()) { + body = this.getKvs().stream().filter(KeyValue::isValid).collect(Collectors.toList()); + HTTPFileArg[] httpFileArgs = httpFileArgs(requestId); + // 文件上传 + if (httpFileArgs.length > 0) { + sampler.setHTTPFiles(httpFileArgs(requestId)); + sampler.setDoMultipart(true); + } + } else { + if (!this.isJson()) { + sampler.setPostBodyRaw(true); + } + KeyValue keyValue = new KeyValue("", this.getRaw()); + keyValue.setEnable(true); + keyValue.setEncode(false); + body.add(keyValue); + } + return body; + } + + private HTTPFileArg[] httpFileArgs(String requestId) { + List list = new ArrayList<>(); + this.getKvs().stream().filter(KeyValue::isFile).filter(KeyValue::isEnable).forEach(keyValue -> { + setFileArg(list, keyValue.getFiles(), keyValue, requestId); + }); + this.getBinary().stream().filter(KeyValue::isFile).filter(KeyValue::isEnable).forEach(keyValue -> { + setFileArg(list, keyValue.getFiles(), keyValue, requestId); + }); + return list.toArray(new HTTPFileArg[0]); + } + + private void setFileArg(List list, List files, KeyValue keyValue, String requestId) { + final String BODY_FILE_DIR = "/opt/metersphere/data/body"; + if (files != null) { + files.forEach(file -> { + String paramName = keyValue.getName() == null ? requestId : keyValue.getName(); + String path = BODY_FILE_DIR + '/' + file.getId() + '_' + file.getName(); + String mimetype = keyValue.getContentType(); + list.add(new HTTPFileArg(path, paramName, mimetype)); + }); + } } public boolean isBinary() { @@ -47,4 +98,11 @@ public class Body { return StringUtils.equals(type, XML); } + public boolean isWwwFROM() { + return StringUtils.equals(type, WWW_FROM); + } + + public boolean isFromData() { + return StringUtils.equals(type, FORM_DATA); + } } diff --git a/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java b/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java index 1110787a35..46dd2f08b8 100644 --- a/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java +++ b/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java @@ -216,6 +216,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl String successContext = ""; String failedContext = ""; String subject = ""; + String event = ""; if (StringUtils.equals(NoticeConstants.Mode.API, report.getTriggerMode())) { successContext = "接口测试 API任务通知:'" + report.getName() + "'执行成功" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + url; failedContext = "接口测试 API任务通知:'" + report.getName() + "'执行失败" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + url; @@ -226,6 +227,12 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl failedContext = "接口测试定时任务通知:'" + report.getName() + "'执行失败" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + url; subject = Translator.get("task_notification"); } + if (StringUtils.equals("Success", report.getStatus())) { + event = NoticeConstants.Event.EXECUTE_SUCCESSFUL; + } + if (StringUtils.equals("Error", report.getStatus())) { + event = NoticeConstants.Event.EXECUTE_FAILED; + } NoticeModel noticeModel = NoticeModel.builder() .successContext(successContext) @@ -234,6 +241,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl .failedMailTemplate("ApiFailedNotification") .testId(testResult.getTestId()) .status(report.getStatus()) + .event(event) .subject(subject) .build(); noticeSendService.send(report.getTriggerMode(), noticeModel); diff --git a/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java b/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java index a8c450c6aa..f8f19bc121 100644 --- a/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java @@ -48,11 +48,14 @@ public abstract class ApiImportAbstractParser implements ApiImportParser { } protected void addContentType(HttpRequest request, String contentType) { - addHeader(request, "Content-Type", contentType); +// addHeader(request, "Content-Type", contentType); } - protected void addCookie(HttpRequest request, String key, String value) { - List headers = Optional.ofNullable(request.getHeaders()).orElse(new ArrayList<>()); + protected void addCookie(List headers, String key, String value) { + addCookie(headers, key, value, ""); + } + + protected void addCookie(List headers, String key, String value, String description) { boolean hasCookie = false; for (KeyValue header : headers) { if (StringUtils.equalsIgnoreCase("Cookie", header.getName())) { @@ -62,12 +65,15 @@ public abstract class ApiImportAbstractParser implements ApiImportParser { } } if (!hasCookie) { - addHeader(request, "Cookie", key + "=" + value + ";"); + addHeader(headers, "Cookie", key + "=" + value + ";", description); } } - protected void addHeader(HttpRequest request, String key, String value) { - List headers = Optional.ofNullable(request.getHeaders()).orElse(new ArrayList<>()); + protected void addHeader(List headers, String key, String value) { + addHeader(headers, key, value, ""); + } + + protected void addHeader(List headers, String key, String value, String description) { boolean hasContentType = false; for (KeyValue header : headers) { if (StringUtils.equalsIgnoreCase(header.getName(), key)) { @@ -75,8 +81,20 @@ public abstract class ApiImportAbstractParser implements ApiImportParser { } } if (!hasContentType) { - headers.add(new KeyValue(key, value)); + headers.add(new KeyValue(key, value, description)); } - request.setHeaders(headers); } +// protected void addHeader(HttpRequest request, String key, String value) { +// List headers = Optional.ofNullable(request.getHeaders()).orElse(new ArrayList<>()); +// boolean hasContentType = false; +// for (KeyValue header : headers) { +// if (StringUtils.equalsIgnoreCase(header.getName(), key)) { +// hasContentType = true; +// } +// } +// if (!hasContentType) { +// headers.add(new KeyValue(key, value)); +// } +// request.setHeaders(headers); +// } } diff --git a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java index f16c220364..b00edd44ca 100644 --- a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java +++ b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java @@ -6,183 +6,212 @@ import com.alibaba.fastjson.JSONObject; import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.definition.ApiDefinitionResult; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; -import io.metersphere.api.dto.definition.request.MsTestElement; -import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.parse.ApiImport; import io.metersphere.api.dto.scenario.Body; import io.metersphere.api.dto.scenario.KeyValue; -import io.metersphere.api.dto.scenario.Scenario; -import io.metersphere.api.dto.scenario.request.HttpRequest; -import io.metersphere.api.dto.scenario.request.Request; import io.metersphere.api.dto.scenario.request.RequestType; -import io.metersphere.commons.constants.MsRequestBodyType; import io.metersphere.commons.constants.SwaggerParameterType; import io.swagger.models.*; import io.swagger.models.parameters.*; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; +import io.swagger.models.properties.*; import io.swagger.parser.SwaggerParser; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.jorphan.collections.HashTree; import java.io.InputStream; +import java.sql.Connection; import java.util.*; public class Swagger2Parser extends ApiImportAbstractParser { + private Map definitions = null; + @Override - public ApiImport parse(InputStream source, ApiTestImportRequest request) { + public ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request) { Swagger swagger; if (StringUtils.isNotBlank(request.getSwaggerUrl())) { swagger = new SwaggerParser().read(request.getSwaggerUrl()); } else { swagger = new SwaggerParser().readWithInfo(getApiTestStr(source)).getSwagger(); } - ApiImport apiImport = new ApiImport(); - apiImport.setScenarios(parseRequests(swagger)); - apiImport.getScenarios().forEach(scenario -> scenario.setEnvironmentId(request.getEnvironmentId())); - return apiImport; - } - - @Override - public ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request) { - ApiImport apiImport = this.parse(source, request); ApiDefinitionImport definitionImport = new ApiDefinitionImport(); - definitionImport.setData(parseSwagger(apiImport)); + definitionImport.setData(parseRequests(swagger)); return definitionImport; } - private List parseSwagger(ApiImport apiImport) { - List results = new LinkedList<>(); - apiImport.getScenarios().forEach(item -> { - item.getRequests().forEach(childItem -> { - if (childItem instanceof HttpRequest) { - HttpRequest res = (HttpRequest) childItem; - ApiDefinitionResult request = new ApiDefinitionResult(); - request.setName(res.getName()); - request.setPath(res.getPath()); - request.setMethod(res.getMethod()); - request.setProtocol(RequestType.HTTP); - MsHTTPSamplerProxy requestElement = new MsHTTPSamplerProxy(); - requestElement.setName(res.getName() + "Postman MHTTPSamplerProxy"); - requestElement.setBody(res.getBody()); - requestElement.setArguments(res.getParameters()); - requestElement.setProtocol(RequestType.HTTP); - requestElement.setPath(res.getPath()); - requestElement.setMethod(res.getMethod()); - requestElement.setId(UUID.randomUUID().toString()); - requestElement.setRest(new ArrayList()); - MsHeaderManager headerManager = new MsHeaderManager(); - headerManager.setId(UUID.randomUUID().toString()); - headerManager.setName(res.getName() + "Postman MsHeaderManager"); - headerManager.setHeaders(res.getHeaders()); - HashTree tree = new HashTree(); - tree.add(headerManager); - LinkedList list = new LinkedList<>(); - list.add(headerManager); - requestElement.setHashTree(list); - request.setRequest(JSON.toJSONString(requestElement)); - results.add(request); - } - - }); - }); - return results; + @Override + public ApiImport parse(InputStream source, ApiTestImportRequest request) { + return null; } - private List parseRequests(Swagger swagger) { + private List parseRequests(Swagger swagger) { + List results = new LinkedList<>(); Map paths = swagger.getPaths(); Set pathNames = paths.keySet(); - Map scenarioMap = new HashMap<>(); + + this.definitions = swagger.getDefinitions(); + for (String pathName : pathNames) { Path path = paths.get(pathName); Map operationMap = path.getOperationMap(); Set httpMethods = operationMap.keySet(); for (HttpMethod method : httpMethods) { Operation operation = operationMap.get(method); - HttpRequest request = new HttpRequest(); - if (StringUtils.isNotBlank(operation.getSummary())) { - request.setName(operation.getSummary()); - } else { - request.setName(operation.getOperationId()); - } - request.setPath(pathName); - request.setUseEnvironment(true); - request.setMethod(method.name()); - parseParameters(operation, swagger.getDefinitions(), request); - List tags = operation.getTags(); - if (tags != null) { - tags.forEach(tag -> { - Scenario scenario = Optional.ofNullable(scenarioMap.get(tag)).orElse(new Scenario()); - List requests = Optional.ofNullable(scenario.getRequests()).orElse(new ArrayList<>()); - requests.add(request); - scenario.setRequests(requests); - scenario.setName(tag); - scenarioMap.put(tag, scenario); - }); - } else { - Scenario scenario = Optional.ofNullable(scenarioMap.get("default")).orElse(new Scenario()); - List requests = Optional.ofNullable(scenario.getRequests()).orElse(new ArrayList<>()); - requests.add(request); - scenario.setRequests(requests); - scenarioMap.put("default", scenario); - } + + ApiDefinitionResult apiDefinition = buildApiDefinition(operation, pathName, method.name()); + MsHTTPSamplerProxy request = buildRequest(operation, pathName, method.name()); + parseParameters(operation, request); + apiDefinition.setRequest(JSON.toJSONString(request)); + apiDefinition.setId(request.getId()); + results.add(apiDefinition); + + +// List tags = operation.getTags(); +// if (tags != null) { +// tags.forEach(tag -> { +// Scenario scenario = Optional.ofNullable(scenarioMap.get(tag)).orElse(new Scenario()); +// List requests = Optional.ofNullable(scenario.getRequests()).orElse(new ArrayList<>()); +// requests.add(request); +// scenario.setRequests(requests); +// scenario.setName(tag); +// scenarioMap.put(tag, scenario); +// }); +// } else { +// Scenario scenario = Optional.ofNullable(scenarioMap.get("default")).orElse(new Scenario()); +// List requests = Optional.ofNullable(scenario.getRequests()).orElse(new ArrayList<>()); +// requests.add(request); +// scenario.setRequests(requests); +// scenarioMap.put("default", scenario); +// } } } - return new ArrayList<>(scenarioMap.values()); + + this.definitions = null; + + return results; } - private void parseParameters(Operation operation, Map definitions, HttpRequest request) { + private ApiDefinitionResult buildApiDefinition(Operation operation, String path, String method) { + ApiDefinitionResult apiDefinition = new ApiDefinitionResult(); + if (StringUtils.isNotBlank(operation.getSummary())) { + apiDefinition.setName(operation.getSummary()); + } else { + apiDefinition.setName(operation.getOperationId()); + } + apiDefinition.setPath(path); + apiDefinition.setProtocol(RequestType.HTTP); + apiDefinition.setMethod(method); + return apiDefinition; + } + private MsHTTPSamplerProxy buildRequest(Operation operation, String path, String method) { + MsHTTPSamplerProxy request = new MsHTTPSamplerProxy(); + if (StringUtils.isNotBlank(operation.getSummary())) { + request.setName(operation.getSummary()); + } else { + request.setName(operation.getOperationId()); + } + request.setPath(path); + request.setMethod(method); + request.setProtocol(RequestType.HTTP); + return request; + } + + private void parseParameters(Operation operation, MsHTTPSamplerProxy request) { List parameters = operation.getParameters(); + request.setId(UUID.randomUUID().toString()); + request.setHeaders(new ArrayList<>()); + request.setArguments(new ArrayList<>()); + request.setRest(new ArrayList<>()); + request.setBody(new Body()); + request.getBody().setType(getBodyType(operation)); + + // todo 路径变量 {xxx} 是否要转换 for (Parameter parameter : parameters) { switch (parameter.getIn()) { -// case SwaggerParameterType.PATH: -// parsePathParameters(parameter, request); -// break; + case SwaggerParameterType.PATH: + parsePathParameters(parameter, request.getRest()); + break; case SwaggerParameterType.QUERY: - parseQueryParameters(parameter, request); + parseQueryParameters(parameter, request.getArguments()); break; case SwaggerParameterType.FORM_DATA: - parseFormDataParameters(parameter, request); + parseFormDataParameters((FormParameter) parameter, request.getBody()); break; case SwaggerParameterType.BODY: - parseBodyParameters(parameter, request, definitions); + parseBodyParameters(parameter, request.getBody()); break; case SwaggerParameterType.HEADER: - parseHeaderParameters(parameter, request); + parseHeaderParameters(parameter, request.getHeaders()); break; case SwaggerParameterType.COOKIE: - parseCookieParameters(parameter, request); + parseCookieParameters(parameter, request.getHeaders()); break; // case SwaggerParameterType.FILE: // parsePathParameters(parameter, request); // break; } } + + +// List responseContentTypes = operation.getProduces(); } - private void parseCookieParameters(Parameter parameter, HttpRequest request) { + private String getBodyType(Operation operation) { + if (CollectionUtils.isEmpty(operation.getConsumes())) { + return Body.RAW; + } + String contentType = operation.getConsumes().get(0); + String bodyType = ""; + switch (contentType) { + case "application/x-www-form-urlencoded": + bodyType = Body.WWW_FROM; + break; + case "multipart/form-data": + bodyType = Body.FORM_DATA; + break; + case "application/json": + bodyType = Body.JSON; + break; + case "application/xml": + bodyType = Body.XML; + break; +// case "": //todo binary 啥类型 +// bodyType = Body.BINARY; +// break; + default: + bodyType = Body.RAW; + } + return bodyType; + } + + private void parsePathParameters(Parameter parameter, List rests) { + PathParameter pathParameter = (PathParameter) parameter; + rests.add(new KeyValue(pathParameter.getName(), "", getDefaultStringValue(parameter.getDescription()))); + } + + private String getDefaultStringValue(String val) { + return StringUtils.isBlank(val) ? "" : val; + } + + private void parseCookieParameters(Parameter parameter, List headers) { CookieParameter cookieParameter = (CookieParameter) parameter; - addCookie(request, cookieParameter.getName(), cookieParameter.getDescription()); + addCookie(headers, cookieParameter.getName(), "", getDefaultStringValue(cookieParameter.getDescription())); } - private void parseHeaderParameters(Parameter parameter, HttpRequest request) { + private void parseHeaderParameters(Parameter parameter, List headers) { HeaderParameter headerParameter = (HeaderParameter) parameter; - addHeader(request, headerParameter.getName(), headerParameter.getDescription()); + addHeader(headers, headerParameter.getName(), "", getDefaultStringValue(headerParameter.getDescription())); } - private void parseBodyParameters(Parameter parameter, HttpRequest request, Map definitions) { + private void parseBodyParameters(Parameter parameter, Body body) { BodyParameter bodyParameter = (BodyParameter) parameter; - Body body = Optional.ofNullable(request.getBody()).orElse(new Body()); - body.setType(MsRequestBodyType.RAW.value()); Model schema = bodyParameter.getSchema(); + // 引用模型 if (schema instanceof RefModel) { String simpleRef = ""; RefModel refModel = (RefModel) bodyParameter.getSchema(); @@ -192,14 +221,15 @@ public class Swagger2Parser extends ApiImportAbstractParser { } else { simpleRef = refModel.getSimpleRef(); } - Model model = definitions.get(simpleRef); + Model model = this.definitions.get(simpleRef); HashSet refSet = new HashSet<>(); refSet.add(simpleRef); if (model != null) { - JSONObject bodyParameters = getBodyJSONObjectParameters(model.getProperties(), definitions, refSet); + JSONObject bodyParameters = getBodyParameters(model.getProperties(), refSet); body.setRaw(bodyParameters.toJSONString()); } } else if (schema instanceof ArrayModel) { + //模型数组 ArrayModel arrayModel = (ArrayModel) bodyParameter.getSchema(); Property items = arrayModel.getItems(); if (items instanceof RefProperty) { @@ -209,21 +239,20 @@ public class Swagger2Parser extends ApiImportAbstractParser { refSet.add(simpleRef); Model model = definitions.get(simpleRef); JSONArray propertyList = new JSONArray(); - propertyList.add(getBodyJSONObjectParameters(model.getProperties(), definitions, refSet)); + propertyList.add(getBodyParameters(model.getProperties(), refSet)); body.setRaw(propertyList.toString()); } } - request.setBody(body); body.setFormat("json"); } - private JSONObject getBodyJSONObjectParameters(Map properties, Map definitions, HashSet refSet) { + private JSONObject getBodyParameters(Map properties, HashSet refSet) { JSONObject jsonObject = new JSONObject(); if (properties != null) { properties.forEach((key, value) -> { if (value instanceof ObjectProperty) { ObjectProperty objectProperty = (ObjectProperty) value; - jsonObject.put(key, getBodyJSONObjectParameters(objectProperty.getProperties(), definitions, refSet)); + jsonObject.put(key, getBodyParameters(objectProperty.getProperties(), refSet)); } else if (value instanceof ArrayProperty) { ArrayProperty arrayProperty = (ArrayProperty) value; Property items = arrayProperty.getItems(); @@ -231,38 +260,50 @@ public class Swagger2Parser extends ApiImportAbstractParser { RefProperty refProperty = (RefProperty) items; String simpleRef = refProperty.getSimpleRef(); if (refSet.contains(simpleRef)) { + //避免嵌套死循环 jsonObject.put(key, new JSONArray()); return; } refSet.add(simpleRef); - Model model = definitions.get(simpleRef); + Model model = this.definitions.get(simpleRef); JSONArray propertyList = new JSONArray(); - propertyList.add(getBodyJSONObjectParameters(model.getProperties(), definitions, refSet)); + propertyList.add(getBodyParameters(model.getProperties(), refSet)); jsonObject.put(key, propertyList); } else { jsonObject.put(key, new ArrayList<>()); } } else { - jsonObject.put(key, Optional.ofNullable(value.getDescription()).orElse("")); + jsonObject.put(key, getDefaultValueByPropertyType(value)); } }); } return jsonObject; } - private void parseFormDataParameters(Parameter parameter, HttpRequest request) { - Body body = Optional.ofNullable(request.getBody()).orElse(new Body()); - body.setType(MsRequestBodyType.FORM_DATA.value()); - List keyValues = Optional.ofNullable(body.getKvs()).orElse(new ArrayList<>()); - keyValues.add(new KeyValue(parameter.getName(), "", parameter.getDescription())); - body.setKvs(keyValues); - request.setBody(body); + private Object getDefaultValueByPropertyType(Property value) { + if (value instanceof LongProperty || value instanceof IntegerProperty + || value instanceof BaseIntegerProperty) { + return 0; + } else if (value instanceof FloatProperty || value instanceof DoubleProperty + || value instanceof DecimalProperty) { + return 0.0; + } else {// todo 其他类型? + return getDefaultStringValue(value.getDescription()); + } } - private void parseQueryParameters(Parameter parameter, HttpRequest request) { + private void parseFormDataParameters(FormParameter parameter, Body body) { + List keyValues = Optional.ofNullable(body.getKvs()).orElse(new ArrayList<>()); + KeyValue kv = new KeyValue(parameter.getName(), "", getDefaultStringValue(parameter.getDescription())); + if (StringUtils.equals(parameter.getType(), "file") ) { + kv.setType("file"); + } + keyValues.add(kv); + body.setKvs(keyValues); + } + + private void parseQueryParameters(Parameter parameter, List arguments) { QueryParameter queryParameter = (QueryParameter) parameter; - List parameters = Optional.ofNullable(request.getParameters()).orElse(new ArrayList<>()); - parameters.add(new KeyValue(queryParameter.getName(), "", queryParameter.getDescription())); - request.setParameters(parameters); + arguments.add(new KeyValue(queryParameter.getName(), "", getDefaultStringValue(queryParameter.getDescription()))); } } diff --git a/backend/src/main/java/io/metersphere/api/parse/old/ApiImportAbstractParser.java b/backend/src/main/java/io/metersphere/api/parse/old/ApiImportAbstractParser.java new file mode 100644 index 0000000000..ac18f2a75a --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/old/ApiImportAbstractParser.java @@ -0,0 +1,82 @@ +package io.metersphere.api.parse.old; + +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.scenario.KeyValue; +import io.metersphere.api.dto.scenario.Scenario; +import io.metersphere.api.dto.scenario.request.HttpRequest; +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.LogUtil; +import org.apache.commons.lang3.StringUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public abstract class ApiImportAbstractParser implements ApiImportParser { + + protected String getApiTestStr(InputStream source) { + StringBuilder testStr = null; + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(source, StandardCharsets.UTF_8))) { + testStr = new StringBuilder(); + String inputStr; + while ((inputStr = bufferedReader.readLine()) != null) { + testStr.append(inputStr); + } + } catch (Exception e) { + MSException.throwException(e.getMessage()); + LogUtil.error(e.getMessage(), e); + } finally { + try { + source.close(); + } catch (IOException e) { + MSException.throwException(e.getMessage()); + LogUtil.error(e.getMessage(), e); + } + } + return testStr.toString(); + } + + protected void setScenarioByRequest(Scenario scenario, ApiTestImportRequest request) { + if (request.getUseEnvironment()) { + scenario.setEnvironmentId(request.getEnvironmentId()); + } + } + + protected void addContentType(HttpRequest request, String contentType) { + addHeader(request, "Content-Type", contentType); + } + + protected void addCookie(HttpRequest request, String key, String value) { + List headers = Optional.ofNullable(request.getHeaders()).orElse(new ArrayList<>()); + boolean hasCookie = false; + for (KeyValue header : headers) { + if (StringUtils.equalsIgnoreCase("Cookie", header.getName())) { + hasCookie = true; + String cookies = Optional.ofNullable(header.getValue()).orElse(""); + header.setValue(cookies + key + "=" + value + ";"); + } + } + if (!hasCookie) { + addHeader(request, "Cookie", key + "=" + value + ";"); + } + } + + protected void addHeader(HttpRequest request, String key, String value) { + List headers = Optional.ofNullable(request.getHeaders()).orElse(new ArrayList<>()); + boolean hasContentType = false; + for (KeyValue header : headers) { + if (StringUtils.equalsIgnoreCase(header.getName(), key)) { + hasContentType = true; + } + } + if (!hasContentType) { + headers.add(new KeyValue(key, value)); + } + request.setHeaders(headers); + } +} diff --git a/backend/src/main/java/io/metersphere/api/parse/old/ApiImportParser.java b/backend/src/main/java/io/metersphere/api/parse/old/ApiImportParser.java new file mode 100644 index 0000000000..edc1c47908 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/old/ApiImportParser.java @@ -0,0 +1,13 @@ +package io.metersphere.api.parse.old; + +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; +import io.metersphere.api.dto.parse.ApiImport; + +import java.io.InputStream; + +public interface ApiImportParser { + ApiImport parse(InputStream source, ApiTestImportRequest request); + ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request); + +} diff --git a/backend/src/main/java/io/metersphere/api/parse/old/ApiImportParserFactory.java b/backend/src/main/java/io/metersphere/api/parse/old/ApiImportParserFactory.java new file mode 100644 index 0000000000..6235617a83 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/old/ApiImportParserFactory.java @@ -0,0 +1,17 @@ +package io.metersphere.api.parse.old; + +import io.metersphere.commons.constants.ApiImportPlatform; +import org.apache.commons.lang3.StringUtils; + +public class ApiImportParserFactory { + public static ApiImportParser getApiImportParser(String platform) { + if (StringUtils.equals(ApiImportPlatform.Metersphere.name(), platform)) { + return new MsParser(); + } else if (StringUtils.equals(ApiImportPlatform.Postman.name(), platform)) { + return new PostmanParser(); + } else if (StringUtils.equals(ApiImportPlatform.Swagger2.name(), platform)) { + return new Swagger2Parser(); + } + return null; + } +} diff --git a/backend/src/main/java/io/metersphere/api/parse/old/JmeterDocumentParser.java b/backend/src/main/java/io/metersphere/api/parse/old/JmeterDocumentParser.java new file mode 100644 index 0000000000..c648df516b --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/old/JmeterDocumentParser.java @@ -0,0 +1,227 @@ +package io.metersphere.api.parse.old; + +import io.metersphere.commons.utils.LogUtil; +import io.metersphere.commons.utils.ScriptEngineUtils; +import org.apache.commons.lang3.StringUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.ByteArrayInputStream; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; + +public class JmeterDocumentParser { + private final static String HASH_TREE_ELEMENT = "hashTree"; + private final static String STRING_PROP = "stringProp"; + private final static String ARGUMENTS = "Arguments"; + private final static String COLLECTION_PROP = "collectionProp"; + private final static String HTTP_SAMPLER_PROXY = "MsHTTPSamplerProxy"; + private final static String ELEMENT_PROP = "elementProp"; + + public static byte[] parse(byte[] source) { + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + try ( + ByteArrayInputStream byteStream = new ByteArrayInputStream(source) + ) { + InputSource inputSource = new InputSource(byteStream); + DocumentBuilder docBuilder = factory.newDocumentBuilder(); + final Document document = docBuilder.parse(inputSource); + final Element jmeterTestPlan = document.getDocumentElement(); + + NodeList childNodes = jmeterTestPlan.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + if (node instanceof Element) { + Element ele = (Element) node; + parseHashTree(ele); + } + } + return documentToBytes(document); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + return source; + } + } + + private static byte[] documentToBytes(Document document) throws TransformerException { + DOMSource domSource = new DOMSource(document); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.transform(domSource, result); + return writer.toString().getBytes(); + } + + private static void parseHashTree(Element hashTree) { + if (invalid(hashTree)) { + return; + } + + if (hashTree.getChildNodes().getLength() > 0) { + final NodeList childNodes = hashTree.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + if (node instanceof Element) { + Element ele = (Element) node; + if (invalid(ele)) { + continue; + } + + if (nodeNameEquals(ele, HASH_TREE_ELEMENT)) { + parseHashTree(ele); + } else if (nodeNameEquals(ele, ARGUMENTS)) { + processArguments(ele); + } else if (nodeNameEquals(ele, HTTP_SAMPLER_PROXY)) { + processHttpSamplerProxy(ele); + } + } + } + } + } + + private static void processHttpSamplerProxy(Element ele) { + if (invalid(ele)) { + return; + } + NodeList childNodes = ele.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node item = childNodes.item(i); + if (!(item instanceof Element)) { + continue; + } + Element element = (Element) item; + if (nodeNameEquals(element, ELEMENT_PROP) && "HTTPsampler.Arguments".equals(element.getAttribute("name"))) { + processArguments(element); + } else if ("HTTPSampler.path".equals(element.getAttribute("name"))) { + processStringProp(element); + } + } + } + + private static void processArguments(Element ele) { + if (invalid(ele)) { + return; + } + NodeList childNodes = ele.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node item = childNodes.item(i); + if (!(item instanceof Element)) { + continue; + } + Element element = (Element) item; + if (nodeNameEquals(item, COLLECTION_PROP) && "Arguments.arguments".equals(element.getAttribute("name"))) { + NodeList elementProps = item.getChildNodes(); + for (int j = 0; j < elementProps.getLength(); j++) { + Node elementProp = elementProps.item(j); + if (!(elementProp instanceof Element)) { + continue; + } + NodeList stringProps = elementProp.getChildNodes(); + for (int k = 0; k < stringProps.getLength(); k++) { + Node stringProp = stringProps.item(k); + if (!(stringProp instanceof Element)) { + continue; + } + processStringProp((Element) stringProp); + } + } + } + } + } + + private static void processStringProp(Element ele) { + String name = ele.getAttribute("name"); + switch (name) { + case "HTTPSampler.path": + String path = ele.getTextContent(); + Map parser = parserUrl(path); + String url = parser.get("URL"); + String params = parser.keySet().stream().filter(k -> !"URL".equals(k)).reduce("?", (u, k) -> { + String v = parser.get(k); + if (!StringUtils.equals("?", u)) { + u += "&"; + } + u += k + "=" + ScriptEngineUtils.calculate(v); + return u; + }); + ele.setTextContent(url + ((params != null && !params.equals("?")) ? params : "")); + break; + case "Argument.value": + String textContent = ele.getTextContent(); + if (StringUtils.startsWith(textContent, "@")) { + ele.setTextContent(ScriptEngineUtils.calculate(textContent)); + } + break; + default: + break; + } + } + + private static boolean nodeNameEquals(Node node, String desiredName) { + return desiredName.equals(node.getNodeName()) || desiredName.equals(node.getLocalName()); + } + + private static boolean invalid(Element ele) { + return !StringUtils.isBlank(ele.getAttribute("enabled")) && !Boolean.parseBoolean(ele.getAttribute("enabled")); + } + + private static Map parserUrl(String url) { +// 传递的URL参数 + Map strUrlParas = new HashMap<>(); + + String strUrl; + String strUrlParams; + + +// 解析访问地址 + if (url.contains("?")) { + String[] strUrlPatten = url.split("\\?"); + strUrl = strUrlPatten[0]; + strUrlParams = strUrlPatten[1]; + + } else { + strUrl = url; + strUrlParams = url; + } + + strUrlParas.put("URL", strUrl); +// 解析参数 + String[] params = null; + + if (strUrlParams.contains("&")) { + params = strUrlParams.split("&"); + } else { + params = new String[]{strUrlParams}; + } + +// 保存参数到参数容器 + for (String p : params) { + if (p.contains("=")) { + String[] param = p.split("="); + if (param.length == 1) { + strUrlParas.put(param[0], ""); + } else { + + String key = param[0]; + String value = param[1]; + + strUrlParas.put(key, value); + } + } + } + return strUrlParas; + } +} diff --git a/backend/src/main/java/io/metersphere/api/parse/old/MsParser.java b/backend/src/main/java/io/metersphere/api/parse/old/MsParser.java new file mode 100644 index 0000000000..5ec129288c --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/old/MsParser.java @@ -0,0 +1,101 @@ +package io.metersphere.api.parse.old; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; +import io.metersphere.api.dto.parse.ApiImport; +import io.metersphere.api.dto.scenario.request.RequestType; +import io.metersphere.commons.constants.MsRequestBodyType; +import org.apache.commons.lang3.StringUtils; + +import java.io.InputStream; + +public class MsParser extends ApiImportAbstractParser { + + @Override + public ApiImport parse(InputStream source, ApiTestImportRequest request) { + String testStr = getApiTestStr(source); + ApiImport apiImport = JSON.parseObject(parsePluginFormat(testStr), ApiImport.class); + apiImport.getScenarios().forEach(scenario -> setScenarioByRequest(scenario, request)); + return apiImport; + } + + @Override + public ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request) { + String testStr = getApiTestStr(source); + ApiDefinitionImport apiImport = JSON.parseObject(testStr, ApiDefinitionImport.class); + return apiImport; + } + + private String parsePluginFormat(String testStr) { + JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField); + if (testObject.get("scenarios") != null) { + return testStr; + } else { + //插件格式 + JSONArray scenarios = new JSONArray(); + testObject.keySet().forEach(scenarioName -> { + JSONObject scenario = new JSONObject(); + scenario.put("name", scenarioName); + JSONArray requestsObjects = new JSONArray(); + JSONObject requestsObject = testObject.getJSONObject(scenarioName); + requestsObject.keySet().forEach(requestName -> { + JSONObject requestObject = new JSONObject(true); + JSONObject requestTmpObject = requestsObject.getJSONObject(requestName); + //排序,确保type在第一个,否则转换失败 + if (StringUtils.isBlank(requestTmpObject.getString("type"))) { + requestObject.put("type", RequestType.HTTP); + } + + requestTmpObject.keySet().forEach(key -> requestObject.put(key, requestTmpObject.get(key))); + requestObject.put("name", requestName); + parseBody(requestObject); + requestsObjects.add(requestObject); + }); + scenario.put("requests", requestsObjects); + scenarios.add(scenario); + }); + JSONObject result = new JSONObject(); + result.put("scenarios", scenarios); + return result.toJSONString(); + } + } + + private void parseBody(JSONObject requestObject) { + if (requestObject.containsKey("body")) { + Object body = requestObject.get("body"); + if (body instanceof JSONArray) { + JSONArray bodies = requestObject.getJSONArray("body"); + if (bodies != null) { + StringBuilder bodyStr = new StringBuilder(); + for (int i = 0; i < bodies.size(); i++) { + String tmp = bodies.getString(i); + bodyStr.append(tmp); + } + JSONObject bodyObject = new JSONObject(); + bodyObject.put("raw", bodyStr); + bodyObject.put("type", MsRequestBodyType.RAW.value()); + requestObject.put("body", bodyObject); + } + } else if (body instanceof JSONObject) { + JSONObject bodyObj = requestObject.getJSONObject("body"); + if (bodyObj != null) { + JSONArray kvs = new JSONArray(); + bodyObj.keySet().forEach(key -> { + JSONObject kv = new JSONObject(); + kv.put("name", key); + kv.put("value", bodyObj.getString(key)); + kvs.add(kv); + }); + JSONObject bodyRes = new JSONObject(); + bodyRes.put("kvs", kvs); + bodyRes.put("type", MsRequestBodyType.KV.value()); + requestObject.put("body", bodyRes); + } + } + } + } +} diff --git a/backend/src/main/java/io/metersphere/api/parse/old/PostmanParser.java b/backend/src/main/java/io/metersphere/api/parse/old/PostmanParser.java new file mode 100644 index 0000000000..aba9b3199a --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/old/PostmanParser.java @@ -0,0 +1,184 @@ +package io.metersphere.api.parse.old; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.ApiDefinitionResult; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; +import io.metersphere.api.dto.definition.request.MsTestElement; +import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager; +import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; +import io.metersphere.api.dto.parse.ApiImport; +import io.metersphere.api.dto.parse.postman.*; +import io.metersphere.api.dto.scenario.Body; +import io.metersphere.api.dto.scenario.KeyValue; +import io.metersphere.api.dto.scenario.Scenario; +import io.metersphere.api.dto.scenario.request.HttpRequest; +import io.metersphere.api.dto.scenario.request.Request; +import io.metersphere.api.dto.scenario.request.RequestType; +import io.metersphere.commons.constants.MsRequestBodyType; +import io.metersphere.commons.constants.PostmanRequestBodyMode; +import org.apache.commons.lang3.StringUtils; +import org.apache.jorphan.collections.HashTree; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +public class PostmanParser extends ApiImportAbstractParser { + + @Override + public ApiImport parse(InputStream source, ApiTestImportRequest request) { + + String testStr = getApiTestStr(source); + PostmanCollection postmanCollection = JSON.parseObject(testStr, PostmanCollection.class); + PostmanCollectionInfo info = postmanCollection.getInfo(); + List variables = postmanCollection.getVariable(); + ApiImport apiImport = new ApiImport(); + List scenarios = new ArrayList<>(); + + Scenario scenario = new Scenario(); + scenario.setName(info.getName()); + setScenarioByRequest(scenario, request); + parseItem(postmanCollection.getItem(), scenario, variables, scenarios); + apiImport.setScenarios(scenarios); + + return apiImport; + } + + @Override + public ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request) { + String testStr = getApiTestStr(source); + PostmanCollection postmanCollection = JSON.parseObject(testStr, PostmanCollection.class); + List variables = postmanCollection.getVariable(); + ApiDefinitionImport apiImport = new ApiDefinitionImport(); + List requests = new ArrayList<>(); + + parseItem(postmanCollection.getItem(), variables, requests); + apiImport.setData(requests); + return apiImport; + } + + private void parseItem(List items, List variables, List scenarios) { + for (PostmanItem item : items) { + List childItems = item.getItem(); + if (childItems != null) { + parseItem(childItems, variables, scenarios); + } else { + ApiDefinitionResult request = parsePostman(item); + if (request != null) { + scenarios.add(request); + } + } + } + } + + private ApiDefinitionResult parsePostman(PostmanItem requestItem) { + PostmanRequest requestDesc = requestItem.getRequest(); + if (requestDesc == null) { + return null; + } + PostmanUrl url = requestDesc.getUrl(); + ApiDefinitionResult request = new ApiDefinitionResult(); + request.setName(requestItem.getName()); + request.setPath(url.getRaw()); + request.setMethod(requestDesc.getMethod()); + request.setProtocol(RequestType.HTTP); + MsHTTPSamplerProxy requestElement = new MsHTTPSamplerProxy(); + requestElement.setName(requestItem.getName() + "Postman MHTTPSamplerProxy"); + requestElement.setBody(parseBody(requestDesc)); + requestElement.setArguments(parseKeyValue(url.getQuery())); + requestElement.setProtocol(RequestType.HTTP); + requestElement.setPath(url.getRaw()); + requestElement.setMethod(requestDesc.getMethod()); + requestElement.setId(UUID.randomUUID().toString()); + requestElement.setRest(new ArrayList()); + MsHeaderManager headerManager = new MsHeaderManager(); + headerManager.setId(UUID.randomUUID().toString()); + headerManager.setName(requestItem.getName() + "Postman MsHeaderManager"); + headerManager.setHeaders(parseKeyValue(requestDesc.getHeader())); + HashTree tree = new HashTree(); + tree.add(headerManager); + LinkedList list = new LinkedList<>(); + list.add(headerManager); + requestElement.setHashTree(list); + request.setRequest(JSON.toJSONString(requestElement)); + return request; + } + + + private List parseKeyValue(List postmanKeyValues) { + if (postmanKeyValues == null) { + return null; + } + List keyValues = new ArrayList<>(); + postmanKeyValues.forEach(item -> keyValues.add(new KeyValue(item.getKey(), item.getValue()))); + return keyValues; + } + + private void parseItem(List items, Scenario scenario, List variables, List scenarios) { + List requests = new ArrayList<>(); + for (PostmanItem item : items) { + List childItems = item.getItem(); + if (childItems != null) { + Scenario subScenario = new Scenario(); + subScenario.setName(item.getName()); + subScenario.setEnvironmentId(scenario.getEnvironmentId()); + parseItem(childItems, subScenario, variables, scenarios); + } else { + Request request = parseRequest(item); + if (request != null) { + requests.add(request); + } + } + } + scenario.setVariables(parseKeyValue(variables)); + scenario.setRequests(requests); + scenarios.add(scenario); + } + + private Request parseRequest(PostmanItem requestItem) { + HttpRequest request = new HttpRequest(); + PostmanRequest requestDesc = requestItem.getRequest(); + if (requestDesc == null) { + return null; + } + PostmanUrl url = requestDesc.getUrl(); + request.setName(requestItem.getName()); + request.setUrl(url.getRaw()); + request.setUseEnvironment(false); + request.setMethod(requestDesc.getMethod()); + request.setHeaders(parseKeyValue(requestDesc.getHeader())); + request.setParameters(parseKeyValue(url.getQuery())); + request.setBody(parseBody(requestDesc)); + return request; + } + + private Body parseBody(PostmanRequest requestDesc) { + Body body = new Body(); + JSONObject postmanBody = requestDesc.getBody(); + if (postmanBody == null) { + return null; + } + String bodyMode = postmanBody.getString("mode"); + if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.RAW.value())) { + body.setRaw(postmanBody.getString(bodyMode)); + body.setType(MsRequestBodyType.RAW.value()); + JSONObject options = postmanBody.getJSONObject("options"); + if (options != null) { + JSONObject raw = options.getJSONObject(PostmanRequestBodyMode.RAW.value()); + if (raw != null) { + body.setFormat(raw.getString("language")); + } + } + } else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FORM_DATA.value()) || StringUtils.equals(bodyMode, PostmanRequestBodyMode.URLENCODED.value())) { + List postmanKeyValues = JSON.parseArray(postmanBody.getString(bodyMode), PostmanKeyValue.class); + body.setType(MsRequestBodyType.KV.value()); + body.setKvs(parseKeyValue(postmanKeyValues)); + } + return body; + } + +} diff --git a/backend/src/main/java/io/metersphere/api/parse/old/Swagger2Parser.java b/backend/src/main/java/io/metersphere/api/parse/old/Swagger2Parser.java new file mode 100644 index 0000000000..5aaac94a95 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/old/Swagger2Parser.java @@ -0,0 +1,268 @@ +package io.metersphere.api.parse.old; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.ApiDefinitionResult; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; +import io.metersphere.api.dto.definition.request.MsTestElement; +import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager; +import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; +import io.metersphere.api.dto.parse.ApiImport; +import io.metersphere.api.dto.scenario.Body; +import io.metersphere.api.dto.scenario.KeyValue; +import io.metersphere.api.dto.scenario.Scenario; +import io.metersphere.api.dto.scenario.request.HttpRequest; +import io.metersphere.api.dto.scenario.request.Request; +import io.metersphere.api.dto.scenario.request.RequestType; +import io.metersphere.commons.constants.MsRequestBodyType; +import io.metersphere.commons.constants.SwaggerParameterType; +import io.swagger.models.*; +import io.swagger.models.parameters.*; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.ObjectProperty; +import io.swagger.models.properties.Property; +import io.swagger.models.properties.RefProperty; +import io.swagger.parser.SwaggerParser; +import org.apache.commons.lang3.StringUtils; +import org.apache.jorphan.collections.HashTree; + +import java.io.InputStream; +import java.util.*; + +public class Swagger2Parser extends ApiImportAbstractParser { + + @Override + public ApiImport parse(InputStream source, ApiTestImportRequest request) { + Swagger swagger; + if (StringUtils.isNotBlank(request.getSwaggerUrl())) { + swagger = new SwaggerParser().read(request.getSwaggerUrl()); + } else { + swagger = new SwaggerParser().readWithInfo(getApiTestStr(source)).getSwagger(); + } + ApiImport apiImport = new ApiImport(); + apiImport.setScenarios(parseRequests(swagger)); + apiImport.getScenarios().forEach(scenario -> scenario.setEnvironmentId(request.getEnvironmentId())); + return apiImport; + } + + @Override + public ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request) { + ApiImport apiImport = this.parse(source, request); + ApiDefinitionImport definitionImport = new ApiDefinitionImport(); + definitionImport.setData(parseSwagger(apiImport)); + return definitionImport; + } + + private List parseSwagger(ApiImport apiImport) { + List results = new LinkedList<>(); + apiImport.getScenarios().forEach(item -> { + item.getRequests().forEach(childItem -> { + if (childItem instanceof HttpRequest) { + HttpRequest res = (HttpRequest) childItem; + ApiDefinitionResult request = new ApiDefinitionResult(); + request.setName(res.getName()); + request.setPath(res.getPath()); + request.setMethod(res.getMethod()); + request.setProtocol(RequestType.HTTP); + MsHTTPSamplerProxy requestElement = new MsHTTPSamplerProxy(); + requestElement.setName(res.getName() + "Postman MHTTPSamplerProxy"); + requestElement.setBody(res.getBody()); + requestElement.setArguments(res.getParameters()); + requestElement.setProtocol(RequestType.HTTP); + requestElement.setPath(res.getPath()); + requestElement.setMethod(res.getMethod()); + requestElement.setId(UUID.randomUUID().toString()); + requestElement.setRest(new ArrayList()); + MsHeaderManager headerManager = new MsHeaderManager(); + headerManager.setId(UUID.randomUUID().toString()); + headerManager.setName(res.getName() + "Postman MsHeaderManager"); + headerManager.setHeaders(res.getHeaders()); +// HashTree tree = new HashTree(); +// tree.add(headerManager); + LinkedList list = new LinkedList<>(); + list.add(headerManager); + requestElement.setHashTree(list); + request.setRequest(JSON.toJSONString(requestElement)); + results.add(request); + } + + }); + }); + return results; + } + + private List parseRequests(Swagger swagger) { + Map paths = swagger.getPaths(); + Set pathNames = paths.keySet(); + Map scenarioMap = new HashMap<>(); + for (String pathName : pathNames) { + Path path = paths.get(pathName); + Map operationMap = path.getOperationMap(); + Set httpMethods = operationMap.keySet(); + for (HttpMethod method : httpMethods) { + Operation operation = operationMap.get(method); + HttpRequest request = new HttpRequest(); + if (StringUtils.isNotBlank(operation.getSummary())) { + request.setName(operation.getSummary()); + } else { + request.setName(operation.getOperationId()); + } + request.setPath(pathName); + request.setUseEnvironment(true); + request.setMethod(method.name()); + parseParameters(operation, swagger.getDefinitions(), request); + List tags = operation.getTags(); + if (tags != null) { + tags.forEach(tag -> { + Scenario scenario = Optional.ofNullable(scenarioMap.get(tag)).orElse(new Scenario()); + List requests = Optional.ofNullable(scenario.getRequests()).orElse(new ArrayList<>()); + requests.add(request); + scenario.setRequests(requests); + scenario.setName(tag); + scenarioMap.put(tag, scenario); + }); + } else { + Scenario scenario = Optional.ofNullable(scenarioMap.get("default")).orElse(new Scenario()); + List requests = Optional.ofNullable(scenario.getRequests()).orElse(new ArrayList<>()); + requests.add(request); + scenario.setRequests(requests); + scenarioMap.put("default", scenario); + } + + } + } + return new ArrayList<>(scenarioMap.values()); + } + + private void parseParameters(Operation operation, Map definitions, HttpRequest request) { + + List parameters = operation.getParameters(); + + for (Parameter parameter : parameters) { + switch (parameter.getIn()) { +// case SwaggerParameterType.PATH: +// parsePathParameters(parameter, request); +// break; + case SwaggerParameterType.QUERY: + parseQueryParameters(parameter, request); + break; + case SwaggerParameterType.FORM_DATA: + parseFormDataParameters(parameter, request); + break; + case SwaggerParameterType.BODY: + parseBodyParameters(parameter, request, definitions); + break; + case SwaggerParameterType.HEADER: + parseHeaderParameters(parameter, request); + break; + case SwaggerParameterType.COOKIE: + parseCookieParameters(parameter, request); + break; +// case SwaggerParameterType.FILE: +// parsePathParameters(parameter, request); +// break; + } + } + } + + private void parseCookieParameters(Parameter parameter, HttpRequest request) { + CookieParameter cookieParameter = (CookieParameter) parameter; + addCookie(request, cookieParameter.getName(), cookieParameter.getDescription()); + } + + private void parseHeaderParameters(Parameter parameter, HttpRequest request) { + HeaderParameter headerParameter = (HeaderParameter) parameter; + addHeader(request, headerParameter.getName(), headerParameter.getDescription()); + } + + private void parseBodyParameters(Parameter parameter, HttpRequest request, Map definitions) { + BodyParameter bodyParameter = (BodyParameter) parameter; + Body body = Optional.ofNullable(request.getBody()).orElse(new Body()); + body.setType(MsRequestBodyType.RAW.value()); + Model schema = bodyParameter.getSchema(); + + if (schema instanceof RefModel) { + String simpleRef = ""; + RefModel refModel = (RefModel) bodyParameter.getSchema(); + String originalRef = refModel.getOriginalRef(); + if (refModel.getOriginalRef().split("/").length > 3) { + simpleRef = originalRef.replace("#/definitions/", ""); + } else { + simpleRef = refModel.getSimpleRef(); + } + Model model = definitions.get(simpleRef); + HashSet refSet = new HashSet<>(); + refSet.add(simpleRef); + if (model != null) { + JSONObject bodyParameters = getBodyJSONObjectParameters(model.getProperties(), definitions, refSet); + body.setRaw(bodyParameters.toJSONString()); + } + } else if (schema instanceof ArrayModel) { + ArrayModel arrayModel = (ArrayModel) bodyParameter.getSchema(); + Property items = arrayModel.getItems(); + if (items instanceof RefProperty) { + RefProperty refProperty = (RefProperty) items; + String simpleRef = refProperty.getSimpleRef(); + HashSet refSet = new HashSet<>(); + refSet.add(simpleRef); + Model model = definitions.get(simpleRef); + JSONArray propertyList = new JSONArray(); + propertyList.add(getBodyJSONObjectParameters(model.getProperties(), definitions, refSet)); + body.setRaw(propertyList.toString()); + } + } + request.setBody(body); + body.setFormat("json"); + } + + private JSONObject getBodyJSONObjectParameters(Map properties, Map definitions, HashSet refSet) { + JSONObject jsonObject = new JSONObject(); + if (properties != null) { + properties.forEach((key, value) -> { + if (value instanceof ObjectProperty) { + ObjectProperty objectProperty = (ObjectProperty) value; + jsonObject.put(key, getBodyJSONObjectParameters(objectProperty.getProperties(), definitions, refSet)); + } else if (value instanceof ArrayProperty) { + ArrayProperty arrayProperty = (ArrayProperty) value; + Property items = arrayProperty.getItems(); + if (items instanceof RefProperty) { + RefProperty refProperty = (RefProperty) items; + String simpleRef = refProperty.getSimpleRef(); + if (refSet.contains(simpleRef)) { + jsonObject.put(key, new JSONArray()); + return; + } + refSet.add(simpleRef); + Model model = definitions.get(simpleRef); + JSONArray propertyList = new JSONArray(); + propertyList.add(getBodyJSONObjectParameters(model.getProperties(), definitions, refSet)); + jsonObject.put(key, propertyList); + } else { + jsonObject.put(key, new ArrayList<>()); + } + } else { + jsonObject.put(key, Optional.ofNullable(value.getDescription()).orElse("")); + } + }); + } + return jsonObject; + } + + private void parseFormDataParameters(Parameter parameter, HttpRequest request) { + Body body = Optional.ofNullable(request.getBody()).orElse(new Body()); + body.setType(MsRequestBodyType.FORM_DATA.value()); + List keyValues = Optional.ofNullable(body.getKvs()).orElse(new ArrayList<>()); + keyValues.add(new KeyValue(parameter.getName(), "", parameter.getDescription())); + body.setKvs(keyValues); + request.setBody(body); + } + + private void parseQueryParameters(Parameter parameter, HttpRequest request) { + QueryParameter queryParameter = (QueryParameter) parameter; + List parameters = Optional.ofNullable(request.getParameters()).orElse(new ArrayList<>()); + parameters.add(new KeyValue(queryParameter.getName(), "", queryParameter.getDescription())); + request.setParameters(parameters); + } +} diff --git a/backend/src/main/java/io/metersphere/api/service/APITestService.java b/backend/src/main/java/io/metersphere/api/service/APITestService.java index 9b1e621284..bcb068c941 100644 --- a/backend/src/main/java/io/metersphere/api/service/APITestService.java +++ b/backend/src/main/java/io/metersphere/api/service/APITestService.java @@ -6,9 +6,9 @@ import io.metersphere.api.dto.*; import io.metersphere.api.dto.parse.ApiImport; import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter; import io.metersphere.api.jmeter.JMeterService; -import io.metersphere.api.parse.ApiImportParser; -import io.metersphere.api.parse.ApiImportParserFactory; -import io.metersphere.api.parse.JmeterDocumentParser; +import io.metersphere.api.parse.old.ApiImportParser; +import io.metersphere.api.parse.old.ApiImportParserFactory; +import io.metersphere.api.parse.old.JmeterDocumentParser; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiTestFileMapper; import io.metersphere.base.mapper.ApiTestMapper; diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index 05f3665256..8786acb243 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -227,7 +227,6 @@ public class ApiDefinitionService { private ApiDefinition createTest(ApiDefinitionResult request, ApiDefinitionMapper batchMapper) { SaveApiDefinitionRequest saveReq = new SaveApiDefinitionRequest(); BeanUtils.copyBean(saveReq, request); - saveReq.setId(UUID.randomUUID().toString()); checkNameExist(saveReq); final ApiDefinitionWithBLOBs test = new ApiDefinitionWithBLOBs(); BeanUtils.copyBean(test, request); @@ -340,7 +339,6 @@ public class ApiDefinitionService { item.setModuleId(importRequest.getModuleId()); item.setModulePath(importRequest.getModulePath()); item.setEnvironmentId(importRequest.getEnvironmentId()); - item.setId(UUID.randomUUID().toString()); item.setUserId(null); createTest(item, batchMapper); if (i % 300 == 0) { diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml index 9a9a8b2d51..b6f0bc1771 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml @@ -364,6 +364,6 @@ from test_case, project where test_case.project_id = project.id and project.workspace_id = #{workspaceId} - and test_case.id = #{caseId}; + and test_case.id = #{caseId} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/notice/sender/NoticeModel.java b/backend/src/main/java/io/metersphere/notice/sender/NoticeModel.java index bdfec0b3d0..bef8bda4d0 100644 --- a/backend/src/main/java/io/metersphere/notice/sender/NoticeModel.java +++ b/backend/src/main/java/io/metersphere/notice/sender/NoticeModel.java @@ -17,6 +17,10 @@ public class NoticeModel { * 保存状态 */ private String status; + /** + * Event + */ + private String event; /** * 消息主题 */ diff --git a/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java b/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java index 597820a06a..1adc46a06b 100644 --- a/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java +++ b/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java @@ -1,5 +1,6 @@ package io.metersphere.notice.service; +import com.alibaba.nacos.client.utils.StringUtils; import io.metersphere.commons.constants.NoticeConstants; import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.notice.domain.MessageDetail; @@ -22,6 +23,10 @@ public class NoticeSendService { @Resource private DingNoticeSender dingNoticeSender; + private void event(String event) { + + } + private NoticeSender getNoticeSender(MessageDetail messageDetail) { NoticeSender noticeSender = null; switch (messageDetail.getType()) { @@ -56,8 +61,10 @@ public class NoticeSendService { messageDetails = noticeService.searchMessageByType(taskType); break; } - messageDetails.forEach(messageDetail -> - this.getNoticeSender(messageDetail).send(messageDetail, noticeModel) - ); + messageDetails.forEach(messageDetail -> { + if (StringUtils.equals(messageDetail.getEvent(), noticeModel.getEvent())) { + this.getNoticeSender(messageDetail).send(messageDetail, noticeModel); + } + }); } } diff --git a/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java b/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java index 8525f51a34..6b9ea8226f 100644 --- a/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java +++ b/backend/src/main/java/io/metersphere/performance/notice/PerformanceNoticeTask.java @@ -63,6 +63,7 @@ public class PerformanceNoticeTask { String successContext = ""; String failedContext = ""; String subject = ""; + String event = ""; if (StringUtils.equals(NoticeConstants.Mode.API, loadTestReport.getTriggerMode())) { successContext = "性能测试 API任务通知:" + loadTestReport.getName() + "执行成功" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + url; failedContext = "性能测试 API任务通知:" + loadTestReport.getName() + "执行失败" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + url; @@ -74,6 +75,13 @@ public class PerformanceNoticeTask { subject = Translator.get("task_notification"); } + if (PerformanceTestStatus.Completed.name().equals(loadTestReport.getStatus())) { + event = NoticeConstants.Event.EXECUTE_SUCCESSFUL; + } + if (PerformanceTestStatus.Error.name().equals(loadTestReport.getStatus())) { + event = NoticeConstants.Event.EXECUTE_FAILED; + } + NoticeModel noticeModel = NoticeModel.builder() .successContext(successContext) .successMailTemplate("PerformanceApiSuccessNotification") @@ -82,6 +90,7 @@ public class PerformanceNoticeTask { .testId(loadTestReport.getTestId()) .status(loadTestReport.getStatus()) .subject(subject) + .event(event) .build(); noticeSendService.send(loadTestReport.getTriggerMode(), noticeModel); } diff --git a/backend/src/main/java/io/metersphere/track/service/IssuesService.java b/backend/src/main/java/io/metersphere/track/service/IssuesService.java index c2aefecbf9..4239dbb49e 100644 --- a/backend/src/main/java/io/metersphere/track/service/IssuesService.java +++ b/backend/src/main/java/io/metersphere/track/service/IssuesService.java @@ -100,6 +100,7 @@ public class IssuesService { .subject(Translator.get("task_defect_notification")) .mailTemplate("IssuesCreate") .paramMap(paramMap) + .event(NoticeConstants.Event.CREATE) .build(); noticeSendService.send(NoticeConstants.TaskType.DEFECT_TASK, noticeModel); } diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseCommentService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseCommentService.java index 1aa688a420..1410744fc1 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseCommentService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseCommentService.java @@ -73,6 +73,7 @@ public class TestCaseCommentService { .subject(Translator.get("test_review_task_notice")) .mailTemplate("ReviewComments") .paramMap(paramMap) + .event(NoticeConstants.Event.COMMENT) .build(); noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel); } diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java index a3ab852fa1..cf68b5e59a 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java @@ -112,6 +112,7 @@ public class TestCaseReviewService { .subject(Translator.get("test_review_task_notice")) .mailTemplate("ReviewInitiate") .paramMap(paramMap) + .event(NoticeConstants.Event.CREATE) .build(); noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel); } @@ -216,6 +217,7 @@ public class TestCaseReviewService { .subject(Translator.get("test_review_task_notice")) .mailTemplate("ReviewEnd") .paramMap(paramMap) + .event(NoticeConstants.Event.UPDATE) .build(); noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel); } @@ -318,6 +320,7 @@ public class TestCaseReviewService { .subject(Translator.get("test_review_task_notice")) .mailTemplate("ReviewDelete") .paramMap(paramMap) + .event(NoticeConstants.Event.DELETE) .build(); noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel); } catch (Exception e) { @@ -460,6 +463,7 @@ public class TestCaseReviewService { .subject(Translator.get("test_review_task_notice")) .mailTemplate("ReviewEnd") .paramMap(paramMap) + .event(NoticeConstants.Event.UPDATE) .build(); noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel); } catch (Exception e) { diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java index 850e9fd3e8..36bfad4a84 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java @@ -115,6 +115,7 @@ public class TestPlanService { .subject(Translator.get("test_plan_notification")) .mailTemplate("TestPlanStart") .paramMap(paramMap) + .event(NoticeConstants.Event.CREATE) .build(); noticeSendService.send(NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel); } @@ -158,6 +159,7 @@ public class TestPlanService { .subject(Translator.get("test_plan_notification")) .mailTemplate("TestPlanEnd") .paramMap(paramMap) + .event(NoticeConstants.Event.UPDATE) .build(); noticeSendService.send(NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel); } @@ -258,9 +260,9 @@ public class TestPlanService { deleteTestCaseByPlanId(planId); testPlanProjectService.deleteTestPlanProjectByPlanId(planId); int num = testPlanMapper.deleteByPrimaryKey(planId); - List userIds = new ArrayList<>(); + List relatedUsers = new ArrayList<>(); AddTestPlanRequest testPlans = new AddTestPlanRequest(); - userIds.add(testPlan.getCreator()); + relatedUsers.add(testPlan.getCreator()); try { BeanUtils.copyBean(testPlans, testPlan); String context = getTestPlanContext(testPlans, NoticeConstants.Event.DELETE); @@ -269,10 +271,11 @@ public class TestPlanService { paramMap.put("creator", user.getName()); NoticeModel noticeModel = NoticeModel.builder() .context(context) - .relatedUsers(userIds) + .relatedUsers(relatedUsers) .subject(Translator.get("test_plan_notification")) .mailTemplate("TestPlanDelete") .paramMap(paramMap) + .event(NoticeConstants.Event.DELETE) .build(); noticeSendService.send(NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel); } catch (Exception e) { @@ -510,6 +513,7 @@ public class TestPlanService { .subject(Translator.get("test_plan_notification")) .mailTemplate("TestPlanEnd") .paramMap(paramMap) + .event(NoticeConstants.Event.UPDATE) .build(); noticeSendService.send(NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel); } catch (Exception e) { diff --git a/frontend/src/business/App.vue b/frontend/src/business/App.vue index b3bd049661..4efdc55ae0 100644 --- a/frontend/src/business/App.vue +++ b/frontend/src/business/App.vue @@ -7,7 +7,7 @@ - + @@ -100,7 +100,6 @@ export default { height: 37px; background-repeat: no-repeat; background-position: 50% center; - background-image: url("../assets/logo-light-MeterSphere.svg"); } .menus > * { diff --git a/frontend/src/business/components/api/definition/components/Run.vue b/frontend/src/business/components/api/definition/components/Run.vue index 69da69a55e..3d9e370d69 100644 --- a/frontend/src/business/components/api/definition/components/Run.vue +++ b/frontend/src/business/components/api/definition/components/Run.vue @@ -75,21 +75,23 @@ }); } }); - request.body.binary.forEach(param => { - if (param.files) { - param.files.forEach(item => { - if (item.file) { - if (!item.id) { - let fileId = getUUID().substring(0, 12); - item.name = item.file.name; - item.id = fileId; + if (request.body.binary) { + request.body.binary.forEach(param => { + if (param.files) { + param.files.forEach(item => { + if (item.file) { + if (!item.id) { + let fileId = getUUID().substring(0, 12); + item.name = item.file.name; + item.id = fileId; + } + obj.bodyUploadIds.push(item.id); + bodyUploadFiles.push(item.file); } - obj.bodyUploadIds.push(item.id); - bodyUploadFiles.push(item.file); - } - }); - } - }); + }); + } + }); + } } }); return bodyUploadFiles; diff --git a/frontend/src/business/components/api/definition/components/body/ApiBody.vue b/frontend/src/business/components/api/definition/components/body/ApiBody.vue index ce8d599ae8..adaa1d4d8c 100644 --- a/frontend/src/business/components/api/definition/components/body/ApiBody.vue +++ b/frontend/src/business/components/api/definition/components/body/ApiBody.vue @@ -1,7 +1,7 @@ diff --git a/frontend/src/business/components/settings/organization/components/DefectTaskNotification.vue b/frontend/src/business/components/settings/organization/components/DefectTaskNotification.vue index 27f3aa6c24..2699ccac3f 100644 --- a/frontend/src/business/components/settings/organization/components/DefectTaskNotification.vue +++ b/frontend/src/business/components/settings/organization/components/DefectTaskNotification.vue @@ -11,7 +11,7 @@ {{ $t('commons.cancel') }} { - this.form.defectTask = response.data; + this.defectTask = response.data; }) }, handleEdit(index, data) { @@ -169,7 +167,7 @@ export default { Task.isSet = true; Task.identification = ''; Task.taskType = TASK_TYPE - this.form.defectTask.push(Task) + this.defectTask.push(Task) }, handleAddTask(index, data) { diff --git a/frontend/src/business/components/settings/organization/components/JenkinsNotification.vue b/frontend/src/business/components/settings/organization/components/JenkinsNotification.vue index 8906d9ad4f..baa7c9387f 100644 --- a/frontend/src/business/components/settings/organization/components/JenkinsNotification.vue +++ b/frontend/src/business/components/settings/organization/components/JenkinsNotification.vue @@ -11,11 +11,11 @@ + :data="jenkinsTask" + class="tb-edit" + border + :cell-style="rowClass" + :header-cell-style="headClass"> @@ -36,10 +36,10 @@ + v-for="item in jenkinsReceiverOptions" + :key="item.id" + :label="item.name" + :value="item.id"> @@ -51,10 +51,10 @@ :disabled="!scope.row.isSet" @change="handleEdit(scope.$index, scope.row)" > + v-for="item in receiveTypeOptions" + :key="item.value" + :label="item.label" + :value="item.value"> @@ -69,31 +69,31 @@ @@ -115,18 +115,16 @@ export default { }, data() { return { - form: { - jenkinsTask: [{ - taskType: "jenkinsTask", - event: "", - userIds: [], - type: [], - webhook: "", - isSet: true, - identification: "", - isReadOnly: false, - }], - }, + jenkinsTask: [{ + taskType: "jenkinsTask", + event: "", + userIds: [], + type: [], + webhook: "", + isSet: true, + identification: "", + isReadOnly: false, + }], jenkinsEventOptions: [ {value: 'EXECUTE_SUCCESSFUL', label: this.$t('schedule.event_success')}, {value: 'EXECUTE_FAILED', label: this.$t('schedule.event_failed')} @@ -144,7 +142,7 @@ export default { methods: { initForm() { this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => { - this.form.jenkinsTask = response.data; + this.jenkinsTask = response.data; }) }, handleEdit(index, data) { @@ -163,7 +161,7 @@ export default { Task.isSet = true; Task.identification = ''; Task.taskType = TASK_TYPE - this.form.jenkinsTask.push(Task) + this.jenkinsTask.push(Task) }, handleAddTask(index, data) { if (data.event && data.userIds.length > 0 && data.type) { diff --git a/frontend/src/business/components/settings/organization/components/ScheduleTaskNotification.vue b/frontend/src/business/components/settings/organization/components/ScheduleTaskNotification.vue index 42002779e3..0d7b8600aa 100644 --- a/frontend/src/business/components/settings/organization/components/ScheduleTaskNotification.vue +++ b/frontend/src/business/components/settings/organization/components/ScheduleTaskNotification.vue @@ -2,7 +2,8 @@
- + {{ $t('organization.message.create_new_notification') }} @@ -10,7 +11,7 @@ {{ $t('commons.cancel') }} {{ $t('commons.edit') }} + >{{ $t('commons.edit') }} + { + initForm() { + this.result = this.$get('/notice/search/message/' + this.testId, response => { // console.log(response.data); - this.form.scheduleTask = response.data; + this.scheduleTask = response.data; }) }, handleEdit(index, data) { @@ -158,7 +159,7 @@ export default { data.webhook = ''; } }, - handleAddTaskModel(type) { + handleAddTaskModel() { let Task = {}; Task.event = []; Task.userIds = []; @@ -166,13 +167,11 @@ export default { Task.webhook = ''; Task.isSet = true; Task.identification = ''; - if (type === 'scheduleTask') { - Task.taskType = 'SCHEDULE_TASK'; - Task.testId=this.testId; - this.form.scheduleTask.push(Task); - } + Task.taskType = 'SCHEDULE_TASK'; + Task.testId = this.testId; + this.scheduleTask.push(Task); }, - handleEditTask(index,data) { + handleEditTask(index, data) { data.isSet = true; data.testId = this.testId; if (data.type === 'EMAIL') { diff --git a/frontend/src/business/components/settings/organization/components/TestPlanTaskNotification.vue b/frontend/src/business/components/settings/organization/components/TestPlanTaskNotification.vue index 8c68858d0d..dc89d40597 100644 --- a/frontend/src/business/components/settings/organization/components/TestPlanTaskNotification.vue +++ b/frontend/src/business/components/settings/organization/components/TestPlanTaskNotification.vue @@ -11,7 +11,7 @@ {{ $t('commons.cancel') }} { - this.form.testCasePlanTask = response.data; - this.form.testCasePlanTask.forEach(planTask => { + this.testCasePlanTask = response.data; + this.testCasePlanTask.forEach(planTask => { this.handleTestPlanReceivers(planTask); }); }) @@ -175,7 +170,7 @@ export default { Task.isSet = true; Task.identification = ''; Task.taskType = TASK_TYPE - this.form.testCasePlanTask.push(Task) + this.testCasePlanTask.push(Task) }, handleAddTask(index, data) { @@ -236,6 +231,13 @@ export default { } row.testPlanReceiverOptions = testPlanReceivers; }, + }, + watch: { + testPlanReceiverOptions(value) { + if (value && value.length > 0) { + this.initForm(); + } + } } } diff --git a/frontend/src/business/components/settings/organization/components/TestReviewNotification.vue b/frontend/src/business/components/settings/organization/components/TestReviewNotification.vue index 2dbe6148c8..5509ffdbd8 100644 --- a/frontend/src/business/components/settings/organization/components/TestReviewNotification.vue +++ b/frontend/src/business/components/settings/organization/components/TestReviewNotification.vue @@ -11,7 +11,7 @@ {{ $t('commons.cancel') }} { - this.form.reviewTask = response.data; - this.form.reviewTask.forEach(planTask => { + this.reviewTask = response.data; + this.reviewTask.forEach(planTask => { this.handleReviewReceivers(planTask); }); }) @@ -176,7 +171,7 @@ export default { Task.isSet = true; Task.identification = ''; Task.taskType = TASK_TYPE - this.form.reviewTask.push(Task) + this.reviewTask.push(Task) }, handleAddTask(index, data) { @@ -242,6 +237,13 @@ export default { } row.reviewReceiverOptions = reviewReceiverOptions; } + }, + watch: { + reviewReceiverOptions(value) { + if (value && value.length > 0) { + this.initForm(); + } + } } } diff --git a/frontend/src/business/components/xpack b/frontend/src/business/components/xpack index a22a3005d9..8a972a1987 160000 --- a/frontend/src/business/components/xpack +++ b/frontend/src/business/components/xpack @@ -1 +1 @@ -Subproject commit a22a3005d9bd254793fcf634d72539cbdf31be3a +Subproject commit 8a972a198775b3783ed6e4cef27197e53d1ebdc8