ITENTIAL ADAPTERS TECHNICAL RESOURCE
Adapter Mock Data
Defining Mock Data in an Adapter
- Mock data represents the data that the external system will return on an API call. This data is stored in the adapter so that the adapter can use it to respond to API calls when running in ”stub” mode.
- Mock data can be captured in different ways. The Adapter Builder will extract it from Swagger if the responses are in the Swagger documentation. In addition, it can be captured using Postman, when you run the adapter that was built through integration tests (using isSaveMockData), or through the adapter logs if logging at the debug level.
- With mock data you can test the entire adapter (not just adapter.js) in standalone mode using the built-in integration tests that come with the adapter. These tests will run through the adapter and the adapter libraries up to the point where the API call is made, and then instead of making the call, the mock data will be returned. This capability allows you to test the full flow of data through the adapter, including translation.
- What mock data cannot test is true authentication, if the URL is correct, that the request data is accurate, or that the response is the most up-to-date response (although if you captured it then, it should be). Mock data is also not maintained. So as things change, your mock data may need to be updated.
Running an Adapter in Stub Mode
Mock Field Definitions
- Mock data is simply the response from the other system.
- It will typically be JSON, but it should match the datatype or responseDatatype that is defined in the action.json.
- In this example, all the fields are unique to the response and determined by the external system.
Mock Data
{
"data": {
"authentication": {
"authentication-method": [
{
"priority": 1,
"scope": "remote",
"statistics": {
"called": 2,
"failure": 3,
"skipped": 10,
"success": 10
},
"type": "tacacs"
}
]
}
}
}
- There is also an older format for mock data that allows you to put status information into the response (for testing purposes, i.e. errors).
- status: This field represents the status code that is returned from the other system. It is not part of the mock data.
- response: This is the object that will contain the mock data. Instead of just putting the mock data into the file, it should be added in the response object.
- Since mock data is not an actual HTTP response, it does not contain headers to specify information such as the status of the request. Therefore, including a status can be beneficial.
Mock Data
{
"status": 200,
"response": {
"allowDelete":true,
"alternateName":"string",
"dateAdded":0,
"description":"TESTING",
"disableConcurrentPolling":true,
"disablePolling":true,
"disableThresholding":true,
"id":1245,
"ipAddress":"10.10.10.1",
"isDeleted":true,
"isNew":true,
"lastDiscovery":0,
"name":"Michael1",
"numElements":0,
"pluginManagerId":0
}
}
Mock Data Usage & Examples
Defined in Action.Json
- For each action there is an array of responseObjects. These tell the adapter the various responses that are available for the action.
- The adapter has a hierarchy for determining which response to use for a request.
- responseObjects
- mockFile: This is used by the adapter libraries when running in stub mode (not integrated) to tell the adapter where the mock data that should be returned is located. It should be a file within the entity (generally all mock data files are in the mockdatafiles directory to prevent clutter in the base entity directory).
ACTION.JSON
{
"name": "getIP",
"protocol": "REST",
"method": "GET",
"entitypath": "{base_path}/{version}/addresses/{pathv1}",
"schema": "schema.json",
"timeout": 3000,
"datatype": "PLAIN",
"sendEmpty": true,
"headers": {},
"responseObjects": [
{
"type": "default",
"key": "",
"mockFile": "mockdatafiles/getIP-default.json"
}
]
},
Mock Data Files
- Mock data files should be in a place defined in the action.json.
- In the above example, a file should exist in: mockdatafiles/getIP-default.json.
Multiple Mock Data Files
The adapter has a hierarchy for determining which response to use for a request.
Mock data hierarchy:
- Match data in the body.
- Match data in a path variable.
- Match data in a query or option.
- If there is a body (withBody).
- If there is a path variable (withPathv#).
- If there is a query (withQuery).
- If there is an option (withOption).
- Otherwise default.
Note: The old mock data format will still work since #5-8 are effectively the old way.
- On a call with a body { name: ‘abc123’ } the a.json would be returned.
- On a call with a path variable – http://system:80/path/ver/addresses/error the b.json would be returned.
- On a call with a query variable – http://system:80/path/ver/addresses?name=happy the c.json would be returned.
ACTION.JSON
{
"name": "getIP",
"entitypath": "{base_path}/{version}/addresses/{pathv1}?{query}",
….
"responseObjects": [
{
"type": "name-abc123",
"key": "",
"mockFile": "a.json"
},
{
"type": "error",
"key": "",
"mockFile": "b.json"
},
{
"type": "name=happy",
"key": "",
"mockFile": "c.json"
}
]
},
- Can still support different mock data based on the URI structure:
- path variables (withPathv#)
- query (withQuery)
- On a call with a path variable – http://system:80/path/ver/addresses/abc123 the y.json is returned
- On a call with a query variable – http://system:80/path/ver/addresses?name=abc123 the z.json is returned.
- Otherwise the x.json is returned.
ACTION.JSON
{
"name": "getIP",
"entitypath": "{base_path}/{version}/addresses/{pathv1}?{query}",
….
"responseObjects": [
{
"type": "default",
"key": "",
"mockFile": "x.json"
},
{
"type": "withPathv1",
"key": "",
"mockFile": "y.json"
},
{
"type": "withQuery",
"key": "",
"mockFile": "z.json"
}
]
},
Capture Mock Data from Postman
This image illustrates the response body when mock data is captured using Postman.
Capture Mock Data from Test
- When the isSaveMockData flag is set to true (default is false) and the stub flag is set to false (default is true) in the adapterTestIntegration.js file, and you run a true integration test, it will make all API calls to the other system and save the responses into mock data files. It will also edit the appropriate action.json file so that the next time a call is made in standalone mode, it will return the new mock data.
- The saveMockData method is already in the individual calls built by the Adapter Builder. This method does not do anything unless the two flags are set properly.
ADAPTERTESTINTEGRATION.JS
const isSaveMockData = true;
const stub = false;
...
describe ('#createDeployment-errors', () => {
it('should work if integrated or standalone with mockdata', (done) => {
try {
a.createDeployment(apisApiId, apisCreateDeploymentBodyParam, null,
(data, error) => {
try {
runCommonAsserts(data, error);
if (stub) {
assert.equal('string', data.response.CreatedDate);
assert.equal('string', data.response.DeploymentId);
...
} else {
assert.equal('string', data.response.CreatedDate);
}
saveMockData('Apis', 'createDeployment', 'default', data);
done();
} catch (err) {
log.error(`Test Failure: ${err}`);
done(err);
}
});
} catch (error) {
log.error(`Adapter Exception: ${error}`);
done(error);
}
}).timeout(attemptTimeout);
});
- There is another property that is also in the request section – return_raw. This property makes the raw response from the other system available in the result that was returned. The saveMockData method will use this data if it is available since it has not been translated. In contrast, if you are using translation, saveMockData will save the translated response, and you will then need to edit the data and revert the translation.
ADAPTERTESTINTEGRATION.JS
return_raw: true,
...
describe ('#createDeployment-errors', () => {
it('should work if integrated or standalone with mockdata', (done) => {
try {
a.createDeployment(apisApiId, apisCreateDeploymentBodyParam, null,
(data, error) => {
try {
runCommonAsserts(data, error);
if (stub) {
assert.equal('string', data.response.CreatedDate);
assert.equal('string', data.response.DeploymentId);
...
} else {
assert.equal('string', data.response.CreatedDate);
}
saveMockData('Apis', 'createDeployment', 'default', data);
done();
} catch (err) {
log.error(`Test Failure: ${err}`);
done(err);
}
});
} catch (error) {
log.error(`Adapter Exception: ${error}`);
done(error);
}
}).timeout(attemptTimeout);
});
Capture Mock Data from Adapter Log
You need to have the adapter in debug mode in order to capture these logs. Then you can use these logs for mock data for future testing by storing the response part of the log into the mock data file for the specific call.
CALL RETURN – This is the full response prior to any JSON parsing.
ADAPTER LOGS
debug: Test-eai-connectorRest-makeRequest: CALL RETURN:
{"status":"success","code":201,"response":"{\n\"type\" :
\"oci/card\",\n\"id\" : 308,\n\"href\" :
\"oci/card/308\",\n\"transientAttributes\" : { },\n\"key\" :
{\n\"type\" : \"oci/cardKey\",\n\"keyValue\" : 308\n}\n}","redirects":0,"tripTime":"197ms"}
CALL RESPONSE –This is the response or a partial response after JSON parsing.
ADAPTER LOGS
debug: Test-eai-restHandler-handleRestRequest: RESPONSE:
{"type":"oci/card","id":308,"href":"oci/card/308","transientAttributes"
:{},"key" :{"type":"oci/cardKey","keyValue":308}}
Adapter Support
If you experience any problems or can’t figure out how to capture your mock data, don’t hesitate to contact us. The Itential Adapters Team is here to help!
- For help with mock data:
- Create a ticket (ISD, IPSO or ADAPT).
- You can work the ticket or allow the Itential Adapter Team to verify if your mock data was properly captured.
- Once all changes are made to your mock data files, update the adapter-utilsdependency in your adapter or run the adapterMigrator.
- To update your adapter-utilsdependency:
- Change the version in the package.jsondependencies.
- rm –rf node modules•rm package-lock.json
- npminstall