mirror of
https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-consumer.git
synced 2026-09-21 16:52:03 -07:00
feat(tests): Added Usage Unit Tests
This commit is contained in:
Generated
+2
@@ -16879,6 +16879,7 @@
|
|||||||
"resolved": "http://94.130.170.209:4873/mkdirp/-/mkdirp-0.5.6.tgz",
|
"resolved": "http://94.130.170.209:4873/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.6"
|
"minimist": "^1.2.6"
|
||||||
},
|
},
|
||||||
@@ -26109,6 +26110,7 @@
|
|||||||
"resolved": "http://94.130.170.209:4873/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
|
"resolved": "http://94.130.170.209:4873/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
|
||||||
"integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
|
"integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.1.11",
|
"graceful-fs": "^4.1.11",
|
||||||
"imurmurhash": "^0.1.4",
|
"imurmurhash": "^0.1.4",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
REST API Controller library for the /ipfs route
|
REST API Controller library for the /usage route
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Global npm libraries
|
// Global npm libraries
|
||||||
@@ -13,19 +13,17 @@ class UsageRESTControllerLib {
|
|||||||
this.adapters = localConfig.adapters
|
this.adapters = localConfig.adapters
|
||||||
if (!this.adapters) {
|
if (!this.adapters) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Instance of Adapters library required when instantiating /ipfs REST Controller.'
|
'Instance of Adapters library required when instantiating /usage REST Controller.'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
this.useCases = localConfig.useCases
|
this.useCases = localConfig.useCases
|
||||||
if (!this.useCases) {
|
if (!this.useCases) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Instance of Use Cases library required when instantiating /ipfs REST Controller.'
|
'Instance of Use Cases library required when instantiating /usage REST Controller.'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encapsulate dependencies
|
// Encapsulate dependencies
|
||||||
// this.UserModel = this.adapters.localdb.Users
|
|
||||||
// this.userUseCases = this.useCases.user
|
|
||||||
|
|
||||||
// Bind 'this' object to all subfunctions
|
// Bind 'this' object to all subfunctions
|
||||||
this.getStatus = this.getStatus.bind(this)
|
this.getStatus = this.getStatus.bind(this)
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ class TimerControllers {
|
|||||||
cleanUsage () {
|
cleanUsage () {
|
||||||
try {
|
try {
|
||||||
this.useCases.usage.cleanUsage()
|
this.useCases.usage.cleanUsage()
|
||||||
|
|
||||||
|
return true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error in time-controller.js/cleanUsage(): ', err)
|
console.error('Error in time-controller.js/cleanUsage(): ', err)
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class UsageUseCases {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bind 'this' object to all subfunctions
|
// Bind 'this' object to all subfunctions
|
||||||
|
this.cleanUsage = this.cleanUsage.bind(this)
|
||||||
this.getRestSummary = this.getRestSummary.bind(this)
|
this.getRestSummary = this.getRestSummary.bind(this)
|
||||||
this.getTopIps = this.getTopIps.bind(this)
|
this.getTopIps = this.getTopIps.bind(this)
|
||||||
this.getTopEndpoints = this.getTopEndpoints.bind(this)
|
this.getTopEndpoints = this.getTopEndpoints.bind(this)
|
||||||
@@ -36,6 +37,7 @@ class UsageUseCases {
|
|||||||
const twentyFourHoursAgo = now.getTime() - (60000 * 60 * 24)
|
const twentyFourHoursAgo = now.getTime() - (60000 * 60 * 24)
|
||||||
|
|
||||||
restCalls = restCalls.filter(x => x.timestamp > twentyFourHoursAgo)
|
restCalls = restCalls.filter(x => x.timestamp > twentyFourHoursAgo)
|
||||||
|
return restCalls
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error in usage-use-cases.js/cleanUsage()')
|
console.error('Error in usage-use-cases.js/cleanUsage()')
|
||||||
throw err
|
throw err
|
||||||
@@ -58,7 +60,6 @@ class UsageUseCases {
|
|||||||
getTopIps () {
|
getTopIps () {
|
||||||
try {
|
try {
|
||||||
const ips = restCalls.map(x => x.ip)
|
const ips = restCalls.map(x => x.ip)
|
||||||
|
|
||||||
// Create a Map to count occurrences of each IP address string
|
// Create a Map to count occurrences of each IP address string
|
||||||
const countMap = new Map()
|
const countMap = new Map()
|
||||||
ips.forEach(ip => {
|
ips.forEach(ip => {
|
||||||
@@ -132,4 +133,4 @@ function usageMiddleware () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { UsageUseCases, usageMiddleware }
|
export { UsageUseCases, usageMiddleware, restCalls }
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
End-to-end tests for /usage endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import config from '../../../config/index.js'
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import axios from 'axios'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
import util from 'util'
|
||||||
|
|
||||||
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
|
const LOCALHOST = `http://localhost:${config.port}`
|
||||||
|
|
||||||
|
let sandbox
|
||||||
|
|
||||||
|
describe('Usage', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('GET /usage', () => {
|
||||||
|
it('should return usage status', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'get',
|
||||||
|
url: `${LOCALHOST}/usage`
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await axios(options)
|
||||||
|
|
||||||
|
assert.property(result.data, 'status')
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('GET /usage/ips', () => {
|
||||||
|
it('should return ips', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'get',
|
||||||
|
url: `${LOCALHOST}/usage/ips`
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await axios(options)
|
||||||
|
|
||||||
|
assert.property(result.data, 'ips')
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('GET /usage/endpoints', () => {
|
||||||
|
it('should return ips', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'get',
|
||||||
|
url: `${LOCALHOST}/usage/endpoints`
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await axios(options)
|
||||||
|
|
||||||
|
assert.property(result.data, 'endpoints')
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the REST API middleware that handle response errors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public npm libraries
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import errorMiddleware from '../../../../../src/controllers/rest-api/middleware/error.js'
|
||||||
|
import { context as mockContext } from '../../../../unit/mocks/ctx-mock.js'
|
||||||
|
|
||||||
|
describe('#Validators', () => {
|
||||||
|
let ctx
|
||||||
|
let sandbox
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// Mock the context object.
|
||||||
|
ctx = mockContext()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('#errorMiddleware', () => {
|
||||||
|
it('should run next function', async () => {
|
||||||
|
// Spy on next
|
||||||
|
const next = sinon.spy(() => { })
|
||||||
|
errorMiddleware()(ctx, next)
|
||||||
|
|
||||||
|
assert.isTrue(next.calledOnce)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle unknown status error', async () => {
|
||||||
|
try {
|
||||||
|
const next = async () => {
|
||||||
|
const e = new Error('test error')
|
||||||
|
e.status = null
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
await errorMiddleware()(ctx, next)
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (error) {
|
||||||
|
assert.equal(ctx.status, 500)
|
||||||
|
assert.equal(ctx.body, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should handle known status error', async () => {
|
||||||
|
try {
|
||||||
|
const next = async () => {
|
||||||
|
const e = new Error('test error')
|
||||||
|
e.status = 422
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
await errorMiddleware()(ctx, next)
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (error) {
|
||||||
|
assert.equal(ctx.status, 422)
|
||||||
|
assert.equal(ctx.body, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the REST API handler for the /usage endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public npm libraries
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
// Local support libraries
|
||||||
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
import UsageController from '../../../../../src/controllers/rest-api/usage/controller.js'
|
||||||
|
|
||||||
|
import { context as mockContext } from '../../../mocks/ctx-mock.js'
|
||||||
|
|
||||||
|
let uut
|
||||||
|
let sandbox
|
||||||
|
let ctx
|
||||||
|
|
||||||
|
describe('#Usage-REST-Controller', () => {
|
||||||
|
// const testUser = {}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const useCases = new UseCasesMock()
|
||||||
|
uut = new UsageController({ adapters, useCases })
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
ctx = mockContext()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('#constructor', () => {
|
||||||
|
it('should throw an error if adapters are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new UsageController()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Adapters library required when instantiating /usage REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error if useCases are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new UsageController({ adapters })
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Use Cases library required when instantiating /usage REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#Get /usage', () => {
|
||||||
|
it('should return 422 status on biz logic error', async () => {
|
||||||
|
try {
|
||||||
|
sandbox.stub(uut.useCases.usage, 'getRestSummary').throws(new Error('test error'))
|
||||||
|
await uut.getStatus(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(err)
|
||||||
|
assert.equal(err.status, 422)
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return 200 status on success', async () => {
|
||||||
|
await uut.getStatus(ctx)
|
||||||
|
|
||||||
|
// Assert the expected HTTP response
|
||||||
|
assert.equal(ctx.status, 200)
|
||||||
|
|
||||||
|
// Assert that expected properties exist in the returned data.
|
||||||
|
assert.property(ctx.response.body, 'status')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#Get /ips', () => {
|
||||||
|
it('should return 422 status on biz logic error', async () => {
|
||||||
|
try {
|
||||||
|
sandbox.stub(uut.useCases.usage, 'getTopIps').throws(new Error('test error'))
|
||||||
|
await uut.getTopIps(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(err)
|
||||||
|
assert.equal(err.status, 422)
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return 200 status on success', async () => {
|
||||||
|
await uut.getTopIps(ctx)
|
||||||
|
|
||||||
|
// Assert the expected HTTP response
|
||||||
|
assert.equal(ctx.status, 200)
|
||||||
|
|
||||||
|
// Assert that expected properties exist in the returned data.
|
||||||
|
assert.property(ctx.response.body, 'ips')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#Get /endpoints', () => {
|
||||||
|
it('should return 422 status on biz logic error', async () => {
|
||||||
|
try {
|
||||||
|
sandbox.stub(uut.useCases.usage, 'getTopEndpoints').throws(new Error('test error'))
|
||||||
|
await uut.getTopEndpoints(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(err)
|
||||||
|
assert.equal(err.status, 422)
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return 200 status on success', async () => {
|
||||||
|
await uut.getTopEndpoints(ctx)
|
||||||
|
|
||||||
|
// Assert the expected HTTP response
|
||||||
|
assert.equal(ctx.status, 200)
|
||||||
|
|
||||||
|
// Assert that expected properties exist in the returned data.
|
||||||
|
assert.property(ctx.response.body, 'endpoints')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#handleError', () => {
|
||||||
|
it('should pass an error message', () => {
|
||||||
|
try {
|
||||||
|
const err = {
|
||||||
|
status: 422,
|
||||||
|
message: 'Unprocessable Entity'
|
||||||
|
}
|
||||||
|
|
||||||
|
uut.handleError(ctx, err)
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Unprocessable Entity')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should still throw error if there is no message', () => {
|
||||||
|
try {
|
||||||
|
const err = {
|
||||||
|
status: 404
|
||||||
|
}
|
||||||
|
|
||||||
|
uut.handleError(ctx, err)
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Not Found')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the REST API handler for the /usage endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public npm libraries
|
||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
// Local support libraries
|
||||||
|
import adapters from '../../../mocks/adapters/index.js'
|
||||||
|
|
||||||
|
import UseCasesMock from '../../../mocks/use-cases/index.js'
|
||||||
|
|
||||||
|
import UsageRouter from '../../../../../src/controllers/rest-api/usage/index.js'
|
||||||
|
|
||||||
|
let uut
|
||||||
|
let sandbox
|
||||||
|
// let ctx
|
||||||
|
|
||||||
|
// const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
||||||
|
|
||||||
|
describe('#Usage-REST-Router', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const useCases = new UseCasesMock()
|
||||||
|
uut = new UsageRouter({ adapters, useCases })
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('#constructor', () => {
|
||||||
|
it('should throw an error if adapters are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new UsageRouter()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Adapters library required when instantiating IPFS REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error if useCases are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new UsageRouter({ adapters })
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of Use Cases library required when instantiating IPFS REST Controller.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#attach', () => {
|
||||||
|
it('should throw an error if app is not passed in.', () => {
|
||||||
|
try {
|
||||||
|
uut.attach()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Must pass app object when attaching REST API controllers.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -79,4 +79,19 @@ describe('#Timer-Controllers', () => {
|
|||||||
assert.equal(result, false)
|
assert.equal(result, false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('#cleanUsage', () => {
|
||||||
|
it('should kick off the Use Case', async () => {
|
||||||
|
const result = await uut.cleanUsage()
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false on error', async () => {
|
||||||
|
sandbox.stub(uut.useCases.usage, 'cleanUsage').throws(new Error('test error'))
|
||||||
|
const result = await uut.cleanUsage()
|
||||||
|
|
||||||
|
assert.equal(result, false)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -31,12 +31,31 @@ class UserUseCaseMock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UsageUseCaseMock {
|
||||||
|
async cleanUsage() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRestSummary() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTopIps(params) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTopEndpoints(existingUser, newData) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class UseCasesMock {
|
class UseCasesMock {
|
||||||
constuctor(localConfig = {}) {
|
constuctor(localConfig = {}) {
|
||||||
// this.user = new UserUseCaseMock(localConfig)
|
// this.user = new UserUseCaseMock(localConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
user = new UserUseCaseMock()
|
user = new UserUseCaseMock()
|
||||||
|
usage = new UsageUseCaseMock()
|
||||||
}
|
}
|
||||||
|
|
||||||
export default UseCasesMock;
|
export default UseCasesMock;
|
||||||
|
|||||||
@@ -0,0 +1,255 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the use-cases/usage-use-cases.js business logic library.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public npm libraries
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
// Local support libraries
|
||||||
|
import adapters from '../mocks/adapters/index.js'
|
||||||
|
|
||||||
|
// Mock
|
||||||
|
import { context as mockContext } from '../mocks/ctx-mock.js'
|
||||||
|
|
||||||
|
// Unit under test (uut)
|
||||||
|
import { UsageUseCases, restCalls, usageMiddleware } from '../../../src/use-cases/usage-use-cases.js'
|
||||||
|
|
||||||
|
describe('#usage-use-case', () => {
|
||||||
|
let uut
|
||||||
|
let sandbox
|
||||||
|
let ctx
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
uut = new UsageUseCases({ adapters })
|
||||||
|
|
||||||
|
// Set as empty array
|
||||||
|
restCalls.splice(0, restCalls.length)
|
||||||
|
|
||||||
|
ctx = mockContext()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('#constructor', () => {
|
||||||
|
it('should throw an error if adapters are not passed in', () => {
|
||||||
|
try {
|
||||||
|
uut = new UsageUseCases()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(
|
||||||
|
err.message,
|
||||||
|
'Instance of adapters must be passed in when instantiating Usage Use Cases library.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#cleanUsage', () => {
|
||||||
|
it('should delete older data than 24 hours', () => {
|
||||||
|
const now = new Date() // Mock date
|
||||||
|
|
||||||
|
// set older mock data
|
||||||
|
restCalls.push({
|
||||||
|
timestamp: now.getTime() - (60000 * 60 * 24),
|
||||||
|
ip: '127.0.0.1'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Set recently mock data
|
||||||
|
restCalls.push({
|
||||||
|
timestamp: now.getTime(),
|
||||||
|
ip: 'localhost'
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = uut.cleanUsage()
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
assert.equal(result.length, 1)
|
||||||
|
assert.equal(result[0].ip, 'localhost')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle error', () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(restCalls, 'filter').throws(new Error('uut error'))
|
||||||
|
|
||||||
|
uut.cleanUsage()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (error) {
|
||||||
|
assert.equal(error.message, 'uut error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('#getRestSummary', () => {
|
||||||
|
it('should get the number of rest calls', () => {
|
||||||
|
// Set mock data
|
||||||
|
restCalls.push({
|
||||||
|
ip: 'localhost'
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = uut.getRestSummary()
|
||||||
|
|
||||||
|
assert.isNumber(result)
|
||||||
|
assert.equal(result, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle error', () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(console, 'log').throws(new Error('uut error'))
|
||||||
|
|
||||||
|
uut.getRestSummary()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (error) {
|
||||||
|
assert.equal(error.message, 'uut error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#getTopIps', () => {
|
||||||
|
it('should get top IPs', () => {
|
||||||
|
// Set mock data
|
||||||
|
restCalls.push({
|
||||||
|
ip: 'localhost'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Set mock data
|
||||||
|
restCalls.push({
|
||||||
|
ip: 'localhost'
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = uut.getTopIps()
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
|
||||||
|
assert.property(result[0], 'ip')
|
||||||
|
assert.property(result[0], 'cnt')
|
||||||
|
|
||||||
|
assert.equal(result[0].ip, 'localhost')
|
||||||
|
assert.equal(result[0].cnt, '2')
|
||||||
|
})
|
||||||
|
it('should return a maximum of 20 values', () => {
|
||||||
|
// Fill Array with 21 values
|
||||||
|
for (let i = 0; i < 21; i++) {
|
||||||
|
restCalls.push({
|
||||||
|
ip: `localhost-${i}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = uut.getTopIps()
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
|
||||||
|
assert.property(result[0], 'ip')
|
||||||
|
assert.property(result[0], 'cnt')
|
||||||
|
|
||||||
|
assert.equal(result.length, 20)
|
||||||
|
})
|
||||||
|
it('should handle error', () => {
|
||||||
|
try {
|
||||||
|
// Set mock data
|
||||||
|
restCalls.push(null)
|
||||||
|
|
||||||
|
uut.getTopIps()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (error) {
|
||||||
|
assert.include(error.message, 'Cannot read properties')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#getTopEndpoints', () => {
|
||||||
|
it('should get top Endpoints', () => {
|
||||||
|
// Set mock data
|
||||||
|
restCalls.push({
|
||||||
|
ip: 'localhost',
|
||||||
|
url: '/api/v1/users',
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Set mock data
|
||||||
|
restCalls.push({
|
||||||
|
ip: 'localhost',
|
||||||
|
url: '/api/v1/users',
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = uut.getTopEndpoints()
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
|
||||||
|
assert.property(result[0], 'endpoint')
|
||||||
|
assert.property(result[0], 'cnt')
|
||||||
|
|
||||||
|
assert.equal(result[0].endpoint, 'GET /api/v1/users')
|
||||||
|
assert.equal(result[0].cnt, '2')
|
||||||
|
})
|
||||||
|
it('should return a maximum of 20 values', () => {
|
||||||
|
// Fill Array with 21 values
|
||||||
|
for (let i = 0; i < 21; i++) {
|
||||||
|
restCalls.push({
|
||||||
|
ip: 'localhost',
|
||||||
|
url: `/api/v1/users-${i}`,
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = uut.getTopEndpoints()
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
|
||||||
|
assert.property(result[0], 'endpoint')
|
||||||
|
assert.property(result[0], 'cnt')
|
||||||
|
|
||||||
|
assert.equal(result.length, 20)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle error', () => {
|
||||||
|
try {
|
||||||
|
// Set mock data
|
||||||
|
restCalls.push(null)
|
||||||
|
|
||||||
|
uut.getTopEndpoints()
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (error) {
|
||||||
|
assert.include(error.message, 'Cannot read properties')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#usageMiddleware', () => {
|
||||||
|
it('should update restCalls state', async () => {
|
||||||
|
// Spy on next
|
||||||
|
const next = sinon.spy(() => { })
|
||||||
|
|
||||||
|
await usageMiddleware()(ctx, next)
|
||||||
|
|
||||||
|
assert.equal(restCalls.length, 1)
|
||||||
|
assert.isTrue(next.called)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle error', async () => {
|
||||||
|
try {
|
||||||
|
const next = () => { throw new Error('uut error') }
|
||||||
|
|
||||||
|
await usageMiddleware()(ctx, next)
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (error) {
|
||||||
|
assert.equal(error.message, 'uut error')
|
||||||
|
assert.equal(ctx.status, 500)
|
||||||
|
assert.equal(restCalls.length, 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user