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
JavaScript
/**
* 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