/** * Delta Processor 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 . */ 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 { EventEmitter } from 'events'; import { expect, use as chai_use } from 'chai'; chai_use( require( 'chai-as-promised' ) ); describe( 'system.DeltaProcessor', () => { describe( '#getTimestampSortedDeltas', () => { ( <{ label: string, given: any, expected: any }[]>[ { label: 'creates list', given: { rdelta: { data: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, }, ], ratedata: [ { data: { foo: [ 'third_bar' ] }, timestamp: 345, }, { data: { foo: [ 'fourth_bar' ] }, timestamp: 456, }, ] } }, expected: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, type: 'data', }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, type: 'data', }, { data: { foo: [ 'third_bar' ] }, timestamp: 345, type: 'ratedata', }, { data: { foo: [ 'fourth_bar' ] }, timestamp: 456, type: 'ratedata', }, ], }, { label: 'creates list with no ratedata', given: { rdelta: { data: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, }, ], ratedata: [] } }, expected: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, type: 'data', }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, type: 'data', }, ], }, { label: 'creates list when rate occurs between two saves', given: { rdelta: { data: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, }, { data: { foo: [ 'fourth_bar' ] }, timestamp: 456, }, ], ratedata: [ { data: { foo: [ 'third_bar' ] }, timestamp: 345, }, ], }, }, expected: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, type: 'data', }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, type: 'data', }, { data: { foo: [ 'third_bar' ] }, timestamp: 345, type: 'ratedata', }, { data: { foo: [ 'fourth_bar' ] }, timestamp: 456, type: 'data', }, ], }, ] ).forEach( ( { given, expected, label } ) => it( label, () => { const sut = new Sut( createMockDeltaDao(), createMockDeltaPublisher(), new EventEmitter(), ); const actual = sut.getTimestampSortedDeltas( given ); expect( actual ).to.deep.equal( expected ); } ) ); } ); describe( '#getDeltas', () => { ( <{ label: string, type: DeltaType, given: any, expected: any }[]>[ { label: 'return empty array if no deltas are present', type: 'data', given: { rdelta: {}, }, expected: [], }, { label: 'return full list if no lastPublished index is found', type: 'data', given: { rdelta: { data: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, }, ], }, }, expected: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, type: 'data', }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, type: 'data', }, ], }, { label: 'marks deltas with their type', type: 'data', given: { rdelta: { data: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, }, ], }, totalPublishDelta: { data: 0, }, }, expected: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, type: 'data', }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, type: 'data', }, ], }, { label: 'trims delta array based on index', type: 'data', given: { rdelta: { data: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, }, ], }, totalPublishDelta: { data: 1, }, }, expected: [ { data: { foo: [ 'second_bar' ] }, timestamp: 234, type: 'data', }, ], }, ] ).forEach( ( { type, given, expected, label } ) => it( label, () => { const sut = new Sut( createMockDeltaDao(), createMockDeltaPublisher(), new EventEmitter(), ); const actual = sut.getDeltas( given, type ); expect( actual ).to.deep.equal( expected ); } ) ); } ); describe( '#process', () => { ( <{ label: string, given: any[], expected: any }[]>[ { label: 'No deltas are processed', docs: [ { id: 123, lastUpdate: 123123123, bucket: {}, rdelta: {}, }, ], expected: [], }, { label: 'Publishes deltas in order', given: [ { id: 123, lastUpdate: 123123123, bucket: { foo: [ 'start_bar' ] }, rdelta: { data: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123123, }, { data: { foo: [ 'second_bar' ] }, timestamp: 234123, }, ], }, }, ], expected: [ { delta: { foo: [ 'first_bar' ] }, bucket: { foo: [ 'first_bar' ] }, doc_id: 123, }, { delta: { foo: [ 'second_bar' ] }, bucket: { foo: [ 'second_bar' ] }, doc_id: 123, }, ], }, { label: 'Publishes deltas in order for multiple documents', given: [ { id: 123, lastUpdate: 123123123, bucket: { foo: 'start_bar' }, rdelta: { data: [ { data: { foo: [ 'second_bar' ] }, timestamp: 234, }, ], ratedata: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, }, ], }, }, { id: 234, lastUpdate: 123123123, bucket: { foo: 'start_bar' }, rdelta: { data: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, }, { data: { foo: [ 'third_bar' ] }, timestamp: 345, }, ], }, }, { id: 345, lastUpdate: 123123123, bucket: { foo: 'start_bar' }, rdelta: { ratedata: [ { data: { foo: [ 'first_bar' ] }, timestamp: 123, }, { data: { foo: [ 'second_bar' ] }, timestamp: 234, }, ], }, }, ], expected: [ { delta: { foo: [ 'first_bar' ] }, bucket: { foo: [ 'first_bar' ] }, doc_id: 123, }, { delta: { foo: [ 'second_bar' ] }, bucket: { foo: [ 'second_bar' ] }, doc_id: 123, }, { delta: { foo: [ 'first_bar' ] }, bucket: { foo: [ 'first_bar' ] }, doc_id: 234, }, { delta: { foo: [ 'second_bar' ] }, bucket: { foo: [ 'second_bar' ] }, doc_id: 234, }, { delta: { foo: [ 'third_bar' ] }, bucket: { foo: [ 'third_bar' ] }, doc_id: 234, }, { delta: { foo: [ 'first_bar' ] }, bucket: { foo: [ 'first_bar' ] }, doc_id: 345, }, { delta: { foo: [ 'second_bar' ] }, bucket: { foo: [ 'second_bar' ] }, doc_id: 345, }, ], }, ] ).forEach( ( { given, expected, label } ) => it( label, () => { let published: any = []; const dao = createMockDeltaDao(); const publisher = createMockDeltaPublisher(); const emitter = new EventEmitter(); dao.getUnprocessedDocuments = (): Promise[]> => { return Promise.resolve( given ); } publisher.publish = ( delta, bucket, doc_id ): Promise => { published.push( { delta: delta.data, bucket: bucket, doc_id: doc_id, } ); return Promise.resolve(); } return expect( new Sut( dao, publisher, emitter ).process() ) .to.eventually.deep.equal( undefined ) .then( _ => expect( published ).to.deep.equal( expected ) ); } ) ); } ); } ); function createMockDeltaDao(): DeltaDao { return { getUnprocessedDocuments() { return Promise.resolve( [] ); }, advanceDeltaIndex() { return Promise.resolve(); }, markDocumentAsProcessed() { return Promise.resolve(); }, setErrorFlag() { return Promise.resolve(); }, getErrorCount() { return Promise.resolve( 0 ); }, }; } function createMockDeltaPublisher(): AmqpPublisher { return { publish() { return Promise.resolve(); }, }; }