Conflicts:
	frontend/src/business/components/xpack
This commit is contained in:
shiziyuan9527 2021-03-11 16:46:58 +08:00
commit 6500e0cf4a
66 changed files with 3611 additions and 124510 deletions

View File

@ -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<ScenarioImport> {
@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<MsTestElement> 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<ApiScenarioWithBLOBs> scenarioWithBLOBs = new LinkedList<>();
parseScenarioWithBLOBs(scenarioWithBLOBs, msScenario, request);
scenarioImport.setData(scenarioWithBLOBs);
return scenarioImport;
}
private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> 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<HarEntry> items, MsScenario scenario, LinkedList<MsTestElement> 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<ScenarioVariable> parseScenarioVariable(List<PostmanKeyValue> postmanKeyValues) {
// if (postmanKeyValues == null) {
// return null;
// }
// List<ScenarioVariable> 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<KeyValue> 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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<ApiDefinitionImport> {
protected void buildModule(ApiModule parentModule, ApiDefinitionWithBLOBs apiDefinition, List<String> tags) {
if (tags != null) {
tags.forEach(tag -> {
ApiModule module = ApiDefinitionImportUtil.buildModule(parentModule, tag, this.projectId);
apiDefinition.setModuleId(module.getId());
});
}else {
apiDefinition.setModuleId(parentModule.getId());
}
}
}

View File

@ -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<String, Model> 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<ApiDefinitionWithBLOBs> parseRequests(Har har, ApiTestImportRequest importRequest) {
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
ApiModule parentNode = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
List<HarEntry> 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<HarQueryParm> queryStringList = harRequest.queryString;
queryStringList.forEach(harQueryParm -> {
parseQueryParameters(harQueryParm, request.getArguments());
});
List<HarHeader> harHeaderList = harRequest.headers;
harHeaderList.forEach(harHeader -> {
parseHeaderParameters(harHeader, request.getHeaders());
});
List<HarCookie> 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<KeyValue> headers) {
addCookie(headers, harCookie.name, harCookie.value, harCookie.comment, false);
}
private void parseHeaderParameters(HarHeader harHeader, List<KeyValue> 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<KeyValue> msHeaders) {
List<HarHeader> 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<String, Schema> infoMap = new HashMap();
if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
contentType = org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE;
List<HarPostParam> 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<HarPostParam> 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<HarPostParam> 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<KeyValue> arguments) {
arguments.add(new KeyValue(harQueryParm.name, harQueryParm.value, harQueryParm.comment, false));
}
}

View File

@ -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;
}
}

View File

@ -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);
// }
// }
// }
//
//}

View File

@ -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 + "]";
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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 + "]";
}
}

View File

@ -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<HarEntry> {
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);
}
}

View File

@ -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);
}
}

View File

@ -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<HarPage> pages;
public List<HarEntry> entries;
public String comment;
@Override
public String toString() {
return "HarLog [version=" + version + ", creator=" + creator + ", browser=" + browser + ", pages=" + pages
+ ", entries=" + entries + ", comment=" + comment + "]";
}
}

View File

@ -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<HarEntry> 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);
}
}

View File

@ -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 + "]";
}
}

View File

@ -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<HarPostParam> params;
public String text;
public String comment;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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<HarCookie> cookies;
public List<HarHeader> headers;
public List<HarQueryParm> queryString;
public HarPostData postData;
public long headersSize;
public long bodySize;
public String comment;
@Override
public String toString() {
return this.method + " " + this.url + " " + this.httpVersion;
}
}

View File

@ -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<HarHeader> headers;
public List<HarCookie> cookies;
public HarContent content;
public String redirectURL;
public long headersSize;
public long bodySize;
@Override
public String toString() {
return "HTTP " + this.status + " (" + this.statusText + ")";
}
}

View File

@ -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 + "]";
}
}

View File

@ -40,6 +40,8 @@ public class MsJSR223Processor extends MsTestElement {
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
processor.setName(this.getName() + "<->" + name);
}
processor.setProperty("MS-ID", this.getId());
processor.setProperty(TestElement.TEST_CLASS, JSR223Sampler.class.getName());
processor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
processor.setProperty("cacheKey", "true");

View File

