rates_test.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. Copyright 2019 The Vitess Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package stats
  14. import (
  15. "expvar"
  16. "testing"
  17. "time"
  18. )
  19. // For tests, we want to control exactly the time used by Rates.
  20. // The way Rates works is:
  21. // - at creation, do a snapshot.
  22. // - every interval, do a snapshot.
  23. // So in these tests, we make sure to always call snapshot() every interval.
  24. // We do other actions after epsilon, but then wait for intervalMinusEpsilon
  25. // and call snapshot().
  26. const (
  27. interval = 1 * time.Second
  28. epsilon = 50 * time.Millisecond
  29. intervalMinusEpsilon = interval - epsilon
  30. )
  31. func TestRates(t *testing.T) {
  32. now := time.Now()
  33. timeNow = func() time.Time {
  34. return now
  35. }
  36. clear()
  37. c := NewCountersWithSingleLabel("rcounter1", "rcounter help", "label")
  38. r := NewRates("rates1", c, 3, -1*time.Second)
  39. r.snapshot()
  40. now = now.Add(epsilon)
  41. c.Add("tag1", 0)
  42. c.Add("tag2", 0)
  43. now = now.Add(intervalMinusEpsilon)
  44. r.snapshot()
  45. now = now.Add(epsilon)
  46. checkRates(t, r, "after 1s", 0.0, `{"tag1":[0],"tag2":[0]}`)
  47. c.Add("tag1", 10)
  48. c.Add("tag2", 20)
  49. now = now.Add(intervalMinusEpsilon)
  50. r.snapshot()
  51. now = now.Add(epsilon)
  52. checkRates(t, r, "after 2s", 30.0, `{"tag1":[0,10],"tag2":[0,20]}`)
  53. now = now.Add(intervalMinusEpsilon)
  54. r.snapshot()
  55. now = now.Add(epsilon)
  56. checkRates(t, r, "after 3s", 0.0, `{"tag1":[0,10,0],"tag2":[0,20,0]}`)
  57. now = now.Add(intervalMinusEpsilon)
  58. r.snapshot()
  59. now = now.Add(epsilon)
  60. checkRates(t, r, "after 4s", 0.0, `{"tag1":[10,0,0],"tag2":[20,0,0]}`)
  61. }
  62. func checkRates(t *testing.T, r *Rates, desc string, wantRate float64, wantRateMap string) {
  63. if got := r.String(); got != wantRateMap {
  64. t.Errorf("%v: want %s, got %s", desc, wantRateMap, got)
  65. }
  66. if got := r.TotalRate(); got != wantRate {
  67. t.Errorf("%v: want rate %v, got rate %v", desc, wantRate, got)
  68. }
  69. }
  70. func TestRatesConsistency(t *testing.T) {
  71. now := time.Now()
  72. timeNow = func() time.Time {
  73. return now
  74. }
  75. // This tests the following invariant: in the time window
  76. // covered by rates, the sum of the rates reported must be
  77. // equal to the count reported by the counter.
  78. clear()
  79. c := NewCountersWithSingleLabel("rcounter4", "rcounter4 help", "label")
  80. r := NewRates("rates4", c, 100, -1*time.Second)
  81. r.snapshot()
  82. now = now.Add(epsilon)
  83. c.Add("a", 1000)
  84. now = now.Add(intervalMinusEpsilon)
  85. r.snapshot()
  86. now = now.Add(epsilon)
  87. c.Add("a", 1)
  88. now = now.Add(intervalMinusEpsilon)
  89. r.snapshot()
  90. now = now.Add(epsilon)
  91. result := r.Get()
  92. counts := c.Counts()
  93. t.Logf("r.Get(): %v", result)
  94. t.Logf("c.Counts(): %v", counts)
  95. rate, count := result["a"], counts["a"]
  96. var sum float64
  97. for _, v := range rate {
  98. sum += v
  99. }
  100. if sum != float64(counts["a"]) {
  101. t.Errorf("rate inconsistent with count: sum of %v != %v", rate, count)
  102. }
  103. }
  104. func TestRatesHook(t *testing.T) {
  105. clear()
  106. c := NewCountersWithSingleLabel("rcounter2", "rcounter2 help", "label")
  107. var gotname string
  108. var gotv *Rates
  109. clear()
  110. Register(func(name string, v expvar.Var) {
  111. gotname = name
  112. gotv = v.(*Rates)
  113. })
  114. v := NewRates("rates2", c, 2, 10*time.Second)
  115. if gotname != "rates2" {
  116. t.Errorf("want rates2, got %s", gotname)
  117. }
  118. if gotv != v {
  119. t.Errorf("want %#v, got %#v", v, gotv)
  120. }
  121. }