Task
Develop a mock for testing asynchronous messaging with an external system.
As an example, consider a case of checking the validity of a promotional code by an external system. Step by step:
1) We send a request to the service of an external system;
The PUT request contains fields (for example, in headers):
promotionalCode = correctPromotionalCode
correlationId = a random string to be returned to the callback
replyTo = address of the service receiving the callback
2) The external system responds synchronously - 204 No content;
3) After 5 seconds, the external system sends an asynchronous callback (to the replyTo address from the request):
POST request with message body:
status = "success" if the request promotionalCode is "correctPromotionalCode", otherwise "validationError"
correlationId = correlationId from query
Decision
To solve this problem, we use SoapUI. This tool is quite flexible in terms of creating "smart" moxervices, as it allows you to write scripts both at the stages of starting / stopping moxervice (Start Script / Stop Script) and before / after receiving a request (OnRequest Script / AfterRequest Script).
Let's start:
1) Create a new project in SoapUI, for example, "test-soapui-project" (or select an existing one) and create two REST MockService for it.
Validation REST MockService - :
Path , , "/SP/ValidationSystem",
Port ,
Host "localhost".
Validation Receiving CALLBACK REST MockService - callback ( "Validation REST MockService" ):
Path , , "/SP/SpHost"
2) Validation REST MockService :
PUT
:
Resource Path , , "/validation"
Method Rest , PUT ( 1 )
PUT 204 No content
:
Http Status Code , "204 - No Content",
Content | Media type , "application/json".
Properties:
promotionalCode, replyTo, correlationId PUT.
OnRequest Script - 204 No content ( 2 ). Properties:
*log.info , script log.
AfterRequest Script - . callback , ( 5 ), callback replyTo ( 3 ):
:
log.info" Afterequest Script - "
import java.lang.Exception
// callback' , Properties
def replyTo = context.mockService.getPropertyValue('replyTo')
def correlationId = context.mockService.getPropertyValue('correlationId')
def promotionalCode = context.mockService.getPropertyValue('promotionalCode')
def status = "testStatus"
if ( promotionalCode.contains("correctPromotionalCode")){
status="success"
}
else
{
status="validationError"
}
//
Thread.sleep(5000)
log.info" callback"
// callback - POST
def conn = new URL(replyTo).openConnection();
def message = """\
{
"status":"${status}",
"correlationId":"${correlationId}"
}
"""
conn.setRequestMethod("POST")
conn.setDoOutput(true)
conn.setRequestProperty("Content-Type", "application/json")
conn.getOutputStream().write(message.getBytes("UTF-8"));
def postRC = conn.getResponseCode();
println(postRC);
if(postRC.equals(200)) {
println(conn.getInputStream().getText());
}
log.info" callback"
log.info" Afterequest Script - "
3) Validation Receiving CALLBACK REST MockService :
POST
:
Resource Path , , "/callback"
Method Rest , POST.
POST 200 OK
:
Http Status Code , "200 - OK",
Content | Media type , "application/json".
OnRequest Script - , callback , :
4)
5)
, , Postman:
PUT validation 1 (Validation REST MockService), Headers 3 ,
replyTo callback - 2 (Validation Receiving CALLBACK REST MockService)
- 204 No Content.
script log SoapUI , callback 2:
Portainer:
1) images SoapUI:
docker hub . fbascheper/soapui-mockservice-runner (https://hub.docker.com/r/fbascheper/soapui-mockservice-runner/)<o:p>
Portainer images
2) :
Compose file:
version: "3.7"
services:
soapui-validation:
image: fbascheper/soapui-mockservice-runner:latest
volumes:
- /soapui/soapui-prj:/home/soapui/soapui-prj
environment:
- MOCK_SERVICE_NAME=Validation REST MockService
- PROJECT=/home/soapui/soapui-prj/test-soapui-project.xml
ports:
- 7703:8080
:
image - docker hub (https://hub.docker.com/r/fbascheper/soapui-mockservice-runner/)
volumes - soapUI , : " ": " "
MOCK_SERVICE_NAME - soapUI
PROJECT - soapUI , : ยซ " " volumesยป + ( test-soapui-project)
ports - ( port soapUI), " ": " "
* in our example, the soapUI project was placed on the server in / soapui / soapui-prj /
go to Portainer in the Stacks section,
add a new stack:
- specify in the Name field how our stack will be named, for example, sp-soapui-mocks,
- copy the Compose file text in the Web editor,
Deploy the stack.
As a result, the sp-soapui-mocks stack will be formed, in which the service specified in the compose file is launched:
Total
We got an asynchronous moxervice that satisfies the task at hand. The service is launched on a common server and is available to all project participants. At the moment, he helps us develop and test the application in the absence of a third-party system API.