basicstat_test.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // Copyright 2011 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.stats.BasicStatTest');
  15. goog.setTestOnly('goog.stats.BasicStatTest');
  16. goog.require('goog.array');
  17. goog.require('goog.stats.BasicStat');
  18. goog.require('goog.string.format');
  19. goog.require('goog.testing.PseudoRandom');
  20. goog.require('goog.testing.jsunit');
  21. goog.require('goog.userAgent');
  22. function testGetSlotBoundary() {
  23. var stat = new goog.stats.BasicStat(1654);
  24. assertEquals('Checking interval', 33, stat.slotInterval_);
  25. assertEquals(132, stat.getSlotBoundary_(125));
  26. assertEquals(165, stat.getSlotBoundary_(132));
  27. assertEquals(132, stat.getSlotBoundary_(99));
  28. assertEquals(99, stat.getSlotBoundary_(98));
  29. }
  30. function testCheckForTimeTravel() {
  31. var stat = new goog.stats.BasicStat(1000);
  32. // no slots yet, should always be OK
  33. stat.checkForTimeTravel_(100);
  34. stat.checkForTimeTravel_(-1);
  35. stat.incBy(1, 125); // creates a first bucket, ending at t=140
  36. // Even though these go backwards in time, our basic fuzzy check passes
  37. // because we just check that the time is within the latest interval bucket.
  38. stat.checkForTimeTravel_(141);
  39. stat.checkForTimeTravel_(140);
  40. stat.checkForTimeTravel_(139);
  41. stat.checkForTimeTravel_(125);
  42. stat.checkForTimeTravel_(124);
  43. stat.checkForTimeTravel_(120);
  44. // State should still be the same, all of the above times are valid.
  45. assertEquals('State unchanged when called with good times', 1, stat.get(125));
  46. stat.checkForTimeTravel_(119);
  47. assertEquals('Reset after called with a bad time', 0, stat.get(125));
  48. }
  49. function testConstantIncrementPerSlot() {
  50. var stat = new goog.stats.BasicStat(1000);
  51. var now = 1000;
  52. for (var i = 0; i < 50; ++i) {
  53. var newMax = 1000 + i;
  54. var newMin = 1000 - i;
  55. stat.incBy(newMin, now);
  56. stat.incBy(newMax, now);
  57. var msg = goog.string.format(
  58. 'now=%d i=%d newMin=%d newMax=%d', now, i, newMin, newMax);
  59. assertEquals(msg, 2000 * (i + 1), stat.get(now));
  60. assertEquals(msg, newMax, stat.getMax(now));
  61. assertEquals(msg, newMin, stat.getMin(now));
  62. now += 20; // push into the next slots
  63. }
  64. // The next increment should cause old data to fall off.
  65. stat.incBy(1, now);
  66. assertEquals(2000 * 49 + 1, stat.get(now));
  67. assertEquals(1, stat.getMin(now));
  68. assertEquals(1049, stat.getMax(now));
  69. now += 20; // drop off another bucket
  70. stat.incBy(1, now);
  71. assertEquals(2000 * 48 + 2, stat.get(now));
  72. assertEquals(1, stat.getMin(now));
  73. assertEquals(1049, stat.getMax(now));
  74. }
  75. function testSparseBuckets() {
  76. var stat = new goog.stats.BasicStat(1000);
  77. var now = 1000;
  78. stat.incBy(10, now);
  79. assertEquals(10, stat.get(now));
  80. now += 5000; // the old slot is now still in memory, but should be ignored
  81. stat.incBy(1, now);
  82. assertEquals(1, stat.get(now));
  83. }
  84. function testFuzzy() {
  85. var stat = new goog.stats.BasicStat(1000);
  86. var test = new PerfectlySlowStat(1000);
  87. var rand = new goog.testing.PseudoRandom(58849020);
  88. var eventCount = 0;
  89. // test over 5 simulated seconds (2 for IE, due to timeouts)
  90. var simulationDuration = goog.userAgent.IE ? 2000 : 5000;
  91. for (var now = 1000; now < simulationDuration;) {
  92. var count = Math.floor(rand.random() * 2147483648);
  93. var delay = Math.floor(rand.random() * 25);
  94. for (var i = 0; i <= delay; ++i) {
  95. var time = now + i;
  96. var msg = goog.string.format('now=%d eventCount=%d', time, eventCount);
  97. var expected = test.getStats(now + i);
  98. assertEquals(expected.count, stat.get(time));
  99. assertEquals(expected.min, stat.getMin(time));
  100. assertEquals(expected.max, stat.getMax(time));
  101. }
  102. now += delay;
  103. stat.incBy(count, now);
  104. test.incBy(count, now);
  105. eventCount++;
  106. }
  107. }
  108. /**
  109. * A horribly inefficient implementation of BasicStat that stores
  110. * every event in an array and dynamically filters to perform
  111. * aggregations.
  112. * @constructor
  113. */
  114. var PerfectlySlowStat = function(interval) {
  115. this.interval_ = interval;
  116. this.slotSize_ = Math.floor(interval / goog.stats.BasicStat.NUM_SLOTS_);
  117. this.events_ = [];
  118. };
  119. PerfectlySlowStat.prototype.incBy = function(amt, now) {
  120. this.events_.push({'time': now, 'count': amt});
  121. };
  122. PerfectlySlowStat.prototype.getStats = function(now) {
  123. var end = Math.floor(now / this.slotSize_) * this.slotSize_ + this.slotSize_;
  124. var start = end - this.interval_;
  125. var events =
  126. goog.array.filter(this.events_, function(e) { return e.time >= start });
  127. return {
  128. 'count':
  129. goog.array.reduce(events, function(sum, e) { return sum + e.count }, 0),
  130. 'min': goog.array.reduce(
  131. events, function(min, e) { return Math.min(min, e.count); },
  132. Number.MAX_VALUE),
  133. 'max': goog.array.reduce(
  134. events, function(max, e) { return Math.max(max, e.count); },
  135. Number.MIN_VALUE)
  136. };
  137. };