UNPKG

qminer

Version:

A C++ based data analytics platform for processing large-scale real-time streams containing structured and unstructured data

1,230 lines (1,149 loc) 276 kB
/** * Copyright (c) 2015, Jozef Stefan Institute, Quintelligence d.o.o. and contributors * All rights reserved. * * This source code is licensed under the FreeBSD license found in the * LICENSE file in the root directory of this source tree. */ var qm = require('../../index.js'); var assert = require('../../src/nodejs/scripts/assert.js'); describe('Stream Aggregator Tests', function () { var base = undefined; var store = undefined; beforeEach(function () { base = new qm.Base({ mode: 'createClean', schema: [ { name: 'People', fields: [ { name: 'Name', type: 'string', primary: true }, { name: 'Gender', type: 'string' } ], } ] }); store = base.store('People'); }); afterEach(function () { base.close(); }); describe('Constructor Tests', function () { it('should construct a new stream aggregator for the People store using new qm.StreamAggr', function () { var aggr = new qm.StreamAggr(base, new function () { var length = 0; this.name = 'nameLength'; this.onAdd = function (rec) { length = rec.Name.length; } this.saveJson = function (limit) { return { val: length }; } }, 'People'); store.push({ Name: "John", Gender: "Male" }); assert.strictEqual(aggr.saveJson().val, 4); }); it('should test onStep for javascript new qm.StreamAggr', function () { var aggr = new qm.StreamAggr(base, new function () { var length = 0; this.onStep = function () { length++; } this.saveJson = function (limit) { return { val: length }; } }, 'People'); aggr.onStep(); aggr.onStep(); assert.strictEqual(aggr.saveJson().val, 2); }); it('should test stream aggr construction using functions', function () { var s = store.addStreamAggr(new function () { var length = 0; this.data = 0; this.name = 'nameLength'; this.onAdd = function (rec) { this.data++; length = rec.Name.length; } this.saveJson = function (limit) { return { val: length, thisVal: this.data }; } }()); store.push({ Name: "John", Gender: "Male" }); assert.strictEqual(s.saveJson().val, 4); assert.strictEqual(s.saveJson().thisVal, 1); }) it('should test stream aggr construction using classes ', function () { if (Number(process.versions.modules) >= 46) { class S { constructor() { this.data = 0; } onAdd(rec) { this.data++; } saveJson() { return { thisVal: this.data }; } } var s = store.addStreamAggr(new S()); store.push({ Name: "John", Gender: "Male" }); assert.strictEqual(s.saveJson().thisVal, 1); } }); it('should test stream aggr construction using objects ', function () { var S = { onAdd: function (rec) { assert(Object.is(this, S)); this.touched = true; console.log('touched ' + this.touched);}, saveJson: function () { return { touched: this.touched }; } }; var s = store.addStreamAggr(S); store.push({ Name: "John", Gender: "Male" }); assert(s.saveJson().touched); }); it('should test stream aggr construction using prototypes ', function () { var t = null; function S() { } S.prototype.onAdd = function (rec) { assert(Object.is(this, t)); } S.prototype.saveJson = function () { return { } } t = new S(); var s = store.addStreamAggr(t); store.push({ Name: "John", Gender: "Male" }); }); }); describe('JsStreamAggr Test', function () { it('should test saveStateJson and loadStateJson for javascript implemented stream aggregate', function () { var aggr = new qm.StreamAggr(base, new function () { var state = { calls : 0}; this.onStep = function () { state.calls++; } this.saveStateJson = function () { return state; } this.loadStateJson = function (_state) { state = _state; } }, 'People'); var s0 = aggr.saveStateJson(); assert.strictEqual(s0.calls, 0); aggr.onStep(); var s1 = aggr.saveStateJson(); assert.strictEqual(s1.calls, 1); // new aggregate var aggr2 = new qm.StreamAggr(base, new function () { var state = { calls : 0}; this.onStep = function () { state.calls++; } this.saveStateJson = function () { return state; } this.loadStateJson = function (_state) { state = _state; } }, 'People'); // load last state from the first aggregate aggr2.loadStateJson(s1); // get state of the second aggregate and compare var s2 = aggr2.saveStateJson(); assert.strictEqual(s2.calls, 1); }); it('should test getParams and setParams', function () { var s = new qm.StreamAggr(base, new function () { var data = {}; var val = 1; this.onAdd = function (rec) { data[rec.Name] = data[rec.Name] == undefined ? 1 : data[rec.Name] + 1; }; this.saveJson = function (limit) { return data; }; this.getParams = function () { return val; }; this.setParams = function (value) { val = value; }; }); assert.strictEqual(s.getParams(), 1); assert.strictEqual(s.setParams(2), undefined); assert.strictEqual(s.getParams(), 2); }); it('should test getFloat and getInteger with string input', function () { var s = new qm.StreamAggr(base, new function () { var data = {}; this.onAdd = function (rec) { data[rec.Name] = data[rec.Name] == undefined ? 1 : data[rec.Name] + 1; }; this.saveJson = function (limit) { return data; }; this.getFloat = function (name) { return data[name] == undefined ? null : data[name]; }; this.getInteger = function (name) { return data[name] == undefined ? null : data[name]; }; }); var rec1 = store.newRecord({ Name: 'John', Gender: 'Male' }); var rec2 = store.newRecord({ Name: 'Mary', Gender: 'Female' }); s.onAdd(rec1); assert.strictEqual(s.getFloat('John'), 1); assert.strictEqual(s.getFloat('Mary'), null); assert.strictEqual(s.getInteger('John'), 1); assert.strictEqual(s.getInteger('Mary'), null); s.onAdd(rec1); assert.strictEqual(s.getFloat('John'), 2); assert.strictEqual(s.getFloat('Mary'), null); assert.strictEqual(s.getInteger('John'), 2); assert.strictEqual(s.getInteger('Mary'), null); s.onAdd(rec2); assert.strictEqual(s.getFloat('John'), 2); assert.strictEqual(s.getFloat('Mary'), 1); assert.strictEqual(s.getInteger('John'), 2); assert.strictEqual(s.getInteger('Mary'), 1); }); it('should test isNameFloat and isNameInteger. getFloat (or getInteger) should always return null when isNameFloat (or isNameInteger) returns false', function () { var s = new qm.StreamAggr(base, new function () { var data = {}; this.onAdd = function (rec) { data[rec.Name] = data[rec.Name] == undefined ? 1 : data[rec.Name] + 1; }; this.saveJson = function (limit) { return data; }; this.getFloat = function (name) { return data[name] == undefined ? null : data[name]; }; this.getInteger = function (name) { return data[name] == undefined ? null : data[name]; }; this.isNameFloat = function (name) { if (name == 'John') { return true; } else { return false; } }; this.isNameInteger = function (name) { if (name == 'John') { return true; } else { return false; } }; }); var rec1 = store.newRecord({ Name: 'John', Gender: 'Male' }); var rec2 = store.newRecord({ Name: 'Mary', Gender: 'Female' }); s.onAdd(rec1); assert.strictEqual(s.getFloat('John'), 1); assert.strictEqual(s.getFloat('Mary'), null); assert.strictEqual(s.getInteger('John'), 1); assert.strictEqual(s.getInteger('Mary'), null); s.onAdd(rec1); assert.strictEqual(s.getFloat('John'), 2); assert.strictEqual(s.getFloat('Mary'), null); assert.strictEqual(s.getInteger('John'), 2); assert.strictEqual(s.getInteger('Mary'), null); s.onAdd(rec2); assert.strictEqual(s.getFloat('John'), 2); assert.strictEqual(s.getFloat('Mary'), null); assert.strictEqual(s.getInteger('John'), 2); assert.strictEqual(s.getInteger('Mary'), null); }); it('should serialize and deserialize a JS implemented stream aggregate', function () { var s = store.addStreamAggr(new function () { var data = {}; this.onAdd = function (rec) { data = { Name: rec.Name, Gender: rec.Gender }; }; this.saveJson = function (limit) { return data; }; this.save = function (fout) { fout.writeJson(data); }; this.load = function (fin) { data = fin.readJson(); }; this.reset = function () { data = {}; }; this.init = function() { return data.Name != undefined; } }); assert(!s.init); // add a record store.push({ Name: 'John', Gender: 'Male' }); assert(s.init); // check state var state = s.saveJson(); assert.strictEqual(state.Name, 'John'); assert.strictEqual(state.Gender, 'Male'); // save state var fnm = 'js_aggr.bin'; var fout = qm.fs.openWrite(fnm); s.save(fout); fout.close(); // reset state s.reset(); assert.strictEqual(Object.keys(s.saveJson()).length, 0); // load state var fin = qm.fs.openRead(fnm); s.load(fin); var restoredState = s.saveJson(); assert.strictEqual(restoredState.Name, 'John'); assert.strictEqual(restoredState.Gender, 'Male'); fin.close(); }); it('should register a Js extractor, which counts record.name string length', function () { var s = store.addStreamAggr(new function () { var data = 0; this.name = 'anomaly'; this.onAdd = function (rec) { //console.log('updated stream aggr for: ', rec.Name); data = rec.Name.length; }; this.saveJson = function (limit) { return { val: data }; }; this.getInt = function () { return data; }; this.getFlt = function () { throw 'error'; }; this.getTm = function () { }; }); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); assert(s.saveJson().val == 4); var id2 = base.store('People').push({ Name: "Mary", Gender: "Female" }); assert(s.saveJson().val == 4); var id3 = base.store('People').push({ Name: "Jim", Gender: "Male" }); assert(s.saveJson().val == 3); assert.throws( function() { s.getFlt() == 3 }); assert.throws( function() { s.getTm() == 3 }); }) it('should register a Js extractor, which counts the number of records in store', function () { var s = store.addStreamAggr(new function () { var numberOfRecords = 0; this.name = 'counter'; this.onAdd = function (rec) { numberOfRecords++; } this.onDelete = function (rec) { numberOfRecords--; } this.saveJson = function (limit) { return { val: numberOfRecords }; } }); assert.strictEqual(s.saveJson().val, 0); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); assert.strictEqual(s.saveJson().val, 1); var id2 = base.store('People').push({ Name: "Mary", Gender: "Female" }); assert.strictEqual(s.saveJson().val, 2); base.store('People').clear(); assert.strictEqual(s.saveJson().val, 0); }) it('should register a Js extractor, which counts the number of records in store and number of updates', function () { var s = store.addStreamAggr(new function () { var numberOfRecords = 0; var numberOfUpdates = 0; this.name = 'counter'; this.onAdd = function (rec) { numberOfRecords++; } this.onDelete = function (rec) { numberOfRecords--; } this.onUpdate = function (rec) { numberOfUpdates++; } this.saveJson = function (limit) { return { records: numberOfRecords, updates: numberOfUpdates }; } }); assert.strictEqual(s.saveJson().records, 0); assert.strictEqual(s.saveJson().updates, 0); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); assert.strictEqual(s.saveJson().records, 1); assert.strictEqual(s.saveJson().updates, 0); var id2 = base.store('People').push({ Name: "Mary", Gender: "Female" }); assert.strictEqual(s.saveJson().records, 2); assert.strictEqual(s.saveJson().updates, 0); var id2 = base.store('People').push({ Name: "John", Gender: "Male" }); assert.strictEqual(s.saveJson().records, 2); assert.strictEqual(s.saveJson().updates, 1); }) }); describe('OnAdd Tests', function () { it('should execute the onAdd function and return 4', function () { var aggr = new qm.StreamAggr(base, new function () { var length = 0; this.name = 'nameLength'; this.onAdd = function (rec) { length = rec.Name.length; } this.saveJson = function (limit) { return { val: length }; } }); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); aggr.onAdd(base.store('People')[0]); //aggr.onAdd({ Name: "John", Gender: "Male" }); // doesn't digest a JSON record assert.strictEqual(aggr.saveJson().val, 4); }) it('should throw an exception if the onAdd function is not defined', function () { assert.throws(function () { var aggr = new qm.StreamAggr(base, new function () { var length = 0; this.name = 'nameLength'; }); }); }) }); describe('Fallback to OnStep tests', function () { it('should execute OnStep instead of OnAdd', function () { var aggr = new qm.StreamAggr(base, new function () { var count = 0; this.name = 'counter'; this.onStep = function () { count++; } this.saveJson = function (limit) { return { val: count }; } }, "People"); assert.strictEqual(aggr.saveJson().val, 0); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); assert.strictEqual(aggr.saveJson().val, 1); var id2 = base.store('People').push({ Name: "Mary", Gender: "Female" }); assert.strictEqual(aggr.saveJson().val, 2); var id3 = base.store('People').push({ Name: "Bob", Gender: "Male" }); assert.strictEqual(aggr.saveJson().val, 3); }) }); describe('Reset Tests', function () { it('should reset the stream aggregate to 0', function () { var aggr = new qm.StreamAggr(base, new function () { var length = 0; this.name = 'nameLength'; this.onAdd = function (rec) { length = rec.Name.length; } this.saveJson = function (limit) { return { val: length }; } this.reset = function () { length = 0;} }); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); aggr.onAdd(base.store('People')[0]); aggr.reset(); assert.strictEqual(aggr.saveJson().val, 0); }) }); describe('OnUpdate Tests', function () { it('should execute the onUpdate function and return 1', function () { var aggr = new qm.StreamAggr(base, new function () { var type = null; this.name = 'GenderUpdateLength'; this.onAdd = function (rec) { type = null; } this.onUpdate = function (rec) { type = rec.Gender == "Male" ? 0 : 1; } this.saveJson = function (limit) { return { val: type }; } }); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); aggr.onAdd(base.store('People')[0]); assert.strictEqual(aggr.saveJson().val, null); var id2 = base.store('People').push({ Name: "John", Gender: "Female" }); aggr.onUpdate(base.store('People')[0]); assert.strictEqual(aggr.saveJson().val, 1); }) // unexpectively exits node it('should throw an exception if the onAdd function is not defined with the onUpdate', function () { assert.throws(function () { var aggr = new qm.StreamAggr(base, new function () { var type = null; this.name = 'GenderUpdateLength'; this.onUpdate = function (rec) { type = rec.Gender == "Male" ? 0 : 1; } this.saveJson = function (limit) { return { val: type }; } }); }); }) }); describe('SaveJson Tests', function () { it('should return a JSON object containing the pair val: length', function () { var aggr = new qm.StreamAggr(base, new function () { var length = 0; this.name = 'nameLength'; this.onAdd = function (rec) { length = rec.Name.length; } this.saveJson = function (limit) { return { val: length }; } }); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); aggr.onAdd(base.store('People')[0]); assert.strictEqual(aggr.saveJson().val, 4); }) it('should return a JSON object containing two pairs, for name and for Gender', function () { var aggr = new qm.StreamAggr(base, new function () { var length = 0; var type = null; this.name = 'PeopleAggr'; this.onAdd = function (rec) { length = rec.Name.length; type = rec.Gender == "Male" ? 0 : 1; } this.saveJson = function (limit) { return { name: length, Gender: type }; } }); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); aggr.onAdd(base.store('People')[0]); assert.strictEqual(aggr.saveJson().name, 4); assert.strictEqual(aggr.saveJson().Gender, 0); }) }); describe('OnDelete Tests', function () { it('should execute the onDelete function and return 1', function () { var aggr = new qm.StreamAggr(base, new function () { var numberOfDeleted = 0; this.name = 'deleteAggr'; this.onAdd = function (rec) { return; } this.onDelete = function (rec) { numberOfDeleted++; } this.saveJson = function (limit) { return { deleted: numberOfDeleted }; } }); var id1 = base.store('People').push({ Name: "John", Gender: "Male" }); aggr.onDelete(base.store('People')[0]); assert.strictEqual(aggr.saveJson().deleted, 1); }) }); }); describe('Time Series Window Buffer Tests', function () { var base = undefined; var store = undefined; beforeEach(function () { base = new qm.Base({ mode: 'createClean', schema: [{ name: 'Function', fields: [ { name: 'Time', type: 'datetime' }, { name: 'Value', type: 'float' } ] }] }); store = base.store('Function'); }); afterEach(function () { base.close(); }); describe('Constructor Tests', function () { it('should construct the time series window buffer', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.strictEqual(sa.init, false); }) // unexpected node exit it('should throw an exception if the keys timestamp and value are missing', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', winsize: 2000 }; assert.throws(function () { var sa = store.addStreamAggr(aggr); }); }) }); describe('Adding Records Tests', function () { it('should update the time and value of the stream aggregate', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); var json = sa.saveJson(); assert.strictEqual(new Date(json.Time).getTime(), new Date('2015-06-10T14:13:32.0').getTime()); assert.strictEqual(json.Val, 1); store.push({ Time: '2015-06-10T14:17:45.0', Value: 2 }); json = sa.saveJson(); assert.strictEqual(new Date(json.Time).getTime(), new Date('2015-06-10T14:17:45.0').getTime()); assert.strictEqual(json.Val, 2); }) }); describe('Updating Only Time Test', function () { it('should update the time and value of the stream aggregate', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:23:32.0', Value: 2 }); store.push({ Time: '2015-06-10T14:33:32.0', Value: 3 }); sa.onTime(new Date('2016-02-03T14:13:32.0').getTime()); assert.strictEqual(new Date(sa.getTimestamp()-0).toString(), new Date('2016-02-03T14:13:32.0').toString()); }) }); describe('Reset Tests', function () { it('should reset the stream aggregate', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); var json = sa.saveJson(); assert.strictEqual(new Date(json.Time).getTime(), new Date('2015-06-10T14:13:32.0').getTime()); assert.strictEqual(json.Val, 1); store.push({ Time: '2015-06-10T14:17:45.0', Value: 2 }); json = sa.saveJson(); assert.strictEqual(new Date(json.Time).getTime(), new Date('2015-06-10T14:17:45.0').getTime()); assert.strictEqual(json.Val, 2); // RESET store.resetStreamAggregates(); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); var json = sa.saveJson(); assert.strictEqual(new Date(json.Time).getTime(), new Date('2015-06-10T14:13:32.0').getTime()); assert.strictEqual(json.Val, 1); store.push({ Time: '2015-06-10T14:17:45.0', Value: 2 }); json = sa.saveJson(); assert.strictEqual(new Date(json.Time).getTime(), new Date('2015-06-10T14:17:45.0').getTime()); assert.strictEqual(json.Val, 2); }) }); describe('GetFloatVector Tests', function () { it('should return the float vector of values in the buffer', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); var vec = sa.getFloatVector(); assert.strictEqual(vec[0], 1); assert.strictEqual(vec[1], 2); }) it('should throw an exception when calling getFloatVector in a noninitialized state', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.throws(function () { var vec = sa.getFloatVector(); }); }) it('should return the float vector of values that are still in the window', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); store.push({ Time: '2015-06-10T14:13:34.0', Value: 3 }); store.push({ Time: '2015-06-10T14:13:35.0', Value: 4 }); var vec = sa.getFloatVector(); assert.strictEqual(vec[0], 2); assert.strictEqual(vec[1], 3); assert.strictEqual(vec[2], 4); }) }); describe('GetFloatLength, Tests', function () { it('should return the length of the float vector containing values in the buffer', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); var vec = sa.getFloatVector(); assert.strictEqual(sa.getFloatLength(), 2); }) it('should throw an exception when calling getFloatLength in a noninitialized state', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.throws(function () { var res = sa.getFloatLength(); }); }) }); describe('GetFloatAt Tests', function () { it('should return the value with the index 1', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); assert.strictEqual(sa.getFloatAt(1), 2); }) it('should throw an exception if the vector is empty', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.throws(function () { var val = sa.getFloat(0); }); }) }) describe('GetTimestampVector Tests', function () { it('should return a timestamp vector of dates in the buffer', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); var vec = sa.getTimestampVector(); assert.strictEqual(vec.length, 2); assert.strictEqual(vec[0] - 0, new Date('2015-06-10T14:13:32.000Z').getTime()); assert.strictEqual(vec[1] - 0, new Date('2015-06-10T14:13:33.000Z').getTime()); }) it('should throw an exception when calling getTimestampVector in a noninitialized state', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.throws(function () { var res = sa.getTimestampVector(); }); }) }); describe('GetTimestampLength Tests', function () { it('should return the length of the timestamp vector', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); assert.strictEqual(sa.getTimestampLength(), 2); }) it('should throw an exception when calling getTimestampLength in a noninitialized state', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.throws(function () { var res = sa.getTimestampLength(); }); }) }); describe('GetTimestampAt Tests', function () { it('should return the timestamp with index 1', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); assert.strictEqual(sa.getTimestampAt(0) - 0, new Date('2015-06-10T14:13:32.000Z').getTime()); assert.strictEqual(sa.getTimestampAt(1) - 0, new Date('2015-06-10T14:13:33.000Z').getTime()); }) // throws a C++ exception it('should throw an exception for an empty vector', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.throws(function () { var date = sa.getTimestampAt(0); }); }) }) describe('GetOutFloatVector Tests', function () { it('should return the vector of the leaving values in buffer', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); store.push({ Time: '2015-06-10T14:13:33.2', Value: 3 }); store.push({ Time: '2015-06-10T14:13:33.4', Value: 4 }); store.push({ Time: '2015-06-10T14:13:35.4', Value: 5 }); var vec = sa.getOutFloatVector(); assert.strictEqual(vec.length, 3); assert.strictEqual(vec[0], 1); assert.strictEqual(vec[1], 2); assert.strictEqual(vec[2], 3); }) it('should throw an exception for callin getOutFloatVector on an uninitialized buffer', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.throws(function () { var vec = sa.getOutFloatVector(); }); }) it('should return an empty vector if all values are still in the window', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); store.push({ Time: '2015-06-10T14:13:33.2', Value: 3 }); store.push({ Time: '2015-06-10T14:13:33.4', Value: 4 }); var vec = sa.getOutFloatVector(); assert.strictEqual(vec.length, 0); }) }); describe('GetOutTimestampVector Tests', function () { it('should return the vector containing the leaving timestamps of the buffer', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); store.push({ Time: '2015-06-10T14:13:33.2', Value: 3 }); store.push({ Time: '2015-06-10T14:13:33.4', Value: 4 }); store.push({ Time: '2015-06-10T14:13:35.4', Value: 5 }); var vec = sa.getOutTimestampVector(); assert.strictEqual(vec.length, 3); }) it('should return throw an exception if getOutTimestampVector on an uninitialized buffer', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.throws(function () { var vec = sa.getOutTimestampVector(); }); }) it('should return an empty vector if all records are all in the window', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); store.push({ Time: '2015-06-10T14:13:33.2', Value: 3 }); store.push({ Time: '2015-06-10T14:13:33.4', Value: 4 }); var vec = sa.getOutTimestampVector(); assert.strictEqual(vec.length, 0); }) }); describe('GetNumberOfRecords Tests', function () { it('should return the number of records in the buffer', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T14:13:32.0', Value: 1 }); store.push({ Time: '2015-06-10T14:13:33.0', Value: 2 }); store.push({ Time: '2015-06-10T14:13:33.2', Value: 3 }); store.push({ Time: '2015-06-10T14:13:33.4', Value: 4 }); store.push({ Time: '2015-06-10T14:13:35.4', Value: 5 }); assert.strictEqual(sa.getNumberOfRecords(), 2); }) it('should throw', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.throws(function () { var res = sa.getNumberOfRecords(); }); }) }); describe('Name Test', function () { it('should return the name of the aggregate', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.strictEqual(sa.name, 'TimeSeriesWindowAggr'); }) }); describe('Val Test', function () { it('should return the json object of the aggregate (same as saveJson)', function () { var aggr = { name: 'TimeSeriesWindowAggr', type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 2000 }; var sa = store.addStreamAggr(aggr); assert.strictEqual(sa.init, false); }) }); it('should handle the case when records skip buffer', function () { var aggr = { type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 1, delay: 1, }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T00:00:00.000', Value: 0 }); // empty store.push({ Time: '2015-06-10T00:00:00.001', Value: 1 }); // 1 value store.push({ Time: '2015-06-10T00:00:00.004', Value: 4 }); // never enters the buffer store.push({ Time: '2015-06-10T00:00:00.007', Value: 7 }); // empty assert.strictEqual(sa.getInFloatVector().length, 0); assert.strictEqual(sa.getOutFloatVector().length, 0); assert.strictEqual(sa.getFloatVector().length, 0); }); it('should handle the case when records skip buffer variation 2', function () { var aggr = { type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 1, delay: 1, }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T00:00:00.000', Value: 0 }); // empty store.push({ Time: '2015-06-10T00:00:00.001', Value: 1 }); // 1 value store.push({ Time: '2015-06-10T00:00:00.003', Value: 3 }); // never enters the buffer, influences the buffer store.push({ Time: '2015-06-10T00:00:00.006', Value: 6 }); // empty assert.strictEqual(sa.getInFloatVector().length, 0); assert.strictEqual(sa.getOutFloatVector().length, 1); assert.strictEqual(sa.getFloatVector().length, 0); }); it('should handle the case when records skip buffer variation 3', function () { var aggr = { type: 'timeSeriesWinBuf', store: 'Function', timestamp: 'Time', value: 'Value', winsize: 1, delay: 10, }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T00:00:00.000', Value: 0 }); // empty store.push({ Time: '2015-06-10T00:00:00.010', Value: 1 }); // 1 value store.push({ Time: '2015-06-10T00:00:00.015', Value: 2 }); // never enters the buffer store.push({ Time: '2015-06-10T00:00:00.016', Value: 3 }); // empty assert.strictEqual(sa.getInFloatVector().length, 0); assert.strictEqual(sa.getOutFloatVector().length, 0); assert.strictEqual(sa.getFloatVector().length, 0); }); it('should handle start empty, stay empty: (Bs | I, O, Be) = (0 | 0, 0, 0): ', function () { var aggr = { type: 'timeSeriesWinBuf', timestamp: 'Time', value: 'Value', winsize: 1, delay: 1, }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T00:00:00.000', Value: 0 }); // empty store.push({ Time: '2015-06-10T00:00:00.003', Value: 3 }); // stays empty assert.strictEqual(sa.getInFloatVector().length, 0); assert.strictEqual(sa.getOutFloatVector().length, 0); assert.strictEqual(sa.getFloatVector().length, 0); }); it('should handle start empty, get insert: (Bs | I, O, Be) = (0 | 1, 0, 1): ', function () { var aggr = { type: 'timeSeriesWinBuf', timestamp: 'Time', value: 'Value', winsize: 1, delay: 1, }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T00:00:00.000', Value: 0 }); // empty store.push({ Time: '2015-06-10T00:00:00.002', Value: 2 }); // gets insert assert.strictEqual(sa.getInFloatVector().length, 1); assert.strictEqual(sa.getOutFloatVector().length, 0); assert.strictEqual(sa.getFloatVector().length, 1); }); it('should handle start nonempty, no changes: (Bs | I, O, Be) = (1 | 0, 0, 1): ', function () { var aggr = { type: 'timeSeriesWinBuf', timestamp: 'Time', value: 'Value', winsize: 1, delay: 2, }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T00:00:00.000', Value: 0 }); // empty store.push({ Time: '2015-06-10T00:00:00.002', Value: 2 }); // now nonempty store.push({ Time: '2015-06-10T00:00:00.003', Value: 3 }); // no changes assert.strictEqual(sa.getInFloatVector().length, 0); assert.strictEqual(sa.getOutFloatVector().length, 0); assert.strictEqual(sa.getFloatVector().length, 1); }); it('should handle start nonempty, forget all: (Bs | I, O, Be) = (1 | 0, 1, 0): ', function () { var aggr = { type: 'timeSeriesWinBuf', timestamp: 'Time', value: 'Value', winsize: 1, delay: 2, }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T00:00:00.000', Value: 0 }); // empty store.push({ Time: '2015-06-10T00:00:00.002', Value: 2 }); // now nonempty store.push({ Time: '2015-06-10T00:00:00.006', Value: 6 }); // forget all assert.strictEqual(sa.getInFloatVector().length, 0); assert.strictEqual(sa.getOutFloatVector().length, 1); assert.strictEqual(sa.getFloatVector().length, 0); }); it('should handle start nonempty, forget some: (Bs | I, O, Be) = (1 | 0, 1, 1): ', function () { var aggr = { type: 'timeSeriesWinBuf', timestamp: 'Time', value: 'Value', winsize: 1, delay: 2, }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T00:00:00.000', Value: 0 }); // empty store.push({ Time: '2015-06-10T00:00:00.001', Value: 1 }); // empty store.push({ Time: '2015-06-10T00:00:00.003', Value: 3 }); // 2 values store.push({ Time: '2015-06-10T00:00:00.004', Value: 4 }); // forget one assert.strictEqual(sa.getInFloatVector().length, 0); assert.strictEqual(sa.getOutFloatVector().length, 1); assert.strictEqual(sa.getFloatVector().length, 1); }); it('should handle start nonempty, insert some: (Bs | I, O, Be) = (1 | 1, 0, 1): ', function () { var aggr = { type: 'timeSeriesWinBuf', timestamp: 'Time', value: 'Value', winsize: 1, delay: 1, }; var sa = store.addStreamAggr(aggr); store.push({ Time: '2015-06-10T00:00:00.000', Value: 0 }); // empty store.push({ Time: '2015-06-10T00:00:00.001', Value: 1 }); // 1 val store.push({ Time: '2015-06-10T00:00:00.002', Value: 2 }); // 2 values assert.strict