Commit 05e2f7f3 authored by xie.qin's avatar xie.qin

firstly commit.

parent 7136930e
......@@ -49,8 +49,8 @@ dependencies {
testImplementation 'io.cucumber:cucumber-java:6.10.4'
testImplementation 'io.cucumber:cucumber-junit:6.10.4'
testImplementation 'io.cucumber:cucumber-spring:6.10.4'
//testImplementation 'io.rest-assured:spring-mock-mvc:4.4.0'
testImplementation 'io.qameta.allure:allure-junit4:2.14.0'
testImplementation 'io.rest-assured:spring-mock-mvc:4.4.0'
//testImplementation 'io.qameta.allure:allure-junit4:2.14.0'
//testImplementation 'io.qameta.allure:allure-cucumber4-jvm:2.14.0'
testImplementation 'io.qameta.allure:allure-cucumber6-jvm:2.14.0'
}
......
......@@ -4,7 +4,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class VersionController {
public class BackendServiceController {
@GetMapping("/version")
public String getVersion() {
return "1.0";
......
......@@ -7,20 +7,17 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fuzamei.autotest.properties.BackendServiceProperties;
import com.fuzamei.autotest.properties.GlobalProperties;
import io.qameta.allure.restassured.AllureRestAssured;
import io.restassured.http.ContentType;
import io.restassured.http.Header;
import io.restassured.http.Headers;
import io.restassured.http.Method;
import io.restassured.response.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;
......@@ -30,7 +27,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
@Slf4j
@Component
public class ParseOpenApi {
public class OpenApiParser {
@Autowired
BackendServiceProperties backendServiceProperties;
......@@ -137,9 +134,6 @@ public class ParseOpenApi {
else if (node.toString().contains("xml")){
contentType = ContentType.XML;
}
else if (node.toString().contains("json") || node.toString().contains("javascript")){
contentType = ContentType.JSON;
}
else if (node.toString().contains("multipart")){
contentType = ContentType.MULTIPART;
}
......@@ -149,9 +143,12 @@ public class ParseOpenApi {
else if (node.toString().contains("urlencoded")){
contentType = ContentType.URLENC;
}
else{
else if (node.toString().contains("html")){
contentType = ContentType.HTML;
}
else {
contentType = ContentType.JSON;
}
break;
}
}
......@@ -178,13 +175,18 @@ public class ParseOpenApi {
Header userName = new Header("User-Name", globalProperties.getDftusername());
Headers notNullHeaders = new Headers(userID, userName);
//parse field parameters
//parse field parameters(path, request.json_body)
ArrayNode parametersArrayNode = null;
Map<String, Object> reqJsonBody = new HashMap<String, Object>();
/*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){
log.debug("It's analyzing json node: /paths/<each_path>/<each_http_method>/parameters[]/in/{}", paraNode.get("in").asText());
log.debug("It's analyzing json node: /paths{}/{}/parameters[]/in/{}", URL, httpMethod, paraNode.get("in").asText());
String txtInVal = paraNode.get("in").asText();
//String strInVal = paraNode.get("in").toString();
if (txtInVal.equalsIgnoreCase("query")) {
......@@ -211,7 +213,117 @@ public class ParseOpenApi {
String bodyRef = bodySchema.get("originalRef").asText();
log.debug("get json_body from ref /definitions/{}", bodyRef);
JsonNode jsonNodeReqBody = definitionNode.get(bodyRef).get("properties");
reqJsonBody = translatePropertyToJsonBody(jsonNodeReqBody, definitionNode);
reqJsonBody = translatePropertyToJsonBody(bodyRef, jsonNodeReqBody, definitionNode);
}
else {
/*if (bodySchema.get("type").asText().equalsIgnoreCase("object")){
Map<String, String> tmpObj = new HashMap<>();
tmpObj.put("test", "test");
reqJsonBody.put(property.getKey(), tmpObj);*/
switch (bodySchema.get("type").asText().toLowerCase()){
case "string":
if (bodySchema.has("format") && bodySchema.get("format").asText().equalsIgnoreCase("binary")){
//"description": "合约文件包",
final String binaryStrPath = "src" + File.separatorChar + "test" + File.separatorChar + "resources" + File.separatorChar + "testdatacollection" + File.separatorChar + "common" + File.separatorChar + "appBinaryString.zip";
/*byte[] binaryStr = readFileInBytesToString(binaryStrPath);
if (binaryStr == null){
log.error("cannot find out the file to transport.");
break;
}*/
reqJsonBody.put(paraNode.get("name").asText(), binaryStrPath);
}
else {
reqJsonBody.put(paraNode.get("name").asText(), globalProperties.getDftstring());
}
break;
case "object":
if (bodySchema.has("additionalProperties")){
String tmpDataType = bodySchema.get("additionalProperties").get("type").asText().toLowerCase();
switch (tmpDataType){
case "string":
reqJsonBody.put(paraNode.get("name").asText(), globalProperties.getDftstring());
break;
case "number":
reqJsonBody.put(paraNode.get("name").asText(), globalProperties.getDftnumber());
break;
case "object":
Map<String, String> tmpObj = new HashMap<>();
tmpObj.put("test", globalProperties.getDftstring());
reqJsonBody.put(paraNode.get("name").asText(), tmpObj);
break;
}
}
else {
Map<String, String> tmpObj = new HashMap<>();
tmpObj.put("test", globalProperties.getDftstring());
reqJsonBody.put(paraNode.get("name").asText(), tmpObj);
}
break;
case "array":
if (bodySchema.has("items") && bodySchema.get("items").has("type")){
switch (bodySchema.get("items").get("type").asText()){
case "string":
List<String> tmpStrArr = new ArrayList<>();
tmpStrArr.add(globalProperties.getDftstring());
tmpStrArr.add(globalProperties.getDftstring());
reqJsonBody.put(paraNode.get("name").asText(), tmpStrArr);
break;
case "integer":
if (bodySchema.get("items").has("format")){
if (bodySchema.get("items").get("format").asText().equalsIgnoreCase("int64")){
List<String> tmpInt64Arr = new ArrayList<>();
tmpInt64Arr.add(globalProperties.getInt64max());
tmpInt64Arr.add(globalProperties.getInt64max());
reqJsonBody.put(paraNode.get("name").asText(), tmpInt64Arr);
}
else{
List<Integer> tmpInt32Arr = new ArrayList<>();
tmpInt32Arr.add(globalProperties.getInt32max());
tmpInt32Arr.add(globalProperties.getInt32max());
reqJsonBody.put(paraNode.get("name").asText(), tmpInt32Arr);
}
}
else{
List<Integer> tmpInt32Arr = new ArrayList<>();
tmpInt32Arr.add(globalProperties.getInt32max());
tmpInt32Arr.add(globalProperties.getInt32max());
reqJsonBody.put(paraNode.get("name").asText(), tmpInt32Arr);
}
break;
default:
break;
}
}
else if(bodySchema.has("items") && bodySchema.get("items").has("originalRef")){
String bodyRef = bodySchema.get("items").get("originalRef").asText();
JsonNode jsonNodeReqBody = definitionNode.get(bodyRef).get("properties");
reqJsonBody = translatePropertyToJsonBody(bodyRef, jsonNodeReqBody, definitionNode);
}
else{
log.error("This array structure is not defined in handling scenario. Its structure is: {}", bodySchema.toString());
}
break;
case "number":
reqJsonBody.put(paraNode.get("name").asText(), globalProperties.getDftnumber());
break;
case "boolean":
reqJsonBody.put(paraNode.get("name").asText(), globalProperties.getDftboolean());
break;
case "integer":
//N/A, not this case.
break;
}
}
//as swagger-ui issue, to handle path "post /chainserver/chainversion" specially here.
//add binary str file in body.
if (path.contains("/chainserver/chainversion") && httpMethod.equals(Method.POST)){
final String binaryStrPath = "src" + File.separatorChar + "test" + File.separatorChar + "resources" + File.separatorChar + "testdatacollection" + File.separatorChar + "common" + File.separatorChar + globalProperties.getLatestchain33version() + ".tar.gz";
/*byte[] binaryStr = readFileInBytesToString(binaryStrPath);
if (binaryStr == null){
log.error("cannot find out the file to transport.");
break;
}*/
reqJsonBody.put("file", binaryStrPath);
}
}
}
......@@ -232,7 +344,7 @@ public class ParseOpenApi {
if (eachRespNodeSchemaValue.has("originalRef")){ //type="object" and it has properties' detail info
String tmpRef = eachRespNodeSchemaValue.get("originalRef").asText();
JsonNode jsonNodeRespBody = definitionNode.get(tmpRef).get("properties");
respJsonBody = translatePropertyToJsonBody(jsonNodeRespBody, definitionNode);
respJsonBody = produceExpectedResponseBody(tmpRef, jsonNodeRespBody, definitionNode);
}
else if (eachRespNodeSchemaValue.has("type") && eachRespNodeSchemaValue.get("type").asText().equalsIgnoreCase("array")) { //type="array"
/**
......@@ -240,22 +352,42 @@ public class ParseOpenApi {
"200": {"description": "OK", "schema": {"type": "array","items": {"$ref": "#/definitions/SysDict对象","originalRef": "SysDict对象" }}}
*/
if (eachRespNodeSchemaValue.has("items")) {
if (!eachRespNodeSchemaValue.get("items").has("originalRef")){
if (eachRespNodeSchemaValue.get("items").has("originalRef")){
String tmpRef = eachRespNodeSchemaValue.get("items").get("originalRef").asText();
JsonNode jsonNodeRespBody = definitionNode.get(tmpRef).get("properties");
respJsonBody = translatePropertyToJsonBody(jsonNodeRespBody, definitionNode);
respJsonBody = produceExpectedResponseBody(tmpRef, jsonNodeRespBody, definitionNode); //object array only save 1st element(a object) for matching.
/*Map<String, Object> eachEleInRespArr = translatePropertyToJsonBody(jsonNodeRespBody, definitionNode);
//List<Map<String, Object>> mapArrayData = new ArrayList<>();
//mapArrayData.add(eachEleInRespArr);
//respJsonBody.put("array.object", mapArrayData);*/
}
else {
String tmpArrayDataType = eachRespNodeSchemaValue.get("items").get("type").asText().toLowerCase();
respJsonBody.put("type", "array."+tmpArrayDataType); //{type: array.string}
}
}
else {
log.error("This response schema does not handle, its structure is: {}", eachRespNodeSchemaValue.toString());
break;
}
}
else if (eachRespNodeSchemaValue.has("type") && eachRespNodeSchemaValue.get("type").asText().equalsIgnoreCase("object") && eachRespNodeSchemaValue.has("additionalProperties")) {
if (eachRespNodeSchemaValue.get("additionalProperties").has("format")){
respJsonBody.put("type", "array.object." + eachRespNodeSchemaValue.get("format").asText().toLowerCase());
}
else {
respJsonBody.put("type", "array.object." + eachRespNodeSchemaValue.get("type").asText().toLowerCase());
}
}
else{
//type="string, integer, boolean, number", not array
//type="string, int64, int32, boolean, number", not array
//"200": {"description": "OK", "schema": { "type": "boolean" } }
respJsonBody.put("type", eachRespNodeSchemaValue.get("type").asText().toLowerCase());
if (eachRespNodeSchemaValue.has("type") && eachRespNodeSchemaValue.has("format")){
respJsonBody.put("type", eachRespNodeSchemaValue.get("format").asText().toLowerCase());
}
else {
respJsonBody.put("type", eachRespNodeSchemaValue.get("type").asText().toLowerCase());
}
}
break;
}
......@@ -263,48 +395,88 @@ public class ParseOpenApi {
}
RestfulMessage restfulMsgWithHeaders = null;
RestfulMessage restfulMsgWithoutHeaders = null;
RestfulMessageEntity restfulMsgWithHeaders = null;
RestfulMessageEntity restfulMsgWithoutHeaders = null;
if (!reqJsonBody.isEmpty() ) {
restfulMsgWithHeaders = RestfulMessage.builder()
.headers(notNullHeaders)
.contentType(contentType)
.method(httpMethod)
.path(path)
.reqJsonBody(reqJsonBody)
.statusCode(statusCode)
.respJsonBody(respJsonBody)
.build();
restfulMsgWithoutHeaders = RestfulMessage.builder()
.contentType(contentType)
.method(httpMethod)
.path(path)
.reqJsonBody(reqJsonBody)
.statusCode(statusCode)
.respJsonBody(respJsonBody)
.build();
if (!respJsonBody.isEmpty()) {
restfulMsgWithHeaders = RestfulMessageEntity.builder()
.headers(notNullHeaders)
.contentType(contentType)
.method(httpMethod)
.path(path)
.reqJsonBody(reqJsonBody)
.statusCode(statusCode)
.respJsonBody(respJsonBody)
.build();
restfulMsgWithoutHeaders = RestfulMessageEntity.builder()
.contentType(contentType)
.method(httpMethod)
.path(path)
.reqJsonBody(reqJsonBody)
.statusCode(statusCode)
.respJsonBody(respJsonBody)
.build();
}
else {
restfulMsgWithHeaders = RestfulMessageEntity.builder()
.headers(notNullHeaders)
.contentType(contentType)
.method(httpMethod)
.path(path)
.reqJsonBody(reqJsonBody)
.statusCode(statusCode)
//.respJsonBody(respJsonBody)
.build();
restfulMsgWithoutHeaders = RestfulMessageEntity.builder()
.contentType(contentType)
.method(httpMethod)
.path(path)
.reqJsonBody(reqJsonBody)
.statusCode(statusCode)
//.respJsonBody(respJsonBody)
.build();
}
}
else {
restfulMsgWithHeaders = RestfulMessage.builder()
.headers(notNullHeaders)
.contentType(contentType)
.method(httpMethod)
.path(path)
.statusCode(statusCode)
.respJsonBody(respJsonBody)
.build();
restfulMsgWithoutHeaders = RestfulMessage.builder()
.contentType(contentType)
.method(httpMethod)
.path(path)
.statusCode(statusCode)
.respJsonBody(respJsonBody)
.build();
}
if (!respJsonBody.isEmpty()) {
restfulMsgWithHeaders = RestfulMessageEntity.builder()
.headers(notNullHeaders)
.contentType(contentType)
.method(httpMethod)
.path(path)
.statusCode(statusCode)
.respJsonBody(respJsonBody)
.build();
restfulMsgWithoutHeaders = RestfulMessageEntity.builder()
.contentType(contentType)
.method(httpMethod)
.path(path)
.statusCode(statusCode)
.respJsonBody(respJsonBody)
.build();
}
else {
restfulMsgWithHeaders = RestfulMessageEntity.builder()
.headers(notNullHeaders)
.contentType(contentType)
.method(httpMethod)
.path(path)
.statusCode(statusCode)
//.respJsonBody(respJsonBody)
.build();
restfulMsgWithoutHeaders = RestfulMessageEntity.builder()
.contentType(contentType)
.method(httpMethod)
.path(path)
.statusCode(statusCode)
//.respJsonBody(respJsonBody)
.build();
}
}
//publish message and wait subscriber(e.g. rest-assure) to send out request
RestfulMessageEvent restfulMessageEvent = new RestfulMessageEvent(this);
......@@ -315,12 +487,12 @@ public class ParseOpenApi {
applicationContext.publishEvent(restfulMessageEvent);
}
private Map<String, Object> translatePropertyToJsonBody(JsonNode jsonNodeReqBody, JsonNode definitionNode) {
private Map<String, Object> translatePropertyToJsonBody(String refKey, JsonNode jsonNodeReqBody, JsonNode definitionNode) {
Map<String, Object> reqJsonBody = new HashMap<String, Object>();
Iterator<Map.Entry<String, JsonNode>> it = jsonNodeReqBody.fields();
while (it.hasNext()) {
Map.Entry<String, JsonNode> property = it.next();
//"accountId": {"type": "integer", "format": "int64", "description": "账户id"}
//e.g property = "accountId": {"type": "integer", "format": "int64", "description": "账户id"}
if (property.getValue().has("type")){
switch (property.getValue().get("type").asText().toLowerCase()){
case "integer":
......@@ -344,17 +516,26 @@ public class ParseOpenApi {
if (property.getValue().has("additionalProperties") && property.getValue().get("additionalProperties").has("originalRef")){
//"attributes":{"type": "object", "description": "商品属性信息", "additionalProperties": {"originalRef": "商品属性信息"}}
String refField = property.getValue().get("additionalProperties").get("originalRef").asText();
if (refField.equals(refKey)){
Map<String, String> tmpObj = new HashMap<>();
reqJsonBody.put(property.getKey(), tmpObj);
return reqJsonBody;
}
if (definitionNode.has(refField) && definitionNode.get(refField).has("properties")){
Map<String, Object> subReqJsonBody = translatePropertyToJsonBody(definitionNode.get(refField), definitionNode);
Map<String, Object> subReqJsonBody = translatePropertyToJsonBody(refField, definitionNode.get(refField), definitionNode);
reqJsonBody.put(property.getKey(), subReqJsonBody);
}
else{
reqJsonBody.put(property.getKey(), "{}");
Map<String, String> tmpObj = new HashMap<>();
tmpObj.put("test", "test");
reqJsonBody.put(property.getKey(), tmpObj);
}
}
else{
//"details": {"type": "object", "description": "价格明细", "additionalProperties": {"type": "number"}
reqJsonBody.put(property.getKey(), "{}");
Map<String, String> tmpObj = new HashMap<>();
tmpObj.put("test", "test");
reqJsonBody.put(property.getKey(), tmpObj);
}
break;
case "array":
......@@ -364,7 +545,7 @@ public class ParseOpenApi {
switch (property.getValue().get("items").get("type").asText().toLowerCase()){
case "integer":
if (property.getValue().get("items").has("format") && property.getValue().get("items").get("format").asText().equalsIgnoreCase("int64")){
List<Long> longArrayData = new ArrayList<>();
List<String> longArrayData = new ArrayList<>();
longArrayData.add(globalProperties.getInt64max());
longArrayData.add(globalProperties.getInt64max());
reqJsonBody.put(property.getKey(), longArrayData);
......@@ -395,19 +576,32 @@ public class ParseOpenApi {
reqJsonBody.put(property.getKey(), bigDecimalsArrayData);
break;
case "object":
reqJsonBody.put(property.getKey(), "[]");
List<Map<String, String>> objArrayData = new ArrayList<Map<String, String>>();
Map<String, String> tmpObj = new HashMap<>();
tmpObj.put("test", "test");
tmpObj.put("test", "test");
objArrayData.add(tmpObj);
reqJsonBody.put(property.getKey(), objArrayData);
break;
}
}
//"nodes": {"type": "array", "description": "节点列表", "items": { "$ref": "#/definitions/ChainNodeRequest","originalRef": "ChainNodeRequest"}}
else {
String refField = property.getValue().get("items").get("originalRef").asText();
if (refField.equals(refKey)){
List<String> tmpArr = new ArrayList<>();
reqJsonBody.put(property.getKey(), tmpArr);
return reqJsonBody;
}
if (definitionNode.has(refField) && definitionNode.get(refField).has("properties")){
Map<String, Object> subReqJsonBody = translatePropertyToJsonBody(definitionNode.get(refField), definitionNode);
Map<String, Object> subReqJsonBody = translatePropertyToJsonBody(refField, definitionNode.get(refField), definitionNode);
reqJsonBody.put(property.getKey(), subReqJsonBody);
}
else{
reqJsonBody.put(property.getKey(), "[]");
List<String> tmpArr = new ArrayList<>();
tmpArr.add("test");
tmpArr.add("test");
reqJsonBody.put(property.getKey(), tmpArr);
}
}
}
......@@ -417,16 +611,148 @@ public class ParseOpenApi {
//"chainExplorerNodeRequest": {"description": "浏览器部署节点信息","$ref": "#/definitions/ChainExplorerNodeRequest","originalRef": "ChainExplorerNodeRequest"}
else if(property.getValue().has("originalRef")) {
String refField = property.getValue().get("originalRef").asText();
if (refField.equals(refKey)){
List<String> tmpArr = new ArrayList<>();
reqJsonBody.put(property.getKey(), tmpArr);
return reqJsonBody;
}
if (definitionNode.has(refField) && definitionNode.get(refField).has("properties")){
Map<String, Object> subReqJsonBody = translatePropertyToJsonBody(definitionNode.get(refField), definitionNode);
Map<String, Object> subReqJsonBody = translatePropertyToJsonBody(refField, definitionNode.get(refField), definitionNode);
reqJsonBody.put(property.getKey(), subReqJsonBody);
}
else{
reqJsonBody.put(property.getKey(), "{}");
Map<String, String> tmpObj = new HashMap<>();
tmpObj.put("test", "test");
reqJsonBody.put(property.getKey(), tmpObj);
}
}
}
return reqJsonBody;
}
private Map<String, Object> produceExpectedResponseBody(String refKey, JsonNode jsonNodeReqBody, JsonNode definitionNode) {
Map<String, Object> respJsonBody = new HashMap<String, Object>();
Iterator<Map.Entry<String, JsonNode>> it = jsonNodeReqBody.fields();
while (it.hasNext()) {
Map.Entry<String, JsonNode> property = it.next();
//"accountId": {"type": "integer", "format": "int64", "description": "账户id"}
if (property.getValue().has("type")){
switch (property.getValue().get("type").asText().toLowerCase()){
case "integer":
if (property.getValue().get("format").asText().equalsIgnoreCase("int32")){
respJsonBody.put(property.getKey(), "int32");
}
else{
respJsonBody.put(property.getKey(), "int64");
}
break;
case "object":
if (property.getValue().has("additionalProperties") && property.getValue().get("additionalProperties").has("originalRef")){
//"attributes":{"type": "object", "description": "商品属性信息", "additionalProperties": {"originalRef": "商品属性信息"}}
String refField = property.getValue().get("additionalProperties").get("originalRef").asText();
if (refField.equals(refKey)){
respJsonBody.put(property.getKey(), "object");
return respJsonBody;
}
if (definitionNode.has(refField) && definitionNode.get(refField).has("properties")){
Map<String, Object> objRespJsonBody = produceExpectedResponseBody(refField, definitionNode.get(refField), definitionNode);
respJsonBody.put(property.getKey(), objRespJsonBody);
}
else{
respJsonBody.put(property.getKey(), "object");
}
}
else{
//"details": {"type": "object", "description": "价格明细", "additionalProperties": {"type": "number"}
respJsonBody.put(property.getKey(), "object");
}
break;
case "array":
if (property.getValue().has("items")){
//"param": {"type": "array","description": "合约调用参数,用于合约调用","items": {"type": "object"}}
if (property.getValue().get("items").has("type") && !property.getValue().get("items").has("originalRef")){
switch (property.getValue().get("items").get("type").asText().toLowerCase()){
case "integer":
if (property.getValue().get("items").has("format") && property.getValue().get("items").get("format").asText().equalsIgnoreCase("int64")){
respJsonBody.put(property.getKey(), "array.int64");
}
else{
respJsonBody.put(property.getKey(), "array.int32");
}
break;
default:
respJsonBody.put(property.getKey(), "array." + property.getValue().get("items").get("type").asText().toLowerCase() );
}
}
else {
//"nodes": {"type": "array", "description": "节点列表", "items": { "$ref": "#/definitions/ChainNodeRequest","originalRef": "ChainNodeRequest"}}
String refField = property.getValue().get("items").get("originalRef").asText();
if (refField.equals(refKey)){
respJsonBody.put(property.getKey(), "array");
return respJsonBody;
}
if (definitionNode.has(refField) && definitionNode.get(refField).has("properties")){
Map<String, Object> subRespJsonBody = produceExpectedResponseBody(refField, definitionNode.get(refField), definitionNode);
respJsonBody.put(property.getKey(), subRespJsonBody);
}
else{
respJsonBody.put(property.getKey(), "array");
}
}
}
break;
default:
respJsonBody.put(property.getKey(), property.getValue().get("type").asText().toLowerCase());
}
}
//"chainExplorerNodeRequest": {"description": "浏览器部署节点信息","$ref": "#/definitions/ChainExplorerNodeRequest","originalRef": "ChainExplorerNodeRequest"}
else if(property.getValue().has("originalRef")) {
String refField = property.getValue().get("originalRef").asText();
if (definitionNode.has(refField) && definitionNode.get(refField).has("properties")){
Map<String, Object> subReqJsonBody = produceExpectedResponseBody(refField, definitionNode.get(refField), definitionNode);
respJsonBody.put(property.getKey(), subReqJsonBody);
}
else{
respJsonBody.put(property.getKey(), "object");
}
}
}
return respJsonBody;
}
private byte[] readFileInBytesToString(String filePath) {
final int readArraySizePerRead = 4096;
File file = new File(filePath);
ArrayList<Byte> bytes = new ArrayList<>();
try {
if (file.exists()) {
DataInputStream isr = new DataInputStream(new FileInputStream(
file));
byte[] tempchars = new byte[readArraySizePerRead];
int charsReadCount = 0;
while ((charsReadCount = isr.read(tempchars)) != -1) {
for(int i = 0 ; i < charsReadCount ; i++){
bytes.add (tempchars[i]);
}
}
isr.close();
}
} catch (IOException e) {
log.error("binary string read error as {}", e.toString());
e.printStackTrace();
return null;
}
return toPrimitives(bytes.toArray(new Byte[0]));
}
private byte[] toPrimitives(Byte[] oBytes) {
byte[] bytes = new byte[oBytes.length];
for (int i = 0; i < oBytes.length; i++) {
bytes[i] = oBytes[i];
}
return bytes;
}
}
......@@ -15,7 +15,7 @@ import java.util.Map;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RestfulMessage {
public class RestfulMessageEntity {
private ContentType contentType;
private Headers headers;
......
......@@ -4,17 +4,17 @@ import org.springframework.context.ApplicationEvent;
public class RestfulMessageEvent extends ApplicationEvent {
private RestfulMessage restfulMsg;
private RestfulMessageEntity restfulMsg;
public RestfulMessageEvent(Object source) {
super(source);
}
public RestfulMessage getMsg() {
public RestfulMessageEntity getMsg() {
return restfulMsg;
}
public void setMsg(RestfulMessage restfulMsg) {
public void setMsg(RestfulMessageEntity restfulMsg) {
this.restfulMsg = restfulMsg;
}
}
......@@ -3,18 +3,23 @@ package com.fuzamei.autotest.openapi;
import com.fuzamei.autotest.properties.SpecificProperties;
import io.qameta.allure.restassured.AllureRestAssured;
import io.restassured.RestAssured;
import io.restassured.builder.MultiPartSpecBuilder;
import io.restassured.config.HttpClientConfig;
import io.restassured.config.RestAssuredConfig;
import io.restassured.http.ContentType;
import io.restassured.mapper.ObjectMapperType;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.specification.MultiPartSpecification;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -34,45 +39,174 @@ public class RestfulMessageEventListener {
@EventListener
public void processRestfulMessageEvent(RestfulMessageEvent restfulMessageEvent){
log.debug("subscriber received a notification.");
RestfulMessage restfulMessage = restfulMessageEvent.getMsg();
RestfulMessageEntity restfulMessageEntity = restfulMessageEvent.getMsg();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(specificProperties.getRestConnTimeout().intValue())
.setConnectionRequestTimeout(specificProperties.getRestReqTimeout().intValue())
.setSocketTimeout(specificProperties.getRestSocketTimeout().intValue())
.build();
RestAssuredConfig config = RestAssured.config()
.httpClient(HttpClientConfig.httpClientConfig()
.setParam(CoreConnectionPNames.CONNECTION_TIMEOUT, specificProperties.getRestConnTimeout().intValue())
.setParam(CoreConnectionPNames.SO_TIMEOUT, specificProperties.getRestSocketTimeout().intValue()));
Response response =
given()
.filter(new AllureRestAssured())
.config(config)
.body(restfulMessage.getReqJsonBody())
.when()
.contentType(restfulMessage.getContentType())
.headers(restfulMessage.getHeaders())
.request(restfulMessage.getMethod(), restfulMessage.getPath())
.then()
//.assertThat()
//.statusCode(restfulMessage.getStatusCode())
.extract()
.response();
.httpClient(HttpClientConfig.httpClientConfig().httpClientFactory(() ->
HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build()));
//response format: {code: "baas.err.success", data: {}, message: "OK", status: "OK"}
assertThat("http status code is not the expectation.", response.getStatusCode(), equalTo(restfulMessage.getStatusCode()));
//check field code in response body
JsonPath jsonPathEvaluator = response.jsonPath();
String respCode = jsonPathEvaluator.get("code");
assertThat("status code in http response is not the expectation.", respCode, equalTo("baas.err.success"));
Response response = null;
if(restfulMessageEntity.getHeaders() != null) {
if (restfulMessageEntity.getReqJsonBody() != null) {
if (restfulMessageEntity.getContentType().equals(ContentType.MULTIPART)){
String filePathName = restfulMessageEntity.getRespJsonBody().get("file").toString();
restfulMessageEntity.getReqJsonBody().remove("file");
MultiPartSpecification multiPartSpecBuilder = new MultiPartSpecBuilder(restfulMessageEntity.getReqJsonBody(), ObjectMapperType.JACKSON_2)
.fileName(filePathName)
.build();
response =
given()
.filter(new AllureRestAssured())
//.config(config)
.multiPart(multiPartSpecBuilder)
//.body(restfulMessageEntity.getReqJsonBody())
.when()
.contentType(restfulMessageEntity.getContentType())
.headers(restfulMessageEntity.getHeaders())
.request(restfulMessageEntity.getMethod(), restfulMessageEntity.getPath())
.then()
//.assertThat()
//.statusCode(restfulMessageEntity.getStatusCode())
.extract()
.response();
}
else {
response =
given()
.filter(new AllureRestAssured())
//.config(config)
.body(restfulMessageEntity.getReqJsonBody())
.when()
.contentType(restfulMessageEntity.getContentType())
.headers(restfulMessageEntity.getHeaders())
.request(restfulMessageEntity.getMethod(), restfulMessageEntity.getPath())
.then()
//.assertThat()
//.statusCode(restfulMessageEntity.getStatusCode())
.extract()
.response();
}
}
else{
response =
given()
.filter(new AllureRestAssured())
//.config(config)
.when()
//.contentType(restfulMessageEntity.getContentType())
.headers(restfulMessageEntity.getHeaders())
.request(restfulMessageEntity.getMethod(), restfulMessageEntity.getPath())
.then()
//.assertThat()
//.statusCode(restfulMessageEntity.getStatusCode())
.extract()
.response();
}
}
else {
if (restfulMessageEntity.getReqJsonBody() != null) {
if (restfulMessageEntity.getContentType().equals(ContentType.MULTIPART)){
String filePathName = restfulMessageEntity.getRespJsonBody().get("file").toString();
restfulMessageEntity.getReqJsonBody().remove("file");
MultiPartSpecification multiPartSpecBuilder = new MultiPartSpecBuilder(restfulMessageEntity.getReqJsonBody(), ObjectMapperType.JACKSON_2)
.fileName(filePathName)
.build();
response =
given()
.filter(new AllureRestAssured())
//.config(config)
.multiPart(multiPartSpecBuilder)
//.body(restfulMessageEntity.getReqJsonBody())
.when()
.contentType(restfulMessageEntity.getContentType())
.headers(restfulMessageEntity.getHeaders())
.request(restfulMessageEntity.getMethod(), restfulMessageEntity.getPath())
.then()
//.assertThat()
//.statusCode(restfulMessageEntity.getStatusCode())
.extract()
.response();
}
else {
response =
given()
.filter(new AllureRestAssured())
//.config(config)
.body(restfulMessageEntity.getReqJsonBody())
.when()
.contentType(restfulMessageEntity.getContentType())
.request(restfulMessageEntity.getMethod(), restfulMessageEntity.getPath())
.then()
//.assertThat()
//.statusCode(restfulMessageEntity.getStatusCode())
.extract()
.response();
}
}
else {
response =
given()
.filter(new AllureRestAssured())
//.config(config)
.when()
//.contentType(restfulMessageEntity.getContentType())
.request(restfulMessageEntity.getMethod(), restfulMessageEntity.getPath())
.then()
//.assertThat()
//.statusCode(restfulMessageEntity.getStatusCode())
.extract()
.response();
}
}
//response format: {code: "baas.err.success", data: {}, message: "OK", status: "OK"}
JsonPath jsonPathEvaluator = null;
try{
assertThat("http status code is not the expectation.", response.getStatusCode(), equalTo(restfulMessageEntity.getStatusCode()));
//check field code in response body
jsonPathEvaluator = response.jsonPath();
String respCode = jsonPathEvaluator.get("code");
assertThat("status code in http response is not the expectation.", respCode, equalTo("baas.err.success"));
}catch (AssertionError ae){
log.error("status_code in response assert failed.");
}
//response json body only match key, not value
//check field data contains all of needed key
try{
Map<String, Object> respBody = new HashMap<>();
respBody = jsonPathEvaluator.getMap("data");
matchKeyInRespWithExpectation(respBody, restfulMessage.getRespJsonBody());
//object
Map<String, Object> objRespBody = new HashMap<>();
if (jsonPathEvaluator != null) {
objRespBody = jsonPathEvaluator.getMap("data");
matchKeyAndDataTypeInRespWithExpectation(objRespBody, restfulMessageEntity.getRespJsonBody());
}
}
catch (ClassCastException e){
String expectedDataType = restfulMessage.getRespJsonBody().get("type").toString();
matchDataTypeInRespWithExpectation(jsonPathEvaluator.get("data"), expectedDataType);
try{
//array
List<Map<String, Object>> arrRespBody = new ArrayList<>();
arrRespBody = jsonPathEvaluator.getList("data");
//objects in array
try{
Map<String, Object> arrEleRespBody = arrRespBody.get(0);
matchKeyAndDataTypeInRespWithExpectation(arrEleRespBody, restfulMessageEntity.getRespJsonBody());
}catch (ClassCastException exception){
//normal array, not objects in array
String expectedDataType = restfulMessageEntity.getRespJsonBody().get("type").toString();
matchDataTypeInRespWithExpectation(arrRespBody.get(0), expectedDataType);
}
}catch (ClassCastException ex){
//neither object, nor array
String expectedDataType = restfulMessageEntity.getRespJsonBody().get("type").toString();
matchDataTypeInRespWithExpectation(jsonPathEvaluator.get("data"), expectedDataType);
}
}
}
......@@ -82,28 +216,39 @@ public class RestfulMessageEventListener {
*/
private void matchKeyInRespWithExpectation(Map<String, Object> recvRespBody, Map<String, Object> expectedRespBody) {
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()) {
log.debug("traversing expectedRespBody now, the key is {}", entry.getKey());
try{
//to match key
assertThat("Cannot found out same key in Response Body.", true, equalTo(recvRespBody.containsKey(entry.getKey())));
//to match type of value
if(entry.getValue() instanceof Map){
matchKeyAndDataTypeInRespWithExpectation((Map<String, Object>) recvRespBody.get(entry.getKey()), (Map<String, Object>) entry.getValue());
}
else if (entry.getValue() instanceof Map[]){
List<Map<String, Object>> recv = (List<Map<String, Object>>)recvRespBody.get(entry.getKey());
Map<String, Object> matchRecv = recv.get(0);
List<Map<String, Object>> expected = (List<Map<String, Object>>)entry.getValue();
Map<String, Object> matchExpected = expected.get(0);
matchKeyAndDataTypeInRespWithExpectation(matchRecv, matchExpected);
}
else {
try {
matchDataTypeInRespWithExpectation(recvRespBody.get(entry.getKey()), entry.getValue().toString());
}catch (AssertionError error){
log.error("After matched, the key:{}'s data type does not match the expectation.", entry.getKey());
break;
}
}
}
catch (AssertionError e){
log.error("After matched, the key {} missed in received response message.", entry.getKey());
break;
}
if(entry.getValue() instanceof Map){
matchKeyInRespWithExpectation((Map<String, Object>) recvRespBody.get(entry.getKey()), (Map<String, Object>) entry.getValue());
}
else if (entry.getValue() instanceof Map[]){
List<Map<String, Object>> recv = (List<Map<String, Object>>)recvRespBody.get(entry.getKey());
Map<String, Object> matchRecv = recv.get(0);
List<Map<String, Object>> expected = (List<Map<String, Object>>)entry.getValue();
Map<String, Object> matchExpected = expected.get(0);
matchKeyInRespWithExpectation(matchRecv, matchExpected);
}
}
}
......@@ -111,7 +256,7 @@ public class RestfulMessageEventListener {
private void matchDataTypeInRespWithExpectation(Object recvDataType, String expectedDataType) {
boolean matched = false;
switch (expectedDataType) {
case "string":
case "string": case "int64":
if (recvDataType instanceof String){
matched = true;
}
......@@ -122,7 +267,12 @@ public class RestfulMessageEventListener {
}
break;
case "integer":
if (recvDataType instanceof Integer || recvDataType instanceof Long) {
if (recvDataType instanceof Integer || recvDataType instanceof Long || recvDataType instanceof String) {
matched = true;
}
break;
case "int32":
if (recvDataType instanceof Integer) {
matched = true;
}
break;
......@@ -131,7 +281,7 @@ public class RestfulMessageEventListener {
matched = true;
}
break;
case "array.string":
case "array.string": case "array.int64":
if (recvDataType instanceof String[]) {
matched = true;
}
......@@ -141,7 +291,7 @@ public class RestfulMessageEventListener {
matched = true;
}
break;
case "array.integer":
case "array.int32":
if (recvDataType instanceof Integer[]) {
matched = true;
}
......@@ -152,7 +302,7 @@ public class RestfulMessageEventListener {
}
break;
case "array.object":
if (recvDataType instanceof Object[]) {
if (recvDataType instanceof Map[]) {
matched = true;
}
break;
......
......@@ -17,11 +17,12 @@ import java.math.BigDecimal;
public class GlobalProperties {
private String release;
private Integer int32max;
private Long int64max;
private String int64max;
private String dftstring;
private Boolean dftboolean;
private BigDecimal dftnumber;
private Long dftuserid;
private String dftusername;
private Integer intmin;
private String latestchain33version;
}
package com.fuzamei.autotest.utils;
public class FileUtils {
}
global.test.release=v2.1.0
global.test.release=v2.2.0
global.test.intmin=0
global.test.int32max=2147483647
global.test.int64max=9223372036854775807
......@@ -7,8 +7,10 @@ global.test.dftboolean=false
global.test.dftnumber=9999999999.99
global.test.dftuserid=87654321
global.test.dftusername=automation
global.test.latestchain33version=chain33_v1.6.6
server.port=8080
logging.level.root=WARN
logging.level.org.springframework=ERROR
logging.level.com.fuzamei.autotest=DEBUG
spring.jackson.default-property-inclusion=non_null
......
......@@ -8,7 +8,13 @@ import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(
features = "src/test/resources/features",
plugin = {"pretty"},
plugin = {"pretty",
"html:target/cucumber/report.html",
"json:target/cucumber/report.json",
"io.qameta.allure.cucumber6jvm.AllureCucumber6Jvm"
//"rerun:target/cucumbre/failed_scenarios.txt"
},
monochrome = true,
extraGlue = "com.fuzamei.autotest.steps",
tags = "not @dryrun"
)
......
package com.fuzamei.autotest.steps.openapi;
import com.fuzamei.autotest.openapi.ParseOpenApi;
import com.fuzamei.autotest.openapi.OpenApiParser;
import com.fuzamei.autotest.properties.BackendServiceProperties;
import com.fuzamei.autotest.properties.GlobalProperties;
import io.cucumber.java.en.Given;
......@@ -20,14 +20,14 @@ public class ApiVerification {
private BackendServiceProperties backendServiceProperties;
@Autowired
private ParseOpenApi parseOpenApi;
private OpenApiParser openApiParser;
@Given("^Found OpenAPI definition for (.*?) service$")
public void foundOpenApiProfileForTestingVer(String serviceName) throws Throwable {
String release = globalProperties.getRelease();
switch (serviceName) {
case "backend":
String openApiFilePath = parseOpenApi.getOpenApiFilePathByVersion(serviceName, release);
String openApiFilePath = openApiParser.getOpenApiFilePathByVersion(serviceName, release);
//log.debug("OpenApi definition for {} locates in {}", serviceName, openApiFilePath);
backendServiceProperties.setOpenapifilepath(openApiFilePath);
break;
......@@ -50,7 +50,7 @@ public class ApiVerification {
default:
break;
}
assertThat(parseOpenApi.analyzeOpenApiAndGenerateRequests(serviceName, targetServiceApiFilePath), is(Boolean.TRUE));
assertThat(openApiParser.analyzeOpenApiAndGenerateRequests(serviceName, targetServiceApiFilePath), is(Boolean.TRUE));
}
......
# new feature
# Tags: optional
Feature: A description
Scenario: A scenario
Given something..
\ No newline at end of file
@api_backend
@restfulapi @backend
Feature: API tests for service of backend
@verifyApi
@sanity
Scenario: Verify the exposed APIs work as design
#Given Found OpenAPI definition for backend service
#When The most basic testing data orgUser is ready for backend service
Given Found OpenAPI definition for backend service
When The most basic testing data orgUser is ready for backend service
Then Analyze OpenAPI file of backend service and generate REST-ful requests automatically
\ No newline at end of file
{
"u_userinfo": {
"id": 87654325,
"id": 87654321,
"phone": "13999999999",
"name": "automation",
"passwd": "admin",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"u_userinfo": {
"id": 87654321,
"phone": "13999999999",
"name": "automation",
"passwd": "admin",
"password": "F6889AA527EA40FB0A2AECC5A28A694E",
"mail": "xie.qin@33.cn",
"create_time": 1625557620511,
"status": 1
},
"u_organization": {
"id": "49d8e2dcb4ed41b5b564ab1608322613",
"name": "automation",
"address": "automation",
"type": "automation",
"creator": 87654321,
"owner": 87654321,
"status": 1,
"create_time": 1625554060376
},
"u_org_user": {
"id": 87654321,
"user_id": 87654321,
"org_id": "49d8e2dcb4ed41b5b564ab1608322613",
"status": 0
},
"u_federation": {
"id": "896bc3c9312abcdea5d5839be79cdda5",
"name": "automation",
"creator": 87654321,
"owner": 87654321,
"create_time": 1625643698310
},
"u_fed_org": {
"id": 87654321,
"fed_id": "896bc3c9312abcdea5d5839be79cdda5",
"org_id": "49d8e2dcb4ed41b5b564ab1608322613",
"status": 0,
"join_time": 1625643698483,
"quit_time": null
}
}
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