feat(接口测试): 代码调整
This commit is contained in:
parent
b86fbafa00
commit
fa23fcdfcd
|
@ -0,0 +1,125 @@
|
||||||
|
package io.metersphere.api.parse;
|
||||||
|
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.commons.utils.ScriptEngineUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
public class JmxDocumentParser {
|
||||||
|
private final static String HASH_TREE_ELEMENT = "hashTree";
|
||||||
|
private final static String STRING_PROP = "stringProp";
|
||||||
|
|
||||||
|
public static byte[] parse(byte[] source) {
|
||||||
|
final InputSource inputSource = new InputSource(new ByteArrayInputStream(source));
|
||||||
|
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
try {
|
||||||
|
|
||||||
|
DocumentBuilder docBuilder = factory.newDocumentBuilder();
|
||||||
|
final Document document = docBuilder.parse(inputSource);
|
||||||
|
final Element jmeterTestPlan = document.getDocumentElement();
|
||||||
|
|
||||||
|
NodeList childNodes = jmeterTestPlan.getChildNodes();
|
||||||
|
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||||
|
Node node = childNodes.item(i);
|
||||||
|
if (node instanceof Element) {
|
||||||
|
Element ele = (Element) node;
|
||||||
|
parseHashTree(ele);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return documentToBytes(document);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] documentToBytes(Document document) throws TransformerException {
|
||||||
|
DOMSource domSource = new DOMSource(document);
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
StreamResult result = new StreamResult(writer);
|
||||||
|
TransformerFactory tf = TransformerFactory.newInstance();
|
||||||
|
Transformer transformer = tf.newTransformer();
|
||||||
|
transformer.transform(domSource, result);
|
||||||
|
return writer.toString().getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseHashTree(Element hashTree) {
|
||||||
|
if (invalid(hashTree)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hashTree.getChildNodes().getLength() > 0) {
|
||||||
|
final NodeList childNodes = hashTree.getChildNodes();
|
||||||
|
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||||
|
Node node = childNodes.item(i);
|
||||||
|
if (node instanceof Element) {
|
||||||
|
Element ele = (Element) node;
|
||||||
|
if (invalid(ele)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodeNameEquals(ele, HASH_TREE_ELEMENT)) {
|
||||||
|
parseHashTree(ele);
|
||||||
|
} else {
|
||||||
|
if (nodeNameEquals(ele, STRING_PROP)) {
|
||||||
|
processStringProp(ele);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void processStringProp(Element ele) {
|
||||||
|
String name = ele.getAttribute("name");
|
||||||
|
NodeList childNodes;
|
||||||
|
switch (name) {
|
||||||
|
case "HTTPSampler.path":
|
||||||
|
childNodes = ele.getChildNodes();
|
||||||
|
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||||
|
Node node = childNodes.item(i);
|
||||||
|
if (node instanceof Element) {
|
||||||
|
String nodeValue = node.getNodeValue();
|
||||||
|
System.out.println(nodeValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Argument.value":
|
||||||
|
childNodes = ele.getChildNodes();
|
||||||
|
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||||
|
Node node = childNodes.item(i);
|
||||||
|
if (node instanceof Element) {
|
||||||
|
String nodeValue = node.getNodeValue();
|
||||||
|
node.setNodeValue(ScriptEngineUtils.calculate(nodeValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean nodeNameEquals(Node node, String desiredName) {
|
||||||
|
return desiredName.equals(node.getNodeName()) || desiredName.equals(node.getLocalName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean invalid(Element ele) {
|
||||||
|
return !StringUtils.isBlank(ele.getAttribute("enabled")) && !Boolean.parseBoolean(ele.getAttribute("enabled"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,11 +8,15 @@ import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
|
||||||
import io.metersphere.api.jmeter.JMeterService;
|
import io.metersphere.api.jmeter.JMeterService;
|
||||||
import io.metersphere.api.parse.ApiImportParser;
|
import io.metersphere.api.parse.ApiImportParser;
|
||||||
import io.metersphere.api.parse.ApiImportParserFactory;
|
import io.metersphere.api.parse.ApiImportParserFactory;
|
||||||
|
import io.metersphere.api.parse.JmxDocumentParser;
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.base.mapper.ApiTestFileMapper;
|
import io.metersphere.base.mapper.ApiTestFileMapper;
|
||||||
import io.metersphere.base.mapper.ApiTestMapper;
|
import io.metersphere.base.mapper.ApiTestMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtApiTestMapper;
|
import io.metersphere.base.mapper.ext.ExtApiTestMapper;
|
||||||
import io.metersphere.commons.constants.*;
|
import io.metersphere.commons.constants.APITestStatus;
|
||||||
|
import io.metersphere.commons.constants.FileType;
|
||||||
|
import io.metersphere.commons.constants.ScheduleGroup;
|
||||||
|
import io.metersphere.commons.constants.ScheduleType;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.BeanUtils;
|
import io.metersphere.commons.utils.BeanUtils;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
@ -145,6 +149,8 @@ public class APITestService {
|
||||||
MSException.throwException(Translator.get("file_cannot_be_null"));
|
MSException.throwException(Translator.get("file_cannot_be_null"));
|
||||||
}
|
}
|
||||||
byte[] bytes = fileService.loadFileAsBytes(file.getFileId());
|
byte[] bytes = fileService.loadFileAsBytes(file.getFileId());
|
||||||
|
// 解析 xml 处理 mock 数据
|
||||||
|
bytes = JmxDocumentParser.parse(bytes);
|
||||||
InputStream is = new ByteArrayInputStream(bytes);
|
InputStream is = new ByteArrayInputStream(bytes);
|
||||||
|
|
||||||
APITestResult apiTest = get(request.getId());
|
APITestResult apiTest = get(request.getId());
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package io.metersphere.commons.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import javax.script.ScriptEngine;
|
||||||
|
import javax.script.ScriptEngineManager;
|
||||||
|
import javax.script.ScriptException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class ScriptEngineUtils {
|
||||||
|
private static final String ENGINE_NAME = "graal.js";
|
||||||
|
private static ScriptEngine engine;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final ScriptEngineManager engineManager = new ScriptEngineManager();
|
||||||
|
engine = engineManager.getEngineByName(ENGINE_NAME);
|
||||||
|
try {
|
||||||
|
String script = IOUtils.toString(ScriptEngineUtils.class.getResource("/javascript/func.js"), StandardCharsets.UTF_8);
|
||||||
|
engine.eval(script);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String calculate(String input) {
|
||||||
|
try {
|
||||||
|
return engine.eval(input).toString();
|
||||||
|
} catch (ScriptException e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
|
import io.metersphere.commons.utils.ScriptEngineUtils;
|
||||||
import io.metersphere.config.KafkaProperties;
|
import io.metersphere.config.KafkaProperties;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.performance.engine.EngineContext;
|
import io.metersphere.performance.engine.EngineContext;
|
||||||
|
@ -377,7 +378,9 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
elementProp.setAttribute("name", jsonObject.getString("name"));
|
elementProp.setAttribute("name", jsonObject.getString("name"));
|
||||||
elementProp.setAttribute("elementType", "Argument");
|
elementProp.setAttribute("elementType", "Argument");
|
||||||
elementProp.appendChild(createStringProp(document, "Argument.name", jsonObject.getString("name")));
|
elementProp.appendChild(createStringProp(document, "Argument.name", jsonObject.getString("name")));
|
||||||
elementProp.appendChild(createStringProp(document, "Argument.value", jsonObject.getString("value")));
|
// 处理 mock data
|
||||||
|
String value = jsonObject.getString("value");
|
||||||
|
elementProp.appendChild(createStringProp(document, "Argument.value", ScriptEngineUtils.calculate(value)));
|
||||||
elementProp.appendChild(createStringProp(document, "Argument.metadata", "="));
|
elementProp.appendChild(createStringProp(document, "Argument.metadata", "="));
|
||||||
item.appendChild(elementProp);
|
item.appendChild(elementProp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,13 @@
|
||||||
|
|
||||||
<ms-dropdown :default-command="body.format" v-if="body.type == 'Raw'" :commands="modes" @command="modeChange"/>
|
<ms-dropdown :default-command="body.format" v-if="body.type == 'Raw'" :commands="modes" @command="modeChange"/>
|
||||||
|
|
||||||
<ms-api-variable :is-read-only="isReadOnly" :items="body.kvs" v-if="body.isKV()"/>
|
<ms-api-variable :is-read-only="isReadOnly"
|
||||||
|
:parameters="body.kvs"
|
||||||
|
:environment="environment"
|
||||||
|
:scenario="scenario"
|
||||||
|
:extract="extract"
|
||||||
|
:description="$t('api_test.request.parameters_desc')"
|
||||||
|
v-if="body.isKV()"/>
|
||||||
<div class="body-raw" v-if="body.type == 'Raw'">
|
<div class="body-raw" v-if="body.type == 'Raw'">
|
||||||
<ms-code-edit :mode="body.format" :read-only="isReadOnly" :data.sync="body.raw" :modes="modes" ref="codeEdit"/>
|
<ms-code-edit :mode="body.format" :read-only="isReadOnly" :data.sync="body.raw" :modes="modes" ref="codeEdit"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +27,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsApiKeyValue from "./ApiKeyValue";
|
import MsApiKeyValue from "./ApiKeyValue";
|
||||||
import {Body, BODY_FORMAT, BODY_TYPE} from "../model/ScenarioModel";
|
import {Body, BODY_FORMAT, BODY_TYPE, Scenario} from "../model/ScenarioModel";
|
||||||
import MsCodeEdit from "../../../common/components/MsCodeEdit";
|
import MsCodeEdit from "../../../common/components/MsCodeEdit";
|
||||||
import MsDropdown from "../../../common/components/MsDropdown";
|
import MsDropdown from "../../../common/components/MsDropdown";
|
||||||
import MsApiVariable from "@/business/components/api/test/components/ApiVariable";
|
import MsApiVariable from "@/business/components/api/test/components/ApiVariable";
|
||||||
|
@ -32,6 +37,9 @@ export default {
|
||||||
components: {MsApiVariable, MsDropdown, MsCodeEdit, MsApiKeyValue},
|
components: {MsApiVariable, MsDropdown, MsCodeEdit, MsApiKeyValue},
|
||||||
props: {
|
props: {
|
||||||
body: Body,
|
body: Body,
|
||||||
|
scenario: Scenario,
|
||||||
|
environment: Object,
|
||||||
|
extract: Object,
|
||||||
isReadOnly: {
|
isReadOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
|
|
@ -34,13 +34,14 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
<ms-api-variable-advance ref="variableAdvance" :environment="environment" :scenario="scenario" :request="request"
|
<ms-api-variable-advance ref="variableAdvance" :environment="environment" :scenario="scenario"
|
||||||
|
:parameters="parameters"
|
||||||
:current-item="currentItem"/>
|
:current-item="currentItem"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {HttpRequest, KeyValue, Scenario} from "../model/ScenarioModel";
|
import {KeyValue, Scenario} from "../model/ScenarioModel";
|
||||||
import {MOCKJS_FUNC} from "@/common/js/constants";
|
import {MOCKJS_FUNC} from "@/common/js/constants";
|
||||||
import MsApiVariableAdvance from "@/business/components/api/test/components/ApiVariableAdvance";
|
import MsApiVariableAdvance from "@/business/components/api/test/components/ApiVariableAdvance";
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ export default {
|
||||||
keyPlaceholder: String,
|
keyPlaceholder: String,
|
||||||
valuePlaceholder: String,
|
valuePlaceholder: String,
|
||||||
description: String,
|
description: String,
|
||||||
request: HttpRequest,
|
parameters: Array,
|
||||||
environment: Object,
|
environment: Object,
|
||||||
scenario: Scenario,
|
scenario: Scenario,
|
||||||
isReadOnly: {
|
isReadOnly: {
|
||||||
|
@ -63,7 +64,6 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentItem: null,
|
currentItem: null,
|
||||||
parameters: [],
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -90,13 +90,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {calculate, HttpRequest, Scenario} from "@/business/components/api/test/model/ScenarioModel";
|
import {calculate, Scenario} from "@/business/components/api/test/model/ScenarioModel";
|
||||||
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiVariableAdvance",
|
name: "MsApiVariableAdvance",
|
||||||
props: {
|
props: {
|
||||||
request: HttpRequest,
|
parameters: Array,
|
||||||
environment: Object,
|
environment: Object,
|
||||||
scenario: Scenario,
|
scenario: Scenario,
|
||||||
currentItem: Object,
|
currentItem: Object,
|
||||||
|
@ -162,9 +162,6 @@ export default {
|
||||||
this.itemValueVisible = true;
|
this.itemValueVisible = true;
|
||||||
},
|
},
|
||||||
prepareData() {
|
prepareData() {
|
||||||
if (this.request) {
|
|
||||||
this.parameters = this.request.parameters;
|
|
||||||
}
|
|
||||||
if (this.scenario) {
|
if (this.scenario) {
|
||||||
let variables = this.scenario.variables;
|
let variables = this.scenario.variables;
|
||||||
this.scenarioParams = [
|
this.scenarioParams = [
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
<el-tabs v-model="activeName">
|
<el-tabs v-model="activeName">
|
||||||
<el-tab-pane :label="$t('api_test.request.parameters')" name="parameters">
|
<el-tab-pane :label="$t('api_test.request.parameters')" name="parameters">
|
||||||
<ms-api-variable :is-read-only="isReadOnly"
|
<ms-api-variable :is-read-only="isReadOnly"
|
||||||
:request="request"
|
:parameters="request.parameters"
|
||||||
:environment="request.environment"
|
:environment="request.environment"
|
||||||
:scenario="scenario"
|
:scenario="scenario"
|
||||||
:extract="request.extract"
|
:extract="request.extract"
|
||||||
|
@ -56,7 +56,11 @@
|
||||||
<ms-api-key-value :is-read-only="isReadOnly" :suggestions="headerSuggestions" :items="request.headers"/>
|
<ms-api-key-value :is-read-only="isReadOnly" :suggestions="headerSuggestions" :items="request.headers"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.request.body')" name="body" v-if="isNotGet">
|
<el-tab-pane :label="$t('api_test.request.body')" name="body" v-if="isNotGet">
|
||||||
<ms-api-body :is-read-only="isReadOnly" :body="request.body"/>
|
<ms-api-body :is-read-only="isReadOnly"
|
||||||
|
:body="request.body"
|
||||||
|
:scenario="scenario"
|
||||||
|
:extract="request.extract"
|
||||||
|
:environment="request.environment"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
|
<el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
|
||||||
<ms-api-assertions :is-read-only="isReadOnly" :assertions="request.assertions"/>
|
<ms-api-assertions :is-read-only="isReadOnly" :assertions="request.assertions"/>
|
||||||
|
|
|
@ -722,8 +722,6 @@ class JMXHttpRequest {
|
||||||
});
|
});
|
||||||
for (let i = 0; i < parameters.length; i++) {
|
for (let i = 0; i < parameters.length; i++) {
|
||||||
let parameter = parameters[i];
|
let parameter = parameters[i];
|
||||||
// 非 GET 请求中出现了 url 参数
|
|
||||||
parameter.value = calculate(parameter.value);
|
|
||||||
path += (parameter.name + '=' + parameter.value);
|
path += (parameter.name + '=' + parameter.value);
|
||||||
if (i !== parameters.length - 1) {
|
if (i !== parameters.length - 1) {
|
||||||
path += '&';
|
path += '&';
|
||||||
|
@ -921,9 +919,6 @@ class JMXGenerator {
|
||||||
|
|
||||||
addRequestArguments(httpSamplerProxy, request) {
|
addRequestArguments(httpSamplerProxy, request) {
|
||||||
let args = this.filterKV(request.parameters);
|
let args = this.filterKV(request.parameters);
|
||||||
args.forEach(arg => {
|
|
||||||
arg.value = calculate(arg.value);
|
|
||||||
});
|
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
httpSamplerProxy.add(new HTTPSamplerArguments(args));
|
httpSamplerProxy.add(new HTTPSamplerArguments(args));
|
||||||
}
|
}
|
||||||
|
@ -933,9 +928,6 @@ class JMXGenerator {
|
||||||
let body = [];
|
let body = [];
|
||||||
if (request.body.isKV()) {
|
if (request.body.isKV()) {
|
||||||
body = this.filterKV(request.body.kvs);
|
body = this.filterKV(request.body.kvs);
|
||||||
body.forEach(arg => {
|
|
||||||
arg.value = calculate(arg.value);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
httpSamplerProxy.boolProp('HTTPSampler.postBodyRaw', true);
|
httpSamplerProxy.boolProp('HTTPSampler.postBodyRaw', true);
|
||||||
body.push({name: '', value: request.body.raw, encode: false});
|
body.push({name: '', value: request.body.raw, encode: false});
|
||||||
|
|
Loading…
Reference in New Issue