Commit 31146c0b authored by xie.qin's avatar xie.qin

temp commit.

parent 1d5801ea
......@@ -77,9 +77,12 @@ N/A
##### 优点
- 测试数据支持动态修改,无需重启服务。
- 返回结果支持参数化,即可以根据请求路径中的参数,动态替换返回结果中对应的参数的值。
- 自动适配客户端http请求模式(HTTP1.X/HTTP2)并响应
- 适配客户端http/https请求模式并响应;HTTP协议支持HTTP1.X和HTTP2, HTTP2同时支持h2和h2c
- 如何在本机生成证书?使用命令: keytool -genkey -alias netty-reactor -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
- 相关参数应根据在application.properties内的定义进行修改
- 相关参数应根据在application.properties内的定义进行修改
- curl命令验证例子: curl -H "Content-Type:application/json" -X POST -d '{"user_id": "123", "coin":100, "success":1, "msg":"OK!" }' -v --http2-prior-knowledge http://172.22.17.74:8080/userservice/fedFromOrg/87654321
......@@ -34,6 +34,9 @@ dependencies {
implementation 'io.rest-assured:xml-path:4.4.0'
implementation 'io.rest-assured:json-schema-validator:4.4.0'
implementation 'io.qameta.allure:allure-rest-assured:2.14.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'io.qameta.allure:allure-okhttp3:2.14.0'
compileOnly 'org.projectlombok:lombok:1.18.20'
testCompileOnly 'org.projectlombok:lombok:1.18.20'
runtimeOnly 'mysql:mysql-connector-java'
......
package com.fuzamei.autotest.openapi;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class H2RestMessageEntity {
private MediaType contentType;
private String method;
private Boolean isHttps;
private String path;
private RequestBody requestBody;
private Integer statusCode;
private ResponseBody responseBody;
}
package com.fuzamei.autotest.openapi;
import org.springframework.context.ApplicationEvent;
public class H2RestMessageEvent extends ApplicationEvent {
private H2RestMessageEntity restfulMsg;
public H2RestMessageEvent(Object source) {
super(source);
}
public H2RestMessageEntity getMsg() {
return restfulMsg;
}
public void setMsg(H2RestMessageEntity restfulMsg) {
this.restfulMsg = restfulMsg;
}
}
package com.fuzamei.autotest.openapi;
import com.fuzamei.autotest.properties.GlobalProperties;
import io.restassured.http.Header;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Headers;
import okhttp3.Request;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.Iterator;
@Component
@Slf4j
public class H2RestMessageEventListener {
@Autowired
GlobalProperties globalProperties;
@EventListener
public void processRestfulMessageEvent(H2RestMessageEvent h2RestMessageEvent){
H2RestMessageEntity h2RestMessageEntity = h2RestMessageEvent.getMsg();
log.debug("subscriber received a http2 message and the message content is {}. ", h2RestMessageEntity.toString());
processRestMsgEventWithHttp2(h2RestMessageEntity);
}
private void processRestMsgEventWithHttp2(H2RestMessageEntity h2RestMessageEntity) {
final String tmpTarget = h2RestMessageEntity.getMethod() + " " + h2RestMessageEntity.getPath();
Request request = null;
try {
switch (h2RestMessageEntity.getMethod()){
case "get":
request = new Request.Builder()
.url(h2RestMessageEntity.getPath())
.header("User-ID", globalProperties.getDftuserid().toString())
.header("User-Name", globalProperties.getDftusername())
.get()
.build();
break;
case "post":
request = new Request.Builder()
.url(h2RestMessageEntity.getPath())
.header("User-ID", globalProperties.getDftuserid().toString())
.header("User-Name", globalProperties.getDftusername())
.post(h2RestMessageEntity.getRequestBody())
.build();
break;
case "put":
request = new Request.Builder()
.url(h2RestMessageEntity.getPath())
.header("User-ID", globalProperties.getDftuserid().toString())
.header("User-Name", globalProperties.getDftusername())
.put(h2RestMessageEntity.getRequestBody())
.build();
break;
default:
break;
}
}
catch (Exception ex){
log.error("HTTP2 REST message [{}] send failed as error: {}", tmpTarget, ex);
throwExceptionInFeatureTest(restfulMessageEntity, ex.toString());
return;
}
}
}
package com.fuzamei.autotest.openapi;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fuzamei.autotest.properties.GlobalProperties;
import io.restassured.http.Method;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class H2RestMessageProducer {
@Resource
private ApplicationContext applicationContext;
public void produceRestMessageWithModeH2(MediaType mediaType, RestfulMessageEntity restfulMessageEntity) {
String path = restfulMessageEntity.getPath();
Boolean isHttps = false;
if (path.contains("https:")){
isHttps = true;
}
RequestBody requestBody = null;
if (restfulMessageEntity.getReqJsonBody() != null) {
String strReqJsonBody = restfulMessageEntity.getReqJsonBody().toString();
requestBody = RequestBody.create(strReqJsonBody, mediaType);
}
else if (restfulMessageEntity.getReqJsonArrayBody() != null) {
String strReqJsonArrBody = restfulMessageEntity.getReqJsonArrayBody().toString();
requestBody = RequestBody.create(strReqJsonArrBody, mediaType);
}
else if (restfulMessageEntity.getMapperReqJsonBody() != null) {
String strReqMapperBody = restfulMessageEntity.getMapperReqJsonBody().toString();
requestBody = RequestBody.create(strReqMapperBody, mediaType);
}
ResponseBody responseBody = null;
MediaType responseMediaType = MediaType.get("application/json; charset=utf-8");
if (restfulMessageEntity.getRespJsonBody() != null) {
String strRespJsonBody = restfulMessageEntity.getRespJsonBody().toString();
responseBody = ResponseBody.create(strRespJsonBody, responseMediaType);
}
else if (restfulMessageEntity.getRespJsonArrayBody() != null) {
String strRespJsonArrBody = restfulMessageEntity.getRespJsonArrayBody().toString();
responseBody = ResponseBody.create(strRespJsonArrBody, responseMediaType);
}
else if (restfulMessageEntity.getMapperRespJsonBody() != null) {
String strRespMapperBody = restfulMessageEntity.getMapperRespJsonBody().toString();
responseBody = ResponseBody.create(strRespMapperBody, responseMediaType);
}
H2RestMessageEntity h2RestMessageEntity = H2RestMessageEntity.builder()
.contentType(mediaType)
.method(restfulMessageEntity.getMethod().name().toLowerCase())
.path(path)
.isHttps(isHttps)
.requestBody(requestBody)
.responseBody(responseBody)
.build();
H2RestMessageEvent h2RestMessageEvent = new H2RestMessageEvent(this);
h2RestMessageEvent.setMsg(h2RestMessageEntity);
applicationContext.publishEvent(h2RestMessageEvent);
}
}
......@@ -12,6 +12,7 @@ import io.restassured.http.Header;
import io.restassured.http.Headers;
import io.restassured.http.Method;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
......@@ -76,15 +77,7 @@ public class OpenApiParser {
public void handleEachHttpMethodInOpenApiFile(String URL, Method httpMethod, JsonNode methodNode, JsonNode definitionNode, String serviceName) {
String path = "";
//parse field consumes
ContentType contentType = ContentType.JSON;
if (methodNode.has("consumes")) {
ArrayNode consumesArrayNode = (ArrayNode) methodNode.get("consumes");
for (JsonNode node : consumesArrayNode){
contentType = translateStringToContentType(node.asText());
break;
}
}
Boolean h2Enabled = false;
//get whole path
switch (serviceName.toLowerCase()){
case "backend":
......@@ -103,8 +96,30 @@ public class OpenApiParser {
path.replaceAll("\\{.*?\\}", globalProperties.getInt32max().toString()); //replaced by 9223372036854775807 ??
}
log.info("now we're handling REST request: '{} {}'", httpMethod.name(), path);
if (backendServiceProperties.getHttp2()){
h2Enabled = true;
}
break;
}
//parse field consumes
ContentType contentType = ContentType.JSON;
if (methodNode.has("consumes")) {
ArrayNode consumesArrayNode = (ArrayNode) methodNode.get("consumes");
for (JsonNode node : consumesArrayNode){
contentType = translateStringToContentType(node.asText());
break;
}
}
//preprocess for okhttp/http2
MediaType mediaType = MediaType.get("application/json; charset=utf-8");
if (methodNode.has("consumes")) {
ArrayNode consumesArrayNode = (ArrayNode) methodNode.get("consumes");
String combinedMediaType = "";
for (JsonNode node : consumesArrayNode) {
combinedMediaType += node.asText() + ";";
}
mediaType = MediaType.get(combinedMediaType);
}
//specify headers. only two conditions: with User-ID, User-Name or without User-ID, User-Name
Header userID = new Header("User-ID", globalProperties.getDftuserid().toString());
Header userName = new Header("User-Name", globalProperties.getDftusername());
......@@ -114,11 +129,7 @@ public class OpenApiParser {
ArrayNode parametersArrayNode = null;
Map<String, Object> reqJsonBody = new HashMap<String, Object>();
List<Object> reqJsonArrayBody = new ArrayList<>();
/*if(contentType.compareTo(ContentType.JSON) == 0) {
}
else {
//handle contentType = multipart/form-data
}*/
if (methodNode.has("parameters")) {
parametersArrayNode = (ArrayNode) methodNode.get("parameters");
for (JsonNode paraNode : parametersArrayNode){
......@@ -548,6 +559,12 @@ public class OpenApiParser {
}
}
if (h2Enabled){
H2RestMessageProducer h2RestMessageProducer = new H2RestMessageProducer();
h2RestMessageProducer.produceRestMessageWithModeH2(mediaType, restfulMsgWithHeaders);
return;
}
//publish message and wait subscriber(e.g. rest-assure) to send out request
RestfulMessageEvent restfulMessageEvent = new RestfulMessageEvent(this);
restfulMessageEvent.setMsg(restfulMsgWithHeaders);
......@@ -889,4 +906,5 @@ public class OpenApiParser {
return null;
}
}
}
......@@ -2,8 +2,6 @@ package com.fuzamei.autotest.openapi;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fuzamei.autotest.properties.BackendServiceProperties;
import com.fuzamei.autotest.properties.GlobalProperties;
import com.fuzamei.autotest.properties.SpecificProperties;
import io.qameta.allure.restassured.AllureRestAssured;
import io.restassured.RestAssured;
......@@ -17,7 +15,7 @@ import io.restassured.path.json.exception.JsonPathException;
import io.restassured.response.Response;
import io.restassured.specification.MultiPartSpecification;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.aop.AspectException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -41,24 +39,11 @@ public class RestfulMessageEventListener {
@Autowired
SpecificProperties specificProperties;
@Autowired
BackendServiceProperties backendServiceProperties;
@Autowired
GlobalProperties globalProperties;
@EventListener
public void processRestfulMessageEvent(RestfulMessageEvent restfulMessageEvent){
RestfulMessageEntity restfulMessageEntity = restfulMessageEvent.getMsg();
log.debug("subscriber received a message and the message content is {}. ", restfulMessageEntity.toString());
if (!backendServiceProperties.getHttp2()){
processRestMsgEventWithHttp1x(restfulMessageEntity);
}
else{
processRestMsgEventWithHttp2(restfulMessageEntity);
}
processRestMsgEventWithHttp1x(restfulMessageEntity);
}
private void processRestMsgEventWithHttp1x(RestfulMessageEntity restfulMessageEntity) {
......@@ -88,6 +73,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.multiPart(multiPartSpecBuilder)
//.body(restfulMessageEntity.getReqJsonBody())
......@@ -104,6 +90,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.body(restfulMessageEntity.getReqJsonBody())
.when()
......@@ -121,6 +108,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.body(restfulMessageEntity.getMapperReqJsonBody(), ObjectMapperType.JACKSON_2)
.when()
......@@ -137,6 +125,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.body(restfulMessageEntity.getReqJsonArrayBody())
.when()
......@@ -153,6 +142,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.when()
//.contentType(restfulMessageEntity.getContentType())
......@@ -183,6 +173,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.multiPart(multiPartSpecBuilder)
//.body(restfulMessageEntity.getReqJsonBody())
......@@ -200,6 +191,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.body(restfulMessageEntity.getReqJsonBody())
.when()
......@@ -216,6 +208,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.body(restfulMessageEntity.getMapperReqJsonBody(), ObjectMapperType.JACKSON_2)
.when()
......@@ -231,6 +224,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.body(restfulMessageEntity.getReqJsonArrayBody())
.when()
......@@ -246,6 +240,7 @@ public class RestfulMessageEventListener {
response =
given()
.filter(new AllureRestAssured())
.relaxedHTTPSValidation()
//.config(config)
.when()
//.contentType(restfulMessageEntity.getContentType())
......@@ -395,10 +390,6 @@ public class RestfulMessageEventListener {
}
private void processRestMsgEventWithHttp2(RestfulMessageEntity restfulMessageEntity) {
}
private void matchKeyAndDataTypeInRespWithExpectation(Map<String, Object> recvRespBody, Map<String, Object> expectedRespBody) {
//how to match: traverse expectedRespBody and found corresponding key in recvRespBody
for (Map.Entry<String, Object> entry : expectedRespBody.entrySet()) {
......
......@@ -12,7 +12,7 @@ global.test.datacollectionpath=src/test/resources/testdatacollection/
server.port=8080
server.http2.enabled=true
server.ssl.enabled=true
server.ssl.enabled=false
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=123456
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment