diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/HarScenarioParser.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/HarScenarioParser.java new file mode 100644 index 0000000000..92cc0b654c --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/HarScenarioParser.java @@ -0,0 +1,150 @@ +package io.metersphere.api.dto.automation.parse; + +import com.alibaba.fastjson.JSONArray; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.parse.har.HarUtils; +import io.metersphere.api.dto.definition.parse.har.model.*; +import io.metersphere.api.dto.definition.request.MsScenario; +import io.metersphere.api.dto.definition.request.MsTestElement; +import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; +import io.metersphere.api.dto.scenario.KeyValue; +import io.metersphere.api.jmeter.RequestResult; +import io.metersphere.api.jmeter.ResponseResult; +import io.metersphere.api.parse.HarScenarioAbstractParser; +import io.metersphere.api.service.ApiScenarioModuleService; +import io.metersphere.base.domain.ApiScenarioModule; +import io.metersphere.base.domain.ApiScenarioWithBLOBs; +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.CommonBeanFactory; +import io.metersphere.commons.utils.LogUtil; +import org.apache.commons.lang3.ObjectUtils; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +public class HarScenarioParser extends HarScenarioAbstractParser { + + @Override + public ScenarioImport parse(InputStream source, ApiTestImportRequest request) { + Har har = null; + try { + String sourceStr = getApiTestStr(source); + har = HarUtils.read(sourceStr); + } catch (Exception e) { + MSException.throwException(e.getMessage()); + LogUtil.error(e.getMessage(), e); + } + + if (ObjectUtils.isEmpty(har)) { + MSException.throwException("解析失败,请确认选择的是 Har 格式!"); + } + + ScenarioImport scenarioImport = new ScenarioImport(); + + String harName = request.getFileName(); + // 场景步骤 + LinkedList apiScenarioWithBLOBs = new LinkedList<>(); +// ApiScenarioWithBLOBs scenario = new ApiScenarioWithBLOBs(); +// scenario.setName(harName); + + MsScenario msScenario = new MsScenario(); + msScenario.setName(harName); + this.projectId = request.getProjectId(); + if (!ObjectUtils.isEmpty(har.log)&&!ObjectUtils.isEmpty(har.log.entries)) { + parseItem(har.log.entries, msScenario, apiScenarioWithBLOBs); + } + + // 生成场景对象 + List scenarioWithBLOBs = new LinkedList<>(); + parseScenarioWithBLOBs(scenarioWithBLOBs, msScenario, request); + scenarioImport.setData(scenarioWithBLOBs); + return scenarioImport; + } + + private void parseScenarioWithBLOBs(List scenarioWithBLOBsList, MsScenario msScenario, ApiTestImportRequest request) { + ApiScenarioModule module = ApiScenarioImportUtil.getSelectModule(request.getModuleId()); + if (module == null) { + ApiScenarioModuleService apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class); + module = apiModuleService.getNewModule(msScenario.getName(), projectId, 1); + } + + ApiScenarioWithBLOBs scenarioWithBLOBs = parseScenario(msScenario); + if (module != null) { + scenarioWithBLOBs.setApiScenarioModuleId(module.getId()); + scenarioWithBLOBs.setModulePath("/" + module.getName()); + } + scenarioWithBLOBsList.add(scenarioWithBLOBs); + } + + private void parseItem(List items, MsScenario scenario, LinkedList results) { + for (HarEntry item : items) { + MsHTTPSamplerProxy request = parseHar(item); + if (request != null) { + results.add(request); + } + request.setRequestResult(getRequestResult(request,item)); + } + scenario.setHashTree(results); + } + +// private List parseScenarioVariable(List postmanKeyValues) { +// if (postmanKeyValues == null) { +// return null; +// } +// List keyValues = new ArrayList<>(); +// postmanKeyValues.forEach(item -> keyValues.add(new ScenarioVariable(item.getKey(), item.getValue(), item.getDescription(), VariableTypeConstants.CONSTANT.name()))); +// return keyValues; +// } +private RequestResult getRequestResult(MsHTTPSamplerProxy samplerProxy,HarEntry harEntry) { + HarRequest request = harEntry.request; + HarResponse response = harEntry.response; + + RequestResult requestResult = new RequestResult(); + requestResult.setName("Response"); + requestResult.setUrl(request.url); + requestResult.setMethod(request.method); + if(samplerProxy.getBody()!= null){ + List keyValueList = new ArrayList<>(); + if(!ObjectUtils.isEmpty(request.queryString)){ + for (HarQueryParm model : request.queryString) { + KeyValue keyValue = new KeyValue(model.name,model.value); + keyValueList.add(keyValue); + } + } + if(!ObjectUtils.isEmpty(request.postData)&&!ObjectUtils.isEmpty(request.postData.params)){ + for (HarPostParam model : request.postData.params) { + KeyValue keyValue = new KeyValue(model.name,model.value); + keyValueList.add(keyValue); + } + } + + requestResult.setBody(JSONArray.toJSONString(keyValueList)); + } + + requestResult.setHeaders(JSONArray.toJSONString(request.headers)); + requestResult.setRequestSize(request.bodySize); +// requestResult.setStartTime(result.getStartTime()); +// requestResult.setEndTime(result.getEndTime()); +// requestResult.setTotalAssertions(result.getAssertionResults().length); +// requestResult.setSuccess(result.isSuccessful()); +// requestResult.setError(result.getErrorCount()); + if(!ObjectUtils.isEmpty(request.cookies)){ + requestResult.setCookies(JSONArray.toJSONString(request.cookies)); + } + + ResponseResult responseResult = requestResult.getResponseResult(); + responseResult.setHeaders(JSONArray.toJSONString(response.headers)); +// responseResult.setLatency(result.getLatency()); + responseResult.setResponseCode(String.valueOf(response.status)); + responseResult.setResponseSize(response.bodySize); +// responseResult.setResponseTime(result.getTime()); + if(response.content != null && response.content.text != null){ + responseResult.setBody(response.content.text); + responseResult.setResponseMessage(response.content.text); + } + + return requestResult; +} +} diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/ScenarioImportParserFactory.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/ScenarioImportParserFactory.java index b2509a9eed..ff47ce30bb 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/parse/ScenarioImportParserFactory.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/ScenarioImportParserFactory.java @@ -12,6 +12,8 @@ public class ScenarioImportParserFactory { return new PostmanScenarioParser(); } else if (StringUtils.equals(ApiImportPlatform.Jmeter.name(), platform)) { return new MsJmeterParser(); + } else if (StringUtils.equals(ApiImportPlatform.Har.name(), platform)) { + return new HarScenarioParser(); } return null; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImportParserFactory.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImportParserFactory.java index 3b73d92f0c..f7db9334b0 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImportParserFactory.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImportParserFactory.java @@ -12,6 +12,8 @@ public class ApiDefinitionImportParserFactory { return new PostmanDefinitionParser(); } else if (StringUtils.equals(ApiImportPlatform.Swagger2.name(), platform)) { return new Swagger2Parser(); + }else if (StringUtils.equals(ApiImportPlatform.Har.name(), platform)) { + return new HarParser(); } return null; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarAbstractParser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarAbstractParser.java new file mode 100644 index 0000000000..b437567bb0 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarAbstractParser.java @@ -0,0 +1,27 @@ +package io.metersphere.api.dto.definition.parse; + + +import io.metersphere.api.parse.ApiImportAbstractParser; +import io.metersphere.base.domain.ApiDefinitionWithBLOBs; +import io.metersphere.base.domain.ApiModule; + +import java.util.List; + +/** + * @author song.tianyang + * @Date 2021/3/10 11:15 上午 + * @Description + */ +public abstract class HarAbstractParser extends ApiImportAbstractParser { + + protected void buildModule(ApiModule parentModule, ApiDefinitionWithBLOBs apiDefinition, List tags) { + if (tags != null) { + tags.forEach(tag -> { + ApiModule module = ApiDefinitionImportUtil.buildModule(parentModule, tag, this.projectId); + apiDefinition.setModuleId(module.getId()); + }); + }else { + apiDefinition.setModuleId(parentModule.getId()); + } + } +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarParser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarParser.java new file mode 100644 index 0000000000..ed54de8e5e --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarParser.java @@ -0,0 +1,218 @@ +package io.metersphere.api.dto.definition.parse; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.parse.har.HarUtils; +import io.metersphere.api.dto.definition.parse.har.model.*; +import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; +import io.metersphere.api.dto.definition.response.HttpResponse; +import io.metersphere.api.dto.scenario.Body; +import io.metersphere.api.dto.scenario.KeyValue; +import io.metersphere.api.dto.scenario.request.RequestType; +import io.metersphere.base.domain.ApiDefinitionWithBLOBs; +import io.metersphere.base.domain.ApiModule; +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.LogUtil; +import io.metersphere.commons.utils.XMLUtils; +import io.swagger.models.Model; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author song.tianyang + * @Date 2021/3/10 11:14 上午 + * @Description + */ +public class HarParser extends HarAbstractParser { + + private Map definitions = null; + + @Override + public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) { + Har har = null; + try { + String sourceStr = getApiTestStr(source); + har = HarUtils.read(sourceStr); + } catch (Exception e) { + MSException.throwException(e.getMessage()); + LogUtil.error(e.getMessage(), e); + } + + if (ObjectUtils.isEmpty(har)) { + MSException.throwException("解析失败,请确认选择的是 Har 格式!"); + } + + ApiDefinitionImport definitionImport = new ApiDefinitionImport(); + this.projectId = request.getProjectId(); + definitionImport.setData(parseRequests(har, request)); + return definitionImport; + } + + + private List parseRequests(Har har, ApiTestImportRequest importRequest) { + List results = new ArrayList<>(); + + ApiModule parentNode = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId()); + + List harEntryList = new ArrayList<>(); + if (har.log != null && har.log.entries != null) { + harEntryList = har.log.entries; + } + + for (HarEntry entry : harEntryList) { + HarRequest harRequest = entry.request; + + //默认取路径的最后一块 + String reqName = ""; + if (harRequest.url != null) { + String[] nameArr = harRequest.url.split("/"); + reqName = nameArr[nameArr.length - 1]; + } + + if (harRequest != null) { + MsHTTPSamplerProxy request = super.buildRequest(reqName, harRequest.url, harRequest.method); + ApiDefinitionWithBLOBs apiDefinition = super.buildApiDefinition(request.getId(), reqName, harRequest.url, harRequest.method, importRequest); + parseParameters(harRequest, request); + parseRequestBody(harRequest, request.getBody()); + addBodyHeader(request); + apiDefinition.setRequest(JSON.toJSONString(request)); + apiDefinition.setResponse(JSON.toJSONString(parseResponse(entry.response))); + buildModule(parentNode, apiDefinition, null); + results.add(apiDefinition); + } + } + + return results; + } + + private void parseParameters(HarRequest harRequest, MsHTTPSamplerProxy request) { + List queryStringList = harRequest.queryString; + queryStringList.forEach(harQueryParm -> { + parseQueryParameters(harQueryParm, request.getArguments()); + }); + List harHeaderList = harRequest.headers; + harHeaderList.forEach(harHeader -> { + parseHeaderParameters(harHeader, request.getHeaders()); + }); + List harCookieList = harRequest.cookies; + harCookieList.forEach(harCookie -> { + parseCookieParameters(harCookie, request.getHeaders()); + }); + } + + + private String getDefaultStringValue(String val) { + return StringUtils.isBlank(val) ? "" : val; + } + + private void parseCookieParameters(HarCookie harCookie, List headers) { + addCookie(headers, harCookie.name, harCookie.value, harCookie.comment, false); + } + + private void parseHeaderParameters(HarHeader harHeader, List headers) { + addHeader(headers, harHeader.name, harHeader.value,harHeader.comment, "", false); + } + + private HttpResponse parseResponse(HarResponse response) { + HttpResponse msResponse = new HttpResponse(); + msResponse.setBody(new Body()); + msResponse.setHeaders(new ArrayList<>()); + msResponse.setType(RequestType.HTTP); + // todo 状态码要调整? + msResponse.setStatusCode(new ArrayList<>()); + if (response != null) { + String responseCode = String.valueOf(response.status); + msResponse.getStatusCode().add(new KeyValue(responseCode, responseCode)); + parseResponseHeader(response, msResponse.getHeaders()); + parseResponseBody(response, msResponse.getBody()); + } + return msResponse; + } + + private void parseResponseHeader(HarResponse response, List msHeaders) { + List harHeaders = response.headers; + if (harHeaders != null) { + for (HarHeader header : harHeaders) { + msHeaders.add(new KeyValue(header.name, header.value, header.comment)); + } + } + } + + private void parseResponseBody(HarResponse response, Body body) { + parseResponseBody(response.content, body); + } + + private void parseRequestBody(HarRequest requestBody, Body body) { + if (requestBody == null) { + return; + } + HarPostData content = requestBody.postData; + if (!StringUtils.equalsIgnoreCase("GET", requestBody.method) || requestBody.postData == null) { + return; + } + String contentType = content.mimeType; + if (StringUtils.isEmpty(contentType)) { + body.setRaw(content.text); + } else { + Map infoMap = new HashMap(); + + if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { + contentType = org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; + List postParams = content.params; + for (HarPostParam postParam : postParams) { + KeyValue kv = new KeyValue(postParam.name,postParam.value); + body.getKvs().add(kv); + } + } else if (contentType.startsWith(org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE)) { + contentType = org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; + List postParams = content.params; + for (HarPostParam postParam : postParams) { + KeyValue kv = new KeyValue(postParam.name,postParam.value); + body.getKvs().add(kv); + } + } else if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_JSON_VALUE)) { + contentType = org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + body.setRaw(content.text); + } else if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_XML_VALUE)) { + contentType = org.springframework.http.MediaType.APPLICATION_XML_VALUE; + body.setRaw(parseXmlBody(content.text)); + } else if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE)) { + contentType = org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; + List postParams = content.params; + for (HarPostParam postParam : postParams) { + KeyValue kv = new KeyValue(postParam.name,postParam.value); + body.getKvs().add(kv); + } + } else { + body.setRaw(content.text); + } + } + body.setType(getBodyType(contentType)); + } + + private void parseResponseBody(HarContent content, Body body) { + if (content == null) { + return; + } + String contentType = content.mimeType; + body.setType(getBodyType(contentType)); + body.setRaw(content.text); + } + + private String parseXmlBody(String xmlString) { + JSONObject object = JSONObject.parseObject(getDefaultStringValue(xmlString)); + return XMLUtils.jsonToXmlStr(object); + } + + private void parseQueryParameters(HarQueryParm harQueryParm, List arguments) { + arguments.add(new KeyValue(harQueryParm.name, harQueryParm.value, harQueryParm.comment, false)); + } +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/HarUtils.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/HarUtils.java new file mode 100644 index 0000000000..f6cd6b0f41 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/HarUtils.java @@ -0,0 +1,54 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har; + +import com.alibaba.fastjson.JSONObject; +import com.google.gson.JsonSyntaxException; +import io.metersphere.api.dto.definition.parse.har.model.Har; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.IOException; + +/** + * Utility class for working with HAR files. + * + * @author sangupta + * + */ +public class HarUtils { + + public static Har read(File file) throws JsonSyntaxException, IOException { + Har har = JSONObject.parseObject(FileUtils.readFileToString(file), Har.class); + return har; + } + + + public static Har read(String harJson) throws JsonSyntaxException, IOException { + if(StringUtils.isEmpty(harJson)) { + throw new IllegalArgumentException("HAR Json cannot be null/empty"); + } + Har har = JSONObject.parseObject(harJson, Har.class); + return har; + } +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/command/ViewHar.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/command/ViewHar.java new file mode 100644 index 0000000000..0051bbe0f7 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/command/ViewHar.java @@ -0,0 +1,74 @@ +///** +// * +// * har - HAR file reader, writer and viewer +// * Copyright (c) 2014, Sandeep Gupta +// * +// * http://sangupta.com/projects/har +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// * +// */ +// +//package io.metersphere.api.dto.definition.parse.har.command; +// +//import java.io.File; +// +//import com.sangupta.har.HarUtils; +//import com.sangupta.har.model.Har; +//import com.sangupta.har.model.HarEntry; +//import com.sangupta.har.model.HarPage; +//import com.sangupta.jerry.util.AssertUtils; +// +//import io.airlift.command.Arguments; +//import io.airlift.command.Command; +// +//@Command(name = "view", description = "View HAR file") +//public class ViewHar implements Runnable { +// +// @Arguments +// private String file; +// +// @Override +// public void run() { +// Har har = null; +// +// try { +// har = HarUtils.read(new File(this.file)); +// } catch(Exception e) { +// System.out.println("Error reading HAR file: " + e.getMessage()); +// return; +// } +// +// if(har.log == null || AssertUtils.isEmpty(har.log.pages)) { +// System.out.println("HAR file has no pages!"); +// return; +// } +// +// // connect references +// HarUtils.connectReferences(har); +// +// // start displaying +// System.out.println("Number of pages viewed: " + har.log.pages.size()); +// System.out.println(); +// +// for(HarPage page : har.log.pages) { +// System.out.println(page); +// +// // output the calls for this page +// for(HarEntry entry : page.entries) { +// System.out.println("\t" + entry); +// } +// } +// } +// +//} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/Har.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/Har.java new file mode 100644 index 0000000000..7aab6c0b54 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/Har.java @@ -0,0 +1,32 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class Har { + + public HarLog log; + + @Override + public String toString() { + return "Har [log=" + log + "]"; + } +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCache.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCache.java new file mode 100644 index 0000000000..cb27a63554 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCache.java @@ -0,0 +1,32 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarCache { + + public HarCacheDetails beforeRequest; + + public HarCacheDetails afterRequest; + + public String comment; + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCacheDetails.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCacheDetails.java new file mode 100644 index 0000000000..ce782f13ad --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCacheDetails.java @@ -0,0 +1,36 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarCacheDetails { + + public String expires; + + public String lastAccess; + + public String etag; + + public String hitCount; + + public String comment; + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarContent.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarContent.java new file mode 100644 index 0000000000..b755e5f373 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarContent.java @@ -0,0 +1,38 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarContent { + + public long size; + + public String mimeType; + + public long compression; + + public String text; + + public String comment; + + public String encoding; + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCookie.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCookie.java new file mode 100644 index 0000000000..58b25254be --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCookie.java @@ -0,0 +1,67 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarCookie { + + public String name; + + public String value; + + public String path; + + public String expires; + + public boolean httpOnly; + + public boolean secure; + + public String comment; + + @Override + public String toString() { + return "[Cookie: " + this.name + "=" + this.value + "]"; + } + + @Override + public int hashCode() { + if(this.name == null) { + return -1; + } + + return this.name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof HarCookie)) { + return false; + } + + if(this.name == null) { + return false; + } + + HarCookie harCookie = (HarCookie) obj; + return this.name.equals(harCookie.name); + } +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCreator.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCreator.java new file mode 100644 index 0000000000..6daa8b391c --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarCreator.java @@ -0,0 +1,39 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarCreator { + + public String name; + + public String version; + + public String comment; + + @Override + public String toString() { + return "HarCreator [name=" + name + ", version=" + version + ", comment=" + comment + "]"; + } + + + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarEntry.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarEntry.java new file mode 100644 index 0000000000..235e3ae8b5 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarEntry.java @@ -0,0 +1,66 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarEntry implements Comparable { + + public String pageref; + + public String startedDateTime; + + public double time; + + public HarRequest request; + + public HarResponse response; + + public HarCache cache; + + public HarTiming timings; + + public String serverIPAddress; + + public String connection; + + public String comment; + + + + @Override + public String toString() { + return "HarEntry [pageref=" + pageref + ", startedDateTime=" + startedDateTime + ", time=" + time + ", request=" + + request + ", response=" + response + ", cache=" + cache + ", timings=" + timings + + ", serverIPAddress=" + serverIPAddress + ", connection=" + connection + ", comment=" + comment + "]"; + } + + + + @Override + public int compareTo(HarEntry o) { + if(o == null) { + return -1; + } + // parse the time and then return + return this.startedDateTime.compareTo(o.startedDateTime); + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarHeader.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarHeader.java new file mode 100644 index 0000000000..3fb506b984 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarHeader.java @@ -0,0 +1,60 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarHeader { + + public String name; + + public String value; + + public String comment; + + @Override + public String toString() { + return "[Header: " + this.name + "=" + this.value + "]"; + } + + @Override + public int hashCode() { + if(this.name == null) { + return -1; + } + + return this.name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof HarHeader)) { + return false; + } + + if(this.name == null) { + return false; + } + + HarHeader harHeader = (HarHeader) obj; + return this.name.equals(harHeader.name); + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarLog.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarLog.java new file mode 100644 index 0000000000..407ab69ef5 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarLog.java @@ -0,0 +1,50 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +import java.util.List; + +public class HarLog { + + public static final String DEFAULT_HAR_VERSION = "1.2"; + + public String version = DEFAULT_HAR_VERSION; + + public HarCreator creator; + + public HarCreator browser; + + public List pages; + + public List entries; + + public String comment; + + @Override + public String toString() { + return "HarLog [version=" + version + ", creator=" + creator + ", browser=" + browser + ", pages=" + pages + + ", entries=" + entries + ", comment=" + comment + "]"; + } + + + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPage.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPage.java new file mode 100644 index 0000000000..da589cc63b --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPage.java @@ -0,0 +1,71 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +import java.util.List; + +public class HarPage { + + public String startedDateTime; + + public String id; + + public String title; + + public HarPageTiming pageTimings; + + public String comment; + + public transient List entries; + + + + @Override + public String toString() { + return "HarPage [startedDateTime=" + startedDateTime + ", id=" + id + ", title=" + title + ", pageTimings=" + + pageTimings + ", comment=" + comment + "]"; + } + + @Override + public int hashCode() { + if(this.id == null) { + return -1; + } + + return this.id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof HarPage)) { + return false; + } + + if(this.id == null) { + return false; + } + + HarPage harPage = (HarPage) obj; + return this.id.equals(harPage.id); + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPageTiming.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPageTiming.java new file mode 100644 index 0000000000..4664e11688 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPageTiming.java @@ -0,0 +1,39 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarPageTiming { + + public double onContentLoad; + + public double onLoad; + + public String comment; + + @Override + public String toString() { + return "HarPageTiming [onContentLoad=" + onContentLoad + ", onLoad=" + onLoad + ", comment=" + comment + "]"; + } + + + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPostData.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPostData.java new file mode 100644 index 0000000000..caf871c355 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPostData.java @@ -0,0 +1,36 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +import java.util.List; + +public class HarPostData { + + public String mimeType; + + public List params; + + public String text; + + public String comment; + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPostParam.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPostParam.java new file mode 100644 index 0000000000..d6bb6723a4 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarPostParam.java @@ -0,0 +1,64 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarPostParam { + + public String name; + + public String value; + + public String fileName; + + public String contentType; + + public String comment; + + @Override + public String toString() { + return "[Post Param: " + this.name + "=" + this.value + "]"; + } + + @Override + public int hashCode() { + if(this.name == null) { + return -1; + } + + return this.name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof HarPostParam)) { + return false; + } + + if(this.name == null) { + return false; + } + + HarPostParam harPostParam = (HarPostParam) obj; + return this.name.equals(harPostParam.name); + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarQueryParm.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarQueryParm.java new file mode 100644 index 0000000000..37ed8cf749 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarQueryParm.java @@ -0,0 +1,60 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarQueryParm { + + public String name; + + public String value; + + public String comment; + + @Override + public String toString() { + return "[Query Param: " + this.name + "=" + this.value + "]"; + } + + @Override + public int hashCode() { + if(this.name == null) { + return -1; + } + + return this.name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof HarQueryParm)) { + return false; + } + + if(this.name == null) { + return false; + } + + HarQueryParm harQueryParm = (HarQueryParm) obj; + return this.name.equals(harQueryParm.name); + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarRequest.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarRequest.java new file mode 100644 index 0000000000..8b3da8bd90 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarRequest.java @@ -0,0 +1,53 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +import java.util.List; + +public class HarRequest { + + public String method; + + public String url; + + public String httpVersion; + + public List cookies; + + public List headers; + + public List queryString; + + public HarPostData postData; + + public long headersSize; + + public long bodySize; + + public String comment; + + @Override + public String toString() { + return this.method + " " + this.url + " " + this.httpVersion; + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarResponse.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarResponse.java new file mode 100644 index 0000000000..dbef3a0b81 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarResponse.java @@ -0,0 +1,51 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +import java.util.List; + +public class HarResponse { + + public int status; + + public String statusText; + + public String httpVersion; + + public List headers; + + public List cookies; + + public HarContent content; + + public String redirectURL; + + public long headersSize; + + public long bodySize; + + @Override + public String toString() { + return "HTTP " + this.status + " (" + this.statusText + ")"; + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarTiming.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarTiming.java new file mode 100644 index 0000000000..81be64f5d3 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/har/model/HarTiming.java @@ -0,0 +1,50 @@ +/** + * + * har - HAR file reader, writer and viewer + * Copyright (c) 2014, Sandeep Gupta + * + * http://sangupta.com/projects/har + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.metersphere.api.dto.definition.parse.har.model; + +public class HarTiming { + + public double blocked; + + public double dns; + + public double connect; + + public double send; + + public double wait; + + public double receive; + + public double ssl; + + public String comment; + + @Override + public String toString() { + return "HarTiming [blocked=" + blocked + ", dns=" + dns + ", connect=" + connect + ", send=" + send + ", wait=" + + wait + ", receive=" + receive + ", ssl=" + ssl + ", comment=" + comment + "]"; + } + + + +} 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 7da3c3f336..73238aab23 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 @@ -85,8 +85,8 @@ public class MsHTTPSamplerProxy extends MsTestElement { @JSONField(ordinal = 34) private List arguments; -// @JSONField(ordinal = 35) -// private Object requestResult; + @JSONField(ordinal = 35) + private Object requestResult; @JSONField(ordinal = 36) private MsAuthManager authManager; diff --git a/backend/src/main/java/io/metersphere/api/parse/HarScenarioAbstractParser.java b/backend/src/main/java/io/metersphere/api/parse/HarScenarioAbstractParser.java new file mode 100644 index 0000000000..d438d60109 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/HarScenarioAbstractParser.java @@ -0,0 +1,217 @@ +package io.metersphere.api.parse; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import io.metersphere.api.dto.definition.parse.har.model.*; +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.parse.postman.PostmanEvent; +import io.metersphere.api.dto.parse.postman.PostmanKeyValue; +import io.metersphere.api.dto.parse.postman.PostmanRequest; +import io.metersphere.api.dto.parse.postman.PostmanScript; +import io.metersphere.api.dto.scenario.Body; +import io.metersphere.api.dto.scenario.KeyValue; +import io.metersphere.commons.constants.MsRequestBodyType; +import io.metersphere.commons.constants.PostmanRequestBodyMode; +import io.metersphere.commons.utils.XMLUtils; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; +import java.util.stream.Collectors; + +public abstract class HarScenarioAbstractParser extends ApiImportAbstractParser { + + protected MsHTTPSamplerProxy parseHar(HarEntry harEntry) { + HarRequest harRequest = harEntry.request; + if (harRequest == null) { + return null; + } + MsHTTPSamplerProxy request = buildRequest(harRequest.url, harRequest.url,harRequest.method); + if (StringUtils.isNotBlank(request.getPath())) { + String path = request.getPath().split("\\?")[0]; + path = path.replace("{{", "${"); + path = path.replace("}}", "}"); + request.setPath(path); + } else { + request.setPath("/"); + } + parseParameters(harRequest, request); + parseRequestBody(harRequest, request.getBody()); + addBodyHeader(request); + return request; + } + + private void parseParameters(HarRequest harRequest, MsHTTPSamplerProxy request) { + List queryStringList = harRequest.queryString; + queryStringList.forEach(harQueryParm -> { + parseQueryParameters(harQueryParm, request.getArguments()); + }); + List harHeaderList = harRequest.headers; + harHeaderList.forEach(harHeader -> { + parseHeaderParameters(harHeader, request.getHeaders()); + }); + List harCookieList = harRequest.cookies; + harCookieList.forEach(harCookie -> { + parseCookieParameters(harCookie, request.getHeaders()); + }); + } + private void parseRequestBody(HarRequest requestBody, Body body) { + if (requestBody == null) { + return; + } + HarPostData content = requestBody.postData; + if (!StringUtils.equalsIgnoreCase("GET", requestBody.method) || requestBody.postData == null) { + return; + } + String contentType = content.mimeType; + if (StringUtils.isEmpty(contentType)) { + body.setRaw(content.text); + } else { + Map infoMap = new HashMap(); + + if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { + contentType = org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; + List postParams = content.params; + for (HarPostParam postParam : postParams) { + KeyValue kv = new KeyValue(postParam.name,postParam.value); + body.getKvs().add(kv); + } + } else if (contentType.startsWith(org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE)) { + contentType = org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; + List postParams = content.params; + for (HarPostParam postParam : postParams) { + KeyValue kv = new KeyValue(postParam.name,postParam.value); + body.getKvs().add(kv); + } + } else if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_JSON_VALUE)) { + contentType = org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + body.setRaw(content.text); + } else if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_XML_VALUE)) { + contentType = org.springframework.http.MediaType.APPLICATION_XML_VALUE; + body.setRaw(parseXmlBody(content.text)); + } else if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE)) { + contentType = org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; + List postParams = content.params; + for (HarPostParam postParam : postParams) { + KeyValue kv = new KeyValue(postParam.name,postParam.value); + body.getKvs().add(kv); + } + } else { + body.setRaw(content.text); + } + } + body.setType(getBodyType(contentType)); + } + + + private void parseQueryParameters(HarQueryParm harQueryParm, List arguments) { + arguments.add(new KeyValue(harQueryParm.name, harQueryParm.value, harQueryParm.comment, false)); + } + private void parseCookieParameters(HarCookie harCookie, List headers) { + addCookie(headers, harCookie.name, harCookie.value, harCookie.comment, false); + } + + private void parseHeaderParameters(HarHeader harHeader, List headers) { + addHeader(headers, harHeader.name, harHeader.value,harHeader.comment, "", false); + } + + private void addPreScript(MsHTTPSamplerProxy request, List event) { + if (request != null && 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(); + if (script != null && item.getListen().contains("prerequest")) { + List exec = script.getExec(); + if (CollectionUtils.isNotEmpty(exec)) { + exec.forEach(col -> { + if (StringUtils.isNotEmpty(col)) { + scriptStr.append(col + "\n"); + } + }); + } + } + }); + if (StringUtils.isNotBlank(scriptStr)) { + MsJSR223PreProcessor jsr223PreProcessor = new MsJSR223PreProcessor(); + jsr223PreProcessor.setName("JSR223PreProcessor"); + jsr223PreProcessor.setScriptLanguage("javascript"); + jsr223PreProcessor.setScript(scriptStr.toString()); + LinkedList hashTree = new LinkedList<>(); + hashTree.add(jsr223PreProcessor); + request.setHashTree(hashTree); + } + } + } + + 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(), item.getDescription(), item.getContentType()))); + return keyValues; + } + + private void parseBody(Body body, PostmanRequest requestDesc) { + JSONObject postmanBody = requestDesc.getBody(); + if (postmanBody == null) { + return; + } + String bodyMode = postmanBody.getString("mode"); + if (StringUtils.isBlank(bodyMode)) { + return; + } + if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.RAW.value())) { + parseRawBody(body, postmanBody, bodyMode); + } else if (StringUtils.equalsAny(bodyMode, PostmanRequestBodyMode.FORM_DATA.value(), PostmanRequestBodyMode.URLENCODED.value())) { + List postmanKeyValues = JSON.parseArray(postmanBody.getString(bodyMode), PostmanKeyValue.class); + body.setKvs(parseKeyValue(postmanKeyValues)); + if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FORM_DATA.value())) { + body.setType(Body.FORM_DATA); + } else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.URLENCODED.value())) { + body.setType(Body.WWW_FROM); + } + } else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FILE.value())) { + body.setType(Body.BINARY); + body.setKvs(new ArrayList<>()); + } + } + + private String parseXmlBody(String xmlString) { + JSONObject object = JSONObject.parseObject(getDefaultStringValue(xmlString)); + return XMLUtils.jsonToXmlStr(object); + } + + private void parseRawBody(Body body, JSONObject postmanBody, String bodyMode) { + 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) { + String bodyType = ""; + switch (raw.getString("language")) { + case "json": + bodyType = Body.JSON; + break; + case "xml": + bodyType = Body.XML; + break; + default: + bodyType = Body.RAW; + } + body.setType(bodyType); + } + } + } + + private String getDefaultStringValue(String val) { + return StringUtils.isBlank(val) ? "" : val; + } +} diff --git a/backend/src/main/java/io/metersphere/base/domain/ApiDefinition.java b/backend/src/main/java/io/metersphere/base/domain/ApiDefinition.java index 44816f4f6d..4e6bbe85d8 100644 --- a/backend/src/main/java/io/metersphere/base/domain/ApiDefinition.java +++ b/backend/src/main/java/io/metersphere/base/domain/ApiDefinition.java @@ -1,8 +1,7 @@ package io.metersphere.base.domain; -import lombok.Data; - import java.io.Serializable; +import lombok.Data; @Data public class ApiDefinition implements Serializable { @@ -38,5 +37,7 @@ public class ApiDefinition implements Serializable { private String tags; + private String originalState; + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/ApiDefinitionExample.java b/backend/src/main/java/io/metersphere/base/domain/ApiDefinitionExample.java index cf1c6535ff..41b914ba8e 100644 --- a/backend/src/main/java/io/metersphere/base/domain/ApiDefinitionExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/ApiDefinitionExample.java @@ -1193,6 +1193,76 @@ public class ApiDefinitionExample { addCriterion("tags not between", value1, value2, "tags"); return (Criteria) this; } + + public Criteria andOriginalStateIsNull() { + addCriterion("original_state is null"); + return (Criteria) this; + } + + public Criteria andOriginalStateIsNotNull() { + addCriterion("original_state is not null"); + return (Criteria) this; + } + + public Criteria andOriginalStateEqualTo(String value) { + addCriterion("original_state =", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateNotEqualTo(String value) { + addCriterion("original_state <>", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateGreaterThan(String value) { + addCriterion("original_state >", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateGreaterThanOrEqualTo(String value) { + addCriterion("original_state >=", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateLessThan(String value) { + addCriterion("original_state <", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateLessThanOrEqualTo(String value) { + addCriterion("original_state <=", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateLike(String value) { + addCriterion("original_state like", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateNotLike(String value) { + addCriterion("original_state not like", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateIn(List values) { + addCriterion("original_state in", values, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateNotIn(List values) { + addCriterion("original_state not in", values, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateBetween(String value1, String value2) { + addCriterion("original_state between", value1, value2, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateNotBetween(String value1, String value2) { + addCriterion("original_state not between", value1, value2, "originalState"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/src/main/java/io/metersphere/base/domain/ApiScenario.java b/backend/src/main/java/io/metersphere/base/domain/ApiScenario.java index 81c0a35a33..8268740cce 100644 --- a/backend/src/main/java/io/metersphere/base/domain/ApiScenario.java +++ b/backend/src/main/java/io/metersphere/base/domain/ApiScenario.java @@ -43,5 +43,7 @@ public class ApiScenario implements Serializable { private Integer num; + private String originalState; + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/ApiScenarioExample.java b/backend/src/main/java/io/metersphere/base/domain/ApiScenarioExample.java index c679af53c1..9aaff91c8d 100644 --- a/backend/src/main/java/io/metersphere/base/domain/ApiScenarioExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/ApiScenarioExample.java @@ -1393,6 +1393,76 @@ public class ApiScenarioExample { addCriterion("num not between", value1, value2, "num"); return (Criteria) this; } + + public Criteria andOriginalStateIsNull() { + addCriterion("original_state is null"); + return (Criteria) this; + } + + public Criteria andOriginalStateIsNotNull() { + addCriterion("original_state is not null"); + return (Criteria) this; + } + + public Criteria andOriginalStateEqualTo(String value) { + addCriterion("original_state =", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateNotEqualTo(String value) { + addCriterion("original_state <>", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateGreaterThan(String value) { + addCriterion("original_state >", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateGreaterThanOrEqualTo(String value) { + addCriterion("original_state >=", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateLessThan(String value) { + addCriterion("original_state <", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateLessThanOrEqualTo(String value) { + addCriterion("original_state <=", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateLike(String value) { + addCriterion("original_state like", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateNotLike(String value) { + addCriterion("original_state not like", value, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateIn(List values) { + addCriterion("original_state in", values, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateNotIn(List values) { + addCriterion("original_state not in", values, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateBetween(String value1, String value2) { + addCriterion("original_state between", value1, value2, "originalState"); + return (Criteria) this; + } + + public Criteria andOriginalStateNotBetween(String value1, String value2) { + addCriterion("original_state not between", value1, value2, "originalState"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionMapper.xml index d636c33f5c..04d4050045 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiDefinitionMapper.xml @@ -18,6 +18,7 @@ + @@ -84,7 +85,7 @@ id, project_id, `name`, `method`, module_path, environment_id, schedule, `status`, - module_id, user_id, create_time, update_time, protocol, `path`, num, tags + module_id, user_id, create_time, update_time, protocol, `path`, num, tags, original_state description, request, response @@ -143,15 +144,15 @@ schedule, `status`, module_id, user_id, create_time, update_time, protocol, `path`, num, - tags, description, request, - response) + tags, original_state, description, + request, response) values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{method,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR}, #{environmentId,jdbcType=VARCHAR}, #{schedule,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{moduleId,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{protocol,jdbcType=VARCHAR}, #{path,jdbcType=VARCHAR}, #{num,jdbcType=INTEGER}, - #{tags,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR}, #{request,jdbcType=LONGVARCHAR}, - #{response,jdbcType=LONGVARCHAR}) + #{tags,jdbcType=VARCHAR}, #{originalState,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR}, + #{request,jdbcType=LONGVARCHAR}, #{response,jdbcType=LONGVARCHAR}) insert into api_definition @@ -204,6 +205,9 @@ tags, + + original_state, + description, @@ -263,6 +267,9 @@ #{tags,jdbcType=VARCHAR}, + + #{originalState,jdbcType=VARCHAR}, + #{description,jdbcType=LONGVARCHAR}, @@ -331,6 +338,9 @@ tags = #{record.tags,jdbcType=VARCHAR}, + + original_state = #{record.originalState,jdbcType=VARCHAR}, + description = #{record.description,jdbcType=LONGVARCHAR}, @@ -363,6 +373,7 @@ `path` = #{record.path,jdbcType=VARCHAR}, num = #{record.num,jdbcType=INTEGER}, tags = #{record.tags,jdbcType=VARCHAR}, + original_state = #{record.originalState,jdbcType=VARCHAR}, description = #{record.description,jdbcType=LONGVARCHAR}, request = #{record.request,jdbcType=LONGVARCHAR}, response = #{record.response,jdbcType=LONGVARCHAR} @@ -387,7 +398,8 @@ protocol = #{record.protocol,jdbcType=VARCHAR}, `path` = #{record.path,jdbcType=VARCHAR}, num = #{record.num,jdbcType=INTEGER}, - tags = #{record.tags,jdbcType=VARCHAR} + tags = #{record.tags,jdbcType=VARCHAR}, + original_state = #{record.originalState,jdbcType=VARCHAR} @@ -440,6 +452,9 @@ tags = #{tags,jdbcType=VARCHAR}, + + original_state = #{originalState,jdbcType=VARCHAR}, + description = #{description,jdbcType=LONGVARCHAR}, @@ -469,6 +484,7 @@ `path` = #{path,jdbcType=VARCHAR}, num = #{num,jdbcType=INTEGER}, tags = #{tags,jdbcType=VARCHAR}, + original_state = #{originalState,jdbcType=VARCHAR}, description = #{description,jdbcType=LONGVARCHAR}, request = #{request,jdbcType=LONGVARCHAR}, response = #{response,jdbcType=LONGVARCHAR} @@ -490,7 +506,8 @@ protocol = #{protocol,jdbcType=VARCHAR}, `path` = #{path,jdbcType=VARCHAR}, num = #{num,jdbcType=INTEGER}, - tags = #{tags,jdbcType=VARCHAR} + tags = #{tags,jdbcType=VARCHAR}, + original_state = #{originalState,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioMapper.xml index dba0bfbdb4..96c4137138 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiScenarioMapper.xml @@ -21,6 +21,7 @@ + @@ -87,7 +88,7 @@ id, project_id, tags, user_id, api_scenario_module_id, module_path, `name`, `level`, `status`, principal, step_total, follow_people, schedule, create_time, update_time, - pass_rate, last_result, report_id, num + pass_rate, last_result, report_id, num, original_state scenario_definition, description @@ -147,16 +148,16 @@ principal, step_total, follow_people, schedule, create_time, update_time, pass_rate, last_result, report_id, - num, scenario_definition, description - ) + num, original_state, scenario_definition, + description) values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{apiScenarioModuleId,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{level,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{principal,jdbcType=VARCHAR}, #{stepTotal,jdbcType=INTEGER}, #{followPeople,jdbcType=VARCHAR}, #{schedule,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{passRate,jdbcType=VARCHAR}, #{lastResult,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR}, - #{num,jdbcType=INTEGER}, #{scenarioDefinition,jdbcType=LONGVARCHAR}, #{description,jdbcType=LONGVARCHAR} - ) + #{num,jdbcType=INTEGER}, #{originalState,jdbcType=VARCHAR}, #{scenarioDefinition,jdbcType=LONGVARCHAR}, + #{description,jdbcType=LONGVARCHAR}) insert into api_scenario @@ -218,6 +219,9 @@ num, + + original_state, + scenario_definition, @@ -283,6 +287,9 @@ #{num,jdbcType=INTEGER}, + + #{originalState,jdbcType=VARCHAR}, + #{scenarioDefinition,jdbcType=LONGVARCHAR}, @@ -357,6 +364,9 @@ num = #{record.num,jdbcType=INTEGER}, + + original_state = #{record.originalState,jdbcType=VARCHAR}, + scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR}, @@ -389,6 +399,7 @@ last_result = #{record.lastResult,jdbcType=VARCHAR}, report_id = #{record.reportId,jdbcType=VARCHAR}, num = #{record.num,jdbcType=INTEGER}, + original_state = #{record.originalState,jdbcType=VARCHAR}, scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR}, description = #{record.description,jdbcType=LONGVARCHAR} @@ -415,7 +426,8 @@ pass_rate = #{record.passRate,jdbcType=VARCHAR}, last_result = #{record.lastResult,jdbcType=VARCHAR}, report_id = #{record.reportId,jdbcType=VARCHAR}, - num = #{record.num,jdbcType=INTEGER} + num = #{record.num,jdbcType=INTEGER}, + original_state = #{record.originalState,jdbcType=VARCHAR} @@ -477,6 +489,9 @@ num = #{num,jdbcType=INTEGER}, + + original_state = #{originalState,jdbcType=VARCHAR}, + scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR}, @@ -506,6 +521,7 @@ last_result = #{lastResult,jdbcType=VARCHAR}, report_id = #{reportId,jdbcType=VARCHAR}, num = #{num,jdbcType=INTEGER}, + original_state = #{originalState,jdbcType=VARCHAR}, scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR}, description = #{description,jdbcType=LONGVARCHAR} where id = #{id,jdbcType=VARCHAR} @@ -529,7 +545,8 @@ pass_rate = #{passRate,jdbcType=VARCHAR}, last_result = #{lastResult,jdbcType=VARCHAR}, report_id = #{reportId,jdbcType=VARCHAR}, - num = #{num,jdbcType=INTEGER} + num = #{num,jdbcType=INTEGER}, + original_state = #{originalState,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml index 46f321bd7b..179c83c956 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml @@ -235,7 +235,7 @@ update api_definition - set + set original_state=status, status = 'Trash' where id in @@ -245,7 +245,7 @@ update api_definition - set + set original_state=status, status = 'Trash', module_path = null, module_id = null @@ -255,7 +255,7 @@ update api_definition set - status = 'Underway' + status = original_state where id in #{v} diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml index 139de4d8d5..d9eb034876 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml @@ -275,7 +275,7 @@ update api_scenario - set + set original_state=status, status = 'Trash' where id in @@ -285,7 +285,7 @@ update api_scenario - set + set original_state=status, status = 'Trash', module_path = null, api_scenario_module_id = null @@ -295,7 +295,7 @@ update api_scenario set - status = 'Underway' + status = original_state where id in #{v} diff --git a/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java b/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java index 7470f26b48..95aed8d749 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java +++ b/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java @@ -1,5 +1,5 @@ package io.metersphere.commons.constants; public enum ApiImportPlatform { - Metersphere, Postman, Swagger2, Plugin, Jmeter + Metersphere, Postman, Swagger2, Plugin, Jmeter, Har } diff --git a/backend/src/main/java/io/metersphere/controller/SystemParameterController.java b/backend/src/main/java/io/metersphere/controller/SystemParameterController.java index 8fd47d8dc0..bcc25df6f9 100644 --- a/backend/src/main/java/io/metersphere/controller/SystemParameterController.java +++ b/backend/src/main/java/io/metersphere/controller/SystemParameterController.java @@ -39,6 +39,11 @@ public class SystemParameterController { return SystemParameterService.getVersion(); } + @GetMapping("/theme") + public String getTheme() { + return SystemParameterService.getValue("ui.theme"); + } + @GetMapping("/mail/info") @RequiresRoles(value = {RoleConstants.ADMIN}) public MailInfo mailInfo() { diff --git a/backend/src/main/resources/db/migration/V78__v1.8_release.sql b/backend/src/main/resources/db/migration/V78__v1.8_release.sql index c75d13da28..48db340305 100644 --- a/backend/src/main/resources/db/migration/V78__v1.8_release.sql +++ b/backend/src/main/resources/db/migration/V78__v1.8_release.sql @@ -44,4 +44,10 @@ ALTER TABLE test_case_review ADD tags VARCHAR(2000) NULL; alter table test_plan_api_scenario change environment_id environment longtext null comment 'Relevance environment'; -- file add sort column -alter table file_metadata add sort int default 0; \ No newline at end of file +alter table file_metadata add sort int default 0; + +-- add Original state +alter table api_definition add original_state varchar(64); +alter table api_scenario add original_state varchar(64); +update api_definition set original_state='Underway'; +update api_scenario set original_state='Underway'; \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index a63cffc926..470ac7ad72 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,7 +17,6 @@ "@fortawesome/vue-fontawesome": "^0.1.9", "axios": "^0.21.1", "core-js": "^3.4.3", - "default-passive-events": "^2.0.0", "diffable-html": "^4.0.0", "echarts": "^4.6.0", "el-table-infinite-scroll": "^1.0.10", diff --git a/frontend/src/business/App.vue b/frontend/src/business/App.vue index d547ff19dd..76368547c8 100644 --- a/frontend/src/business/App.vue +++ b/frontend/src/business/App.vue @@ -8,18 +8,20 @@ - + - - + + + + @@ -29,12 +31,14 @@ import MsView from "./components/common/router/View"; import MsUser from "./components/common/head/HeaderUser"; import MsHeaderOrgWs from "./components/common/head/HeaderOrgWs"; import MsLanguageSwitch from "./components/common/head/LanguageSwitch"; -import {saveLocalStorage} from "@/common/js/utils"; +import {hasLicense, saveLocalStorage, setColor, setOriginColor} from "@/common/js/utils"; import {registerRequestHeaders} from "@/common/js/ajax"; +import {ORIGIN_COLOR} from "@/common/js/constants"; const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/); const header = requireComponent.keys().length > 0 ? requireComponent("./license/LicenseMessage.vue") : {}; const display = requireComponent.keys().length > 0 ? requireComponent("./display/Display.vue") : {}; +const theme = requireComponent.keys().length > 0 ? requireComponent("./display/Theme.vue") : {}; export default { name: 'app', @@ -45,16 +49,27 @@ export default { auth: false, header: {}, logoId: '_blank', + color: '' } }, created() { + registerRequestHeaders(); + if (!hasLicense()) { + setOriginColor() + this.color = ORIGIN_COLOR; + } else { + // + this.$get('/system/theme', res => { + this.color = res.data ? res.data : ORIGIN_COLOR; + setColor(this.color, this.color, this.color, this.color); + }) + } if (localStorage.getItem("store")) { this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(localStorage.getItem("store")))) } window.addEventListener("beforeunload", () => { localStorage.setItem("store", JSON.stringify(this.$store.state)) }) - registerRequestHeaders(); }, beforeCreate() { this.$get("/isLogin").then(response => { @@ -83,7 +98,8 @@ export default { MsView, MsTopMenus, MsHeaderOrgWs, - "LicenseMessage": header.default + "LicenseMessage": header.default, + "Theme": theme.default } } @@ -93,7 +109,7 @@ export default { #header-top { width: 100%; padding: 0 10px; - background-color: rgb(44, 42, 72); + background-color: var(--color); color: rgb(245, 245, 245); font-size: 14px; height: 40px; diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index 32cd3a64a2..629d56bafa 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -276,7 +276,9 @@ }, { name: this.$t('test_track.case.batch_move_case'), handleClick: this.handleBatchMove - } + }, + {name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch}, + ], isSelectAllDate: false, selectRows: new Set(), @@ -596,6 +598,29 @@ this.search(); }) }, + handleDeleteBatch(row) { + if (this.trashEnable) { + let ids = Array.from(this.selectRows).map(row => row.id); + this.$post('/api/automation/deleteBatch/', ids, () => { + this.$success(this.$t('commons.delete_success')); + this.search(); + }); + return; + } + this.$alert(this.$t('api_test.definition.request.delete_confirm') + " ?", '', { + confirmButtonText: this.$t('commons.confirm'), + callback: (action) => { + if (action === 'confirm') { + let ids = Array.from(this.selectRows).map(row => row.id); + this.$post('/api/automation/removeToGc/', ids, () => { + this.$success(this.$t('commons.delete_success')); + this.search(); + }); + } + } + }); + }, + execute(row) { this.infoDb = false; let url = "/api/automation/run"; diff --git a/frontend/src/business/components/api/automation/scenario/common/ScenarioImport.vue b/frontend/src/business/components/api/automation/scenario/common/ScenarioImport.vue index e099d29d16..54aa5e4516 100644 --- a/frontend/src/business/components/api/automation/scenario/common/ScenarioImport.vue +++ b/frontend/src/business/components/api/automation/scenario/common/ScenarioImport.vue @@ -26,7 +26,7 @@ - + @@ -118,6 +118,13 @@ tip: this.$t('api_test.api_import.jmeter_tip'), exportTip: this.$t('api_test.api_import.jmeter_export_tip'), suffixes: new Set(['jmx']) + }, + { + name: 'Har', + value: 'Har', + tip: this.$t('api_test.api_import.har_tip'), + exportTip: this.$t('api_test.api_import.har_export_tip'), + suffixes: new Set(['har']) } ], selectedPlatform: {}, @@ -150,6 +157,11 @@ } }, }, + computed: { + isHar() { + return this.selectedPlatformValue === 'Har'; + }, + }, methods: { scheduleEdit() { if (!this.formData.swaggerUrl) { diff --git a/frontend/src/business/components/api/definition/components/import/ApiImport.vue b/frontend/src/business/components/api/definition/components/import/ApiImport.vue index 7eb4fa1d4f..9d55688bb7 100644 --- a/frontend/src/business/components/api/definition/components/import/ApiImport.vue +++ b/frontend/src/business/components/api/definition/components/import/ApiImport.vue @@ -28,7 +28,7 @@ - + @@ -146,7 +146,14 @@ export default { tip: this.$t('api_test.api_import.swagger_tip'), exportTip: this.$t('api_test.api_import.swagger_export_tip'), suffixes: new Set(['json']) - } + }, + { + name: 'Har', + value: 'Har', + tip: this.$t('api_test.api_import.har_tip'), + exportTip: this.$t('api_test.api_import.har_export_tip'), + suffixes: new Set(['har']) + }, ], selectedPlatform: {}, selectedPlatformValue: 'Metersphere', @@ -182,6 +189,9 @@ export default { isSwagger2() { return this.selectedPlatformValue === 'Swagger2'; }, + isHar() { + return this.selectedPlatformValue === 'Har'; + }, isScenarioModel() { return this.model === 'scenario'; } diff --git a/frontend/src/business/components/api/definition/components/list/ApiListContainerWithDoc.vue b/frontend/src/business/components/api/definition/components/list/ApiListContainerWithDoc.vue index 53dcb75a05..f3544bbe7c 100644 --- a/frontend/src/business/components/api/definition/components/list/ApiListContainerWithDoc.vue +++ b/frontend/src/business/components/api/definition/components/list/ApiListContainerWithDoc.vue @@ -74,16 +74,16 @@ export default { .active { border: solid 1px #6d317c; - background-color: #7C3985; + background-color: var(--color); color: #FFFFFF; } .case-button { - border-left: solid 1px #6d317c; + border-left: solid 1px var(--color); } .item{ - border: solid 1px #6d317c; + border: solid 1px var(--color); } diff --git a/frontend/src/business/components/api/definition/components/response/ResponseResult.vue b/frontend/src/business/components/api/definition/components/response/ResponseResult.vue index 2682f9dfef..61825a2c97 100644 --- a/frontend/src/business/components/api/definition/components/response/ResponseResult.vue +++ b/frontend/src/business/components/api/definition/components/response/ResponseResult.vue @@ -151,7 +151,7 @@ } this.reqMessages = this.$t('api_test.request.address') + ":\n" + this.response.url + "\n" + this.$t('api_test.scenario.headers') + ":\n" + this.response.headers + "\n" + "Cookies :\n" + - this.response.cookies + "\n" + "Bpdy:" + "\n" + this.response.body; + this.response.cookies + "\n" + "Body:" + "\n" + this.response.body; } }, }, diff --git a/frontend/src/business/components/api/homepage/components/ApiInfoCard.vue b/frontend/src/business/components/api/homepage/components/ApiInfoCard.vue index 5785c09907..a1988d2a19 100644 --- a/frontend/src/business/components/api/homepage/components/ApiInfoCard.vue +++ b/frontend/src/business/components/api/homepage/components/ApiInfoCard.vue @@ -147,7 +147,7 @@ export default { .count-number{ font-family:'ArialMT', 'Arial', sans-serif; font-size:33px; - color: #6C317C; + color: var(--count_number); } .main-number-show { @@ -155,7 +155,7 @@ export default { height: 100px; border-style: solid; border-width: 7px; - border-color: #CDB9D2; + border-color: var(--count_number_shallow); border-radius:50%; } diff --git a/frontend/src/business/components/api/homepage/components/SceneInfoCard.vue b/frontend/src/business/components/api/homepage/components/SceneInfoCard.vue index 0f5a5db41f..e048e5c050 100644 --- a/frontend/src/business/components/api/homepage/components/SceneInfoCard.vue +++ b/frontend/src/business/components/api/homepage/components/SceneInfoCard.vue @@ -137,7 +137,7 @@ export default { .count-number{ font-family:'ArialMT', 'Arial', sans-serif; font-size:33px; - color: #6C317C; + color: var(--count_number); margin:20px auto; } @@ -146,7 +146,7 @@ export default { height: 100px; border-style: solid; border-width: 7px; - border-color: #CDB9D2; + border-color: var(--count_number_shallow); border-radius:50%; } diff --git a/frontend/src/business/components/api/homepage/components/ScheduleTaskInfoCard.vue b/frontend/src/business/components/api/homepage/components/ScheduleTaskInfoCard.vue index 6f9d952ab6..158d819c6b 100644 --- a/frontend/src/business/components/api/homepage/components/ScheduleTaskInfoCard.vue +++ b/frontend/src/business/components/api/homepage/components/ScheduleTaskInfoCard.vue @@ -124,7 +124,7 @@ export default { .count-number{ font-family:'ArialMT', 'Arial', sans-serif; font-size:33px; - color: #6C317C; + color: var(--count_number); } .main-number-show { @@ -132,7 +132,7 @@ export default { height: 100px; border-style: solid; border-width: 7px; - border-color: #CDB9D2; + border-color: var(--count_number_shallow); border-radius:50%; } diff --git a/frontend/src/business/components/api/homepage/components/TestCaseInfoCard.vue b/frontend/src/business/components/api/homepage/components/TestCaseInfoCard.vue index 51c80c0f69..7e61bfbde7 100644 --- a/frontend/src/business/components/api/homepage/components/TestCaseInfoCard.vue +++ b/frontend/src/business/components/api/homepage/components/TestCaseInfoCard.vue @@ -173,7 +173,7 @@ export default { .count-number{ font-family:'ArialMT', 'Arial', sans-serif; font-size:33px; - color: #6C317C; + color: var(--count_number); } .main-number-show { @@ -181,7 +181,7 @@ export default { height: 100px; border-style: solid; border-width: 7px; - border-color: #CDB9D2; + border-color: var(--count_number_shallow); border-radius:50%; } diff --git a/frontend/src/business/components/common/head/HeaderOrgWs.vue b/frontend/src/business/components/common/head/HeaderOrgWs.vue index 7a88e5947c..afb0f29954 100644 --- a/frontend/src/business/components/common/head/HeaderOrgWs.vue +++ b/frontend/src/business/components/common/head/HeaderOrgWs.vue @@ -1,7 +1,7 @@