Unverified Commit b3e0ef86 authored by Dan Jones's avatar Dan Jones
Browse files

test: add poll and publish tests

+ refactor cucumber step functions into test folder
+ rename features after tested adapter methods
+ refactor adapter.validate to call adapter.protocol.validate
parent 1ff6f48a
module.exports = {
default: `--format-options '{"snippetInterface": "synchronous"}'`
}
\ No newline at end of file
default: {
formatOptions: {
snippetInterface: "synchronous"
},
paths: [ 'features/**/*.feature' ],
require: [ 'test/cucumber/**/*.steps.js' ],
},
};
import Validator from 'swagger-model-validator';
import axios from 'axios';
/**
......@@ -9,7 +8,6 @@ class Adapter {
this.protocol = protocol;
this.config = config;
this.axios = axios;
this.validator = new Validator(protocol.schema);
}
/**
......@@ -25,13 +23,7 @@ class Adapter {
* @returns {object}
*/
validate(message) {
return this.validator.validate(
message,
this.protocol.schema.components.schemas.Message,
this.protocol.schema.components.schemas,
false,
true
);
return this.protocol.validate(message);
}
/**
......@@ -113,8 +105,7 @@ class Adapter {
return response;
})
.catch((error) => {
console.error(error);
return Promise.reject(error.response);
return Promise.reject(error);
});
}
......@@ -145,7 +136,7 @@ class Adapter {
return response;
})
.catch((error) => {
return Promise.reject(error.response);
return Promise.reject(error);
});
}
......@@ -178,7 +169,7 @@ class Adapter {
return response;
})
.catch((error) => {
return Promise.reject(error.response);
return Promise.reject(error);
});
}
}
......
'use strict';
var Validator = require('swagger-model-validator');
var axios = require('axios');
/**
......@@ -11,7 +10,6 @@ class Adapter {
this.protocol = protocol;
this.config = config;
this.axios = axios;
this.validator = new Validator(protocol.schema);
}
/**
......@@ -27,13 +25,7 @@ class Adapter {
* @returns {object}
*/
validate(message) {
return this.validator.validate(
message,
this.protocol.schema.components.schemas.Message,
this.protocol.schema.components.schemas,
false,
true
);
return this.protocol.validate(message);
}
/**
......@@ -115,8 +107,7 @@ class Adapter {
return response;
})
.catch((error) => {
console.error(error);
return Promise.reject(error.response);
return Promise.reject(error);
});
}
......@@ -147,7 +138,7 @@ class Adapter {
return response;
})
.catch((error) => {
return Promise.reject(error.response);
return Promise.reject(error);
});
}
......@@ -180,7 +171,7 @@ class Adapter {
return response;
})
.catch((error) => {
return Promise.reject(error.response);
return Promise.reject(error);
});
}
}
......
......@@ -37,8 +37,8 @@ class GenericProtocol {
validate(message) {
return this.validator.validate(
message,
this.protocol.schema.components.schemas.Message,
this.protocol.schema.components.schemas,
this.schema.components.schemas.Message,
this.schema.components.schemas,
false,
true
);
......
......@@ -39,8 +39,8 @@ class GenericProtocol {
validate(message) {
return this.validator.validate(
message,
this.protocol.schema.components.schemas.Message,
this.protocol.schema.components.schemas,
this.schema.components.schemas.Message,
this.schema.components.schemas,
false,
true
);
......
......@@ -9,7 +9,7 @@ Feature: Can the adapter receive messages?
Given valid config
When the adapter instance is created
When the auth method is called
When the queue contains 0 messages
When a mock receive API response is configured to return 0 messages
When the poll method is called
Then a successful response is returned with 0 messages
......@@ -17,14 +17,26 @@ Feature: Can the adapter receive messages?
Given valid config
When the adapter instance is created
When the auth method is called
When the queue contains 2 messages
When a mock receive API response is configured to return 2 messages
When the poll method is called
Then a successful response is returned with 2 messages
Then the protocol "validate" method is called 2 times
Then the protocol "decode" method is called 2 times
Scenario: 10 messages are received succecssfully if the queue contains 10 messages
Given valid config
When the adapter instance is created
When the auth method is called
When the queue contains 10 messages
When a mock receive API response is configured to return 10 messages
When the poll method is called
Then a successful response is returned with 10 messages
Then the protocol "validate" method is called 10 times
Then the protocol "decode" method is called 10 times
Scenario: An invalid token returns a forbidden response
Given valid config
When the adapter instance is created
When the auth method is called
When a mock receive API response is configured to return an error
When the poll method is called
Then an error response is returned with status 403
Feature: Can the adapter publish messages?
The adapter publish method works as expected
Scenario: A message can be published successfully
Given valid config
When the adapter instance is created
When the auth method is called
When a mock send API response is configured to return success
When the publish method is called
Then a successful response is returned with status 200
Scenario: A failed publish returns a 403
Given valid config
When the adapter instance is created
When the auth method is called
When a mock send API response is configured to return an error
When the publish method is called
Then an error response is returned with status 403
......@@ -23,7 +23,8 @@
"lint": "yarn lint:js && yarn lint:prettier",
"lintfix": "prettier --write --list-different . && yarn lint:js --fix",
"prepare": "husky install",
"test": "yarn build && yarn cucumber-js",
"test": "yarn build && yarn cucumber",
"cucumber": "cucumber-js",
"build": "cross-env NODE_ENV=production rollup -c"
},
"lint-staged": {
......
import Validator from 'swagger-model-validator';
import axios from 'axios';
/**
......@@ -9,7 +8,6 @@ export class Adapter {
this.protocol = protocol;
this.config = config;
this.axios = axios;
this.validator = new Validator(protocol.schema);
}
/**
......@@ -25,13 +23,7 @@ export class Adapter {
* @returns {object}
*/
validate(message) {
return this.validator.validate(
message,
this.protocol.schema.components.schemas.Message,
this.protocol.schema.components.schemas,
false,
true
);
return this.protocol.validate(message);
}
/**
......@@ -113,8 +105,7 @@ export class Adapter {
return response;
})
.catch((error) => {
console.error(error);
return Promise.reject(error.response);
return Promise.reject(error);
});
}
......@@ -145,7 +136,7 @@ export class Adapter {
return response;
})
.catch((error) => {
return Promise.reject(error.response);
return Promise.reject(error);
});
}
......@@ -178,7 +169,7 @@ export class Adapter {
return response;
})
.catch((error) => {
return Promise.reject(error.response);
return Promise.reject(error);
});
}
}
......@@ -37,8 +37,8 @@ export class GenericProtocol {
validate(message) {
return this.validator.validate(
message,
this.protocol.schema.components.schemas.Message,
this.protocol.schema.components.schemas,
this.schema.components.schemas.Message,
this.schema.components.schemas,
false,
true
);
......
const assert = require('assert');
const { Given, When, Then } = require('@cucumber/cucumber');
const { fixtures } = require('../../fixtures/server');
const mockValidConfig = fixtures.get('config-valid');
const mockInvalidConfig = fixtures.get('config-invalid');
const mockSchema = require('../../mock/swagger.json');
const { Adapter } = require('../../../dist/adapter');
Given('valid config', function() {
this.config = mockValidConfig
});
When('the adapter instance is created', function() {
//let mockProtocol = new GenericProtocol(this.schema);
let mockAdapter = new Adapter(this.protocol, this.config);
this.adapter = mockAdapter;
});
When('the auth method is called', async function() {
await this.adapter.auth();
});
Then('the adapter credentials are populated', function() {
assert.equal(this.adapter.credentials.token, fixtures.get('response-valid-token').token);
});
Given('invalid config', function() {
this.schema = mockSchema;
this.config = mockInvalidConfig;
});
Then('the adapter auth fails', function() {
this.adapter.auth()
.catch((error) => {
assert.equal(error.response.status, 403);
});
});
\ No newline at end of file
const assert = require('assert');
const { Before, Given, When, Then } = require('@cucumber/cucumber');
const { Before } = require('@cucumber/cucumber');
const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
......@@ -7,24 +7,64 @@ const MockAdapter = require("axios-mock-adapter");
// This sets the mock adapter on the default instance
const mockAxios = new MockAdapter(axios);
const { fixtures } = require('../../test/fixtures/server');
const { fixtures } = require('../../fixtures/server');
const mockValidConfig = fixtures.get('config-valid');
const mockInvalidConfig = fixtures.get('config-invalid');
const mockSchema = require('../../test/mock/swagger.json');
const { Adapter } = require('../../dist/adapter');
const { GenericProtocol } = require('../../dist/protocol');
const mockSchema = require('../../mock/swagger.json');
const { GenericProtocol } = require('../../../dist/protocol');
/**
* Use assert.CallTracker to track internal method calls
* Instead of adding trackers to each method, create a
* single tracked stub function and then use the parameters
* to record what is being tracked.
*/
const tracker = new assert.CallTracker();
const trackedFunction = function(method, params) {
// do nothing;
};
const recorder = tracker.calls(trackedFunction);
let decodeTracker;
class TrackedGenericProtocol extends GenericProtocol {
decode() {
return super.decode()
constructor(schema, services) {
super(schema, services);
this.recorder = services.recorder;
this.tracker = services.tracker;
}
encode(type, message) {
this.recorder('encode', {type, message});
return super.encode(type, message)
}
decode(type, message) {
this.recorder('decode', {type, message});
return super.decode(type, message)
}
validate(message) {
this.recorder('validate', {message});
return super.validate(message);
}
getTrackedCalls(method) {
let calls = this.tracker.getCalls(this.recorder);
let methodCalls = calls.filter(call => call.arguments[0] === method);
return methodCalls;
}
resetTracker() {
this.tracker.reset();
}
}
Before(function() {
this.schema = mockSchema;
this.tracker = tracker;
this.recorder = recorder;
let services = {
recorder: this.recorder,
tracker: this.tracker
};
this.protocol = new TrackedGenericProtocol(this.schema, services);
this.protocol.resetTracker();
this.mockAxios = mockAxios;
this.mockAxios.reset();
......@@ -38,35 +78,4 @@ Before(function() {
{ params: { client_id: mockInvalidConfig.client_id, secret: mockInvalidConfig.secret } }
).reply(403, fixtures.get('response-denied-token'));
});
Given('valid config', function() {
this.schema = mockSchema;
this.config = mockValidConfig
});
When('the adapter instance is created', function() {
let mockProtocol = new GenericProtocol(this.schema);
let mockAdapter = new Adapter(mockProtocol, this.config);
this.adapter = mockAdapter;
});
When('the auth method is called', async function() {
await this.adapter.auth();
});
Then(('the adapter credentials are populated'), function() {
assert.equal(this.adapter.credentials.token, fixtures.get('response-valid-token').token);
});
Given('invalid config', function() {
this.schema = mockSchema;
this.config = mockInvalidConfig;
});
Then('the adapter auth fails', async function() {
this.adapter.auth()
.catch((error) => {
assert.equal(error.response.status, 403);
});
});
\ No newline at end of file
const assert = require('assert');
const { Before, Given, When, Then } = require('@cucumber/cucumber');
const { When, Then } = require('@cucumber/cucumber');
const { fixtures } = require('../../test/fixtures/server');
const { fixtures } = require('../../fixtures/server');
const mockValidConfig = fixtures.get('config-valid');
......@@ -17,20 +17,38 @@ const xMessageResponse = function(xMessages) {
return response;
};
When('the queue contains {int} messages', function(xMessages) {
When('a mock receive API response is configured to return {int} messages', function(xMessages) {
const response = xMessageResponse(xMessages);
this.mockAxios.onGet(
`${mockValidConfig.api}/receive`,
).reply(200, response);
});
When('the poll method is called', async function() {
this.messages = await this.adapter.poll()
.then((response) => {
return response.data;
});
When('a mock receive API response is configured to return an error', function() {
this.mockAxios.onGet(
`${mockValidConfig.api}/receive`,
).reply(403, { message: 'Token expired' })
});
When('the poll method is called', function() {
this.call = this.adapter.poll();
});
Then('a successful response is returned with {int} messages', function(xMessages) {
assert.equal(this.messages.length, xMessages);
});
\ No newline at end of file
this.call
.then(response => {
assert.equal(response.data.length, xMessages);
});
});
Then('the protocol {string} method is called {int} times', function(method, xInvokes) {
const decodes = this.protocol.getTrackedCalls(method);
assert.equal(decodes.length, xInvokes);
});
Then('an error response is returned with status {int}', function(expectedStatus) {
this.call
.catch((error) => {
assert.equal(error.response.status, expectedStatus);
});
});
const assert = require('assert');
const { When, Then } = require('@cucumber/cucumber');
const { fixtures } = require('../../fixtures/server');
const mockValidConfig = fixtures.get('config-valid');
When('a mock send API response is configured to return success', function() {
const response = {};
this.mockAxios.onPost(
`${mockValidConfig.api}/send`,
).reply(200, response);
});
When('a mock send API response is configured to return an error', function() {
this.mockAxios.onPost(
`${mockValidConfig.api}/send`,
).reply(403, { message: 'Token expired' })
});
When('the publish method is called', function() {
const message = fixtures.get('message-vehicle-status');
this.message = message;
const topic = message.metadata.destination;
const body = JSON.stringify(message);
this.call = this.adapter.publish(topic, body);
});
Then('a successful response is returned with status {int}', function(expectedStatus) {
this.call
.then(response => {
assert.equal(response.status, expectedStatus);
});
});
\ No newline at end of file
const assert = require('assert');
const { Before, Given, When, Then } = require('@cucumber/cucumber');
const { Given, When, Then } = require('@cucumber/cucumber');
const { fixtures } = require('../../test/fixtures/server');
const { fixtures } = require('../../fixtures/server');
Given('a valid message', function() {
this.message = fixtures.get('message-vehicle-status');
......
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