@ -82,6 +82,7 @@ public class MsDubboSampler extends MsTestElement {
}
sampler.setProperty(TestElement.TEST_CLASS, DubboSample.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("DubboSampleGui"));
sampler.setProperty("MS-ID", this.getId());
sampler.addTestElement(configCenter(this.getConfigCenter()));
sampler.addTestElement(registryCenter(this.getRegistryCenter()));

View File

@ -85,8 +85,8 @@ public class MsHTTPSamplerProxy extends MsTestElement {
@JSONField(ordinal = 34)
private List<KeyValue> arguments;
// @JSONField(ordinal = 35)
// private Object requestResult;
@JSONField(ordinal = 35)
private Object requestResult;
@JSONField(ordinal = 36)
private MsAuthManager authManager;
@ -106,6 +106,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HttpTestSampleGui"));
sampler.setProperty("MS-ID", this.getId());
sampler.setMethod(this.getMethod());
sampler.setContentEncoding("UTF-8");
sampler.setConnectTimeout(this.getConnectTimeout() == null ? "6000" : this.getConnectTimeout());

View File

@ -119,6 +119,8 @@ public class MsJDBCSampler extends MsTestElement {
}
sampler.setProperty(TestElement.TEST_CLASS, JDBCSampler.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
sampler.setProperty("MS-ID", this.getId());
// request.getDataSource() 是ID需要转换为Name
sampler.setProperty("dataSource", this.dataSource.getName());
sampler.setProperty("query", this.getQuery());

View File

@ -117,6 +117,7 @@ public class MsTCPSampler extends MsTestElement {
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
tcpSampler.setName(this.getName() + "<->" + name);
}
tcpSampler.setProperty("MS-ID", this.getId());
tcpSampler.setProperty(TestElement.TEST_CLASS, TCPSampler.class.getName());
tcpSampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TCPSamplerGui"));

View File

@ -239,7 +239,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
LogUtil.error(e.getMessage(), e);
}
}
sendTask(report, reportUrl, testResult);
sendTask(report, reportUrl, testResult);
}
private static void sendTask(ApiTestReport report, String reportUrl, TestResult testResult) {
@ -303,6 +303,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
private RequestResult getRequestResult(SampleResult result) {
RequestResult requestResult = new RequestResult();
requestResult.setId(result.getSamplerId());
requestResult.setName(result.getSampleLabel());
requestResult.setUrl(result.getUrlAsString());
requestResult.setMethod(getMethod(result));

View File

@ -7,6 +7,8 @@ import java.util.List;
@Data
public class RequestResult {
// 请求ID
private String id;
private String name;

View File

@ -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<T> extends ApiImportAbstractParser<T> {
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<HarQueryParm> queryStringList = harRequest.queryString;
queryStringList.forEach(harQueryParm -> {
parseQueryParameters(harQueryParm, request.getArguments());
});
List<HarHeader> harHeaderList = harRequest.headers;
harHeaderList.forEach(harHeader -> {
parseHeaderParameters(harHeader, request.getHeaders());
});
List<HarCookie> 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<String, Schema> infoMap = new HashMap();
if (contentType.startsWith(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
contentType = org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE;
List<HarPostParam> 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<HarPostParam> 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<HarPostParam> 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<KeyValue> arguments) {
arguments.add(new KeyValue(harQueryParm.name, harQueryParm.value, harQueryParm.comment, false));
}
private void parseCookieParameters(HarCookie harCookie, List<KeyValue> headers) {
addCookie(headers, harCookie.name, harCookie.value, harCookie.comment, false);
}
private void parseHeaderParameters(HarHeader harHeader, List<KeyValue> headers) {
addHeader(headers, harHeader.name, harHeader.value,harHeader.comment, "", false);
}
private void addPreScript(MsHTTPSamplerProxy request, List<PostmanEvent> 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<String> 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<MsTestElement> hashTree = new LinkedList<>();
hashTree.add(jsr223PreProcessor);
request.setHashTree(hashTree);
}
}
}
private List<KeyValue> parseKeyValue(List<PostmanKeyValue> postmanKeyValues) {
if (postmanKeyValues == null) {
return null;
}
List<KeyValue> 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<PostmanKeyValue> 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;
}
}

View File

@ -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;
}

View File

@ -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<String> values) {
addCriterion("original_state in", values, "originalState");
return (Criteria) this;
}
public Criteria andOriginalStateNotIn(List<String> 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 {

View File

@ -43,5 +43,7 @@ public class ApiScenario implements Serializable {
private Integer num;
private String originalState;
private static final long serialVersionUID = 1L;
}

View File

@ -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<String> values) {
addCriterion("original_state in", values, "originalState");
return (Criteria) this;
}
public Criteria andOriginalStateNotIn(List<String> 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 {

View File

@ -18,6 +18,7 @@
<result column="path" jdbcType="VARCHAR" property="path" />
<result column="num" jdbcType="INTEGER" property="num" />
<result column="tags" jdbcType="VARCHAR" property="tags" />
<result column="original_state" jdbcType="VARCHAR" property="originalState" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiDefinitionWithBLOBs">
<result column="description" jdbcType="LONGVARCHAR" property="description" />
@ -84,7 +85,7 @@
</sql>
<sql id="Base_Column_List">
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
</sql>
<sql id="Blob_Column_List">
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>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiDefinitionWithBLOBs">
insert into api_definition
@ -204,6 +205,9 @@
<if test="tags != null">
tags,
</if>
<if test="originalState != null">
original_state,
</if>
<if test="description != null">
description,
</if>
@ -263,6 +267,9 @@
<if test="tags != null">
#{tags,jdbcType=VARCHAR},
</if>
<if test="originalState != null">
#{originalState,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=LONGVARCHAR},
</if>
@ -331,6 +338,9 @@
<if test="record.tags != null">
tags = #{record.tags,jdbcType=VARCHAR},
</if>
<if test="record.originalState != null">
original_state = #{record.originalState,jdbcType=VARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR},
</if>
@ -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}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -440,6 +452,9 @@
<if test="tags != null">
tags = #{tags,jdbcType=VARCHAR},
</if>
<if test="originalState != null">
original_state = #{originalState,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=LONGVARCHAR},
</if>
@ -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}
</update>
</mapper>

View File

@ -21,6 +21,7 @@
<result column="last_result" jdbcType="VARCHAR" property="lastResult" />
<result column="report_id" jdbcType="VARCHAR" property="reportId" />
<result column="num" jdbcType="INTEGER" property="num" />
<result column="original_state" jdbcType="VARCHAR" property="originalState" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioWithBLOBs">
<result column="scenario_definition" jdbcType="LONGVARCHAR" property="scenarioDefinition" />
@ -87,7 +88,7 @@
<sql id="Base_Column_List">
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
</sql>
<sql id="Blob_Column_List">
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>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioWithBLOBs">
insert into api_scenario
@ -218,6 +219,9 @@
<if test="num != null">
num,
</if>
<if test="originalState != null">
original_state,
</if>
<if test="scenarioDefinition != null">
scenario_definition,
</if>
@ -283,6 +287,9 @@
<if test="num != null">
#{num,jdbcType=INTEGER},
</if>
<if test="originalState != null">
#{originalState,jdbcType=VARCHAR},
</if>
<if test="scenarioDefinition != null">
#{scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
@ -357,6 +364,9 @@
<if test="record.num != null">
num = #{record.num,jdbcType=INTEGER},
</if>
<if test="record.originalState != null">
original_state = #{record.originalState,jdbcType=VARCHAR},
</if>
<if test="record.scenarioDefinition != null">
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
@ -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}
<if test="_parameter != null">
@ -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}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -477,6 +489,9 @@
<if test="num != null">
num = #{num,jdbcType=INTEGER},
</if>
<if test="originalState != null">
original_state = #{originalState,jdbcType=VARCHAR},
</if>
<if test="scenarioDefinition != null">
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
@ -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}
</update>
</mapper>

