Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
auto-test
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xie.qin
auto-test
Commits
05e2f7f3
Commit
05e2f7f3
authored
Jul 16, 2021
by
xie.qin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
firstly commit.
parent
7136930e
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
675 additions
and
134 deletions
+675
-134
build.gradle
build.gradle
+2
-2
BackendServiceController.java
...fuzamei/autotest/controller/BackendServiceController.java
+1
-1
OpenApiParser.java
...main/java/com/fuzamei/autotest/openapi/OpenApiParser.java
+392
-66
RestfulMessageEntity.java
...va/com/fuzamei/autotest/openapi/RestfulMessageEntity.java
+1
-1
RestfulMessageEvent.java
...ava/com/fuzamei/autotest/openapi/RestfulMessageEvent.java
+3
-3
RestfulMessageEventListener.java
...fuzamei/autotest/openapi/RestfulMessageEventListener.java
+199
-49
GlobalProperties.java
...ava/com/fuzamei/autotest/properties/GlobalProperties.java
+2
-1
FileUtils.java
src/main/java/com/fuzamei/autotest/utils/FileUtils.java
+4
-0
application.properties
src/main/resources/application.properties
+3
-1
CucumberRunner.java
...test/java/com/fuzamei/autotest/runner/CucumberRunner.java
+7
-1
ApiVerification.java
...a/com/fuzamei/autotest/steps/openapi/ApiVerification.java
+4
-4
user_register.feature
...res/apitest/restful/user_management/user_register.feature
+8
-0
backend.feature
src/test/resources/features/sanitytest/backend.feature
+5
-4
appBinaryString.zip
...t/resources/testdatacollection/common/appBinaryString.zip
+0
-0
chain33_v1.6.6.tar.gz
...resources/testdatacollection/common/chain33_v1.6.6.tar.gz
+0
-0
orgUser.json
...resources/testdatacollection/v2.1.0/testdata/orgUser.json
+1
-1
backendOpenAPI.json
...ces/testdatacollection/v2.2.0/openapi/backendOpenAPI.json
+0
-0
orgUser.json
...ources/testdatacollection/v2.2.0/persistence/orgUser.json
+43
-0
No files found.
build.gradle
View file @
05e2f7f3
...
...
@@ -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'
}
...
...
src/main/java/com/fuzamei/autotest/controller/
Version
Controller.java
→
src/main/java/com/fuzamei/autotest/controller/
BackendService
Controller.java
View file @
05e2f7f3
...
...
@@ -4,7 +4,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import
org.springframework.web.bind.annotation.RestController
;
@RestController
public
class
Version
Controller
{
public
class
BackendService
Controller
{
@GetMapping
(
"/version"
)
public
String
getVersion
()
{
return
"1.0"
;
...
...
src/main/java/com/fuzamei/autotest/openapi/
ParseOpenApi
.java
→
src/main/java/com/fuzamei/autotest/openapi/
OpenApiParser
.java
View file @
05e2f7f3
...
...
@@ -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, int
eger
, boolean, number", not array
//type="string, int
64, 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
;
RestfulMessage
Entity
restfulMsgWithHeaders
=
null
;
RestfulMessage
Entity
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
<
Lo
ng
>
longArrayData
=
new
ArrayList
<>();
List
<
Stri
ng
>
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
;
}
}
src/main/java/com/fuzamei/autotest/openapi/RestfulMessage.java
→
src/main/java/com/fuzamei/autotest/openapi/RestfulMessage
Entity
.java
View file @
05e2f7f3
...
...
@@ -15,7 +15,7 @@ import java.util.Map;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
RestfulMessage
{
public
class
RestfulMessage
Entity
{
private
ContentType
contentType
;
private
Headers
headers
;
...
...
src/main/java/com/fuzamei/autotest/openapi/RestfulMessageEvent.java
View file @
05e2f7f3
...
...
@@ -4,17 +4,17 @@ import org.springframework.context.ApplicationEvent;
public
class
RestfulMessageEvent
extends
ApplicationEvent
{
private
RestfulMessage
restfulMsg
;
private
RestfulMessage
Entity
restfulMsg
;
public
RestfulMessageEvent
(
Object
source
)
{
super
(
source
);
}
public
RestfulMessage
getMsg
()
{
public
RestfulMessage
Entity
getMsg
()
{
return
restfulMsg
;
}
public
void
setMsg
(
RestfulMessage
restfulMsg
)
{
public
void
setMsg
(
RestfulMessage
Entity
restfulMsg
)
{
this
.
restfulMsg
=
restfulMsg
;
}
}
src/main/java/com/fuzamei/autotest/openapi/RestfulMessageEventListener.java
View file @
05e2f7f3
...
...
@@ -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
matchKey
AndDataType
InRespWithExpectation
(
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.int
eger
"
:
case
"array.int
32
"
:
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
;
...
...
src/main/java/com/fuzamei/autotest/properties/GlobalProperties.java
View file @
05e2f7f3
...
...
@@ -17,11 +17,12 @@ import java.math.BigDecimal;
public
class
GlobalProperties
{
private
String
release
;
private
Integer
int32max
;
private
Lo
ng
int64max
;
private
Stri
ng
int64max
;
private
String
dftstring
;
private
Boolean
dftboolean
;
private
BigDecimal
dftnumber
;
private
Long
dftuserid
;
private
String
dftusername
;
private
Integer
intmin
;
private
String
latestchain33version
;
}
src/main/java/com/fuzamei/autotest/utils/FileUtils.java
0 → 100644
View file @
05e2f7f3
package
com
.
fuzamei
.
autotest
.
utils
;
public
class
FileUtils
{
}
src/main/resources/application.properties
View file @
05e2f7f3
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
...
...
src/test/java/com/fuzamei/autotest/runner/CucumberRunner.java
View file @
05e2f7f3
...
...
@@ -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"
)
...
...
src/test/java/com/fuzamei/autotest/steps/openapi/ApiVerification.java
View file @
05e2f7f3
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
));
}
...
...
src/test/resources/features/apitest/restful/user_management/user_register.feature
0 → 100644
View file @
05e2f7f3
# new feature
# Tags: optional
Feature
:
A description
Scenario
:
A
scenario
Given
something..
\ No newline at end of file
src/test/resources/features/
RESTful_APIT
est/backend.feature
→
src/test/resources/features/
sanityt
est/backend.feature
View file @
05e2f7f3
@
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
src/test/resources/testdatacollection/common/appBinaryString.zip
0 → 100644
View file @
05e2f7f3
File added
src/test/resources/testdatacollection/common/chain33_v1.6.6.tar.gz
0 → 100644
View file @
05e2f7f3
File added
src/test/resources/testdatacollection/v2.1.0/testdata/orgUser.json
View file @
05e2f7f3
{
"u_userinfo"
:
{
"id"
:
8765432
5
,
"id"
:
8765432
1
,
"phone"
:
"13999999999"
,
"name"
:
"automation"
,
"passwd"
:
"admin"
,
...
...
src/test/resources/testdatacollection/v2.2.0/openapi/backendOpenAPI.json
0 → 100644
View file @
05e2f7f3
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/test/resources/testdatacollection/v2.2.0/persistence/orgUser.json
0 → 100644
View file @
05e2f7f3
{
"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
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment