diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/server/db/MongoServerDaoTest.js | 157 | ||||
-rw-r--r-- | test/server/db/MongoServerDaoTest.ts | 7 | ||||
-rw-r--r-- | test/system/DeltaProcessorTest.ts | 312 | ||||
-rw-r--r-- | test/system/DeltaPublisherTest.ts | 221 | ||||
-rw-r--r-- | test/system/EventLoggerTest.ts | 103 | ||||
-rw-r--r-- | test/system/EventMediatorTest.ts | 139 | ||||
-rw-r--r-- | test/system/MetricsCollectorTest.ts | 26 | ||||
-rw-r--r-- | test/system/StandardLoggerTest.ts | 178 |
8 files changed, 776 insertions, 367 deletions
diff --git a/test/server/db/MongoServerDaoTest.js b/test/server/db/MongoServerDaoTest.js deleted file mode 100644 index d6c8bf1..0000000 --- a/test/server/db/MongoServerDaoTest.js +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Tests MongoServerDao - * - * Copyright (C) 2010-2019 R-T Specialty, LLC. - * - * This file is part of the Liza Data Collection Framework. - * - * liza is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -'use strict'; -Object.defineProperty(exports, "__esModule", { value: true }); -var MongoServerDao_1 = require("../../../src/server/db/MongoServerDao"); -var chai_1 = require("chai"); -chai_1.use(require('chai-as-promised')); -describe('MongoServerDao', function () { - describe('#saveQuote', function () { - describe("with no save data or push data", function () { - it("saves entire metabucket record individually", function (done) { - var metadata = { - foo: ['bar', 'baz'], - bar: [{ quux: 'quuux' }], - }; - var quote = createStubQuote(metadata); - var sut = new MongoServerDao_1.MongoServerDao(createMockDb( - // update - function (_selector, data) { - chai_1.expect(data.$set['meta.foo']) - .to.deep.equal(metadata.foo); - chai_1.expect(data.$set['meta.bar']) - .to.deep.equal(metadata.bar); - chai_1.expect(data.$push).to.equal(undefined); - done(); - })); - sut.init(function () { - return sut.saveQuote(quote, function () { }, function () { }); - }); - }); - }); - describe("with push data", function () { - it("adds push data to the collection", function (done) { - var push_data = { - foo: ['bar', 'baz'], - bar: [{ quux: 'quuux' }], - }; - var quote = createStubQuote({}); - var sut = new MongoServerDao_1.MongoServerDao(createMockDb( - // update - function (_selector, data) { - chai_1.expect(data.$push['foo']) - .to.deep.equal(push_data.foo); - chai_1.expect(data.$push['bar']) - .to.deep.equal(push_data.bar); - done(); - })); - sut.init(function () { - return sut.saveQuote(quote, function () { }, function () { }, undefined, push_data); - }); - }); - it("skips push data when it is an empty object", function (done) { - var push_data = {}; - var quote = createStubQuote({}); - var sut = new MongoServerDao_1.MongoServerDao(createMockDb( - // update - function (_selector, data) { - chai_1.expect(data.$push).to.equal(undefined); - done(); - })); - sut.init(function () { - return sut.saveQuote(quote, function () { }, function () { }, undefined, push_data); - }); - }); - }); - }); -}); -function createMockDb(on_update) { - var collection_quotes = { - update: on_update, - createIndex: function (_, __, c) { return c(); }, - }; - var collection_seq = { - find: function (_, __, c) { - c(null, { - toArray: function (c) { return c(null, { length: 5 }); }, - }); - }, - }; - var db = { - collection: function (id, c) { - var coll = (id === 'quotes') - ? collection_quotes - : collection_seq; - c(null, coll); - }, - }; - var driver = { - open: function (c) { return c(null, db); }, - on: function () { }, - }; - return driver; -} -function createStubQuote(metadata) { - var program = { - getId: function () { return '1'; }, - ineligibleLockCount: 0, - apis: {}, - internal: {}, - meta: { - arefs: {}, - fields: {}, - groups: {}, - qdata: {}, - qtypes: {}, - }, - mapis: {}, - initQuote: function () { }, - }; - var quote = { - getBucket: function () { return ({ - getData: function () { }, - }); }, - getMetabucket: function () { return ({ - getData: function () { return metadata; }, - }); }, - getId: function () { return 123; }, - getProgramVersion: function () { return 'Foo'; }, - getLastPremiumDate: function () { return 0; }, - getRatedDate: function () { return 0; }, - getExplicitLockReason: function () { return ""; }, - getExplicitLockStep: function () { return 1; }, - isImported: function () { return false; }, - isBound: function () { return false; }, - getTopVisitedStepId: function () { return 1; }, - getTopSavedStepId: function () { return 1; }, - setRatedDate: function () { return quote; }, - setRateBucket: function () { return quote; }, - setRatingData: function () { return quote; }, - getRatingData: function () { return ({ _unavailable_all: '0' }); }, - getProgram: function () { return program; }, - setExplicitLock: function () { return quote; }, - getProgramId: function () { return 'Foo'; }, - getCurrentStepId: function () { return 0; }, - setLastPremiumDate: function () { return quote; }, - }; - return quote; -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTW9uZ29TZXJ2ZXJEYW9UZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiTW9uZ29TZXJ2ZXJEYW9UZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBRUgsWUFBWSxDQUFDOztBQUViLHdFQUE4RTtBQUU5RSw2QkFBK0M7QUFRL0MsVUFBUSxDQUFFLE9BQU8sQ0FBRSxrQkFBa0IsQ0FBRSxDQUFFLENBQUM7QUFHMUMsUUFBUSxDQUFFLGdCQUFnQixFQUFFO0lBRXhCLFFBQVEsQ0FBRSxZQUFZLEVBQUU7UUFFcEIsUUFBUSxDQUFFLGdDQUFnQyxFQUFFO1lBRXhDLEVBQUUsQ0FBRSw2Q0FBNkMsRUFBRSxVQUFBLElBQUk7Z0JBRW5ELElBQU0sUUFBUSxHQUFHO29CQUNiLEdBQUcsRUFBRSxDQUFFLEtBQUssRUFBRSxLQUFLLENBQUU7b0JBQ3JCLEdBQUcsRUFBRSxDQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxDQUFFO2lCQUM3QixDQUFDO2dCQUVGLElBQU0sS0FBSyxHQUFHLGVBQWUsQ0FBRSxRQUFRLENBQUUsQ0FBQztnQkFFMUMsSUFBTSxHQUFHLEdBQUcsSUFBSSwrQkFBRyxDQUFFLFlBQVk7Z0JBQzdCLFNBQVM7Z0JBQ1QsVUFBRSxTQUF3QixFQUFFLElBQWlCO29CQUV6QyxhQUFNLENBQUUsSUFBSSxDQUFDLElBQUksQ0FBRSxVQUFVLENBQUUsQ0FBRTt5QkFDNUIsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUUsUUFBUSxDQUFDLEdBQUcsQ0FBRSxDQUFDO29CQUVuQyxhQUFNLENBQUUsSUFBSSxDQUFDLElBQUksQ0FBRSxVQUFVLENBQUUsQ0FBRTt5QkFDNUIsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUUsUUFBUSxDQUFDLEdBQUcsQ0FBRSxDQUFDO29CQUduQyxhQUFNLENBQUUsSUFBSSxDQUFDLEtBQUssQ0FBRSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENB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
\ No newline at end of file diff --git a/test/server/db/MongoServerDaoTest.ts b/test/server/db/MongoServerDaoTest.ts index b0a83bb..58e6ab9 100644 --- a/test/server/db/MongoServerDaoTest.ts +++ b/test/server/db/MongoServerDaoTest.ts @@ -22,7 +22,7 @@ 'use strict'; import { MongoServerDao as Sut } from "../../../src/server/db/MongoServerDao"; -import { MongoSelector, MongoUpdate } from "mongodb"; +import { MongoSelector, MongoUpdate, MongoDb } from "mongodb"; import { expect, use as chai_use } from 'chai'; import { ServerSideQuote } from "../../../src/server/quote/ServerSideQuote"; import { PositiveInteger } from "../../../src/numeric"; @@ -139,7 +139,7 @@ describe( 'MongoServerDao', () => } ); -function createMockDb( on_update: any ) +function createMockDb( on_update: any ): MongoDb { const collection_quotes = { update: on_update, @@ -166,8 +166,9 @@ function createMockDb( on_update: any ) }, }; - const driver = { + const driver = <MongoDb>{ open: ( c: any ) => c( null, db ), + close: () => {}, on: () => {}, }; diff --git a/test/system/DeltaProcessorTest.ts b/test/system/DeltaProcessorTest.ts index d0cd8f8..3998d68 100644 --- a/test/system/DeltaProcessorTest.ts +++ b/test/system/DeltaProcessorTest.ts @@ -22,7 +22,8 @@ import { DeltaProcessor as Sut } from '../../src/system/DeltaProcessor'; import { AmqpPublisher } from '../../src/system/AmqpPublisher'; import { DeltaDao } from '../../src/system/db/DeltaDao'; -import { DeltaType } from "../../src/bucket/delta"; +import { DeltaType, DeltaDocument } from "../../src/bucket/delta"; +import { DocumentId } from '../../src/document/Document'; import { EventEmitter } from 'events'; import { expect, use as chai_use } from 'chai'; @@ -308,11 +309,12 @@ describe( 'system.DeltaProcessor', () => }[]>[ { label: 'No deltas are processed', - docs: [ + given: [ { id: 123, lastUpdate: 123123123, - bucket: {}, + data: {}, + ratedata: {}, rdelta: {}, }, ], @@ -324,7 +326,8 @@ describe( 'system.DeltaProcessor', () => { id: 123, lastUpdate: 123123123, - bucket: { foo: [ 'start_bar' ] }, + data: { foo: [ 'start_bar' ] }, + ratedata: {}, rdelta: { data: [ { @@ -341,14 +344,16 @@ describe( 'system.DeltaProcessor', () => ], expected: [ { - delta: { foo: [ 'first_bar' ] }, - bucket: { foo: [ 'first_bar' ] }, - doc_id: 123, + doc_id: 123, + delta: { foo: [ 'first_bar' ] }, + bucket: { foo: [ 'first_bar' ] }, + ratedata: {}, }, { - delta: { foo: [ 'second_bar' ] }, - bucket: { foo: [ 'second_bar' ] }, - doc_id: 123, + doc_id: 123, + delta: { foo: [ 'second_bar' ] }, + bucket: { foo: [ 'second_bar' ] }, + ratedata: {}, }, ], }, @@ -358,17 +363,18 @@ describe( 'system.DeltaProcessor', () => { id: 123, lastUpdate: 123123123, - bucket: { foo: 'start_bar' }, + data: { foo: [ 'start_bar_123' ] }, + ratedata: {}, rdelta: { data: [ { - data: { foo: [ 'second_bar' ] }, + data: { foo: [ 'second_bar_123' ] }, timestamp: 234, }, ], ratedata: [ { - data: { foo: [ 'first_bar' ] }, + data: { foo: [ 'first_bar_123' ] }, timestamp: 123, }, ], @@ -377,19 +383,20 @@ describe( 'system.DeltaProcessor', () => { id: 234, lastUpdate: 123123123, - bucket: { foo: 'start_bar' }, + data: { foo: [ 'start_bar_234' ] }, + ratedata: {}, rdelta: { data: [ { - data: { foo: [ 'first_bar' ] }, + data: { foo: [ 'first_bar_234' ] }, timestamp: 123, }, { - data: { foo: [ 'second_bar' ] }, + data: { foo: [ 'second_bar_234' ] }, timestamp: 234, }, { - data: { foo: [ 'third_bar' ] }, + data: { foo: [ 'third_bar_234' ] }, timestamp: 345, }, ], @@ -398,15 +405,16 @@ describe( 'system.DeltaProcessor', () => { id: 345, lastUpdate: 123123123, - bucket: { foo: 'start_bar' }, + data: { foo: [ 'start_bar_345' ] }, + ratedata: {}, rdelta: { ratedata: [ { - data: { foo: [ 'first_bar' ] }, + data: { foo: [ 'first_bar_345' ] }, timestamp: 123, }, { - data: { foo: [ 'second_bar' ] }, + data: { foo: [ 'second_bar_345' ] }, timestamp: 234, }, ], @@ -415,60 +423,73 @@ describe( 'system.DeltaProcessor', () => ], expected: [ { - delta: { foo: [ 'first_bar' ] }, - bucket: { foo: [ 'first_bar' ] }, - doc_id: 123, + doc_id: 123, + delta: { foo: [ 'first_bar_123' ] }, + bucket: { foo: [ 'start_bar_123' ] }, + ratedata: { foo: [ 'first_bar_123' ] }, }, { - delta: { foo: [ 'second_bar' ] }, - bucket: { foo: [ 'second_bar' ] }, - doc_id: 123, + doc_id: 123, + delta: { foo: [ 'second_bar_123' ] }, + bucket: { foo: [ 'second_bar_123' ] }, + ratedata: { foo: [ 'first_bar_123' ] }, }, { - delta: { foo: [ 'first_bar' ] }, - bucket: { foo: [ 'first_bar' ] }, - doc_id: 234, + doc_id: 234, + delta: { foo: [ 'first_bar_234' ] }, + bucket: { foo: [ 'first_bar_234' ] }, + ratedata: {}, }, { - delta: { foo: [ 'second_bar' ] }, - bucket: { foo: [ 'second_bar' ] }, - doc_id: 234, + doc_id: 234, + delta: { foo: [ 'second_bar_234' ] }, + bucket: { foo: [ 'second_bar_234' ] }, + ratedata: {}, }, { - delta: { foo: [ 'third_bar' ] }, - bucket: { foo: [ 'third_bar' ] }, - doc_id: 234, + doc_id: 234, + delta: { foo: [ 'third_bar_234' ] }, + bucket: { foo: [ 'third_bar_234' ] }, + ratedata: {}, }, { - delta: { foo: [ 'first_bar' ] }, - bucket: { foo: [ 'first_bar' ] }, - doc_id: 345, + doc_id: 345, + delta: { foo: [ 'first_bar_345' ] }, + bucket: { foo: [ 'start_bar_345' ] }, + ratedata: { foo: [ 'first_bar_345' ] }, }, { - delta: { foo: [ 'second_bar' ] }, - bucket: { foo: [ 'second_bar' ] }, - doc_id: 345, + doc_id: 345, + delta: { foo: [ 'second_bar_345' ] }, + bucket: { foo: [ 'start_bar_345' ] }, + ratedata: { foo: [ 'second_bar_345' ] }, }, ], }, - ] ).forEach( ( { given, expected, label } ) => it( label, () => + ] ).forEach( ( { label, given, expected } ) => it( label, () => { let published: any = []; const dao = createMockDeltaDao(); const publisher = createMockDeltaPublisher(); const emitter = new EventEmitter(); - dao.getUnprocessedDocuments = (): Promise<Record<string, any>[]> => + dao.getUnprocessedDocuments = (): Promise<DeltaDocument[]> => { return Promise.resolve( given ); } - publisher.publish = ( delta, bucket, doc_id ): Promise<void> => + publisher.publish = ( + doc_id, + delta, + bucket, + ratedata, + ): Promise<void> => { published.push( { - delta: delta.data, - bucket: bucket, - doc_id: doc_id, + doc_id: doc_id, + delta: delta.data, + bucket: bucket, + ratedata: ratedata, } ); return Promise.resolve(); @@ -479,6 +500,203 @@ describe( 'system.DeltaProcessor', () => .then( _ => expect( published ).to.deep.equal( expected ) ); } ) ); } ); + + + describe( 'Error handling', () => + { + it( 'Marks document in error state and continues', () => + { + let published: any = []; + let error_flag_set = false; + const dao = createMockDeltaDao(); + const publisher = createMockDeltaPublisher(); + const emitter = new EventEmitter(); + const doc = <DeltaDocument[]>[ { + id: <DocumentId>123, + lastUpdate: <UnixTimestamp>123123123, + data: { foo: [ 'start_bar' ] }, + ratedata: {}, + rdelta: { + data: [ + { + data: { foo: [ 'first_bar' ] }, + timestamp: <UnixTimestamp>123123, + type: 'data', + } + ], + ratedata: [], + }, + }, + { + id: <DocumentId>234, + lastUpdate: <UnixTimestamp>123123123, + data: { foo: [ 'start_bar' ] }, + ratedata: {}, + rdelta: { + data: [ + { + data: { foo: [ 'first_bar' ] }, + timestamp: <UnixTimestamp>123123, + type: 'data', + } + ], + ratedata: [], + }, + } ]; + + const expected_published = [ + { + doc_id: 123, + delta: { foo: [ 'first_bar' ] }, + bucket: { foo: [ 'first_bar' ] }, + ratedata: {}, + }, + { + doc_id: 234, + delta: { foo: [ 'first_bar' ] }, + bucket: { foo: [ 'first_bar' ] }, + ratedata: {}, + } + ]; + + const expected_error = 'Uh oh'; + + dao.getUnprocessedDocuments = (): Promise<DeltaDocument[]> => + Promise.resolve( doc ); + + dao.markDocumentAsProcessed = ( _doc_id, _ts ): Promise<void> => + Promise.reject( new Error( expected_error ) ); + + dao.setErrorFlag = (): Promise<void> => + { + error_flag_set = true; + return Promise.resolve(); + } + + publisher.publish = ( + doc_id, + delta, + bucket, + ratedata, + ): Promise<void> => + { + published.push( { + doc_id: doc_id, + delta: delta.data, + bucket: bucket, + ratedata: ratedata, + } ); + + return Promise.resolve(); + } + + // Prevent node from converting an error event into an error + emitter.on( 'error', () => {} ); + + return expect( new Sut( dao, publisher, emitter ).process() ) + .to.eventually.deep.equal( undefined ) + .then( _ => + { + expect( error_flag_set ).to.be.true; + expect( published ).to.deep.equal( expected_published ); + } ); + } ); + } ); + + + describe( 'Error handling', () => + { + it( 'Failure to set document error state further processing', () => + { + let published: any = []; + let caught_error = ''; + const dao = createMockDeltaDao(); + const publisher = createMockDeltaPublisher(); + const emitter = new EventEmitter(); + const doc = <DeltaDocument[]>[ { + id: <DocumentId>123, + lastUpdate: <UnixTimestamp>123123123, + data: { foo: [ 'start_bar' ] }, + ratedata: {}, + rdelta: { + data: [ + { + data: { foo: [ 'first_bar' ] }, + timestamp: <UnixTimestamp>123123, + type: 'data', + } + ], + ratedata: [], + }, + }, + { + id: <DocumentId>234, + lastUpdate: <UnixTimestamp>123123123, + data: { foo: [ 'start_bar' ] }, + ratedata: {}, + rdelta: { + data: [ + { + data: { foo: [ 'first_bar' ] }, + timestamp: <UnixTimestamp>123123, + type: 'data', + } + ], + ratedata: [], + }, + } ]; + + // Only one is published + const expected_published = [ { + doc_id: 123, + delta: { foo: [ 'first_bar' ] }, + bucket: { foo: [ 'first_bar' ] }, + ratedata: {}, + } ]; + + const expected_error = 'Uh oh'; + + dao.getUnprocessedDocuments = (): Promise<DeltaDocument[]> => + Promise.resolve( doc ); + + dao.markDocumentAsProcessed = ( _doc_id, _ts ): Promise<void> => + Promise.reject( new Error( 'Couldn\'t mark document' ) ); + + dao.setErrorFlag = (): Promise<void> => + Promise.reject( new Error( expected_error ) ); + + publisher.publish = ( + doc_id, + delta, + bucket, + ratedata, + ): Promise<void> => + { + published.push( { + doc_id: doc_id, + delta: delta.data, + bucket: bucket, + ratedata: ratedata, + } ); + + return Promise.resolve(); + } + + // Prevent node from converting an error event into an error + emitter.on( 'error', () => {} ); + + return expect( + new Sut( dao, publisher, emitter ).process() + .catch( e => { caught_error = e.message } ) + ) + .to.eventually.deep.equal( undefined ) + .then( _ => + { + expect( caught_error ).to.equal( expected_error ); + expect( published ).to.deep.equal( expected_published ); + } ); + } ); + } ); } ); diff --git a/test/system/DeltaPublisherTest.ts b/test/system/DeltaPublisherTest.ts index 40663d0..fcb788c 100644 --- a/test/system/DeltaPublisherTest.ts +++ b/test/system/DeltaPublisherTest.ts @@ -19,13 +19,25 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import { AmqpConnection } from '../../src/system/amqp/AmqpConnection'; +import { Delta, DeltaResult, DeltaType } from '../../src/bucket/delta'; import { DeltaPublisher as Sut } from '../../src/system/DeltaPublisher'; -import { AmqpConfig } from '../../src/system/AmqpPublisher'; +import { DocumentId } from '../../src/document/Document'; +import { Duplex } from 'stream'; import { EventEmitter } from "events"; +import { hasContext } from '../../src/error/ContextError'; +import { AmqpError } from '../../src/error/AmqpError'; +import { Channel } from 'amqplib'; +import { + createAvroEncoder, + AvroEncoderCtr, + AvroSchema, +} from '../../src/system/avro/AvroFactory'; import { expect, use as chai_use } from 'chai'; chai_use( require( 'chai-as-promised' ) ); +const sinon = require( 'sinon' ); describe( 'server.DeltaPublisher', () => { @@ -33,24 +45,96 @@ describe( 'server.DeltaPublisher', () => { it( 'sends a message', () => { - const conf = createMockConf(); - const emitter = new EventEmitter(); + let publish_called = false; + const delta = createMockDelta(); + const bucket = createMockBucketData(); + const ratedata = createMockBucketData(); + const emitter = new EventEmitter(); + const conn = createMockAmqpConnection(); + conn.getAmqpChannel = () => + { + return <Channel>{ + publish: ( _: any, __: any, buf: any, ___: any ) => + { + expect( buf instanceof Buffer ).to.be.true; - console.log( new Sut( conf, emitter, ts_ctr ) ); - expect( true ).to.be.true + publish_called = true; + + return true; + } + }; + }; + + const sut = new Sut( emitter, ts_ctr, createAvroEncoder, conn ); + + return expect( + sut.publish( <DocumentId>123, delta, bucket, ratedata ) + ).to.eventually.deep.equal( undefined ) + .then( _ => + { + expect( publish_called ).to.be.true; + } ); } ); - } ); - describe( '#sendMessage', () => - { - it( 'sends a message', () => + ( <[string, () => Channel | undefined, Error, string ][]>[ + [ + 'Throws an error when publishing was unsuccessful', + () => + { + return <Channel>{ + publish: ( _: any, __: any, _buf: any, ___: any ) => + { + return false; + } + }; + }, + Error, + 'Delta publish failed' + ], + [ + 'Throws an error when no amqp channel is found', + () => + { + return undefined; + }, + AmqpError, + 'Error sending message: No channel' + ] + ] ).forEach( ( [ label, getChannelF, error_type, err_msg ] ) => + it( label, () => { - const conf = createMockConf(); - const emitter = new EventEmitter(); + const delta = createMockDelta(); + const bucket = createMockBucketData(); + const ratedata = createMockBucketData(); + const emitter = new EventEmitter(); + const conn = createMockAmqpConnection(); + const doc_id = <DocumentId>123; + const expected = { + doc_id: doc_id, + delta_type: delta.type, + delta_ts: delta.timestamp + } - console.log( new Sut( conf, emitter, ts_ctr ) ); - expect( true ).to.be.true - } ); + conn.getAmqpChannel = getChannelF; + + const result = new Sut( emitter, ts_ctr, createAvroEncoder, conn ) + .publish( doc_id, delta, bucket, ratedata ); + + return Promise.all( [ + expect( result ).to.eventually.be.rejectedWith( + error_type, err_msg + ), + result.catch( e => + { + if ( !hasContext( e ) ) + { + return expect.fail(); + } + + return expect( e.context ).to.deep.equal( expected ); + } ) + ] ); + } ) ); } ); describe( '#avroEncode parses', () => @@ -137,32 +221,26 @@ describe( 'server.DeltaPublisher', () => { it( label, () => { - let errorCalled = false; + const emitter = createMockEventEmitter(); + const conn = createMockAmqpConnection(); + const data = createMockData( delta_data ); + const sut = new Sut( + emitter, + ts_ctr, + createAvroEncoder, + conn, + ); - const emitter = <EventEmitter>{ - emit( _event_id, _err ) + sut.avroEncode( data ) + .then( b => { - errorCalled = true; - - console.log( 'server.DeltaPublisher.Error' + _err ); - } - } - - const conf = createMockConf(); - const data = createMockData( delta_data ); - const sut = new Sut( conf, emitter, ts_ctr ); - const buffer = sut.avroEncode( data ); - - if ( valid ) - { - expect( typeof(buffer) ).to.equal( 'object' ); - } - else - { - expect( buffer ).to.equal( null ); - } - - expect( valid ).to.equal( !errorCalled ); + expect( typeof(b) ).to.equal( 'object' ); + expect( valid ).to.be.true; + } ) + .catch( _ => + { + expect( valid ).to.be.false; + } ); } ); } ); } ); @@ -301,9 +379,16 @@ describe( 'server.DeltaPublisher', () => { it( label, () => { - const emitter = <EventEmitter>{} - const conf = createMockConf(); - const sut = new Sut( conf, emitter, ts_ctr ); + const encoded = 'FooBar'; + const emitter = createMockEventEmitter(); + const conn = createMockAmqpConnection(); + const avroEncoderCtr = createMockEncoder( encoded ); + const sut = new Sut( + emitter, + ts_ctr, + avroEncoderCtr, + conn, + ); const actual = sut.setDataTypes( delta_data ); expect( actual ).to.deep.equal( expected ); @@ -312,14 +397,39 @@ describe( 'server.DeltaPublisher', () => } ); } ); + function ts_ctr(): UnixTimestamp { return <UnixTimestamp>Math.floor( new Date().getTime() / 1000 ); } -function createMockConf(): AmqpConfig + +function createMockEncoder( mock_encoded_data: string ): AvroEncoderCtr +{ + return ( _schema: AvroSchema ) => + { + const mock = sinon.mock( Duplex ); + + mock.on = ( _: string, __: any ) => {}; + mock.end = ( _: any ) => { return mock_encoded_data; }; + + return mock; + }; +} + + +function createMockEventEmitter(): EventEmitter +{ + return <EventEmitter>{}; +} + + +function createMockAmqpConnection(): AmqpConnection { - return <AmqpConfig>{}; + return <AmqpConnection>{ + connect: () => {}, + getExchangeName: () => { 'Foo' }, + }; } @@ -339,11 +449,8 @@ function createMockData( delta_data: any ): any modified: 1573856916, top_visited_step: '2', }, - session: { - entity_name: 'Foobar', - entity_id: 123123 , - }, - data: null, + data: null, + ratedata: null, delta: { Data: { bucket: delta_data, @@ -356,4 +463,22 @@ function createMockData( delta_data: any ): any }, }, }; +} + + +function createMockBucketData(): Record<string, any> +{ + return { + foo: [ 'bar', 'baz' ] + } +} + + +function createMockDelta(): Delta<any> +{ + return <Delta<any>>{ + type: <DeltaType>'data', + timestamp: <UnixTimestamp>123123123, + data: <DeltaResult<any>>{}, + } }
\ No newline at end of file diff --git a/test/system/EventLoggerTest.ts b/test/system/EventLoggerTest.ts deleted file mode 100644 index b3d5f0f..0000000 --- a/test/system/EventLoggerTest.ts +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Event logger test - * - * Copyright (C) 2010-2019 R-T Specialty, LLC. - * - * This file is part of the Liza Data Collection Framework. - * - * liza is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -import { EventLogger as Sut } from '../../src/system/EventLogger'; -import { EventEmitter } from "events"; -import { expect } from 'chai'; - -const sinon = require( 'sinon' ); - -declare interface MockConsole extends Console { - getLevel(): string, -} - -describe( 'system.EventLogger captures and logs events', () => -{ - [ - { - event_id: 'document-processed', - console_level: 'log', - }, - { - event_id: 'delta-publish', - console_level: 'log', - }, - { - event_id: 'amqp-conn-error', - console_level: 'warn', - }, - { - event_id: 'amqp-reconnect', - console_level: 'warn', - }, - { - event_id: 'amqp-reconnect-fail', - console_level: 'error', - }, - { - event_id: 'avro-err', - console_level: 'error', - }, - { - event_id: 'dao-err', - console_level: 'error', - }, - { - event_id: 'publish-err', - console_level: 'error', - }, - ].forEach( ( { event_id, console_level } ) => - { - it( event_id + ' triggers console output level: ' + console_level, () => - { - const emitter = new EventEmitter(); - const con = createMockConsole(); - const env = 'test'; - - new Sut( con, env, emitter, ts_ctr ); - - emitter.emit( event_id ); - - expect( con.getLevel() ).to.equal( console_level ); - } ); - } ); -} ); - - -function ts_ctr(): UnixTimestamp -{ - return <UnixTimestamp>Math.floor( new Date().getTime() / 1000 ); -} - - -function createMockConsole(): MockConsole -{ - const mock = sinon.mock( console ); - - mock.level = ''; - mock.info = ( _str: string ) => { mock.level = 'info'; }; - mock.log = ( _str: string ) => { mock.level = 'log'; }; - mock.warn = ( _str: string ) => { mock.level = 'warn'; }; - mock.error = ( _str: string ) => { mock.level = 'error'; }; - mock.getLevel = () => mock.level; - - return mock; -}
\ No newline at end of file diff --git a/test/system/EventMediatorTest.ts b/test/system/EventMediatorTest.ts new file mode 100644 index 0000000..581437c --- /dev/null +++ b/test/system/EventMediatorTest.ts @@ -0,0 +1,139 @@ +/** + * Event logger test + * + * Copyright (C) 2010-2019 R-T Specialty, LLC. + * + * This file is part of the Liza Data Collection Framework. + * + * liza is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import { EventMediator as Sut } from '../../src/system/EventMediator'; +import { context } from '../../src/error/ContextError'; +import { EventEmitter } from "events"; +import { expect } from 'chai'; +import { PsrLogger } from '../../src/system/PsrLogger'; + + +describe( 'system.EventLogger captures and logs events', () => +{ + it( 'document-processed triggers log#notice', () => + { + let method_called = false; + + const event_id = 'document-processed'; + const emitter = new EventEmitter(); + const log = createMockLogger(); + + log.notice = ( _str: string ) => { method_called = true; }; + + new Sut( log, emitter ); + + emitter.emit( event_id ); + + expect( method_called ).to.be.true; + } ); + + it( 'delta-publish triggers log#notice', () => + { + let method_called = false; + + const event_id = 'delta-publish'; + const emitter = new EventEmitter(); + const log = createMockLogger(); + + log.notice = ( _str: string ) => { method_called = true; }; + + new Sut( log, emitter ); + + emitter.emit( event_id ); + + expect( method_called ).to.be.true; + } ); + + it( 'amqp-conn-error triggers log#warning', () => + { + let method_called = false; + + const event_id = 'amqp-conn-error'; + const emitter = new EventEmitter(); + const log = createMockLogger(); + + log.warning = ( _str: string ) => { method_called = true; }; + + new Sut( log, emitter ); + + emitter.emit( event_id ); + + expect( method_called ).to.be.true; + } ); + + it( 'amqp-reconnect triggers log#warning', () => + { + let method_called = false; + + const event_id = 'amqp-reconnect'; + const emitter = new EventEmitter(); + const log = createMockLogger(); + + log.warning = ( _str: string ) => { method_called = true; }; + + new Sut( log, emitter ); + + emitter.emit( event_id ); + + expect( method_called ).to.be.true; + } ); + + it( 'context is retrieved from error', () => + { + let method_called = false; + + const event_id = 'error'; + const err_msg = 'Foo'; + const emitter = new EventEmitter(); + const log = createMockLogger(); + const err_context = { bar: 'baz' }; + + log.error = ( str: string, context: any ) => + { + method_called = true; + + expect( str ).to.equal( err_msg ); + expect( context ).to.equal( err_context ); + }; + + new Sut( log, emitter ); + + emitter.emit( event_id, context( new Error( err_msg ), err_context ) ); + + expect( method_called ).to.be.true; + } ); +} ); + + +function createMockLogger(): PsrLogger +{ + return <PsrLogger>{ + debug( _msg: string | object, _context: object ){}, + info( _msg: string | object, _context: object ){}, + notice( _msg: string | object, _context: object ){ console.log( 'asdasd msg: ', _msg ); }, + warning( _msg: string | object, _context: object ){}, + error( _msg: string | object, _context: object ){}, + critical( _msg: string | object, _context: object ){}, + alert( _msg: string | object, _context: object ){}, + emergency( _msg: string | object, _context: object ){}, + log( _level: any, _msg: string | object, _context: object ){}, + }; +}
\ No newline at end of file diff --git a/test/system/MetricsCollectorTest.ts b/test/system/MetricsCollectorTest.ts index 07867a8..eafc77d 100644 --- a/test/system/MetricsCollectorTest.ts +++ b/test/system/MetricsCollectorTest.ts @@ -19,13 +19,15 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -import { PrometheusFactory } from '../../src/system/PrometheusFactory'; +import { + PrometheusFactory, + PrometheusConfig, +} from '../../src/system/PrometheusFactory'; import { Histogram, Pushgateway, Counter, Gauge } from 'prom-client'; import { EventEmitter } from 'events'; import { expect } from 'chai'; import { MetricsCollector as Sut, - PrometheusConfig, MetricTimer, } from '../../src/system/MetricsCollector'; @@ -35,8 +37,8 @@ describe( 'system.MetricsCollector captures events and pushes metrics', () => { it( 'process-complete event is hooked', () => { - let histogram_called = false; - let counter_called = false; + let histogram_called = false; + let counter_called = false; const emitter = new EventEmitter(); const conf = createMockConfig(); @@ -46,18 +48,20 @@ describe( 'system.MetricsCollector captures events and pushes metrics', () => counter_cb: () => { counter_called = true }, } ); - new Sut( factory, conf, emitter, timer ); + const sut = new Sut( factory, conf, emitter, timer ); emitter.emit( 'delta-process-end' ); expect( histogram_called ).to.be.true; expect( counter_called ).to.be.true; + + sut.stop(); } ); it( 'process-error event is hooked', () => { - let counter_called = false; + let counter_called = false; const emitter = new EventEmitter(); const conf = createMockConfig(); @@ -66,11 +70,13 @@ describe( 'system.MetricsCollector captures events and pushes metrics', () => counter_cb: () => { counter_called = true }, } ); - new Sut( factory, conf, emitter, timer ); + const sut = new Sut( factory, conf, emitter, timer ); emitter.emit( 'delta-process-error' ); expect( counter_called ).to.be.true; + + sut.stop(); } ); @@ -80,7 +86,7 @@ describe( 'system.MetricsCollector captures events and pushes metrics', () => const uid = 'foo'; const start_time_ns = 1234; const end_time_ns = 5678; - const expected_ms = ( end_time_ns - start_time_ns ) / 1000; + const expected_ms = ( end_time_ns - start_time_ns ) / 1000000; const emitter = new EventEmitter(); const conf = createMockConfig(); const timer = createMockTimer( start_time_ns, end_time_ns ); @@ -88,12 +94,14 @@ describe( 'system.MetricsCollector captures events and pushes metrics', () => histogram_cb: ( n: number ) => { actual_ms = n }, } ); - new Sut( factory, conf, emitter, timer ); + const sut = new Sut( factory, conf, emitter, timer ); emitter.emit( 'delta-process-start', uid ); emitter.emit( 'delta-process-end', uid ); expect( actual_ms ).to.be.equal( expected_ms ); + + sut.stop(); } ); } ); diff --git a/test/system/StandardLoggerTest.ts b/test/system/StandardLoggerTest.ts new file mode 100644 index 0000000..918bfd1 --- /dev/null +++ b/test/system/StandardLoggerTest.ts @@ -0,0 +1,178 @@ +/** + * Event logger test + * + * Copyright (C) 2010-2019 R-T Specialty, LLC. + * + * This file is part of the Liza Data Collection Framework. + * + * liza is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import { StandardLogger as Sut } from '../../src/system/StandardLogger'; +import { LogLevel } from '../../src/system/PsrLogger'; +import { expect } from 'chai'; + +const sinon = require( 'sinon' ); + +declare interface MockConsole extends Console { + getLevel(): string, + getStr(): string, +} + +describe( 'system.EventLogger captures and logs events', () => +{ + it( 'debug triggers console output level: info', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + + sut.debug( 'Foo' ); + + expect( con.getLevel() ).to.equal( 'info' ); + } ); + + it( 'info triggers console output level: info', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + + sut.info( 'Foo' ); + + expect( con.getLevel() ).to.equal( 'info' ); + } ); + + it( 'notice triggers console output level: log', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + + sut.notice( 'Foo' ); + + expect( con.getLevel() ).to.equal( 'log' ); + } ); + + it( 'warning triggers console output level: warn', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + + sut.warning( 'Foo' ); + + expect( con.getLevel() ).to.equal( 'warn' ); + } ); + + it( 'error triggers console output level: error', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + + sut.error( 'Foo' ); + + expect( con.getLevel() ).to.equal( 'error' ); + } ); + + it( 'critical triggers console output level: error', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + + sut.critical( 'Foo' ); + + expect( con.getLevel() ).to.equal( 'error' ); + } ); + + it( 'alert triggers console output level: error', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + + sut.alert( 'Foo' ); + + expect( con.getLevel() ).to.equal( 'error' ); + } ); + + it( 'emergency triggers console output level: error', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + + sut.emergency( 'Foo' ); + + expect( con.getLevel() ).to.equal( 'error' ); + } ); + + it( 'log triggers corresponding log level', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + + sut.log( LogLevel.ERROR, 'Foo' ); + + expect( con.getLevel() ).to.equal( 'error' ); + } ); + + it( 'Context is included in structured output', () => + { + const con = createMockConsole(); + const env = 'test'; + const sut = new Sut( con, ts_ctr, env ); + const context = { bar: 'baz' }; + const expected_output = { + message: 'Foo', + timestamp: 123123, + service: 'quote-server', + env: 'test', + severity: 'NOTICE', + context: { + bar: 'baz', + }, + }; + + sut.notice( 'Foo', context ); + + expect( con.getStr() ).to.deep.equal( expected_output ); + } ); +} ); + + +function ts_ctr(): UnixTimestamp +{ + return <UnixTimestamp>123123; +} + + +function createMockConsole(): MockConsole +{ + const mock = sinon.mock( console ); + + mock.lvl = ''; + mock.str = ''; + mock.info = ( str: string ) => { mock.str = str; mock.lvl = 'info'; }; + mock.log = ( str: string ) => { mock.str = str; mock.lvl = 'log'; }; + mock.warn = ( str: string ) => { mock.str = str; mock.lvl = 'warn'; }; + mock.error = ( str: string ) => { mock.str = str; mock.lvl = 'error'; }; + mock.getLevel = () => mock.lvl; + mock.getStr = () => mock.str; + + return mock; +} |