Commit 80607371 authored by Dan Jones's avatar Dan Jones
Browse files

Merge branch '20-sort-out-linting-config' into 'dev'

Resolve "Sort out linting config"

Closes #20

See merge request !13
parents a8e98ce4 b9dfcc49
...@@ -3,24 +3,19 @@ module.exports = { ...@@ -3,24 +3,19 @@ module.exports = {
env: { env: {
browser: true, browser: true,
node: true, node: true,
'jest/globals': true, es6: true,
}, },
parserOptions: { parserOptions: {
parser: '@babel/eslint-parser', parser: '@babel/eslint-parser',
// Fix "No Babel config file detected for [file]" error sourceType: 'module',
// https://github.com/babel/babel/issues/11975#issuecomment-786803214
requireConfigFile: false, requireConfigFile: false,
ecmaVersion: 'latest',
}, },
extends: [ extends: ['eslint:recommended', 'plugin:prettier/recommended'],
'eslint:recommended', ignorePatterns: ['**/dist/'],
'prettier',
],
// required to lint *.vue files
plugins: ['vue', 'jest', 'prettier'],
// add your custom rules here // add your custom rules here
rules: { rules: {
'no-console': ['warn', { allow: ['warn', 'error'] }], 'no-console': ['error', { allow: ['warn', 'error'] }],
'no-debugger': 'warn',
'no-unused-vars': ['error', { args: 'none' }], 'no-unused-vars': ['error', { args: 'none' }],
}, },
}; };
### # Ignore artifacts:
# Place your Prettier ignore content here **/dist/
**/*.esm.js
### **/*.ssr.js
# .gitignore content is duplicated here due to https://github.com/prettier/prettier/issues/8506 **/*.min.js
**/.nyc-output/
# Created by .ignore support plugin (hsz.mobi) **/.nuxt/
### Node template **/.turbo/
# Logs \ No newline at end of file
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# IDE / Editor
.idea
# macOS
.DS_Store
# Vim swap files
*.swp
{
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"bracketSameLine": false,
"arrowParens": "always",
"endOfLine": "lf"
}
module.exports = {
trailingComma: 'es5',
tabWidth: 2,
useTabs: false,
semi: true,
singleQuote: true,
bracketSameLine: false,
arrowParens: 'always',
endOfLine: 'lf',
};
...@@ -4,4 +4,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of ...@@ -4,4 +4,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
# backbone-adapter-javascript # backbone-adapter-javascript
Generic adapter for the communications-backbone. Generic adapter for the communications-backbone.
Implements: Implements:
- client credentials grant - client credentials grant
- http send/receive/notify to backbone - http send/receive/notify to backbone
- websockets send and receive - websockets send and receive
- validation of messages against a specified OpenAPI schema - validation of messages against a specified OpenAPI schema
- decode/encode stubs - decode/encode stubs
## Setup ## Setup
``` ```
yarn install yarn install
...@@ -18,27 +18,27 @@ yarn install ...@@ -18,27 +18,27 @@ yarn install
yarn copytests yarn copytests
``` ```
## Test ## Test
The tests are written in [cucumber](https://cucumber.io/docs/installation/javascript/) The tests are written in [cucumber](https://cucumber.io/docs/installation/javascript/)
This means we can have a common suite of [gherkin](https://github.com/cucumber/gherkin) This means we can have a common suite of [gherkin](https://github.com/cucumber/gherkin)
tests across adapter ports written in multiple languages. tests across adapter ports written in multiple languages.
``` ```
yarn test yarn test
``` ```
## Installing in your project ## Installing in your project
We may publish this to a public registry but for now you need to install the package We may publish this to a public registry but for now you need to install the package
from git. from git.
### Requirements ### Requirements
An `axios` library. Axios is included as a dev dependency to run the tests. An `axios` library. Axios is included as a dev dependency to run the tests.
I've not installed it as a runtime dependency because in nuxt you need to I've not installed it as a runtime dependency because in nuxt you need to
use `@nuxtjs/axios` instead. use `@nuxtjs/axios` instead.
**TODO fix this in rollup config** **TODO fix this in rollup config**
...@@ -54,15 +54,15 @@ yarn add git+https://git.noc.ac.uk/communications-backbone-system/backbone-adapt ...@@ -54,15 +54,15 @@ yarn add git+https://git.noc.ac.uk/communications-backbone-system/backbone-adapt
npm install git+https://git.noc.ac.uk/communications-backbone-system/backbone-adapter-javascript.git npm install git+https://git.noc.ac.uk/communications-backbone-system/backbone-adapter-javascript.git
``` ```
## Schema ## Schema
The example code uses a mock schema with some example messages. The intention is the message The example code uses a mock schema with some example messages. The intention is the message
protocol schema is retreived from an external source. protocol schema is retreived from an external source.
## Config ## Config
To run the adapter you need a credentials file called `soar-config.json`. To run the adapter you need a credentials file called `soar-config.json`.
This will be provided by the backbone operator or requested via the API. This will be provided by the backbone operator or requested via the API.
```json ```json
{ {
...@@ -74,44 +74,44 @@ This will be provided by the backbone operator or requested via the API. ...@@ -74,44 +74,44 @@ This will be provided by the backbone operator or requested via the API.
} }
``` ```
### Topics ### Topics
When sending messages you should publish them using a topic matching [this definition](https://git.noc.ac.uk/communications-backbone-system/backbone-message-format#topics). When sending messages you should publish them using a topic matching [this definition](https://git.noc.ac.uk/communications-backbone-system/backbone-message-format#topics).
## Encoding and decoding ## Encoding and decoding
### Decoding ### Decoding
Decoding refers to translation from the backbone message protocol into a Decoding refers to translation from the backbone message protocol into a
native format for the client app to process. native format for the client app to process.
All messages received from the backbone are parsed and validated against the All messages received from the backbone are parsed and validated against the
protocol schema and then passed to the protocol decode function. protocol schema and then passed to the protocol decode function.
By overriding the decode function the client can define local actions to be By overriding the decode function the client can define local actions to be
executed when a message of a given type is received. executed when a message of a given type is received.
### Encoding ### Encoding
Encoding refers to translation from the client app's native format into a Encoding refers to translation from the client app's native format into a
message conforming to the backbone message protocol. message conforming to the backbone message protocol.
The equivalent encode method allows the client to define translations per The equivalent encode method allows the client to define translations per
message type to transform local data into a message conforming to the message type to transform local data into a message conforming to the
protocol schema for transmission. protocol schema for transmission.
Messages passed to the publish and broadcast methods should have been Messages passed to the publish and broadcast methods should have been
encoded and validated against the protocol schema. encoded and validated against the protocol schema.
## Publish vs Broadcast ## Publish vs Broadcast
It is intended that all normal-operation messages will be published on It is intended that all normal-operation messages will be published on
a given topic allowing clients to choose which message topics to a given topic allowing clients to choose which message topics to
subscribe to. subscribe to.
Broadcast is provided for contingency scenarios. The intention is that Broadcast is provided for contingency scenarios. The intention is that
in the case of a failure/abort a message can be sent to all parties in the case of a failure/abort a message can be sent to all parties
which bypasses any existing messages in the publish queue. which bypasses any existing messages in the publish queue.
The client implementation can chose to take no-action on decoding one of The client implementation can chose to take no-action on decoding one of
these messages but they will be made available to all clients. these messages but they will be made available to all clients.
module.exports = { module.exports = {
default: { default: {
formatOptions: { formatOptions: {
snippetInterface: "synchronous" snippetInterface: 'synchronous',
}, },
paths: [ 'test/features/**/*.feature' ], paths: ['test/features/**/*.feature'],
require: [ 'test/cucumber/**/*.steps.js' ], require: ['test/cucumber/**/*.steps.js'],
}, },
}; };
...@@ -12,14 +12,14 @@ class Adapter { ...@@ -12,14 +12,14 @@ class Adapter {
/** /**
* Test parsing the message based on the provided protocol schema * Test parsing the message based on the provided protocol schema
* *
* The message must be successfully json decoded into an object * The message must be successfully json decoded into an object
* prior to validation * prior to validation
* *
* At present this returns the validation result which is an * At present this returns the validation result which is an
* object containing a boolean valid field as well as details * object containing a boolean valid field as well as details
* of any errors. * of any errors.
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
validate(message) { validate(message) {
...@@ -81,12 +81,12 @@ class Adapter { ...@@ -81,12 +81,12 @@ class Adapter {
/** /**
* Call the GET /receive endpoint and process the messages with decode * Call the GET /receive endpoint and process the messages with decode
* *
* Returns the response * Returns the response
* @param {boolean} is_retry * @param {boolean} is_retry
* @returns {object} * @returns {object}
*/ */
poll(is_retry=false) { poll(is_retry = false) {
let adapterConfig = this.config; let adapterConfig = this.config;
return this.getAuthorizationHeader() return this.getAuthorizationHeader()
.then((headers) => { .then((headers) => {
...@@ -109,11 +109,13 @@ class Adapter { ...@@ -109,11 +109,13 @@ class Adapter {
}) })
.catch((error) => { .catch((error) => {
let retry = false; let retry = false;
switch(error.response.status) { switch (error.response.status) {
case 403: { case 403:
this.credentials = null; {
retry = true; this.credentials = null;
} break; retry = true;
}
break;
case 503: { case 503: {
retry = true; retry = true;
} }
...@@ -124,15 +126,15 @@ class Adapter { ...@@ -124,15 +126,15 @@ class Adapter {
} }
/** /**
* Publish a message to the backbone with the specified topic * Publish a message to the backbone with the specified topic
* *
* Messages should be passed through encode before sending * Messages should be passed through encode before sending
* @param {string} topic * @param {string} topic
* @param {string} body * @param {string} body
* @param {boolean} is_retry * @param {boolean} is_retry
* @returns * @returns
*/ */
publish(topic, body, is_retry=false) { publish(topic, body, is_retry = false) {
let adapterConfig = this.config; let adapterConfig = this.config;
return this.getAuthorizationHeader() return this.getAuthorizationHeader()
.then((headers) => { .then((headers) => {
...@@ -152,11 +154,13 @@ class Adapter { ...@@ -152,11 +154,13 @@ class Adapter {
}) })
.catch((error) => { .catch((error) => {
let retry = false; let retry = false;
switch(error.response.status) { switch (error.response.status) {
case 403: { case 403:
this.credentials = null; {
retry = true; this.credentials = null;
} break; retry = true;
}
break;
case 503: { case 503: {
retry = true; retry = true;
} }
...@@ -168,17 +172,17 @@ class Adapter { ...@@ -168,17 +172,17 @@ class Adapter {
/** /**
* Broadcast the message on the backbone * Broadcast the message on the backbone
* *
* Broadcast messages bypass the normal publisher queues * Broadcast messages bypass the normal publisher queues
* this means they can be used to deliver messages more * this means they can be used to deliver messages more
* quickly in an emergency scenario. * quickly in an emergency scenario.
* *
* Messages should be passed through encode before sending * Messages should be passed through encode before sending
* @param {string} body * @param {string} body
* @param {boolean} is_retry * @param {boolean} is_retry
* @returns * @returns
*/ */
broadcast(body, is_retry=false) { broadcast(body, is_retry = false) {
let adapterConfig = this.config; let adapterConfig = this.config;
return this.getAuthorizationHeader() return this.getAuthorizationHeader()
.then((headers) => { .then((headers) => {
...@@ -197,11 +201,13 @@ class Adapter { ...@@ -197,11 +201,13 @@ class Adapter {
}) })
.catch((error) => { .catch((error) => {
let retry = false; let retry = false;
switch(error.response.status) { switch (error.response.status) {
case 403: { case 403:
this.credentials = null; {
retry = true; this.credentials = null;
} break; retry = true;
}
break;
case 503: { case 503: {
retry = true; retry = true;
} }
......
...@@ -14,14 +14,14 @@ class Adapter { ...@@ -14,14 +14,14 @@ class Adapter {
/** /**
* Test parsing the message based on the provided protocol schema * Test parsing the message based on the provided protocol schema
* *
* The message must be successfully json decoded into an object * The message must be successfully json decoded into an object
* prior to validation * prior to validation
* *
* At present this returns the validation result which is an * At present this returns the validation result which is an
* object containing a boolean valid field as well as details * object containing a boolean valid field as well as details
* of any errors. * of any errors.
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
validate(message) { validate(message) {
...@@ -83,12 +83,12 @@ class Adapter { ...@@ -83,12 +83,12 @@ class Adapter {
/** /**
* Call the GET /receive endpoint and process the messages with decode * Call the GET /receive endpoint and process the messages with decode
* *
* Returns the response * Returns the response
* @param {boolean} is_retry * @param {boolean} is_retry
* @returns {object} * @returns {object}
*/ */
poll(is_retry=false) { poll(is_retry = false) {
let adapterConfig = this.config; let adapterConfig = this.config;
return this.getAuthorizationHeader() return this.getAuthorizationHeader()
.then((headers) => { .then((headers) => {
...@@ -111,11 +111,13 @@ class Adapter { ...@@ -111,11 +111,13 @@ class Adapter {
}) })
.catch((error) => { .catch((error) => {
let retry = false; let retry = false;
switch(error.response.status) { switch (error.response.status) {
case 403: { case 403:
this.credentials = null; {
retry = true; this.credentials = null;
} break; retry = true;
}
break;
case 503: { case 503: {
retry = true; retry = true;
} }
...@@ -126,15 +128,15 @@ class Adapter { ...@@ -126,15 +128,15 @@ class Adapter {
} }
/** /**
* Publish a message to the backbone with the specified topic * Publish a message to the backbone with the specified topic
* *
* Messages should be passed through encode before sending * Messages should be passed through encode before sending
* @param {string} topic * @param {string} topic
* @param {string} body * @param {string} body
* @param {boolean} is_retry * @param {boolean} is_retry
* @returns * @returns
*/ */
publish(topic, body, is_retry=false) { publish(topic, body, is_retry = false) {
let adapterConfig = this.config; let adapterConfig = this.config;
return this.getAuthorizationHeader() return this.getAuthorizationHeader()
.then((headers) => { .then((headers) => {
...@@ -154,11 +156,13 @@ class Adapter { ...@@ -154,11 +156,13 @@ class Adapter {
}) })
.catch((error) => { .catch((error) => {
let retry = false; let retry = false;
switch(error.response.status) { switch (error.response.status) {
case 403: { case 403:
this.credentials = null; {
retry = true; this.credentials = null;
} break; retry = true;
}
break;
case 503: { case 503: {
retry = true; retry = true;
} }
...@@ -170,17 +174,17 @@ class Adapter { ...@@ -170,17 +174,17 @@ class Adapter {
/** /**
* Broadcast the message on the backbone * Broadcast the message on the backbone
* *
* Broadcast messages bypass the normal publisher queues * Broadcast messages bypass the normal publisher queues
* this means they can be used to deliver messages more * this means they can be used to deliver messages more
* quickly in an emergency scenario. * quickly in an emergency scenario.
* *
* Messages should be passed through encode before sending * Messages should be passed through encode before sending
* @param {string} body * @param {string} body
* @param {boolean} is_retry * @param {boolean} is_retry
* @returns * @returns
*/ */
broadcast(body, is_retry=false) { broadcast(body, is_retry = false) {
let adapterConfig = this.config; let adapterConfig = this.config;
return this.getAuthorizationHeader() return this.getAuthorizationHeader()
.then((headers) => { .then((headers) => {
...@@ -199,11 +203,13 @@ class Adapter { ...@@ -199,11 +203,13 @@ class Adapter {
}) })
.catch((error) => { .catch((error) => {
let retry = false; let retry = false;
switch(error.response.status) { switch (error.response.status) {
case 403: { case 403:
this.credentials = null; {
retry = true; this.credentials = null;
} break; retry = true;
}
break;
case 503: { case 503: {
retry = true; retry = true;
} }
......
...@@ -3,25 +3,25 @@ import Validator from 'swagger-model-validator'; ...@@ -3,25 +3,25 @@ import Validator from 'swagger-model-validator';
/** /**
* GenericProtocol defines a simple passthru handler for messages * GenericProtocol defines a simple passthru handler for messages
* This can be extended to handle different schemas * This can be extended to handle different schemas
* *
* The assumption is that all messages conform to a single * The assumption is that all messages conform to a single
* wrapper schema definition. Different payloads are handled * wrapper schema definition. Different payloads are handled
* by a oneOf definitions within the schema determined by a * by a oneOf definitions within the schema determined by a
* field value. * field value.
* *
* This class can be extended and overridden to handle * This class can be extended and overridden to handle
* different schemas and to implement the client specific * different schemas and to implement the client specific
* logic related to be executed when invoked for a given * logic related to be executed when invoked for a given
* message type. * message type.
* *
* By default encode and decode are just passthru stubs * By default encode and decode are just passthru stubs
* *
* decode is invoked when receiving a message from the backbone * decode is invoked when receiving a message from the backbone
* encode is invoked before delivering a message to the backbone * encode is invoked before delivering a message to the backbone
* *
* The intention is that these allow you to transform the message * The intention is that these allow you to transform the message
* and call invoke internal functions and services as required * and call invoke internal functions and services as required
*/ */
class GenericProtocol { class GenericProtocol {
constructor(schema, services) { constructor(schema, services) {
...@@ -32,7 +32,7 @@ class GenericProtocol { ...@@ -32,7 +32,7 @@ class GenericProtocol {
/** /**
* Create a Validator from the provided JSONSchema * Create a Validator from the provided JSONSchema
* @param {object} schema * @param {object} schema
* @returns {Validator} * @returns {Validator}
*/ */
createValidator(schema) { createValidator(schema) {
...@@ -40,8 +40,8 @@ class GenericProtocol { ...@@ -40,8 +40,8 @@ class GenericProtocol {
} }
/** /**
* Validate that a message meets the reqiured schema * Validate that a message meets the reqiured schema
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
validate(message) { validate(message) {
...@@ -56,35 +56,34 @@ class GenericProtocol { ...@@ -56,35 +56,34 @@ class GenericProtocol {
/** /**
* Identify the payload type from the message content * Identify the payload type from the message content
* @param {object} message * @param {object} message
* @returns {string} * @returns {string}
*/ */
getType(message) { getType(message) {
try { try {
return message.payload.message_type; return message.payload.message_type;
} catch(error) { } catch (error) {
return null; return null;
} }
} }
/** /**
* Invoked on receiving a message from the backbone * Invoked on receiving a message from the backbone
* *
* Whilst type isn't used in the generic stub it will * Whilst type isn't used in the generic stub it will
* be needed by sub-classes overriding the decode method * be needed by sub-classes overriding the decode method
* @param {string} type * @param {string} type
* @param {object} message * @param {object} message
* @returns {*} * @returns {*}
*/ */
decode(type, message) { decode(type, message) {
return message; return message;
} }
/** /**
* Invoked on receiving an invalid message from the backbone * Invoked on receiving an invalid message from the backbone
* *
* @param {object} message * @param {object} message
* @param {object} validation * @param {object} validation
* @returns {*} * @returns {*}
*/ */
...@@ -94,11 +93,11 @@ class GenericProtocol { ...@@ -94,11 +93,11 @@ class GenericProtocol {
/** /**
* Optionally invoked before delivering a message to the backbone * Optionally invoked before delivering a message to the backbone
* *
* Whilst type isn't used in the generic stub it will * Whilst type isn't used in the generic stub it will
* be needed by sub-classes overriding the encode method * be needed by sub-classes overriding the encode method
* @param {string} type * @param {string} type
* @param {*} message * @param {*} message
* @returns {object} * @returns {object}
*/ */
encode(type, message) { encode(type, message) {
...@@ -106,12 +105,11 @@ class GenericProtocol { ...@@ -106,12 +105,11 @@ class GenericProtocol {
} }
} }
/** /**
* GenericSoarProtocol defines a simple passthru handler for messages * GenericSoarProtocol defines a simple passthru handler for messages
* *
* This provides the same as above but loads a version of the * This provides the same as above but loads a version of the
* SoAR message protocol * SoAR message protocol
*/ */
class GenericSoarProtocol extends GenericProtocol { class GenericSoarProtocol extends GenericProtocol {
constructor(schema, services) { constructor(schema, services) {
...@@ -120,42 +118,41 @@ class GenericSoarProtocol extends GenericProtocol { ...@@ -120,42 +118,41 @@ class GenericSoarProtocol extends GenericProtocol {
/** /**
* Create a Validator from the provided JSONSchema * Create a Validator from the provided JSONSchema
* *
* If schema is a string build a URL and retrieve the * If schema is a string build a URL and retrieve the
* schema from gitlab * schema from gitlab
* @param {string|object} schema * @param {string|object} schema
* @returns {object} * @returns {object}
*/ */
createValidator(schema) { createValidator(schema) {
if (typeof schema === 'string' && schema.match(/^[\w\.]+$/)) { if (typeof schema === 'string' && schema.match(/^[\w.]+$/)) {
this.loadSchema(schema) this.loadSchema(schema).then((schema) => {
.then((schema) => { this.validator = new Validator(schema);
this.validator = new Validator(schema);
}); });
} else { } else {
this.validator = new Validator(schema); this.validator = new Validator(schema);
} }
} }
/** /**
* Load schema from gitlab by tag/branch/commitref * Load schema from gitlab by tag/branch/commitref
* @param {string} version * @param {string} version
* @returns {object} * @returns {object}
*/ */
loadSchema(version) { loadSchema(version) {
this.axios = axios; this.axios = axios;
let repository = "https://git.noc.ac.uk/communications-backbone-system/backbone-message-format"; let repository =
'https://git.noc.ac.uk/communications-backbone-system/backbone-message-format';
let url = `${repository}/-/raw/${version}/project/soar/swagger.json`; let url = `${repository}/-/raw/${version}/project/soar/swagger.json`;
return this.axios.get(url) return this.axios.get(url).then((response) => {
.then((response) => {
this.schema = response.data; this.schema = response.data;
return response.data; return response.data;
}); });
} }
/** /**
* Validate that a message meets the reqiured schema * Validate that a message meets the reqiured schema
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
validate(message) { validate(message) {
......
...@@ -5,25 +5,25 @@ var Validator = require('swagger-model-validator'); ...@@ -5,25 +5,25 @@ var Validator = require('swagger-model-validator');
/** /**
* GenericProtocol defines a simple passthru handler for messages * GenericProtocol defines a simple passthru handler for messages
* This can be extended to handle different schemas * This can be extended to handle different schemas
* *
* The assumption is that all messages conform to a single * The assumption is that all messages conform to a single
* wrapper schema definition. Different payloads are handled * wrapper schema definition. Different payloads are handled
* by a oneOf definitions within the schema determined by a * by a oneOf definitions within the schema determined by a
* field value. * field value.
* *
* This class can be extended and overridden to handle * This class can be extended and overridden to handle
* different schemas and to implement the client specific * different schemas and to implement the client specific
* logic related to be executed when invoked for a given * logic related to be executed when invoked for a given
* message type. * message type.
* *
* By default encode and decode are just passthru stubs * By default encode and decode are just passthru stubs
* *
* decode is invoked when receiving a message from the backbone * decode is invoked when receiving a message from the backbone
* encode is invoked before delivering a message to the backbone * encode is invoked before delivering a message to the backbone
* *
* The intention is that these allow you to transform the message * The intention is that these allow you to transform the message
* and call invoke internal functions and services as required * and call invoke internal functions and services as required
*/ */
class GenericProtocol { class GenericProtocol {
constructor(schema, services) { constructor(schema, services) {
...@@ -34,7 +34,7 @@ class GenericProtocol { ...@@ -34,7 +34,7 @@ class GenericProtocol {
/** /**
* Create a Validator from the provided JSONSchema * Create a Validator from the provided JSONSchema
* @param {object} schema * @param {object} schema
* @returns {Validator} * @returns {Validator}
*/ */
createValidator(schema) { createValidator(schema) {
...@@ -42,8 +42,8 @@ class GenericProtocol { ...@@ -42,8 +42,8 @@ class GenericProtocol {
} }
/** /**
* Validate that a message meets the reqiured schema * Validate that a message meets the reqiured schema
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
validate(message) { validate(message) {
...@@ -58,35 +58,34 @@ class GenericProtocol { ...@@ -58,35 +58,34 @@ class GenericProtocol {
/** /**
* Identify the payload type from the message content * Identify the payload type from the message content
* @param {object} message * @param {object} message
* @returns {string} * @returns {string}
*/ */
getType(message) { getType(message) {
try { try {
return message.payload.message_type; return message.payload.message_type;
} catch(error) { } catch (error) {
return null; return null;
} }
} }
/** /**
* Invoked on receiving a message from the backbone * Invoked on receiving a message from the backbone
* *
* Whilst type isn't used in the generic stub it will * Whilst type isn't used in the generic stub it will
* be needed by sub-classes overriding the decode method * be needed by sub-classes overriding the decode method
* @param {string} type * @param {string} type
* @param {object} message * @param {object} message
* @returns {*} * @returns {*}
*/ */
decode(type, message) { decode(type, message) {
return message; return message;
} }
/** /**
* Invoked on receiving an invalid message from the backbone * Invoked on receiving an invalid message from the backbone
* *
* @param {object} message * @param {object} message
* @param {object} validation * @param {object} validation
* @returns {*} * @returns {*}
*/ */
...@@ -96,11 +95,11 @@ class GenericProtocol { ...@@ -96,11 +95,11 @@ class GenericProtocol {
/** /**
* Optionally invoked before delivering a message to the backbone * Optionally invoked before delivering a message to the backbone
* *
* Whilst type isn't used in the generic stub it will * Whilst type isn't used in the generic stub it will
* be needed by sub-classes overriding the encode method * be needed by sub-classes overriding the encode method
* @param {string} type * @param {string} type
* @param {*} message * @param {*} message
* @returns {object} * @returns {object}
*/ */
encode(type, message) { encode(type, message) {
...@@ -108,12 +107,11 @@ class GenericProtocol { ...@@ -108,12 +107,11 @@ class GenericProtocol {
} }
} }
/** /**
* GenericSoarProtocol defines a simple passthru handler for messages * GenericSoarProtocol defines a simple passthru handler for messages
* *
* This provides the same as above but loads a version of the * This provides the same as above but loads a version of the
* SoAR message protocol * SoAR message protocol
*/ */
class GenericSoarProtocol extends GenericProtocol { class GenericSoarProtocol extends GenericProtocol {
constructor(schema, services) { constructor(schema, services) {
...@@ -122,42 +120,41 @@ class GenericSoarProtocol extends GenericProtocol { ...@@ -122,42 +120,41 @@ class GenericSoarProtocol extends GenericProtocol {
/** /**
* Create a Validator from the provided JSONSchema * Create a Validator from the provided JSONSchema
* *
* If schema is a string build a URL and retrieve the * If schema is a string build a URL and retrieve the
* schema from gitlab * schema from gitlab
* @param {string|object} schema * @param {string|object} schema
* @returns {object} * @returns {object}
*/ */
createValidator(schema) { createValidator(schema) {
if (typeof schema === 'string' && schema.match(/^[\w\.]+$/)) { if (typeof schema === 'string' && schema.match(/^[\w.]+$/)) {
this.loadSchema(schema) this.loadSchema(schema).then((schema) => {
.then((schema) => { this.validator = new Validator(schema);
this.validator = new Validator(schema);
}); });
} else { } else {
this.validator = new Validator(schema); this.validator = new Validator(schema);
} }
} }
/** /**
* Load schema from gitlab by tag/branch/commitref * Load schema from gitlab by tag/branch/commitref
* @param {string} version * @param {string} version
* @returns {object} * @returns {object}
*/ */
loadSchema(version) { loadSchema(version) {
this.axios = axios; this.axios = axios;
let repository = "https://git.noc.ac.uk/communications-backbone-system/backbone-message-format"; let repository =
'https://git.noc.ac.uk/communications-backbone-system/backbone-message-format';
let url = `${repository}/-/raw/${version}/project/soar/swagger.json`; let url = `${repository}/-/raw/${version}/project/soar/swagger.json`;
return this.axios.get(url) return this.axios.get(url).then((response) => {
.then((response) => {
this.schema = response.data; this.schema = response.data;
return response.data; return response.data;
}); });
} }
/** /**
* Validate that a message meets the reqiured schema * Validate that a message meets the reqiured schema
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
validate(message) { validate(message) {
......
...@@ -8,7 +8,6 @@ module.exports = { ...@@ -8,7 +8,6 @@ module.exports = {
'^.+\\.js$': 'babel-jest', '^.+\\.js$': 'babel-jest',
}, },
collectCoverage: true, collectCoverage: true,
collectCoverageFrom: [ collectCoverageFrom: [],
],
testEnvironment: 'jsdom', testEnvironment: 'jsdom',
}; };
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
"copytest:features": "npx recursive-copy -w node_modules/backbone-adapter-testsuite/features test/features", "copytest:features": "npx recursive-copy -w node_modules/backbone-adapter-testsuite/features test/features",
"copytest:fixtures": "npx recursive-copy -w node_modules/backbone-adapter-testsuite/fixtures test/fixtures", "copytest:fixtures": "npx recursive-copy -w node_modules/backbone-adapter-testsuite/fixtures test/fixtures",
"copytests": "npm run copytest:features && npm run copytest:fixtures", "copytests": "npm run copytest:features && npm run copytest:fixtures",
"lint:js": "eslint --ext \".js\" --ignore-path .gitignore .", "lint:js": "eslint -c .eslintrc.js --ext .js --ignore-path .gitignore .",
"lint:prettier": "prettier --check .", "lint:prettier": "prettier --check .",
"lint": "yarn lint:js && yarn lint:prettier", "lint": "yarn lint:js && yarn lint:prettier",
"lintfix": "prettier --write --list-different . && yarn lint:js --fix", "lintfix": "prettier --write --list-different . && yarn lint:js --fix",
...@@ -51,14 +51,14 @@ ...@@ -51,14 +51,14 @@
"babel-jest": "^27.4.4", "babel-jest": "^27.4.4",
"backbone-adapter-testsuite": "git+https://git.noc.ac.uk/communications-backbone-system/backbone-adapter-testsuite.git#dev", "backbone-adapter-testsuite": "git+https://git.noc.ac.uk/communications-backbone-system/backbone-adapter-testsuite.git#dev",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^8.4.1", "eslint": "^8.36.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"husky": "^7.0.4", "husky": "^7.0.4",
"jest": "^27.4.4", "jest": "^27.4.4",
"lint-staged": "^12.1.2", "lint-staged": "^12.1.2",
"openapi-schema-validator": "^12.1.0", "openapi-schema-validator": "^12.1.0",
"prettier": "^2.5.1", "prettier": "^2.8.4",
"recursive-copy-cli": "^1.0.20", "recursive-copy-cli": "^1.0.20",
"rollup": "^3.9.1" "rollup": "^3.9.1"
} }
......
...@@ -12,14 +12,14 @@ export class Adapter { ...@@ -12,14 +12,14 @@ export class Adapter {
/** /**
* Test parsing the message based on the provided protocol schema * Test parsing the message based on the provided protocol schema
* *
* The message must be successfully json decoded into an object * The message must be successfully json decoded into an object
* prior to validation * prior to validation
* *
* At present this returns the validation result which is an * At present this returns the validation result which is an
* object containing a boolean valid field as well as details * object containing a boolean valid field as well as details
* of any errors. * of any errors.
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
validate(message) { validate(message) {
...@@ -81,12 +81,12 @@ export class Adapter { ...@@ -81,12 +81,12 @@ export class Adapter {
/** /**
* Call the GET /receive endpoint and process the messages with decode * Call the GET /receive endpoint and process the messages with decode
* *
* Returns the response * Returns the response
* @param {boolean} is_retry * @param {boolean} is_retry
* @returns {object} * @returns {object}
*/ */
poll(is_retry=false) { poll(is_retry = false) {
let adapterConfig = this.config; let adapterConfig = this.config;
return this.getAuthorizationHeader() return this.getAuthorizationHeader()
.then((headers) => { .then((headers) => {
...@@ -109,11 +109,13 @@ export class Adapter { ...@@ -109,11 +109,13 @@ export class Adapter {
}) })
.catch((error) => { .catch((error) => {
let retry = false; let retry = false;
switch(error.response.status) { switch (error.response.status) {
case 403: { case 403:
this.credentials = null; {
retry = true; this.credentials = null;
} break; retry = true;
}
break;
case 503: { case 503: {
retry = true; retry = true;
} }
...@@ -124,15 +126,15 @@ export class Adapter { ...@@ -124,15 +126,15 @@ export class Adapter {
} }
/** /**
* Publish a message to the backbone with the specified topic * Publish a message to the backbone with the specified topic
* *
* Messages should be passed through encode before sending * Messages should be passed through encode before sending
* @param {string} topic * @param {string} topic
* @param {string} body * @param {string} body
* @param {boolean} is_retry * @param {boolean} is_retry
* @returns * @returns
*/ */
publish(topic, body, is_retry=false) { publish(topic, body, is_retry = false) {
let adapterConfig = this.config; let adapterConfig = this.config;
return this.getAuthorizationHeader() return this.getAuthorizationHeader()
.then((headers) => { .then((headers) => {
...@@ -152,11 +154,13 @@ export class Adapter { ...@@ -152,11 +154,13 @@ export class Adapter {
}) })
.catch((error) => { .catch((error) => {
let retry = false; let retry = false;
switch(error.response.status) { switch (error.response.status) {
case 403: { case 403:
this.credentials = null; {
retry = true; this.credentials = null;
} break; retry = true;
}
break;
case 503: { case 503: {
retry = true; retry = true;
} }
...@@ -168,17 +172,17 @@ export class Adapter { ...@@ -168,17 +172,17 @@ export class Adapter {
/** /**
* Broadcast the message on the backbone * Broadcast the message on the backbone
* *
* Broadcast messages bypass the normal publisher queues * Broadcast messages bypass the normal publisher queues
* this means they can be used to deliver messages more * this means they can be used to deliver messages more
* quickly in an emergency scenario. * quickly in an emergency scenario.
* *
* Messages should be passed through encode before sending * Messages should be passed through encode before sending
* @param {string} body * @param {string} body
* @param {boolean} is_retry * @param {boolean} is_retry
* @returns * @returns
*/ */
broadcast(body, is_retry=false) { broadcast(body, is_retry = false) {
let adapterConfig = this.config; let adapterConfig = this.config;
return this.getAuthorizationHeader() return this.getAuthorizationHeader()
.then((headers) => { .then((headers) => {
...@@ -197,11 +201,13 @@ export class Adapter { ...@@ -197,11 +201,13 @@ export class Adapter {
}) })
.catch((error) => { .catch((error) => {
let retry = false; let retry = false;
switch(error.response.status) { switch (error.response.status) {
case 403: { case 403:
this.credentials = null; {
retry = true; this.credentials = null;
} break; retry = true;
}
break;
case 503: { case 503: {
retry = true; retry = true;
} }
......
import { GenericProtocol } from '~/modules/comms-adapter/protocol'; import { GenericProtocol } from '~/modules/comms-adapter/protocol';
/** /**
* *
*/ */
export class ExampleClientProtocol extends GenericProtocol { export class ExampleClientProtocol extends GenericProtocol {
constructor(schema, services) { constructor(schema, services) {
super(schema, services); super(schema, services);
// bootstrap any injected services // bootstrap any injected services
} }
/** /**
* Process a message received from the backbone * Process a message received from the backbone
* *
* This method is overridden to take appropriate * This method is overridden to take appropriate
* action for each message type. * action for each message type.
* *
* Further methods can then be defined to handle * Further methods can then be defined to handle
* each message type. * each message type.
* *
* You can use this to take action directly or * You can use this to take action directly or
* transform that data to invoke an existing process. * transform that data to invoke an existing process.
* @param {string} type * @param {string} type
* @param {object} message * @param {object} message
* @returns * @returns
*/ */
decode(type, message) { decode(type, message) {
switch (type) { switch (type) {
...@@ -39,13 +38,13 @@ export class ExampleClientProtocol extends GenericProtocol { ...@@ -39,13 +38,13 @@ export class ExampleClientProtocol extends GenericProtocol {
/** /**
* Transform local data into a message conforming to the protocol schema * Transform local data into a message conforming to the protocol schema
* *
* When a client event occurs the local data is passed through * When a client event occurs the local data is passed through
* encode to handle the translation from the native client format * encode to handle the translation from the native client format
* into a message conforming to the protocol schema. * into a message conforming to the protocol schema.
* @param {string} type * @param {string} type
* @param {object} message * @param {object} message
* @returns * @returns
*/ */
encode(type, message) { encode(type, message) {
return message; return message;
...@@ -53,8 +52,8 @@ export class ExampleClientProtocol extends GenericProtocol { ...@@ -53,8 +52,8 @@ export class ExampleClientProtocol extends GenericProtocol {
/** /**
* Act upon a received VehicleStatus message * Act upon a received VehicleStatus message
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
decodeVehicleStatus(message) { decodeVehicleStatus(message) {
const battery = message.battery_percentage; const battery = message.battery_percentage;
...@@ -66,7 +65,7 @@ export class ExampleClientProtocol extends GenericProtocol { ...@@ -66,7 +65,7 @@ export class ExampleClientProtocol extends GenericProtocol {
/** /**
* Act upon a received VehicleMission message * Act upon a received VehicleMission message
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
decodeVehicleMission(message) { decodeVehicleMission(message) {
...@@ -76,7 +75,7 @@ export class ExampleClientProtocol extends GenericProtocol { ...@@ -76,7 +75,7 @@ export class ExampleClientProtocol extends GenericProtocol {
/** /**
* Transform local data into a VehicleStatus message * Transform local data into a VehicleStatus message
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
encodeVehicleStatus(message) { encodeVehicleStatus(message) {
......
...@@ -3,25 +3,25 @@ import Validator from 'swagger-model-validator'; ...@@ -3,25 +3,25 @@ import Validator from 'swagger-model-validator';
/** /**
* GenericProtocol defines a simple passthru handler for messages * GenericProtocol defines a simple passthru handler for messages
* This can be extended to handle different schemas * This can be extended to handle different schemas
* *
* The assumption is that all messages conform to a single * The assumption is that all messages conform to a single
* wrapper schema definition. Different payloads are handled * wrapper schema definition. Different payloads are handled
* by a oneOf definitions within the schema determined by a * by a oneOf definitions within the schema determined by a
* field value. * field value.
* *
* This class can be extended and overridden to handle * This class can be extended and overridden to handle
* different schemas and to implement the client specific * different schemas and to implement the client specific
* logic related to be executed when invoked for a given * logic related to be executed when invoked for a given
* message type. * message type.
* *
* By default encode and decode are just passthru stubs * By default encode and decode are just passthru stubs
* *
* decode is invoked when receiving a message from the backbone * decode is invoked when receiving a message from the backbone
* encode is invoked before delivering a message to the backbone * encode is invoked before delivering a message to the backbone
* *
* The intention is that these allow you to transform the message * The intention is that these allow you to transform the message
* and call invoke internal functions and services as required * and call invoke internal functions and services as required
*/ */
export class GenericProtocol { export class GenericProtocol {
constructor(schema, services) { constructor(schema, services) {
...@@ -32,7 +32,7 @@ export class GenericProtocol { ...@@ -32,7 +32,7 @@ export class GenericProtocol {
/** /**
* Create a Validator from the provided JSONSchema * Create a Validator from the provided JSONSchema
* @param {object} schema * @param {object} schema
* @returns {Validator} * @returns {Validator}
*/ */
createValidator(schema) { createValidator(schema) {
...@@ -40,8 +40,8 @@ export class GenericProtocol { ...@@ -40,8 +40,8 @@ export class GenericProtocol {
} }
/** /**
* Validate that a message meets the reqiured schema * Validate that a message meets the reqiured schema
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
validate(message) { validate(message) {
...@@ -56,35 +56,34 @@ export class GenericProtocol { ...@@ -56,35 +56,34 @@ export class GenericProtocol {
/** /**
* Identify the payload type from the message content * Identify the payload type from the message content
* @param {object} message * @param {object} message
* @returns {string} * @returns {string}
*/ */
getType(message) { getType(message) {
try { try {
return message.payload.message_type; return message.payload.message_type;
} catch(error) { } catch (error) {
return null; return null;
} }
} }
/** /**
* Invoked on receiving a message from the backbone * Invoked on receiving a message from the backbone
* *
* Whilst type isn't used in the generic stub it will * Whilst type isn't used in the generic stub it will
* be needed by sub-classes overriding the decode method * be needed by sub-classes overriding the decode method
* @param {string} type * @param {string} type
* @param {object} message * @param {object} message
* @returns {*} * @returns {*}
*/ */
decode(type, message) { decode(type, message) {
return message; return message;
} }
/** /**
* Invoked on receiving an invalid message from the backbone * Invoked on receiving an invalid message from the backbone
* *
* @param {object} message * @param {object} message
* @param {object} validation * @param {object} validation
* @returns {*} * @returns {*}
*/ */
...@@ -94,11 +93,11 @@ export class GenericProtocol { ...@@ -94,11 +93,11 @@ export class GenericProtocol {
/** /**
* Optionally invoked before delivering a message to the backbone * Optionally invoked before delivering a message to the backbone
* *
* Whilst type isn't used in the generic stub it will * Whilst type isn't used in the generic stub it will
* be needed by sub-classes overriding the encode method * be needed by sub-classes overriding the encode method
* @param {string} type * @param {string} type
* @param {*} message * @param {*} message
* @returns {object} * @returns {object}
*/ */
encode(type, message) { encode(type, message) {
...@@ -106,12 +105,11 @@ export class GenericProtocol { ...@@ -106,12 +105,11 @@ export class GenericProtocol {
} }
} }
/** /**
* GenericSoarProtocol defines a simple passthru handler for messages * GenericSoarProtocol defines a simple passthru handler for messages
* *
* This provides the same as above but loads a version of the * This provides the same as above but loads a version of the
* SoAR message protocol * SoAR message protocol
*/ */
export class GenericSoarProtocol extends GenericProtocol { export class GenericSoarProtocol extends GenericProtocol {
constructor(schema, services) { constructor(schema, services) {
...@@ -120,42 +118,41 @@ export class GenericSoarProtocol extends GenericProtocol { ...@@ -120,42 +118,41 @@ export class GenericSoarProtocol extends GenericProtocol {
/** /**
* Create a Validator from the provided JSONSchema * Create a Validator from the provided JSONSchema
* *
* If schema is a string build a URL and retrieve the * If schema is a string build a URL and retrieve the
* schema from gitlab * schema from gitlab
* @param {string|object} schema * @param {string|object} schema
* @returns {object} * @returns {object}
*/ */
createValidator(schema) { createValidator(schema) {
if (typeof schema === 'string' && schema.match(/^[\w\.]+$/)) { if (typeof schema === 'string' && schema.match(/^[\w.]+$/)) {
this.loadSchema(schema) this.loadSchema(schema).then((schema) => {
.then((schema) => { this.validator = new Validator(schema);
this.validator = new Validator(schema);
}); });
} else { } else {
this.validator = new Validator(schema); this.validator = new Validator(schema);
} }
} }
/** /**
* Load schema from gitlab by tag/branch/commitref * Load schema from gitlab by tag/branch/commitref
* @param {string} version * @param {string} version
* @returns {object} * @returns {object}
*/ */
loadSchema(version) { loadSchema(version) {
this.axios = axios; this.axios = axios;
let repository = "https://git.noc.ac.uk/communications-backbone-system/backbone-message-format"; let repository =
'https://git.noc.ac.uk/communications-backbone-system/backbone-message-format';
let url = `${repository}/-/raw/${version}/project/soar/swagger.json`; let url = `${repository}/-/raw/${version}/project/soar/swagger.json`;
return this.axios.get(url) return this.axios.get(url).then((response) => {
.then((response) => { this.schema = response.data;
this.schema = response.data
return response.data; return response.data;
}); });
} }
/** /**
* Validate that a message meets the reqiured schema * Validate that a message meets the reqiured schema
* @param {object} message * @param {object} message
* @returns {object} * @returns {object}
*/ */
validate(message) { validate(message) {
...@@ -167,4 +164,4 @@ export class GenericSoarProtocol extends GenericProtocol { ...@@ -167,4 +164,4 @@ export class GenericSoarProtocol extends GenericProtocol {
false false
); );
} }
} }
\ No newline at end of file
...@@ -3,17 +3,19 @@ const { When, Then } = require('@cucumber/cucumber'); ...@@ -3,17 +3,19 @@ const { When, Then } = require('@cucumber/cucumber');
const { fixtures } = require('../../fixtures/server'); const { fixtures } = require('../../fixtures/server');
When('the auth method is called', async function() { When('the auth method is called', async function () {
await this.adapter.auth(); await this.adapter.auth();
}); });
Then('the adapter credentials are populated', function() { Then('the adapter credentials are populated', function () {
assert.equal(this.adapter.credentials.token, fixtures.get('response-valid-token').token); assert.equal(
this.adapter.credentials.token,
fixtures.get('response-valid-token').token
);
}); });
Then('the adapter auth fails', function() { Then('the adapter auth fails', function () {
this.adapter.auth() this.adapter.auth().catch((error) => {
.catch((error) => {
assert.equal(error.response.status, 403); assert.equal(error.response.status, 403);
}); });
}); });
\ No newline at end of file
const assert = require('assert'); const assert = require('assert');
const { Before } = require('@cucumber/cucumber'); const { Before } = require('@cucumber/cucumber');
const axios = require("axios"); const axios = require('axios');
const MockAdapter = require("axios-mock-adapter"); const MockAdapter = require('axios-mock-adapter');
// This sets the mock adapter on the default instance // This sets the mock adapter on the default instance
const mockAxios = new MockAdapter(axios); const mockAxios = new MockAdapter(axios);
...@@ -17,13 +17,13 @@ const { GenericProtocol } = require('../../../dist/protocol'); ...@@ -17,13 +17,13 @@ const { GenericProtocol } = require('../../../dist/protocol');
const { Adapter } = require('../../../dist/adapter'); const { Adapter } = require('../../../dist/adapter');
/** /**
* Use assert.CallTracker to track internal method calls * Use assert.CallTracker to track internal method calls
* Instead of adding trackers to each method, create a * Instead of adding trackers to each method, create a
* single tracked stub function and then use the parameters * single tracked stub function and then use the parameters
* to record what is being tracked. * to record what is being tracked.
*/ */
const tracker = new assert.CallTracker(); const tracker = new assert.CallTracker();
const trackedFunction = function(method, params) { const trackedFunction = function (method, params) {
// do nothing; // do nothing;
}; };
const recorder = tracker.calls(trackedFunction); const recorder = tracker.calls(trackedFunction);
...@@ -51,7 +51,7 @@ class TrackedAdapter extends Adapter { ...@@ -51,7 +51,7 @@ class TrackedAdapter extends Adapter {
} }
getTrackedCalls(method) { getTrackedCalls(method) {
let calls = this.tracker.getCalls(this.recorder); let calls = this.tracker.getCalls(this.recorder);
let methodCalls = calls.filter(call => call.arguments[0] === method); let methodCalls = calls.filter((call) => call.arguments[0] === method);
return methodCalls; return methodCalls;
} }
resetTracker() { resetTracker() {
...@@ -65,20 +65,20 @@ class TrackedGenericProtocol extends GenericProtocol { ...@@ -65,20 +65,20 @@ class TrackedGenericProtocol extends GenericProtocol {
this.tracker = tracker; this.tracker = tracker;
} }
encode(type, message) { encode(type, message) {
this.recorder('encode', {type, message}); this.recorder('encode', { type, message });
return super.encode(type, message) return super.encode(type, message);
} }
decode(type, message) { decode(type, message) {
this.recorder('decode', {type, message}); this.recorder('decode', { type, message });
return super.decode(type, message) return super.decode(type, message);
} }
validate(message) { validate(message) {
this.recorder('validate', {message}); this.recorder('validate', { message });
return super.validate(message); return super.validate(message);
} }
getTrackedCalls(method) { getTrackedCalls(method) {
let calls = this.tracker.getCalls(this.recorder); let calls = this.tracker.getCalls(this.recorder);
let methodCalls = calls.filter(call => call.arguments[0] === method); let methodCalls = calls.filter((call) => call.arguments[0] === method);
return methodCalls; return methodCalls;
} }
resetTracker() { resetTracker() {
...@@ -86,35 +86,45 @@ class TrackedGenericProtocol extends GenericProtocol { ...@@ -86,35 +86,45 @@ class TrackedGenericProtocol extends GenericProtocol {
} }
} }
Before(function() { Before(function () {
this.api = mockValidConfig.api; this.api = mockValidConfig.api;
this.schema = mockSchema; this.schema = mockSchema;
this.tracker = tracker; this.tracker = tracker;
this.recorder = recorder; this.recorder = recorder;
let services = { let services = {
recorder, recorder,
tracker tracker,
}; };
this.classes = { this.classes = {
TrackedAdapter, TrackedAdapter,
TrackedGenericProtocol, TrackedGenericProtocol,
}; };
this.callCounts = {}; this.callCounts = {};
this.protocol = new this.classes.TrackedGenericProtocol(this.schema, services); this.protocol = new this.classes.TrackedGenericProtocol(
this.schema,
services
);
this.protocol.setupCallTracking(this.recorder, this.tracker); this.protocol.setupCallTracking(this.recorder, this.tracker);
this.protocol.resetTracker(); this.protocol.resetTracker();
this.mockAxios = mockAxios; this.mockAxios = mockAxios;
this.mockAxios.reset(); this.mockAxios.reset();
this.mockAxios.resetHistory(); this.mockAxios.resetHistory();
this.mockAxios.onGet( this.mockAxios
`${mockValidConfig.api}/token`, .onGet(`${mockValidConfig.api}/token`, {
{ params: { client_id: mockValidConfig.client_id, secret: mockValidConfig.secret } } params: {
).reply(200, fixtures.get('response-valid-token')); client_id: mockValidConfig.client_id,
secret: mockValidConfig.secret,
},
})
.reply(200, fixtures.get('response-valid-token'));
this.mockAxios.onGet( this.mockAxios
`${mockInvalidConfig.api}/token`, .onGet(`${mockInvalidConfig.api}/token`, {
{ params: { client_id: mockInvalidConfig.client_id, secret: mockInvalidConfig.secret } } params: {
).reply(403, fixtures.get('response-denied-token')); client_id: mockInvalidConfig.client_id,
secret: mockInvalidConfig.secret,
}); },
\ No newline at end of file })
.reply(403, fixtures.get('response-denied-token'));
});
...@@ -5,24 +5,25 @@ const { fixtures } = require('../../fixtures/server'); ...@@ -5,24 +5,25 @@ const { fixtures } = require('../../fixtures/server');
const mockValidConfig = fixtures.get('config-valid'); const mockValidConfig = fixtures.get('config-valid');
When('a mock notify API response is configured to return success', function() { When('a mock notify API response is configured to return success', function () {
const response = {}; const response = {};
this.mockAxios.onPost( this.mockAxios.onPost(`${mockValidConfig.api}/notify`).reply(200, response);
`${mockValidConfig.api}/notify`,
).reply(200, response);
}); });
When('a mock notify API response is configured to return a {int} error', function(statusCode) { When(
const statusMessages = { 'a mock notify API response is configured to return a {int} error',
403: 'Token expired', function (statusCode) {
503: 'Service unavailable' const statusMessages = {
}; 403: 'Token expired',
this.mockAxios.onPost( 503: 'Service unavailable',
`${mockValidConfig.api}/notify`, };
).reply(statusCode, { message: statusMessages[statusCode] }) this.mockAxios
}); .onPost(`${mockValidConfig.api}/notify`)
.reply(statusCode, { message: statusMessages[statusCode] });
When('the broadcast method is called', function() { }
);
When('the broadcast method is called', function () {
const message = fixtures.get('message-vehicle-status'); const message = fixtures.get('message-vehicle-status');
this.message = message; this.message = message;
const body = JSON.stringify(message); const body = JSON.stringify(message);
...@@ -30,7 +31,7 @@ When('the broadcast method is called', function() { ...@@ -30,7 +31,7 @@ When('the broadcast method is called', function() {
this.callCounts.broadcast = this.adapter.getTrackedCalls('broadcast').length; this.callCounts.broadcast = this.adapter.getTrackedCalls('broadcast').length;
}); });
When('the broadcast method is called with is_retry on', function() { When('the broadcast method is called with is_retry on', function () {
const message = fixtures.get('message-vehicle-status'); const message = fixtures.get('message-vehicle-status');
this.message = message; this.message = message;
const body = JSON.stringify(message); const body = JSON.stringify(message);
...@@ -38,13 +39,13 @@ When('the broadcast method is called with is_retry on', function() { ...@@ -38,13 +39,13 @@ When('the broadcast method is called with is_retry on', function() {
this.callCounts.broadcast = this.adapter.getTrackedCalls('broadcast').length; this.callCounts.broadcast = this.adapter.getTrackedCalls('broadcast').length;
}); });
Then('the broadcast method was called with is_retry on', function() { Then('the broadcast method was called with is_retry on', function () {
let broadcastCalls = this.adapter.getTrackedCalls('broadcast'); let broadcastCalls = this.adapter.getTrackedCalls('broadcast');
let lastCall = broadcastCalls[broadcastCalls.length-1]; let lastCall = broadcastCalls[broadcastCalls.length - 1];
assert.ok(lastCall.arguments[1].is_retry); assert.ok(lastCall.arguments[1].is_retry);
}); });
Then('the broadcast method is not called again', function() { Then('the broadcast method is not called again', function () {
let newBroadcastCallCount = this.adapter.getTrackedCalls('broadcast').length; let newBroadcastCallCount = this.adapter.getTrackedCalls('broadcast').length;
assert.equal(this.callCounts.broadcast, newBroadcastCallCount); assert.equal(this.callCounts.broadcast, newBroadcastCallCount);
}); });
\ No newline at end of file
...@@ -8,60 +8,71 @@ const mockInvalidConfig = fixtures.get('config-invalid'); ...@@ -8,60 +8,71 @@ const mockInvalidConfig = fixtures.get('config-invalid');
const mockSchema = require('../../mock/swagger.json'); const mockSchema = require('../../mock/swagger.json');
// const { Adapter } = require('../../../dist/adapter'); // const { Adapter } = require('../../../dist/adapter');
Given('valid config', function() { Given('valid config', function () {
this.config = mockValidConfig this.config = mockValidConfig;
}); });
Given('invalid config', function() { Given('invalid config', function () {
this.schema = mockSchema; this.schema = mockSchema;
this.config = mockInvalidConfig; this.config = mockInvalidConfig;
}); });
When('the adapter instance is created', function() { When('the adapter instance is created', function () {
this.adapter = new this.classes.TrackedAdapter(this.protocol, this.config); this.adapter = new this.classes.TrackedAdapter(this.protocol, this.config);
this.adapter.setupCallTracking(this.recorder, this.tracker); this.adapter.setupCallTracking(this.recorder, this.tracker);
}); });
Then('a successful response is returned with status {int}', function(expectedStatus) { Then(
this.call 'a successful response is returned with status {int}',
.then(response => { function (expectedStatus) {
assert.equal(response.status, expectedStatus); this.call.then((response) => {
}); assert.equal(response.status, expectedStatus);
}); });
}
);
Then('an error response is returned with status {int}', function(expectedStatus) { Then(
this.call 'an error response is returned with status {int}',
.catch((error) => { function (expectedStatus) {
assert.equal(error.response.status, expectedStatus); this.call.catch((error) => {
}); assert.equal(error.response.status, expectedStatus);
}); });
}
);
Then('the credentials are deleted', function() { Then('the credentials are deleted', function () {
assert.equal(this.adapter.credentials, null); assert.equal(this.adapter.credentials, null);
}); });
Then('the credentials are not deleted', function() { Then('the credentials are not deleted', function () {
assert.notEqual(this.adapter.credentials, null); assert.notEqual(this.adapter.credentials, null);
}); });
When('the {string} method call counts are checked', function(method) { When('the {string} method call counts are checked', function (method) {
let newCallCount = this.adapter.getTrackedCalls(method).length; let newCallCount = this.adapter.getTrackedCalls(method).length;
this.callCounts[method] = newCallCount; this.callCounts[method] = newCallCount;
}); });
Then('the {string} method is not called again', function(method) { Then('the {string} method is not called again', function (method) {
let newCallCount = this.adapter.getTrackedCalls(method).length; let newCallCount = this.adapter.getTrackedCalls(method).length;
assert.equal(this.callCounts[method], newCallCount); assert.equal(this.callCounts[method], newCallCount);
}); });
Then('the total number of calls to {string} was {int}', function(method, expectedCallCount) { Then(
let callCount = this.adapter.getTrackedCalls(method).length; 'the total number of calls to {string} was {int}',
assert.equal(callCount, expectedCallCount); function (method, expectedCallCount) {
}); let callCount = this.adapter.getTrackedCalls(method).length;
assert.equal(callCount, expectedCallCount);
Then('the total number of {string} requests to {string} was {int}', function(method, endpoint, expectedCallCount) { }
let url = `${this.api}${endpoint}`; );
let requestHistory = this.mockAxios.history[method.toLowerCase()].filter((request) => request.url === url);
assert.equal(requestHistory.length, expectedCallCount);
});
Then(
'the total number of {string} requests to {string} was {int}',
function (method, endpoint, expectedCallCount) {
let url = `${this.api}${endpoint}`;
let requestHistory = this.mockAxios.history[method.toLowerCase()].filter(
(request) => request.url === url
);
assert.equal(requestHistory.length, expectedCallCount);
}
);
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