View File

@ -235,7 +235,7 @@
<update id="removeToGc">
update api_definition
set
set original_state=status,
status = 'Trash'
where id in
<foreach collection="ids" item="v" separator="," open="(" close=")">
@ -245,7 +245,7 @@
<update id="removeToGcByExample" parameterType="io.metersphere.base.domain.ApiDefinitionExample">
update api_definition
set
set original_state=status,
status = 'Trash', module_path = null, module_id = null
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
@ -255,7 +255,7 @@
<update id="reduction">
update api_definition
set
status = 'Underway'
status = original_state
where id in
<foreach collection="ids" item="v" separator="," open="(" close=")">
#{v}

View File

@ -275,7 +275,7 @@
<update id="removeToGc">
update api_scenario
set
set original_state=status,
status = 'Trash'
where id in
<foreach collection="ids" item="v" separator="," open="(" close=")">
@ -285,7 +285,7 @@
<update id="removeToGcByExample" parameterType="io.metersphere.base.domain.ApiScenarioExample">
update api_scenario
set
set original_state=status,
status = 'Trash', module_path = null, api_scenario_module_id = null
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
@ -295,7 +295,7 @@
<update id="reduction">
update api_scenario
set
status = 'Underway'
status = original_state
where id in
<foreach collection="ids" item="v" separator="," open="(" close=")">
#{v}

