aboutsummaryrefslogtreecommitdiff
path: root/contexts/data/lib/closure-library/closure/goog/stats/basicstat_test.html
blob: ddb8b07005b310fa097b1f371ad99e86b03e3600 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
<!DOCTYPE html>
<html>
<!--
Copyright 2011 The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Closure Unit Tests - goog.stats.BasicStat</title>
<script src="../base.js" type="text/javascript"></script>
<script type="text/javascript">
  goog.require('goog.array');
  goog.require('goog.stats.BasicStat');
  goog.require('goog.userAgent');
  goog.require('goog.string.format');
  goog.require('goog.testing.jsunit');
  goog.require('goog.testing.PseudoRandom');
</script>
</head>
<body>
<script type="text/javascript">


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.
 */
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)
  };
}

</script>
</body>
</html>