refactor: parameterize configureApp function (inject db list)

Reason: easier testing (mocking) and better readability

Note: did additional refactoring
This commit is contained in:
Jovan Krunić
2020-10-23 10:31:25 +02:00
committed by Rainer Killinger
parent f3b86f0f0d
commit fe7dd09d7e
5 changed files with 58 additions and 38 deletions

View File

@@ -38,12 +38,11 @@ import {thingUpdateRouter} from './routes/thing-update-route';
import {virtualPluginRoute} from './routes/virtual-plugin-route'; import {virtualPluginRoute} from './routes/virtual-plugin-route';
import {BulkStorage} from './storage/bulk-storage'; import {BulkStorage} from './storage/bulk-storage';
import {DatabaseConstructor} from './storage/database'; import {DatabaseConstructor} from './storage/database';
import {Elasticsearch} from './storage/elasticsearch/elasticsearch';
/** /**
* Configure the backend * Configure the backend
*/ */
export async function configureApp(app: Express) { export async function configureApp(app: Express, databases: {[name: string]: DatabaseConstructor; }) {
let integrationTestTimeout: NodeJS.Timeout; let integrationTestTimeout: NodeJS.Timeout;
// request loggers have to be the first middleware to be set in express // request loggers have to be the first middleware to be set in express
app.use(morgan('dev', { app.use(morgan('dev', {
@@ -59,11 +58,8 @@ export async function configureApp(app: Express) {
} }
// tslint:disable-next-line: no-magic-numbers // tslint:disable-next-line: no-magic-numbers
if (res.statusCode < 400) { return res.statusCode < 400;
return true;
}
return false;
}, stream: process.stdout, }, stream: process.stdout,
})); }));
@@ -142,10 +138,6 @@ export async function configureApp(app: Express) {
.on('end', endCallback); .on('end', endCallback);
}); });
const databases: {[name: string]: DatabaseConstructor; } = {
elasticsearch: Elasticsearch,
};
// validate config file // validate config file
await validator.addSchemas(join('node_modules', '@openstapps', 'core', 'lib', 'schema')); await validator.addSchemas(join('node_modules', '@openstapps', 'core', 'lib', 'schema'));

View File