View File

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

View File

@ -44,6 +44,10 @@ public class ShiroUtils {
// filterChainDefinitionMap.put("/document/**", "anon");
}
public static void ignoreCsrfFilter(Map<String, String> filterChainDefinitionMap) {
filterChainDefinitionMap.put("/", "apikey, authc"); // 跳转到 / 不用校验 csrf
}
public static Cookie getSessionIdCookie(){
SimpleCookie sessionIdCookie = new SimpleCookie();
sessionIdCookie.setPath("/");

View File

@ -47,9 +47,11 @@ public class ShiroConfig implements EnvironmentAware {
shiroFilterFactoryBean.getFilters().put("apikey", new ApiKeyFilter());
shiroFilterFactoryBean.getFilters().put("csrf", new CsrfFilter());
Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
ShiroUtils.loadBaseFilterChain(filterChainDefinitionMap);
filterChainDefinitionMap.put("/", "apikey, authc"); // 跳转到 / 不用校验 csrf
ShiroUtils.ignoreCsrfFilter(filterChainDefinitionMap);
filterChainDefinitionMap.put("/**", "apikey, csrf, authc");
return shiroFilterFactoryBean;
}

View File

@ -14,8 +14,7 @@ public class EngineContext {
private String reportId;
private Integer resourceIndex;
private Map<String, Object> properties = new HashMap<>();
private Map<String, String> testData = new HashMap<>();
private Map<String, byte[]> testJars = new HashMap<>();
private Map<String, byte[]> testResourceFiles = new HashMap<>();
public String getTestId() {
return testId;
@ -69,14 +68,6 @@ public class EngineContext {
this.fileType = fileType;
}
public Map<String, String> getTestData() {
return testData;
}
public void setTestData(Map<String, String> testData) {
this.testData = testData;
}
public String getResourcePoolId() {
return resourcePoolId;
}
@ -111,11 +102,11 @@ public class EngineContext {
}
public Map<String, byte[]> getTestJars() {
return testJars;
public Map<String, byte[]> getTestResourceFiles() {
return testResourceFiles;
}
public void setTestJars(Map<String, byte[]> testJars) {
this.testJars = testJars;
public void setTestResourceFiles(Map<String, byte[]> testResourceFiles) {
this.testResourceFiles = testResourceFiles;
}
}

View File

@ -19,7 +19,8 @@ import io.metersphere.service.FileService;
import io.metersphere.service.KubernetesTestEngine;
import io.metersphere.service.TestResourcePoolService;
import org.apache.commons.beanutils.ConstructorUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.reflections8.Reflections;
import org.springframework.stereotype.Service;
@ -92,8 +93,7 @@ public class EngineFactory {
}
List<FileMetadata> jmxFiles = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.JMX.name())).collect(Collectors.toList());
List<FileMetadata> csvFiles = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.CSV.name())).collect(Collectors.toList());
List<FileMetadata> jarFiles = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.JAR.name())).collect(Collectors.toList());
List<FileMetadata> resourceFiles = ListUtils.subtract(fileMetadataList, jmxFiles);
// 合并上传的jmx
byte[] jmxBytes = mergeJmx(jmxFiles);
final EngineContext engineContext = new EngineContext();
@ -156,22 +156,13 @@ public class EngineFactory {
MSException.throwException(e);
}
if (CollectionUtils.isNotEmpty(csvFiles)) {
Map<String, String> data = new HashMap<>();
csvFiles.forEach(cf -> {
FileContent csvContent = fileService.getFileContent(cf.getId());
data.put(cf.getName(), new String(csvContent.getFile()));
});
engineContext.setTestData(data);
}
if (CollectionUtils.isNotEmpty(jarFiles)) {
if (CollectionUtils.isNotEmpty(resourceFiles)) {
Map<String, byte[]> data = new HashMap<>();
jarFiles.forEach(jf -> {
FileContent content = fileService.getFileContent(jf.getId());
data.put(jf.getName(), content.getFile());
resourceFiles.forEach(cf -> {
FileContent csvContent = fileService.getFileContent(cf.getId());
data.put(cf.getName(), csvContent.getFile());
});
engineContext.setTestJars(data);
engineContext.setTestResourceFiles(data);
}
return engineContext;

View File

@ -51,17 +51,9 @@ public class JmeterFileService {
// 每个测试生成一个文件夹
files.put(fileName, context.getContent().getBytes(StandardCharsets.UTF_8));
// 保存测试数据文件
Map<String, String> testData = context.getTestData();
if (!CollectionUtils.isEmpty(testData)) {
for (String k : testData.keySet()) {
String v = testData.get(k);
files.put(k, v.getBytes(StandardCharsets.UTF_8));
}
}
// 保存 byte[] jar
Map<String, byte[]> jarFiles = context.getTestJars();
// 保存 byte[]
Map<String, byte[]> jarFiles = context.getTestResourceFiles();
if (!CollectionUtils.isEmpty(jarFiles)) {
for (String k : jarFiles.keySet()) {
byte[] v = jarFiles.get(k);

View File

@ -32,6 +32,12 @@ public class CsrfFilter extends AnonymousFilter {
if (ApiKeyHandler.isApiKeyCall(WebUtils.toHttp(request))) {
return true;
}
// websocket 不需要csrf
String websocketKey = httpServletRequest.getHeader("Sec-WebSocket-Key");
if (StringUtils.isNotBlank(websocketKey)) {
return true;
}
// 请求头取出的token value
String csrfToken = httpServletRequest.getHeader(TOKEN_NAME);
// 校验 token

File diff suppressed because it is too large Load Diff

View File

@ -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;
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';

View File

@ -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",

View File

@ -100,6 +100,19 @@
active() {
this.isActive = !this.isActive;
},
formatResult(res) {
let resMap = new Map;
if (res && res.scenarios) {
res.scenarios.forEach(item => {
if (item && item.requestResults) {
item.requestResults.forEach(req => {
resMap.set(req.id, req);
})
}
})
}
this.$emit('refresh', resMap);
},
getReport() {
this.init();
if (this.reportId) {
@ -113,7 +126,7 @@
if (!this.content) {
this.content = {scenarios: []};
}
this.$emit('refresh');
this.formatResult(this.content);
} catch (e) {
throw e;
}

View File

@ -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";

View File

@ -184,7 +184,7 @@
<!-- 调试结果 -->
<el-drawer v-if="type!=='detail'" :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr"
:withHeader="true" :modal="false" size="90%">
<ms-api-report-detail :report-id="reportId" :debug="true" :currentProjectId="projectId"/>
<ms-api-report-detail :report-id="reportId" :debug="true" :currentProjectId="projectId" @refresh="detailRefresh"/>
</el-drawer>
<!--场景公共参数-->
@ -291,7 +291,8 @@
response: {},
projectIds: new Set,
projectEnvMap: new Map,
projectList: []
projectList: [],
debugResult: new Map,
}
},
created() {
@ -548,21 +549,32 @@
if (arr[i].hashTree != undefined && arr[i].hashTree.length > 0) {
this.recursiveSorting(arr[i].hashTree);
}
// debug
if (this.debugResult && this.debugResult.get(arr[i].id)) {
arr[i].requestResult = this.debugResult.get(arr[i].id);
}
}
},
sort() {
for (let i in this.scenarioDefinition) {
//
this.scenarioDefinition[i].index = Number(i) + 1;
//
if (this.scenarioDefinition[i].type === ELEMENT_TYPE.LoopController && this.scenarioDefinition[i].hashTree
&& this.scenarioDefinition[i].hashTree.length > 1) {
this.scenarioDefinition[i].countController.proceed = true;
}
// ID
if (!this.scenarioDefinition[i].projectId) {
this.scenarioDefinition[i].projectId = getCurrentProjectID();
}
if (this.scenarioDefinition[i].hashTree != undefined && this.scenarioDefinition[i].hashTree.length > 0) {
this.recursiveSorting(this.scenarioDefinition[i].hashTree);
}
// debug
if (this.debugResult && this.debugResult.get(this.scenarioDefinition[i].id)) {
this.scenarioDefinition[i].requestResult = this.debugResult.get(this.scenarioDefinition[i].id);
}
}
},
addCustomizeApi(request) {
@ -1026,6 +1038,11 @@
arr.forEach(a => this.projectIds.add(a));
})
})
},
detailRefresh(result) {
//
this.debugResult = result;
this.sort()
}
}
}

