2019-11-12 15:07:37 -05:00
|
|
|
/**
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { DeltaProcessor as Sut } from '../../src/system/DeltaProcessor';
|
2019-11-12 16:41:31 -05:00
|
|
|
import { AmqpPublisher } from '../../src/system/AmqpPublisher';
|
2019-11-12 15:07:37 -05:00
|
|
|
import { DeltaDao } from '../../src/system/db/DeltaDao';
|
2019-11-26 19:31:39 -05:00
|
|
|
import { DeltaType } from "../../src/bucket/delta";
|
2019-11-25 12:42:03 -05:00
|
|
|
import { EventEmitter } from 'events';
|
2019-11-12 15:07:37 -05:00
|
|
|
|
|
|
|
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: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
ratedata: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'third_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 345,
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'fourth_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 456,
|
|
|
|
},
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
expected: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'third_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 345,
|
|
|
|
type: 'ratedata',
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'fourth_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 456,
|
|
|
|
type: 'ratedata',
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'creates list with no ratedata',
|
|
|
|
given: {
|
|
|
|
rdelta: {
|
|
|
|
data: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
ratedata: []
|
|
|
|
}
|
|
|
|
},
|
|
|
|
expected: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'creates list when rate occurs between two saves',
|
|
|
|
given: {
|
|
|
|
rdelta: {
|
|
|
|
data: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'fourth_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 456,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
ratedata: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'third_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 345,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'third_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 345,
|
|
|
|
type: 'ratedata',
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'fourth_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 456,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
] ).forEach( ( { given, expected, label } ) => it( label, () =>
|
|
|
|
{
|
2019-11-12 16:41:31 -05:00
|
|
|
const sut = new Sut(
|
|
|
|
createMockDeltaDao(),
|
2019-11-13 14:08:42 -05:00
|
|
|
createMockDeltaPublisher(),
|
2019-11-25 12:42:03 -05:00
|
|
|
new EventEmitter(),
|
2019-11-12 16:41:31 -05:00
|
|
|
);
|
|
|
|
|
2019-11-12 15:07:37 -05:00
|
|
|
const actual = sut.getTimestampSortedDeltas( given );
|
|
|
|
|
|
|
|
expect( actual ).to.deep.equal( expected );
|
|
|
|
} ) );
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
|
|
describe( '#getDeltas', () =>
|
|
|
|
{
|
|
|
|
( <{
|
|
|
|
label: string,
|
2019-11-26 19:31:39 -05:00
|
|
|
type: DeltaType,
|
2019-11-12 15:07:37 -05:00
|
|
|
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: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'marks deltas with their type',
|
|
|
|
type: 'data',
|
|
|
|
given: {
|
|
|
|
rdelta: {
|
|
|
|
data: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2019-11-21 15:59:17 -05:00
|
|
|
totalPublishDelta: {
|
2019-11-12 15:07:37 -05:00
|
|
|
data: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'trims delta array based on index',
|
|
|
|
type: 'data',
|
|
|
|
given: {
|
|
|
|
rdelta: {
|
|
|
|
data: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'first_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 123,
|
|
|
|
},
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2019-11-21 15:59:17 -05:00
|
|
|
totalPublishDelta: {
|
2019-11-12 15:07:37 -05:00
|
|
|
data: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: [
|
|
|
|
{
|
2019-11-26 19:31:39 -05:00
|
|
|
data: { foo: [ 'second_bar' ] },
|
2019-11-12 15:07:37 -05:00
|
|
|
timestamp: 234,
|
|
|
|
type: 'data',
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
] ).forEach( ( { type, given, expected, label } ) => it( label, () =>
|
|
|
|
{
|
2019-11-12 16:41:31 -05:00
|
|
|
const sut = new Sut(
|
|
|
|
createMockDeltaDao(),
|
2019-11-13 14:08:42 -05:00
|
|
|
createMockDeltaPublisher(),
|
2019-11-25 12:42:03 -05:00
|
|
|
new EventEmitter(),
|
2019-11-12 16:41:31 -05:00
|
|
|
);
|
|
|
|
|
2019-11-12 15:07:37 -05:00
|
|
|
const actual = sut.getDeltas( given, type );
|
|
|
|
|
|
|
|
expect( actual ).to.deep.equal( expected );
|
|
|
|
} ) );
|
|
|
|
} );
|
2019-11-26 19:31:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
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<Record<string, any>[]> =>
|
|
|
|
{
|
|
|
|
return Promise.resolve( given );
|
|
|
|
}
|
|
|
|
|
|
|
|
publisher.publish = ( delta, bucket, doc_id ): Promise<void> =>
|
|
|
|
{
|
|
|
|
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 ) );
|
|
|
|
} ) );
|
|
|
|
} );
|
2019-11-12 15:07:37 -05:00
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
|
|
function createMockDeltaDao(): DeltaDao
|
|
|
|
{
|
|
|
|
return <DeltaDao>{
|
2019-11-13 14:08:42 -05:00
|
|
|
getUnprocessedDocuments() { return Promise.resolve( [] ); },
|
2019-11-26 19:31:39 -05:00
|
|
|
advanceDeltaIndex() { return Promise.resolve(); },
|
|
|
|
markDocumentAsProcessed() { return Promise.resolve(); },
|
|
|
|
setErrorFlag() { return Promise.resolve(); },
|
2019-11-21 15:59:17 -05:00
|
|
|
getErrorCount() { return Promise.resolve( 0 ); },
|
2019-11-12 15:07:37 -05:00
|
|
|
};
|
|
|
|
}
|
2019-11-12 16:41:31 -05:00
|
|
|
|
|
|
|
|
|
|
|
function createMockDeltaPublisher(): AmqpPublisher
|
|
|
|
{
|
|
|
|
return <AmqpPublisher>{
|
2019-11-26 19:31:39 -05:00
|
|
|
publish() { return Promise.resolve(); },
|
2019-11-12 16:41:31 -05:00
|
|
|
};
|
|
|
|
}
|