@@ -17,6 +17,7 @@ import {Logger} from '@openstapps/logger';
import express from 'express'; import express from 'express';
import http from 'http'; import http from 'http';
import {configureApp} from './app'; import {configureApp} from './app';
import {Elasticsearch} from './storage/elasticsearch/elasticsearch';
const app = express(); const app = express();
@@ -95,7 +96,7 @@ function onListening() {
Logger.ok(`Listening on ${bind}`); Logger.ok(`Listening on ${bind}`);
} }
configureApp(app) configureApp(app, {elasticsearch: Elasticsearch})
.then(() => { .then(() => {
Logger.ok('Successfully configured express server'); Logger.ok('Successfully configured express server');
// After app setup listen on provided port, on all network interfaces // After app setup listen on provided port, on all network interfaces

View File

@@ -13,14 +13,17 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {SCSearchQuery, SCSearchResponse, SCThings, SCUuid} from '@openstapps/core'; import {SCConfigFile, SCSearchQuery, SCSearchResponse, SCThings, SCThingType, SCUuid} from '@openstapps/core';
import {Express} from 'express'; import {Express} from 'express';
import moment from 'moment';
import {configureApp} from '../src/app'; import {configureApp} from '../src/app';
import express from 'express'; import express from 'express';
import http from 'http'; import http from 'http';
import {configFile} from '../src/common';
import {MailQueue} from '../src/notification/mail-queue';
import {Bulk, BulkStorage} from '../src/storage/bulk-storage'; import {Bulk, BulkStorage} from '../src/storage/bulk-storage';
import {Database} from '../src/storage/database';
import getPort from 'get-port'; import getPort from 'get-port';
import {Database} from '../src/storage/database';
/** /**
* Adds routers and configures an (express) app * Adds routers and configures an (express) app
@@ -29,7 +32,7 @@ import getPort from 'get-port';
export async function startApp(): Promise<Express> { export async function startApp(): Promise<Express> {
const app = express(); const app = express();
await configureApp(app); await configureApp(app, {elasticsearch: ElasticsearchMock});
const server = http.createServer(app); const server = http.createServer(app);
@@ -42,9 +45,9 @@ export async function startApp(): Promise<Express> {
}); });
return new Promise(resolve => server.on('listening', () => { return new Promise(resolve => server.on('listening', () => {
app.set( app.set(
'bulk', 'bulk',
bulkStorage, bulkStorageMock,
); );
resolve(app); resolve(app);
})); }));
@@ -58,7 +61,7 @@ export class ElasticsearchMock implements Database {
private bulk: Bulk | undefined; private bulk: Bulk | undefined;
private storageMock = new Map<string, SCThings>(); private storageMock = new Map<string, SCThings>();
constructor() { constructor(_configFile: SCConfigFile, _mailQueue?: MailQueue) {
// Nothing to do here // Nothing to do here
} }
@@ -98,9 +101,44 @@ export class ElasticsearchMock implements Database {
} }
} }
export const bulkStorage = new BulkStorage(new ElasticsearchMock()); export const bulkStorageMock = new BulkStorage(new ElasticsearchMock(configFile));
export const bulk: Bulk = {
expiration: moment().add(3600, 'seconds')
.format(),
source: 'some_source',
state: 'in progress',
type: SCThingType.Book,
uid: ''
};
export class FooError extends Error { export class FooError extends Error {
} }
export const DEFAULT_TEST_TIMEOUT = 10000; export const DEFAULT_TEST_TIMEOUT = 10000;
export const TRANSPORT_SEND_RESPONSE = 'Send Response';
export const getTransport = (verified: boolean) => {
return {
cc: undefined,
from: undefined,
recipients: undefined,
transportAgent: undefined,
verified: undefined,
isVerified(): boolean {
return verified;
},
send(_subject: string, _message: string): Promise<string> {
return Promise.resolve('');
},
sendMail(_mail: any): Promise<string> {
return Promise.resolve(TRANSPORT_SEND_RESPONSE);
},
verify(): Promise<boolean> {
return Promise.resolve(false);
}
}
}
export const index = 'stapps_footype_foosource_foobar';

View File

@@ -19,32 +19,21 @@ import {
SCBulkRequest, SCBulkRequest,
SCBulkRoute, SCBulkRoute,
SCNotFoundErrorResponse, SCNotFoundErrorResponse,
SCThingType
} from '@openstapps/core'; } from '@openstapps/core';
import {Bulk} from '../../src/storage/bulk-storage';
import {expect} from 'chai'; import {expect} from 'chai';
import {instance as book} from '@openstapps/core/test/resources/Book.1.json'; import {instance as book} from '@openstapps/core/test/resources/Book.1.json';
import moment from 'moment'; import {bulk, DEFAULT_TEST_TIMEOUT} from '../common';
import {DEFAULT_TEST_TIMEOUT} from '../common';
import {testApp} from '../tests-setup'; import {testApp} from '../tests-setup';
describe('Bulk routes', async function () { describe('Bulk routes', async function () {
// increase timeout for the suite // increase timeout for the suite
this.timeout(DEFAULT_TEST_TIMEOUT); this.timeout(DEFAULT_TEST_TIMEOUT);
const bulkObj: Bulk = {
expiration: moment().add(3600, 'seconds')
.format(),
source: 'some_source',
state: 'in progress',
type: SCThingType.Book,
uid: ''
};
const request: SCBulkRequest = { const request: SCBulkRequest = {
expiration: bulkObj.expiration, expiration: bulk.expiration,
source: bulkObj.source, source: bulk.source,
type: bulkObj.type, type: bulk.type,
}; };
const bulkRoute = new SCBulkRoute(); const bulkRoute = new SCBulkRoute();
const bulkAddRoute = new SCBulkAddRoute(); const bulkAddRoute = new SCBulkAddRoute();
const bulkDoneRoute = new SCBulkDoneRoute(); const bulkDoneRoute = new SCBulkDoneRoute();
@@ -62,7 +51,7 @@ describe('Bulk routes', async function () {
expect(status).to.be.equal(bulkRoute.statusCodeSuccess); expect(status).to.be.equal(bulkRoute.statusCodeSuccess);
expect(error).to.be.equal(false); expect(error).to.be.equal(false);
expect(body.uid).to.be.a('string'); expect(body.uid).to.be.a('string');
expect(body).to.deep.equal({...bulkObj, uid: body.uid}); expect(body).to.deep.equal({...bulk, uid: body.uid});
}); });
it('should return (throw) error if a bulk with the provided UID cannot be found when adding to a bulk', async function () { it('should return (throw) error if a bulk with the provided UID cannot be found when adding to a bulk', async function () {

View File

@@ -15,7 +15,7 @@
*/ */
import {SCThingUpdateRoute} from '@openstapps/core'; import {SCThingUpdateRoute} from '@openstapps/core';
import chaiAsPromised from 'chai-as-promised'; import chaiAsPromised from 'chai-as-promised';
import {bulkStorage, DEFAULT_TEST_TIMEOUT} from '../common'; import {bulkStorageMock, DEFAULT_TEST_TIMEOUT} from '../common';
import {expect, use} from 'chai'; import {expect, use} from 'chai';
import {instance as book} from '@openstapps/core/test/resources/Book.1.json'; import {instance as book} from '@openstapps/core/test/resources/Book.1.json';
import {testApp} from '../tests-setup'; import {testApp} from '../tests-setup';
@@ -38,6 +38,6 @@ describe('Thing update route', async function () {
.send(book); .send(book);
expect(status).to.equal(thingUpdateRoute.statusCodeSuccess); expect(status).to.equal(thingUpdateRoute.statusCodeSuccess);
expect(bulkStorage.database.get(book.uid)).to.eventually.be.deep.equal(book); expect(bulkStorageMock.database.get(book.uid)).to.eventually.be.deep.equal(book);
}); });
}); });