View File

@ -26,7 +26,7 @@
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.import_mode')">
<el-form-item v-if="!isHar" :label="$t('commons.import_mode')">
<el-select size="small" v-model="formData.modeId" class="project-select" clearable>
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
@ -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) {

View File

@ -28,7 +28,7 @@
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item v-if="!isScenarioModel" :label="$t('commons.import_mode')">
<el-form-item v-if="!isScenarioModel&&!isHar" :label="$t('commons.import_mode')">
<el-select size="small" v-model="formData.modeId" class="project-select" clearable>
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
@ -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';
}

View File

@ -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;
}
},
},

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -117,6 +117,36 @@
</el-form>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form :inline="true">
<el-form-item>
<div>
{{ $t('load_test.granularity') }}
<el-popover
placement="bottom"
width="400"
trigger="hover">
<el-table :data="granularityData">
<el-table-column property="start" :label="$t('load_test.duration')">
<template v-slot:default="scope">
<span>{{ scope.row.start }} - {{ scope.row.end }}</span>
</template>
</el-table-column>
<el-table-column property="granularity" :label="$t('load_test.granularity')"/>
</el-table>
<i slot="reference" class="el-icon-info pointer"/>
</el-popover>
</div>
</el-form-item>
<el-form-item>
<el-select v-model="granularity" :placeholder="$t('commons.please_select')" size="mini" clearable>
<el-option v-for="op in granularityData" :key="op.granularity" :label="op.granularity" :value="op.granularity"></el-option>
</el-select>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
</template>
@ -134,6 +164,18 @@ export default {
domains: [],
params: [],
statusCodeStr: '',
granularity: undefined,
granularityData: [
{start: 0, end: 100, granularity: 1},
{start: 101, end: 500, granularity: 5},
{start: 501, end: 1000, granularity: 10},
{start: 1001, end: 3000, granularity: 30},
{start: 3001, end: 6000, granularity: 60},
{start: 6001, end: 30000, granularity: 300},
{start: 30001, end: 60000, granularity: 600},
{start: 60001, end: 180000, granularity: 1800},
{start: 180001, end: 360000, granularity: 3600},
]
}
},
props: {
@ -166,6 +208,7 @@ export default {
this.statusCodeStr = this.statusCode.join(',');
this.domains = data.domains || [];
this.params = data.params || [];
this.granularity = data.granularity;
}
});
},
@ -252,6 +295,7 @@ export default {
statusCode: statusCode,
params: this.params,
domains: this.domains,
granularity: this.granularity,
};
},
}
@ -287,4 +331,8 @@ export default {
align: center;
}
.pointer {
cursor: pointer;
}
</style>

