refactor(接口测试): 优化json-schema定义

This commit is contained in:
AgAngle 2024-07-02 16:37:38 +08:00 committed by Craftsman
parent add903346c
commit cc26849807
8 changed files with 66 additions and 110 deletions

View File

@ -1,6 +1,5 @@
package io.metersphere.api.controller.definition;
import com.fasterxml.jackson.databind.node.TextNode;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.domain.ApiDefinition;
@ -10,6 +9,7 @@ import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.request.ApiEditPosRequest;
import io.metersphere.api.dto.request.ApiTransferRequest;
import io.metersphere.api.dto.request.ImportRequest;
import io.metersphere.api.dto.schema.JsonSchemaItem;
import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.service.definition.ApiDefinitionImportService;
import io.metersphere.api.service.definition.ApiDefinitionLogService;
@ -20,6 +20,7 @@ import io.metersphere.project.service.FileModuleService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.dto.OperationHistoryDTO;
import io.metersphere.system.dto.request.OperationHistoryRequest;
import io.metersphere.system.dto.request.OperationHistoryVersionRequest;
@ -282,8 +283,8 @@ public class ApiDefinitionController {
@PostMapping("/preview")
@Operation(summary = "接口测试-接口管理-接口-json-schema-预览")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
public String preview(@RequestBody TextNode jsonSchema) {
return JsonSchemaBuilder.preview(jsonSchema.asText());
public String preview(@RequestBody JsonSchemaItem jsonSchemaItem) {
return JsonSchemaBuilder.preview(JSON.toJSONString(jsonSchemaItem));
}
@PostMapping("/debug")

View File

@ -1,8 +1,6 @@
package io.metersphere.api.dto.request.http.body;
import io.metersphere.api.dto.schema.JsonSchemaItem;
import io.metersphere.api.utils.JsonSchemaBuilder;
import io.metersphere.sdk.util.JSON;
import jakarta.validation.Valid;
import lombok.Data;
@ -13,33 +11,13 @@ import lombok.Data;
*/
@Data
public class JsonBody {
/**
* 是否启用 json-schema
* 默认false
*/
private Boolean enableJsonSchema = false;
/**
* json 参数值
* enableJsonSchema false 时使用该值
*/
private String jsonValue;
/**
* 启用 json-schema 时的参数对象
* enableJsonSchema true 时使用该值
* json-schema 定义
*/
@Valid
private JsonSchemaItem jsonSchema;
/**
* 是否开启动态转换
* 默认为 false
*/
private Boolean enableTransition = false;
//判断是返回jsonValue还是计算JsonSchema
public String getJsonWithSchema() {
if (enableJsonSchema) {
return JsonSchemaBuilder.preview(JSON.toJSONString(jsonSchema));
}
return jsonValue;
}
}

View File

@ -91,6 +91,14 @@ public class JsonSchemaItem {
* 最大值
*/
private BigDecimal maximum;
/**
* 数组最大长度
*/
private Integer maxItems;
/**
* 数组最小长度
*/
private Integer minItems;
/**
* 一般是选择日期格式
*/

View File

@ -13,7 +13,6 @@ import io.metersphere.api.dto.request.http.QueryParam;
import io.metersphere.api.dto.request.http.RestParam;
import io.metersphere.api.dto.request.http.body.*;
import io.metersphere.api.dto.schema.JsonSchemaItem;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.api.utils.JsonSchemaBuilder;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.constants.PropertyConstant;
@ -62,7 +61,7 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
}
} else {
String apiTestStr = getApiTestStr(source);
Map<String, Object> o = ApiDataUtils.parseObject(apiTestStr, Map.class);
Map<String, Object> o = JSON.parseMap(apiTestStr);
// 判断属性 swagger的值是不是3.0开头
if (o instanceof Map map) {
if (map.containsKey("swagger") && !map.get("swagger").toString().startsWith("3.0")) {
@ -152,16 +151,19 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
Content content = requestBody.getContent();
if (content != null) {
List<MsHeader> headers = request.getHeaders();
content.forEach((key, value) -> {
setRequestBodyData(key, value, request.getBody());
Iterator<Map.Entry<String, io.swagger.v3.oas.models.media.MediaType>> iterator = content.entrySet().iterator();
if (iterator.hasNext()) {
// 优先获取第一个
Map.Entry<String, io.swagger.v3.oas.models.media.MediaType> mediaType = iterator.next();
setRequestBodyData(mediaType.getKey(), mediaType.getValue(), request.getBody());
// 如果key不包含Content-Type 则默认添加Content-Type
if (headers.stream().noneMatch(header -> StringUtils.equals(header.getKey(), ApiConstants.CONTENT_TYPE))) {
MsHeader header = new MsHeader();
header.setKey(ApiConstants.CONTENT_TYPE);
header.setValue(key);
header.setValue(mediaType.getKey());
headers.add(header);
}
});
}
} else {
request.getBody().setBodyType(Body.BodyType.NONE.name());
request.getBody().setNoneBody(new NoneBody());
@ -273,45 +275,26 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
}
private void setResponseBodyData(String k, io.swagger.v3.oas.models.media.MediaType value, ResponseBody body) {
//TODO body 默认如果json格式
JsonSchemaItem jsonSchemaItem = parseSchema(value.getSchema());
switch (k) {
case MediaType.APPLICATION_JSON_VALUE, MediaType.ALL_VALUE -> {
body.setBodyType(Body.BodyType.JSON.name());
JsonBody jsonBody = new JsonBody();
jsonBody.setJsonSchema(jsonSchemaItem);
jsonBody.setEnableJsonSchema(false);
if (ObjectUtils.isNotEmpty(value.getExample())) {
jsonBody.setJsonValue(ApiDataUtils.toJSONString(value.getExample()));
}
String jsonString = JSON.toJSONString(jsonSchemaItem);
if (StringUtils.isNotBlank(jsonString)) {
jsonBody.setJsonValue(JsonSchemaBuilder.jsonSchemaToJson(jsonString));
}
body.setJsonBody(jsonBody);
body.setJsonBody(getJsonBody(value, jsonSchemaItem));
}
case MediaType.APPLICATION_XML_VALUE -> {
if (StringUtils.isBlank(body.getBodyType())) {
body.setBodyType(Body.BodyType.XML.name());
}
body.setBodyType(Body.BodyType.XML.name());
XmlBody xml = new XmlBody();
//xml.setValue(XMLUtils.jsonToXmlStr(jsonValue));
body.setXmlBody(xml);
}
case MediaType.MULTIPART_FORM_DATA_VALUE -> {
if (StringUtils.isBlank(body.getBodyType())) {
body.setBodyType(Body.BodyType.FORM_DATA.name());
}
body.setBodyType(Body.BodyType.FORM_DATA.name());
}
case MediaType.APPLICATION_OCTET_STREAM_VALUE -> {
if (StringUtils.isBlank(body.getBodyType())) {
body.setBodyType(Body.BodyType.BINARY.name());
}
body.setBodyType(Body.BodyType.BINARY.name());
}
case MediaType.TEXT_PLAIN_VALUE -> {
if (StringUtils.isBlank(body.getBodyType())) {
body.setBodyType(Body.BodyType.RAW.name());
}
body.setBodyType(Body.BodyType.RAW.name());
RawBody rawBody = new RawBody();
body.setRawBody(rawBody);
}
@ -319,53 +302,46 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
}
}
private JsonBody getJsonBody(io.swagger.v3.oas.models.media.MediaType value, JsonSchemaItem jsonSchemaItem) {
JsonBody jsonBody = new JsonBody();
jsonBody.setJsonSchema(jsonSchemaItem);
if (ObjectUtils.isNotEmpty(value.getExample())) {
jsonBody.setJsonValue(JSON.toJSONString(value.getExample()));
} else {
String jsonString = JSON.toJSONString(jsonSchemaItem);
if (StringUtils.isNotBlank(jsonString)) {
jsonBody.setJsonValue(JsonSchemaBuilder.jsonSchemaToJson(jsonString));
}
}
return jsonBody;
}
private void setRequestBodyData(String k, io.swagger.v3.oas.models.media.MediaType value, Body body) {
//TODO body 默认如果json格式
JsonSchemaItem jsonSchemaItem = parseSchema(value.getSchema());
switch (k) {
case MediaType.APPLICATION_JSON_VALUE, MediaType.ALL_VALUE -> {
body.setBodyType(Body.BodyType.JSON.name());
JsonBody jsonBody = new JsonBody();
jsonBody.setJsonSchema(jsonSchemaItem);
jsonBody.setEnableJsonSchema(false);
if (ObjectUtils.isNotEmpty(value.getExample())) {
jsonBody.setJsonValue(ApiDataUtils.toJSONString(value.getExample()));
}
String jsonString = JSON.toJSONString(jsonSchemaItem);
if (StringUtils.isNotBlank(jsonString)) {
jsonBody.setJsonValue(JsonSchemaBuilder.jsonSchemaToJson(jsonString));
}
body.setJsonBody(jsonBody);
body.setJsonBody(getJsonBody(value, jsonSchemaItem));
}
case MediaType.APPLICATION_XML_VALUE -> {
if (StringUtils.isBlank(body.getBodyType())) {
body.setBodyType(Body.BodyType.XML.name());
}
body.setBodyType(Body.BodyType.XML.name());
XmlBody xml = new XmlBody();
//xml.setValue(XMLUtils.jsonToXmlStr(jsonValue));
body.setXmlBody(xml);
}
case MediaType.APPLICATION_FORM_URLENCODED_VALUE -> {
if (StringUtils.isBlank(body.getBodyType())) {
body.setBodyType(Body.BodyType.WWW_FORM.name());
}
body.setBodyType(Body.BodyType.WWW_FORM.name());
parseWWWFormBody(jsonSchemaItem, body);
}
case MediaType.MULTIPART_FORM_DATA_VALUE -> {
if (StringUtils.isBlank(body.getBodyType())) {
body.setBodyType(Body.BodyType.FORM_DATA.name());
}
body.setBodyType(Body.BodyType.FORM_DATA.name());
parseFormBody(jsonSchemaItem, body);
}
case MediaType.APPLICATION_OCTET_STREAM_VALUE -> {
if (StringUtils.isBlank(body.getBodyType())) {
body.setBodyType(Body.BodyType.BINARY.name());
}
body.setBodyType(Body.BodyType.BINARY.name());
}
case MediaType.TEXT_PLAIN_VALUE -> {
if (StringUtils.isBlank(body.getBodyType())) {
body.setBodyType(Body.BodyType.RAW.name());
}
body.setBodyType(Body.BodyType.RAW.name());
RawBody rawBody = new RawBody();
body.setRawBody(rawBody);
}
@ -523,7 +499,7 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
if (modelByRef != null) {
return switch (modelByRef) {
case ArraySchema arraySchema -> parseArraySchema(arraySchema.getItems(), false);
case ArraySchema arraySchema -> parseArraySchema(arraySchema, false);
case ObjectSchema objectSchema -> parseObject(objectSchema, false);
default -> {
JsonSchemaItem jsonSchemaItem = new JsonSchemaItem();
@ -559,7 +535,7 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
case StringSchema stringSchema -> item = parseString(stringSchema);
case NumberSchema numberSchema -> item = parseNumber(numberSchema);
case BooleanSchema booleanSchema -> item = parseBoolean(booleanSchema);
case ArraySchema arraySchema -> item = parseArraySchema(arraySchema.getItems(), false);
case ArraySchema arraySchema -> item = parseArraySchema(arraySchema, false);
case ObjectSchema objectSchemaItem -> item = parseObject(objectSchemaItem, false);
default -> {
}
@ -604,8 +580,8 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
arrayItem.setItems(new JsonSchemaItem());
yield arrayItem;
}
yield isRef(arraySchema.getItems(), 0) ? parseArraySchema(arraySchema.getItems(), true) :
parseArraySchema(arraySchema.getItems(), false);
yield isRef(arraySchema.getItems(), 0) ? parseArraySchema(arraySchema, true) :
parseArraySchema(arraySchema, false);
}
case ObjectSchema objectSchema -> {
if (onlyOnce) {
@ -720,7 +696,8 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
return jsonSchemaNull;
}
private JsonSchemaItem parseArraySchema(Schema<?> items, boolean onlyOnce) {
private JsonSchemaItem parseArraySchema(ArraySchema arraySchema, boolean onlyOnce) {
Schema<?> items = arraySchema.getItems();
JsonSchemaItem jsonSchemaArray = new JsonSchemaItem();
jsonSchemaArray.setType(PropertyConstant.ARRAY);
jsonSchemaArray.setId(IDGenerator.nextStr());
@ -736,7 +713,8 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
JsonSchemaItem itemsJsonSchema = parseProperty(itemsSchema, onlyOnce);
jsonSchemaArray.setItems(itemsJsonSchema);
jsonSchemaArray.setMaxItems(arraySchema.getMaxItems());
jsonSchemaArray.setMinItems(arraySchema.getMinItems());
return jsonSchemaArray;
}

View File

@ -1,13 +1,11 @@
package io.metersphere.api.parser.jmeter.body;
import io.metersphere.api.dto.request.http.body.JsonBody;
import io.metersphere.api.utils.JsonSchemaBuilder;
import io.metersphere.jmeter.mock.Mock;
import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.sdk.util.JSON;
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;
@ -24,13 +22,7 @@ public class MsJsonBodyConverter extends MsBodyConverter<JsonBody> {
public String parse(HTTPSamplerProxy sampler, JsonBody body, ParameterConfig config) {
sampler.setPostBodyRaw(true);
try {
String raw;
if (body.getEnableJsonSchema()) {
String jsonString = JsonSchemaBuilder.jsonSchemaToJson(JSON.toJSONString(body.getJsonSchema()));
raw = StringEscapeUtils.unescapeJava(jsonString);
} else {
raw = parseJsonMock(body.getJsonValue());
}
String raw = parseJsonMock(body.getJsonValue());
handleRowBody(sampler, raw);
} catch (Exception e) {
LogUtils.error("json mock value is abnormal", e);

View File

@ -231,7 +231,7 @@ public class MockServerService {
boolean isMock = config != null;
String resourceId = config != null ? config.getId() : apiId;
return switch (responseBody.getBodyType()) {
case "JSON" -> responseEntity(responseCode, responseBody.getJsonBody().getJsonWithSchema(), headers);
case "JSON" -> responseEntity(responseCode, responseBody.getJsonBody().getJsonValue(), headers);
case "XML" -> responseEntity(responseCode, responseBody.getXmlBody().getValue(), headers);
case "RAW" -> responseEntity(responseCode, responseBody.getRawBody().getValue(), headers);
case "BINARY" -> handleBinaryBody(responseCode, responseBody, projectId, resourceId, isMock);

View File

@ -1601,9 +1601,9 @@ public class ApiDefinitionControllerTests extends BaseTest {
paramMap.add("request", JSON.toJSONString(request));
this.requestMultipartWithOkAndReturn(IMPORT, paramMap);
paramMap.clear();
inputStream = new FileInputStream(new File(
inputStream = new FileInputStream(
this.getClass().getClassLoader().getResource("file/openapi2.json")
.getPath()));
.getPath());
file = new MockMultipartFile("file", "openapi2.json", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
paramMap.add("file", file);
request.setCoverModule(false);
@ -1612,9 +1612,9 @@ public class ApiDefinitionControllerTests extends BaseTest {
this.requestMultipart(IMPORT, paramMap, status().is5xxServerError());
paramMap.clear();
inputStream = new FileInputStream(new File(
inputStream = new FileInputStream(
this.getClass().getClassLoader().getResource("file/openapi3.json")
.getPath()));
.getPath());
file = new MockMultipartFile("file", "openapi3.json", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
paramMap.add("file", file);
request.setCoverModule(false);
@ -1622,9 +1622,9 @@ public class ApiDefinitionControllerTests extends BaseTest {
paramMap.add("request", JSON.toJSONString(request));
this.requestMultipartWithOkAndReturn(IMPORT, paramMap);
paramMap.clear();
inputStream = new FileInputStream(new File(
inputStream = new FileInputStream(
this.getClass().getClassLoader().getResource("file/openapi4.json")
.getPath()));
.getPath());
file = new MockMultipartFile("file", "openapi4.json", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
paramMap.add("file", file);
request.setCoverModule(false);
@ -1644,9 +1644,9 @@ public class ApiDefinitionControllerTests extends BaseTest {
request.setCoverModule(true);
request.setCoverData(true);
paramMap.clear();
inputStream = new FileInputStream(new File(
inputStream = new FileInputStream(
Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/postman.json"))
.getPath()));
.getPath());
file = new MockMultipartFile("file", "postman.json", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
paramMap.add("file", file);
paramMap.add("request", JSON.toJSONString(request));
@ -1654,9 +1654,9 @@ public class ApiDefinitionControllerTests extends BaseTest {
paramMap.clear();
request.setCoverModule(true);
request.setCoverData(true);
inputStream = new FileInputStream(new File(
inputStream = new FileInputStream(
Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/postman2.json"))
.getPath()));
.getPath());
file = new MockMultipartFile("file", "postman2.json", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
paramMap.add("file", file);
paramMap.add("request", JSON.toJSONString(request));

View File

@ -86,7 +86,6 @@ public class MsHTTPElementTest {
JsonSchemaItem jsonSchemaItem = new JsonSchemaItem();
jsonSchemaItem.setId("11");
jsonBody.setJsonSchema(jsonSchemaItem);
jsonBody.setEnableJsonSchema(false);
body.setJsonBody(jsonBody);
body.setNoneBody(new NoneBody());