feat(接口测试): 自动设置Content-Type请求头

This commit is contained in:
AgAngle 2024-03-21 11:46:59 +08:00 committed by Craftsman
parent 5d64a05a91
commit 121d03127f
21 changed files with 90 additions and 53 deletions

View File

@ -6,6 +6,7 @@ package io.metersphere.api.constants;
*/
public class ApiConstants {
public static final String HTTP_PROTOCOL = "HTTP";
public static final String CONTENT_TYPE = "Content-Type";
private ApiConstants() {}
}

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.request.http.Header;
import io.metersphere.api.dto.request.http.MsHeader;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import lombok.Data;
@ -35,7 +35,7 @@ public class HttpResponse implements Serializable {
@Schema(description = "响应请求头")
@Valid
private List<Header> headers;
private List<MsHeader> headers;
@Schema(description = "响应请求体")
@Valid

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.mockserver;
import io.metersphere.api.dto.definition.ResponseBody;
import io.metersphere.api.dto.request.http.Header;
import io.metersphere.api.dto.request.http.MsHeader;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -17,7 +17,7 @@ public class MockResponse implements Serializable {
private int statusCode;
@Schema(description = "响应请求头")
private List<Header> headers;
private List<MsHeader> headers;
@Schema(description = "是否使用api响应体")
private boolean useApiResponse;

View File

@ -51,7 +51,7 @@ public class MsHTTPElement extends AbstractMsProtocolTestElement {
* 请求头
*/
@Valid
private List<Header> headers;
private List<MsHeader> headers;
/**
* rest参数
*/

View File

@ -9,6 +9,6 @@ import lombok.Data;
* @CreateTime: 2023-11-06 16:59
*/
@Data
public class Header extends KeyValueEnableParam {
public class MsHeader extends KeyValueEnableParam {
}

View File

@ -203,9 +203,9 @@ public class Swagger3Parser<T> implements ImportParser<ApiDefinitionImport> {
ResponseBody body = new ResponseBody();
Map<String, io.swagger.v3.oas.models.headers.Header> headers = value.getHeaders();
if (MapUtils.isNotEmpty(headers)) {
List<Header> headerList = new ArrayList<>();
List<MsHeader> headerList = new ArrayList<>();
headers.forEach((k, v) -> {
Header header = new Header();
MsHeader header = new MsHeader();
header.setKey(k);
header.setValue(getDefaultObjectValue(v.getExample()));
header.setDescription(getDefaultStringValue(v.getDescription()));
@ -431,8 +431,8 @@ public class Swagger3Parser<T> implements ImportParser<ApiDefinitionImport> {
}
private void parseCookieParameters(CookieParameter cookieParameter, List<Header> headers) {
Header headerParams = new Header();
private void parseCookieParameters(CookieParameter cookieParameter, List<MsHeader> headers) {
MsHeader headerParams = new MsHeader();
headerParams.setKey(getDefaultStringValue(cookieParameter.getName()));
headerParams.setDescription(getDefaultStringValue(cookieParameter.getDescription()));
if (cookieParameter.getSchema() != null) {
@ -441,8 +441,8 @@ public class Swagger3Parser<T> implements ImportParser<ApiDefinitionImport> {
headers.add(headerParams);
}
private void parseHeaderParameters(HeaderParameter headerParameter, List<Header> headers) {
Header headerParams = new Header();
private void parseHeaderParameters(HeaderParameter headerParameter, List<MsHeader> headers) {
MsHeader headerParams = new MsHeader();
headerParams.setKey(getDefaultStringValue(headerParameter.getName()));
headerParams.setDescription(getDefaultStringValue(headerParameter.getDescription()));
if (headerParameter.getSchema() != null) {

View File

@ -1,11 +1,9 @@
package io.metersphere.api.parser.jmeter;
import io.metersphere.api.constants.ApiConstants;
import io.metersphere.api.dto.ApiParamConfig;
import io.metersphere.api.dto.request.http.MsHTTPConfig;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.request.http.QueryParam;
import io.metersphere.api.dto.request.http.RestParam;
import io.metersphere.api.dto.request.http.*;
import io.metersphere.api.dto.request.http.auth.BasicAuth;
import io.metersphere.api.dto.request.http.auth.DigestAuth;
import io.metersphere.api.dto.request.http.auth.HTTPAuthConfig;
@ -413,7 +411,33 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
&& (converter instanceof MsWWWFormBodyConverter || converter instanceof MsFormDataBodyConverter)) {
return;
}
converter.parse(sampler, body.getBodyDataByType(), config);
String contentType = converter.parse(sampler, body.getBodyDataByType(), config);
// 自定设置 contentType
if (StringUtils.isBlank(contentType)) {
return;
}
if (msHTTPElement.getHeaders() == null) {
msHTTPElement.setHeaders(new ArrayList<>(1));
}
List<MsHeader> headers = msHTTPElement.getHeaders();
// 查询请求头是否包含当前的 contentType
List<MsHeader> contentTypeHeaders = headers.stream()
.filter(KeyValueEnableParam::getEnable)
.filter(KeyValueParam::isValid)
.filter(header ->
StringUtils.equalsIgnoreCase(header.getKey().trim(), ApiConstants.CONTENT_TYPE)
&& StringUtils.contains(header.getValue(), contentType)
)
.toList();
// 不包含则添加一个
if (CollectionUtils.isEmpty(contentTypeHeaders)) {
MsHeader header = new MsHeader();
header.setEnable(true);
header.setKey(ApiConstants.CONTENT_TYPE);
header.setValue(contentType);
headers.add(header);
}
}
}

View File

@ -5,6 +5,7 @@ import io.metersphere.api.dto.ApiFile;
import io.metersphere.plugin.api.dto.ParameterConfig;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
import org.springframework.http.MediaType;
/**
* 处理 Binary 参数
@ -13,12 +14,13 @@ import org.apache.jmeter.protocol.http.util.HTTPFileArg;
*/
public class MsBinaryBodyConverter extends MsBodyConverter<BinaryBody> {
@Override
public void parse(HTTPSamplerProxy sampler, BinaryBody body, ParameterConfig config) {
public String parse(HTTPSamplerProxy sampler, BinaryBody body, ParameterConfig config) {
ApiFile file = body.getFile();
if (file == null) {
return;
return null;
}
HTTPFileArg httpFileArg = getHttpFileArg(file);
sampler.setHTTPFiles(new HTTPFileArg[]{httpFileArg});
return MediaType.APPLICATION_OCTET_STREAM_VALUE;
}
}

View File

@ -29,12 +29,13 @@ public abstract class MsBodyConverter<T> {
/**
* 解析对应的请求体参数
* 返回 Content-Type
*
* @param sampler
* @param body
* @param config
*/
public abstract void parse(HTTPSamplerProxy sampler, T body, ParameterConfig config);
public abstract String parse(HTTPSamplerProxy sampler, T body, ParameterConfig config);
/**
* 解析文本类型的 kv 参数
@ -110,7 +111,7 @@ public abstract class MsBodyConverter<T> {
* @param sampler
* @param raw
*/
protected static void handleRowBody(HTTPSamplerProxy sampler, String raw) {
protected void handleRowBody(HTTPSamplerProxy sampler, String raw) {
Arguments arguments = new Arguments();
HTTPArgument httpArgument = new HTTPArgument();
httpArgument.setValue(raw);

View File

@ -21,11 +21,11 @@ import java.util.stream.Collectors;
public class MsFormDataBodyConverter extends MsBodyConverter<FormDataBody> {
@Override
public void parse(HTTPSamplerProxy sampler, FormDataBody body, ParameterConfig config) {
public String parse(HTTPSamplerProxy sampler, FormDataBody body, ParameterConfig config) {
List<FormDataKV> formValues = body.getFormValues();
sampler.setDoMultipart(true);
if (CollectionUtils.isEmpty(formValues)) {
return;
return null;
}
List<FormDataKV> validFormValues = formValues.stream()
.filter(FormDataKV::getEnable)
@ -35,6 +35,7 @@ public class MsFormDataBodyConverter extends MsBodyConverter<FormDataBody> {
List<FormDataKV> textFormValues = validFormValues.stream().filter(kv -> !kv.isFile()).collect(Collectors.toList());
sampler.setHTTPFiles(getHttpFileArg(fileFormValues));
sampler.setArguments(getArguments(textFormValues));
return null;
}

View File

@ -9,6 +9,7 @@ import io.metersphere.sdk.util.LogUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.springframework.http.MediaType;
import java.util.HashMap;
import java.util.List;
@ -20,7 +21,7 @@ import java.util.Map;
*/
public class MsJsonBodyConverter extends MsBodyConverter<JsonBody> {
@Override
public void parse(HTTPSamplerProxy sampler, JsonBody body, ParameterConfig config) {
public String parse(HTTPSamplerProxy sampler, JsonBody body, ParameterConfig config) {
sampler.setPostBodyRaw(true);
try {
String raw;
@ -34,6 +35,7 @@ public class MsJsonBodyConverter extends MsBodyConverter<JsonBody> {
} catch (Exception e) {
LogUtils.error("json mock value is abnormal", e);
}
return MediaType.APPLICATION_JSON_VALUE;
}

View File

@ -10,7 +10,8 @@ import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
*/
public class MsNoneBodyConverter extends MsBodyConverter<NoneBody> {
@Override
public void parse(HTTPSamplerProxy sampler, NoneBody body, ParameterConfig config) {
public String parse(HTTPSamplerProxy sampler, NoneBody body, ParameterConfig config) {
// do nothing
return null;
}
}

View File

@ -11,7 +11,8 @@ import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
*/
public class MsRawBodyConverter extends MsBodyConverter<RawBody> {
@Override
public void parse(HTTPSamplerProxy sampler, RawBody body, ParameterConfig config) {
public String parse(HTTPSamplerProxy sampler, RawBody body, ParameterConfig config) {
handleRowBody(sampler, body.getValue());
return null;
}
}

View File

@ -4,6 +4,7 @@ import io.metersphere.api.dto.request.http.body.WWWFormBody;
import io.metersphere.api.dto.request.http.body.WWWFormKV;
import io.metersphere.plugin.api.dto.ParameterConfig;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.springframework.http.MediaType;
import java.util.List;
import java.util.stream.Collectors;
@ -14,12 +15,13 @@ import java.util.stream.Collectors;
*/
public class MsWWWFormBodyConverter extends MsBodyConverter<WWWFormBody> {
@Override
public void parse(HTTPSamplerProxy sampler, WWWFormBody body, ParameterConfig config) {
public String parse(HTTPSamplerProxy sampler, WWWFormBody body, ParameterConfig config) {
List<WWWFormKV> formValues = body.getFormValues();
List<WWWFormKV> validFormValues = formValues.stream()
.filter(WWWFormKV::getEnable)
.filter(WWWFormKV::isValid)
.collect(Collectors.toList());
sampler.setArguments(getArguments(validFormValues));
return MediaType.APPLICATION_FORM_URLENCODED_VALUE;
}
}

View File

@ -3,6 +3,7 @@ package io.metersphere.api.parser.jmeter.body;
import io.metersphere.api.dto.request.http.body.XmlBody;
import io.metersphere.plugin.api.dto.ParameterConfig;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.springframework.http.MediaType;
/**
* @Author: jianxing
@ -10,7 +11,8 @@ import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
*/
public class MsXmlBodyConverter extends MsBodyConverter<XmlBody> {
@Override
public void parse(HTTPSamplerProxy sampler, XmlBody body, ParameterConfig config) {
public String parse(HTTPSamplerProxy sampler, XmlBody body, ParameterConfig config) {
handleRowBody(sampler, body.getValue());
return MediaType.TEXT_XML_VALUE;
}
}

View File

@ -14,7 +14,7 @@ import io.metersphere.api.dto.definition.ApiDefinitionDTO;
import io.metersphere.api.dto.definition.ApiDefinitionPageRequest;
import io.metersphere.api.dto.definition.ApiModuleRequest;
import io.metersphere.api.dto.request.ImportRequest;
import io.metersphere.api.dto.request.http.Header;
import io.metersphere.api.dto.request.http.MsHeader;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.request.http.QueryParam;
import io.metersphere.api.dto.request.http.RestParam;
@ -484,11 +484,11 @@ public class ApiDefinitionImportUtilService {
public boolean dataIsSame(MsHTTPElement dbRequest, MsHTTPElement importRequest) {
boolean same = true;
//判断请求头是否一样
List<Header> dbHeaders = dbRequest.getHeaders();
List<Header> importHeaders = importRequest.getHeaders();
List<MsHeader> dbHeaders = dbRequest.getHeaders();
List<MsHeader> importHeaders = importRequest.getHeaders();
if (CollectionUtils.isNotEmpty(dbHeaders) || CollectionUtils.isNotEmpty(importHeaders)) {
List<String> dbHeaderKeys = dbHeaders.stream().map(Header::getKey).toList();
List<String> importHeaderKeys = importHeaders.stream().map(Header::getKey).toList();
List<String> dbHeaderKeys = dbHeaders.stream().map(MsHeader::getKey).toList();
List<String> importHeaderKeys = importHeaders.stream().map(MsHeader::getKey).toList();
if (paramsIsSame(dbHeaderKeys, importHeaderKeys)) {
return false;
}

View File

@ -5,7 +5,7 @@ import io.metersphere.api.dto.definition.HttpResponse;
import io.metersphere.api.dto.definition.ResponseBody;
import io.metersphere.api.dto.mockserver.HttpRequestParam;
import io.metersphere.api.dto.mockserver.MockResponse;
import io.metersphere.api.dto.request.http.Header;
import io.metersphere.api.dto.request.http.MsHeader;
import io.metersphere.api.dto.request.http.body.Body;
import io.metersphere.api.mapper.*;
import io.metersphere.api.utils.MockServerUtils;
@ -102,7 +102,7 @@ public class MockServerService {
private Object getReturn(ApiDefinitionMockConfig compareMockConfig, String apiId, String projectId, HttpServletResponse response) {
ResponseBody responseBody = null;
List<Header> responseHeader = null;
List<MsHeader> responseHeader = null;
int responseCode = -1;
String useApiResponseId = null;

View File

@ -13,7 +13,7 @@ import io.metersphere.api.dto.definition.request.ApiDefinitionMockUpdateRequest;
import io.metersphere.api.dto.mockserver.KeyValueInfo;
import io.metersphere.api.dto.mockserver.MockMatchRule;
import io.metersphere.api.dto.mockserver.MockResponse;
import io.metersphere.api.dto.request.http.Header;
import io.metersphere.api.dto.request.http.MsHeader;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.request.http.body.Body;
import io.metersphere.api.mapper.*;
@ -629,7 +629,7 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
ResultActions action = mockMvc.perform(requestBuilder);
//判断响应
List<Header> headers;
List<MsHeader> headers;
int statusCode;
ResponseBody responseBody;
if (mockResponse.isUseApiResponse()) {
@ -646,7 +646,7 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
//判断响应码
Assertions.assertEquals(mockServerResponse.getStatus(), statusCode);
//判断响应头
for (Header header : headers) {
for (MsHeader header : headers) {
if (header.getEnable()) {
Assertions.assertEquals(mockServerResponse.getHeader(header.getKey()), header.getValue());
}

View File

@ -11,7 +11,7 @@ import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.request.ApiTransferRequest;
import io.metersphere.api.dto.request.controller.*;
import io.metersphere.api.dto.request.controller.loop.*;
import io.metersphere.api.dto.request.http.Header;
import io.metersphere.api.dto.request.http.MsHeader;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.request.http.QueryParam;
import io.metersphere.api.dto.response.ApiScenarioBatchOperationResponse;
@ -510,15 +510,15 @@ public class ApiScenarioControllerTests extends BaseTest {
}
private void initTestData() {
Header header1 = new Header();
MsHeader header1 = new MsHeader();
header1.setKey("a");
header1.setValue("aaa");
Header header2 = new Header();
MsHeader header2 = new MsHeader();
header2.setKey("c");
header2.setValue("cc");
Header header3 = new Header();
MsHeader header3 = new MsHeader();
header3.setKey("Cookie");
header3.setValue("b=c");

View File

@ -437,7 +437,7 @@ public class MsHTTPElementTest {
msHTTPElement.setName("name");
msHTTPElement.setEnable(true);
Header header = new Header();
MsHeader header = new MsHeader();
header.setEnable(false);
header.setValue("value");
header.setKey("key");
@ -478,7 +478,7 @@ public class MsHTTPElementTest {
httpResponse.setStatusCode("200");
httpResponse.setDefaultFlag(true);
Header header = new Header();
MsHeader header = new MsHeader();
header.setEnable(false);
header.setValue("value");
header.setKey("key");
@ -500,13 +500,13 @@ public class MsHTTPElementTest {
http1Response.setStatusCode("222");
http1Response.setDefaultFlag(true);
http1Response.setHeaders(new ArrayList<>() {{
this.add(new Header() {{
this.add(new MsHeader() {{
this.setEnable(false);
this.setValue("valueA1");
this.setKey("keyA1");
this.setDescription("descA1");
}});
this.add(new Header() {{
this.add(new MsHeader() {{
this.setEnable(true);
this.setValue("headerDefaultValue");
this.setKey("headerDefault");
@ -526,13 +526,13 @@ public class MsHTTPElementTest {
http2Response.setStatusCode("222");
http2Response.setDefaultFlag(false);
http2Response.setHeaders(new ArrayList<>() {{
this.add(new Header() {{
this.add(new MsHeader() {{
this.setEnable(false);
this.setValue("valueB1");
this.setKey("keyB1");
this.setDescription("descB1");
}});
this.add(new Header() {{
this.add(new MsHeader() {{
this.setEnable(true);
this.setValue("valueB2");
this.setKey("keyB2");

View File

@ -9,7 +9,7 @@ import io.metersphere.api.dto.definition.HttpResponse;
import io.metersphere.api.dto.definition.ResponseBinaryBody;
import io.metersphere.api.dto.definition.ResponseBody;
import io.metersphere.api.dto.mockserver.*;
import io.metersphere.api.dto.request.http.Header;
import io.metersphere.api.dto.request.http.MsHeader;
import io.metersphere.api.dto.request.http.body.Body;
import io.metersphere.api.dto.request.http.body.JsonBody;
import io.metersphere.api.dto.request.http.body.RawBody;
@ -285,17 +285,17 @@ public class MockServerTestService {
mockResponse.setBody(body);
}
List<Header> headers = new ArrayList<>() {{
this.add(new Header() {{
List<MsHeader> headers = new ArrayList<>() {{
this.add(new MsHeader() {{
this.setKey("rspHeaderA");
this.setValue("header-1");
}});
this.add(new Header() {{
this.add(new MsHeader() {{
this.setKey("rspHeaderB");
this.setValue("header-2");
this.setEnable(false);
}});
this.add(new Header() {{
this.add(new MsHeader() {{
this.setKey("rspHeaderC");
this.setValue("header-3");
}});