View File

@ -70,7 +70,7 @@
<el-row type="flex" justify="start" align="middle">
<el-upload
style="padding-right: 10px;"
accept=".jar,.csv"
accept=".jar,.csv,.json,.pdf,.jpg,.png,.jpeg,.doc,.docx,.xlsx"
action=""
:limit="fileNumLimit"
multiple
@ -170,7 +170,7 @@ export default {
fileList: [],
tableData: [],
uploadList: [],
metadataIdList:[],
metadataIdList: [],
fileNumLimit: 10,
threadGroups: [],
loadFileVisible: false,
@ -276,7 +276,10 @@ export default {
let self = this;
let file = uploadResources.file;
self.uploadList.push(file);
let type = file.name.substring(file.name.lastIndexOf(".") + 1);
if (type.toLowerCase() !== 'jmx') {
return;
}
let jmxReader = new FileReader();
jmxReader.onload = (event) => {
self.threadGroups = self.threadGroups.concat(findThreadGroup(event.target.result, file.name));

View File

@ -22,7 +22,6 @@ import {left2RightDrag, bottom2TopDrag, right2LeftDrag} from "../common/js/direc
import JsonSchemaEditor from './components/common/json-schema/schema/index';
import JSONPathPicker from 'vue-jsonpath-picker';
import VueClipboard from 'vue-clipboard2'
import 'default-passive-events'
Vue.use(JsonSchemaEditor);
import VuePapaParse from 'vue-papa-parse'
Vue.use(VuePapaParse)

View File

@ -478,7 +478,8 @@ export default {
delete_file: "The file already exists, please delete the file with the same name first!",
thread_num: 'Concurrent users:',
input_thread_num: 'Please enter the number of threads',
duration: 'Duration time (seconds):',
duration: 'Duration time (seconds)',
granularity: 'Aggregation time (seconds)',
input_duration: 'Please enter a duration',
rps_limit: 'RPS Limit:',
input_rps_limit: 'Please enter a limit',
@ -913,7 +914,9 @@ export default {
export_tip: "Export Tip",
ms_tip: "Support for MeterSphere JSON format",
ms_export_tip: "Export jSON-formatted files via MeterSphere website or browser plug-ins",
har_export_tip: "Export Har files by browser dev-tool",
swagger_tip: "Swagger 2.0 and 3.0 json files are supported",
har_tip: "Only Har files are supported",
postman_tip: "Only Postman Collection V2.1 json files are supported",
postman_export_tip: "Export the test collection by Postman",
swagger_export_tip: "Export jSON-formatted files via Swagger website",

View File

@ -475,7 +475,8 @@ export default {
delete_file: "文件已存在,请先删除同名文件!",
thread_num: '并发用户数:',
input_thread_num: '请输入线程数',
duration: '压测时长(秒):',
duration: '压测时长(秒)',
granularity: '聚合时间(秒)',
input_duration: '请输入时长',
rps_limit: 'RPS上限',
input_rps_limit: '请输入限制',
@ -916,8 +917,10 @@ export default {
export_tip: "导出方法",
ms_tip: "支持 Metersphere json 格式",
ms_export_tip: "通过 Metersphere 接口测试页面或者浏览器插件导出 json 格式文件",
har_export_tip: "通过 浏览器的开发者工具 导出 Har 格式文件",
postman_tip: "只支持 Postman Collection v2.1 格式的 json 文件",
swagger_tip: "支持 Swagger 2.0 与 3.0 版本的 json 文件",
har_tip: "只支持 Har 文件",
post_export_tip: "通过 Postman 导出测试集合",
swagger_export_tip: "通过 Swagger 页面导出",
jmeter_export_tip: "通过 Jmeter 生成JMX文件",

View File

@ -475,7 +475,8 @@ export default {
delete_file: "文件已存在,請先刪除同名文件!",
thread_num: '並發用戶數:',
input_thread_num: '請輸入線程數',
duration: '壓測時長(秒):',
duration: '壓測時長(秒)',
granularity: '聚合時間(秒)',
input_duration: '請輸入時長',
rps_limit: 'RPS上限',
input_rps_limit: '請輸入限制',
@ -915,8 +916,10 @@ export default {
export_tip: "導出方法",
ms_tip: "支持 Metersphere json 格式",
ms_export_tip: "通過 Metersphere 接口測試頁面或者瀏覽器插件導出 json 格式文件",
har_export_tip: "通过 瀏覽器到開發者工具 导出 Har 格式文件",
postman_tip: "只支持 Postman Collection v2.1 格式的 json 文件",
swagger_tip: "支持 Swagger 2.0 與 3.0 版本的 json 文件",
har_tip: "只支持 Har 文件",
post_export_tip: "通過 Postman 導出測試集合",
swagger_export_tip: "通過 Swagger 頁面導出",
jmeter_export_tip: "通過 Jmeter 生成JMX文件",