166 lines
5.3 KiB
JavaScript
166 lines
5.3 KiB
JavaScript
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS-IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
goog.provide('goog.stats.BasicStatTest');
|
|
goog.setTestOnly('goog.stats.BasicStatTest');
|
|
|
|
goog.require('goog.array');
|
|
goog.require('goog.stats.BasicStat');
|
|
goog.require('goog.string.format');
|
|
goog.require('goog.testing.PseudoRandom');
|
|
goog.require('goog.testing.jsunit');
|
|
goog.require('goog.userAgent');
|
|
|
|
function testGetSlotBoundary() {
|
|
var stat = new goog.stats.BasicStat(1654);
|
|
assertEquals('Checking interval', 33, stat.slotInterval_);
|
|
|
|
assertEquals(132, stat.getSlotBoundary_(125));
|
|
assertEquals(165, stat.getSlotBoundary_(132));
|
|
assertEquals(132, stat.getSlotBoundary_(99));
|
|
assertEquals(99, stat.getSlotBoundary_(98));
|
|
}
|
|
|
|
function testCheckForTimeTravel() {
|
|
var stat = new goog.stats.BasicStat(1000);
|
|
|
|
// no slots yet, should always be OK
|
|
stat.checkForTimeTravel_(100);
|
|
stat.checkForTimeTravel_(-1);
|
|
|
|
stat.incBy(1, 125); // creates a first bucket, ending at t=140
|
|
|
|
// Even though these go backwards in time, our basic fuzzy check passes
|
|
// because we just check that the time is within the latest interval bucket.
|
|
stat.checkForTimeTravel_(141);
|
|
stat.checkForTimeTravel_(140);
|
|
stat.checkForTimeTravel_(139);
|
|
stat.checkForTimeTravel_(125);
|
|
stat.checkForTimeTravel_(124);
|
|
stat.checkForTimeTravel_(120);
|
|
|
|
// State should still be the same, all of the above times are valid.
|
|
assertEquals('State unchanged when called with good times', 1, stat.get(125));
|
|
|
|
stat.checkForTimeTravel_(119);
|
|
assertEquals('Reset after called with a bad time', 0, stat.get(125));
|
|
}
|
|
|
|
function testConstantIncrementPerSlot() {
|
|
var stat = new goog.stats.BasicStat(1000);
|
|
|
|
var now = 1000;
|
|
for (var i = 0; i < 50; ++i) {
|
|
var newMax = 1000 + i;
|
|
var newMin = 1000 - i;
|
|
stat.incBy(newMin, now);
|
|
stat.incBy(newMax, now);
|
|
|
|
var msg = goog.string.format(
|
|
'now=%d i=%d newMin=%d newMax=%d', now, i, newMin, newMax);
|
|
assertEquals(msg, 2000 * (i + 1), stat.get(now));
|
|
assertEquals(msg, newMax, stat.getMax(now));
|
|
assertEquals(msg, newMin, stat.getMin(now));
|
|
|
|
now += 20; // push into the next slots
|
|
}
|
|
|
|
// The next increment should cause old data to fall off.
|
|
stat.incBy(1, now);
|
|
assertEquals(2000 * 49 + 1, stat.get(now));
|
|
assertEquals(1, stat.getMin(now));
|
|
assertEquals(1049, stat.getMax(now));
|
|
|
|
now += 20; // drop off another bucket
|
|
stat.incBy(1, now);
|
|
assertEquals(2000 * 48 + 2, stat.get(now));
|
|
assertEquals(1, stat.getMin(now));
|
|
assertEquals(1049, stat.getMax(now));
|
|
}
|
|
|
|
function testSparseBuckets() {
|
|
var stat = new goog.stats.BasicStat(1000);
|
|
var now = 1000;
|
|
|
|
stat.incBy(10, now);
|
|
assertEquals(10, stat.get(now));
|
|
|
|
now += 5000; // the old slot is now still in memory, but should be ignored
|
|
stat.incBy(1, now);
|
|
assertEquals(1, stat.get(now));
|
|
}
|
|
|
|
function testFuzzy() {
|
|
var stat = new goog.stats.BasicStat(1000);
|
|
var test = new PerfectlySlowStat(1000);
|
|
var rand = new goog.testing.PseudoRandom(58849020);
|
|
var eventCount = 0;
|
|
|
|
// test over 5 simulated seconds (2 for IE, due to timeouts)
|
|
var simulationDuration = goog.userAgent.IE ? 2000 : 5000;
|
|
for (var now = 1000; now < simulationDuration; ) {
|
|
var count = Math.floor(rand.random() * 2147483648);
|
|
var delay = Math.floor(rand.random() * 25);
|
|
for (var i = 0; i <= delay; ++i) {
|
|
var time = now + i;
|
|
var msg = goog.string.format('now=%d eventCount=%d', time, eventCount);
|
|
var expected = test.getStats(now + i);
|
|
assertEquals(expected.count, stat.get(time));
|
|
assertEquals(expected.min, stat.getMin(time));
|
|
assertEquals(expected.max, stat.getMax(time));
|
|
}
|
|
|
|
now += delay;
|
|
stat.incBy(count, now);
|
|
test.incBy(count, now);
|
|
eventCount++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* A horribly inefficient implementation of BasicStat that stores
|
|
* every event in an array and dynamically filters to perform
|
|
* aggregations.
|
|
* @constructor
|
|
*/
|
|
var PerfectlySlowStat = function(interval) {
|
|
this.interval_ = interval;
|
|
this.slotSize_ = Math.floor(interval / goog.stats.BasicStat.NUM_SLOTS_);
|
|
this.events_ = [];
|
|
};
|
|
|
|
PerfectlySlowStat.prototype.incBy = function(amt, now) {
|
|
this.events_.push({'time': now, 'count': amt});
|
|
};
|
|
|
|
PerfectlySlowStat.prototype.getStats = function(now) {
|
|
var end = Math.floor(now / this.slotSize_) * this.slotSize_ + this.slotSize_;
|
|
var start = end - this.interval_;
|
|
var events = goog.array.filter(this.events_,
|
|
function(e) { return e.time >= start });
|
|
return {
|
|
'count': goog.array.reduce(events,
|
|
function(sum, e) { return sum + e.count },
|
|
0),
|
|
'min': goog.array.reduce(events,
|
|
function(min, e) { return Math.min(min, e.count); },
|
|
Number.MAX_VALUE),
|
|
'max': goog.array.reduce(events,
|
|
function(max, e) { return Math.max(max, e.count); },
|
|
Number.MIN_VALUE)
|
|
};
|
|
};
|