-
Notifications
You must be signed in to change notification settings - Fork 1
Back end code architecture and documentation
In this part, we will add documentation about back-end part of the tool, which contains Master and Slaves, these following will be documented :
- Overall code architecture description
- The presentation of the APIStatus file
- The Master-Slave Socket connection protocol
- The Master event sequence at startup
- The relations with front-end
- The code fragments
The back-end runs on NodeJS, an HTTP Server which contains an Express Application handling all endpoints and a Socket Server handling all real-time messages.

There are not many endpoints and socket events but enough to make Slaves and front-end working as the tool should.
When launched, there is a sequence of event occurring before the service is accessible :
- In case of crash/reboot instead of an initial boot, it is necessary to restore the state of Slaves and data used before this crash/reboot. The Master gather all the informations it was supposed to be aware of before its crash/restart in the APIStatus file which will be explained in the next part, but the main information would be :
- All API’s being tested, so it needs to gather informations about these API’s such as its general infos (name, etc)
- the Slaves currently testing an API and their state in the process of testing, so it needs to allow the Socket reconnection of these Slaves (explained below).
- Creation a new Express application so as to manage its endpoints for usage and handle requests.
- It enables CORS (required for Angular usage), the parsing of JSON in requests, etc…
- It creates all endpoints (see below for endpoints explanations)
- Embodiment of this created Express application in an HTTP Server.
- Creation of the socket server, with the HTTP Server, which, on connection, discriminates two type of connection :
- WebClient : Create a necessary connection which is necessary for Front-End Angular work.
- SlaveClient : Allow connection based on the name of the Slave.
- Start the HTTP Server.
The APIStatus file is the center of the tool, this is where all API's to be tested, results of test of these API's, etc...
This file is a list of these API. An API, in this context, is a dynamic object describing a real API and the progress of its testing.
An API is described as follows :
- A name, which is simple the baseUrl of the OpenAPI Specification file sent.
- A list of HTTP requests to be tested, which come directly from the list of operations present in the OpenAPI file
- The list of servers which are testing the API
- The results of Uptime tests.
- The OpenAPI Test Configuration
- The current progress of test which is the number of steps done since the beginning of the test, and its total progress which is the total number of steps.
As said, it's a dynamic object, it is initialized with the sending of an OpenAPI Specification file from the User, from this file, a Parser will be used in order to retrieve all the operations, and transform these as HTTP requests objects used by HTTP Request Sending libraries.
The transformation looks like this figure :
This is an OpenAPI Specification described operation :
"/pet": {
"post": {
"tags": [
"pet"
],
"summary": "Add a new pet to the store",
"description": "",
"operationId": "addPet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
},
}This is the corresponding HTTP Request object :
{
"operationId": "addPet",
"method": "post",
"headers": {
"Content-Type": "application/json"
},
"params": {},
"url": "https://petstore.swagger.io/v2/pet",
"data": {
"id": 0,
"category": {
"id": 0,
"name": "string"
},
"name": "doggie",
"photoUrls": [
"string"
],
"tags": [
{
"id": 0,
"name": "string"
}
],
"status": "available"
},
"testResults": {
"api-0-asia-northeast1-b-latency": {
"latencyRecords": [
{
"date": "2019-07-12T01:15:08.489+02:00",
"error": false,
"code": "500",
"latencyMs": 511.2
},
{
"date": "2019-07-13T07:21:03.747+02:00",
"error": false,
"code": "500",
"latencyMs": 1061.8
},
{
"date": "2019-07-13T17:18:06.078+02:00",
"error": false,
"code": "500",
"latencyMs": 850.1
}
],
"totalTest": 3,
"avgSuccess": 0.3333333333333333,
"meanLatency": "807.70",
"success": 0
}
}
}During the transformation, there is a determination of the parameters, we give value on the parameters we will use in the testing. This is dependent to the OpenAPITestConfiguration's parameter definition strategy (see OpenAPI Extension Proposal).
These HTTP Requests objects are also dynamic, as the process of testing progresses, it will be aggregated by Latency records.
This is the list of servers currently online and testing the API.
A Server gather all information in order to understand the current state of a Slave, to communicate with the cloud service provider, to see its progress in the process of testing the API.
See below an example :
{
"name": "api-0-asia-northeast1-b-latency",
"testType": "latency",
"executionType": "masterHandled",
"region": "asia-northeast1",
"zone": "asia-northeast1-b",
"location": "Tokyo, Japan",
"status": "Test failed, please delete this configuration and create a new one.",
"state": "testing",
"substate": "waiting",
"progress": 51,
"totalProgress": 8500,
"repetitionsRemaining": 497
}The test results are all the records measured by the Slaves, the Uptime results are located at the root of the API object, as in the OpenAPI Extension Proposal. The Latency results are located in each HTTP Request object they belong to.
This is directly linked to the OpenAPI Extension Proposal. The only difference if this one is that this is what directly comes from the Angular application :
"testConfig": {
"latency": {
"repetitions": 1000,
"interval": {
"iso8601format": "PT1H"
},
"dp-hours": "01",
"timeoutThreshold": 10000,
"zones": [
"asia-east2",
"asia-northeast2",
"europe-west4"
],
"parameterDefinitionStrategy": "provided"
},
"uptime": {
"repetitions": 5000,
"interval": {
"iso8601format": "PT10M"
},
"dp-minutes": "010",
"zones": [
"europe-north1",
"europe-west2",
"us-east4"
],
"timeoutThreshold": 10000
}
}This object is transformed before the export.
The Master-Slave protocol ensure reliability in the Socket connection between those two actors, the Master and the Slave.
This is directly linked to the notion of State and Substate of a Slave. But there are two case of study for this protocol :
- In a usual case, the Master runs, and a Slave is being created and tests an API. This case has already been seen in the What is a Slave section.
- When the Master crashes and proceeds to a reboot.
- When a SlaveHandled Slave crashes and has to reboot. This part needs to be finished.
During its execution, the Master keeps in memory the state of every Slaves. When the Master crashes, the Socket connection between the two is lost, resulting in a Slave trying to reconnect indefinitely while continuing its test process. When a record occur, the Slave directly sends the result to the Master, if it is disconnected, it will store the result in cache and continue its testing.
Once the Master is back up online, it reads again all the APIStatus file, restoring all Slaves with each state and add each one to a 'disconnected slaves' Map. The Socket Server is turn back on, the Slave trying to reconnect since disconnection finally connects to the Master. The Master, because the Slave is part of 'disconnected slaves', at the connection, send the 'reconnection' event to the Slave. When receiving a 'reconnection' event, the Slave searching in its cache for unsent results and send all of them sequentially. From there, everything is back normal.
Here is a figure explaining the sequential events of this case :
In overall, the tool manages a list of API’s to be tested, display these in a dashboard while testing it in background, then allow the export of these results to the User. The Master program is composed of :
- The
APIStatusfolder which contains : - The
APIStatus.jsonfile which contains all current tested API’s data.- The functions used to access or edit these data.
- The
ExpressManagementfolder which contains :- The public folder contains the Angular compiled application.
- expressCreation is the file containing all the functions used for the Master start up.
-
expressEndpoint.jsis the file managing the express endpoints. For example, the behavior of the ‘/OpenAPI’ endpoint is described in this file.
- The
GoogleCloudManagementfolder which contains :- The functions to interact with Google Cloud Platform API for instance creation and management.
- The
GCPKeyFile.jsonfile which contains all the private keys to use the GCP API. - The
regionList.jsonfile which lists all the datacenters of GCP with the location, region and zone names.
- The
Parsersfolder which contains :- The OpenAPI JSON parser for parsing JSON OpenAPI Specifications file. This parser transforms all API’s operation into an HTTP Request Object, necessary for the tests which gathers method, parameters, headers information.
- The PetStore parser, which does the same as OpenAPI JSON parser, but has hardcoded parameters value, for development purposes (as for FakeAPIParser).
- The
SocketServerManagementfolder which contains :-
socketServerCreation.jswhich gathers the server creation and the ‘on client connection’ discrimination (WebClient and SlaveClient, explained later). -
socketServerSlaveManagement.jswhich contains all functions managing the Slave connection events (to be explained in a specific part) -
socketServerWebClientManagement.jswhich contains all functions managing the WebClient connection events :-
APIStatus: Send the APIStatus data to the client -
deleteAPI: Delete the API and all the Slaves currently testing it -
openApiTestConfig: Receive a new OpenAPI Test Configuration, store it, create the Slaves and wait them to connect.
-
-
The Slave program is, briefly, the program which connects to the Master, waits for test information, execute the tests, and then shuts down.
For the first version of the OpenAPI Extension Proposal, only two non-functional properties are tested : Latency and Uptime.
Here is a description of these two type of test.
The Latency test, according to the OpenAPI Extension Proposal, is the calculation of the time between the sending of a request to a certain operation and the return of the response.
The Slave will test the Latency of an API by requesting sequentially all its operations with the parameters and data decided by the Master. In fact, the Slave just get an object ready to be used by the HTTP NodeJS library.
The Uptime test, according to the OpenAPI Extension Proposal, is the determination whether an API is available or not to handle requests. The Slave will test Uptime of an API by sending this OPTIONS request where :
- The
openapihostis thehostparameter in the OpenAPI Specification file - The
openapibasepathis thebasePathparameter in the OpenAPI Specification file
OPTIONS / HTTP/1.1
Host: https://openapihost/openapibasepath
Content-Type: application/json; charset=utf-8If the request gets a response before the timeoutThreshold, then the Slaves send a true value to the Master, false otherwise.
Because of the existence of two execution type (SlaveHandled and MasterHandled slaves), there is a 'single' version of these two tests and a 'multiple' version one.
The 'single' version is simply the previous described test.
The 'multiple' version encompass the 'single' version by launching it the number of time the OpenAPITestConfiguration repetition parameter of the said test indicates it. Between each repetition, a timer is launched for a duration of the interval parameter of the test in the OpenAPITestConfiguration.
A repetition is the fact of running a 'single' version of a test, but inside a test, there can be multiple records. See below the figure which show the succession of event sent from the Slaves to the Master.
