github.com/google/cloudprober@v0.11.3/metrics/eventmetrics_test.go (about) 1 // Copyright 2017 The Cloudprober Authors. 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 15 package metrics 16 17 import ( 18 "fmt" 19 "testing" 20 "time" 21 ) 22 23 func newEventMetrics(sent, rcvd, rtt int64, respCodes map[string]int64) *EventMetrics { 24 respCodesVal := NewMap("code", NewInt(0)) 25 for k, v := range respCodes { 26 respCodesVal.IncKeyBy(k, NewInt(v)) 27 } 28 em := NewEventMetrics(time.Now()). 29 AddMetric("sent", NewInt(sent)). 30 AddMetric("rcvd", NewInt(rcvd)). 31 AddMetric("rtt", NewInt(rtt)). 32 AddMetric("resp-code", respCodesVal) 33 return em 34 } 35 36 func verifyOrder(em *EventMetrics, names ...string) error { 37 keys := em.MetricsKeys() 38 for i := range names { 39 if keys[i] != names[i] { 40 return fmt.Errorf("Metrics not in order. At Index: %d, Expected: %s, Got: %s", i, names[i], keys[i]) 41 } 42 } 43 return nil 44 } 45 46 func verifyEventMetrics(t *testing.T, m *EventMetrics, sent, rcvd, rtt int64, respCodes map[string]int64) { 47 // Verify that metrics are ordered correctly. 48 if err := verifyOrder(m, "sent", "rcvd", "rtt", "resp-code"); err != nil { 49 t.Error(err) 50 } 51 52 expectedMetrics := map[string]int64{ 53 "sent": sent, 54 "rcvd": rcvd, 55 "rtt": rtt, 56 } 57 for k, eVal := range expectedMetrics { 58 if m.Metric(k).(NumValue).Int64() != eVal { 59 t.Errorf("Unexpected metric value. Expected: %d, Got: %d", eVal, m.Metric(k).(*Int).Int64()) 60 } 61 } 62 for k, eVal := range respCodes { 63 if m.Metric("resp-code").(*Map).GetKey(k).Int64() != eVal { 64 t.Errorf("Unexpected metric value. Expected: %d, Got: %d", eVal, m.Metric("resp-code").(*Map).GetKey(k).Int64()) 65 } 66 } 67 } 68 69 func TestEventMetricsUpdate(t *testing.T) { 70 rttVal := NewInt(0) 71 rttVal.Str = func(i int64) string { 72 return fmt.Sprintf("%.3f", float64(i)/1000) 73 } 74 m := newEventMetrics(0, 0, 0, make(map[string]int64)) 75 m.AddLabel("ptype", "http") 76 77 m2 := newEventMetrics(32, 22, 220100, map[string]int64{ 78 "200": 22, 79 }) 80 m.Update(m2) 81 // We'll verify later that mClone is un-impacted by further updates. 82 mClone := m.Clone() 83 84 // Verify that "m" has been updated correctly. 85 verifyEventMetrics(t, m, 32, 22, 220100, map[string]int64{ 86 "200": 22, 87 }) 88 89 m3 := newEventMetrics(30, 30, 300100, map[string]int64{ 90 "200": 22, 91 "204": 8, 92 }) 93 m.Update(m3) 94 95 // Verify that "m" has been updated correctly. 96 verifyEventMetrics(t, m, 62, 52, 520200, map[string]int64{ 97 "200": 44, 98 "204": 8, 99 }) 100 101 // Verify that even though "m" has changed, mClone is as m was after first update 102 verifyEventMetrics(t, mClone, 32, 22, 220100, map[string]int64{ 103 "200": 22, 104 }) 105 106 // Log metrics in string format 107 // t.Log(m.String()) 108 109 expectedString := fmt.Sprintf("%d labels=ptype=http sent=62 rcvd=52 rtt=520200 resp-code=map:code,200:44,204:8", m.Timestamp.Unix()) 110 s := m.String() 111 if s != expectedString { 112 t.Errorf("em.String()=%s, want=%s", s, expectedString) 113 } 114 } 115 116 func TestEventMetricsSubtractCounters(t *testing.T) { 117 rttVal := NewInt(0) 118 rttVal.Str = func(i int64) string { 119 return fmt.Sprintf("%.3f", float64(i)/1000) 120 } 121 m := newEventMetrics(10, 10, 1000, make(map[string]int64)) 122 m.AddLabel("ptype", "http") 123 124 // First run 125 m2 := newEventMetrics(32, 22, 220100, map[string]int64{ 126 "200": 22, 127 }) 128 gEM, err := m2.SubtractLast(m) 129 if err != nil { 130 t.Fatalf("Unexpected error: %v", err) 131 } 132 verifyEventMetrics(t, gEM, 22, 12, 219100, map[string]int64{ 133 "200": 22, 134 }) 135 136 // Second run 137 m3 := newEventMetrics(42, 31, 300100, map[string]int64{ 138 "200": 24, 139 "204": 8, 140 }) 141 142 gEM, err = m3.SubtractLast(m2) 143 if err != nil { 144 t.Fatalf("Unexpected error: %v", err) 145 } 146 verifyEventMetrics(t, gEM, 10, 9, 80000, map[string]int64{ 147 "200": 2, 148 "204": 8, 149 }) 150 151 // Third run, expect reset 152 m4 := newEventMetrics(10, 8, 1100, map[string]int64{ 153 "200": 8, 154 }) 155 gEM, err = m4.SubtractLast(m3) 156 if err != nil { 157 t.Fatalf("Unexpected error: %v", err) 158 } 159 verifyEventMetrics(t, gEM, 10, 8, 1100, map[string]int64{ 160 "200": 8, 161 }) 162 } 163 164 func TestKey(t *testing.T) { 165 m := newEventMetrics(42, 31, 300100, map[string]int64{ 166 "200": 24, 167 "204": 8, 168 }).AddLabel("probe", "google-homepage") 169 170 key := m.Key() 171 wantKey := "sent,rcvd,rtt,resp-code,probe=google-homepage" 172 173 if key != wantKey { 174 t.Errorf("Got key: %s, wanted: %s", key, wantKey) 175 } 176 } 177 178 func BenchmarkEventMetricsStringer(b *testing.B) { 179 em := newEventMetrics(32, 22, 220100, map[string]int64{ 180 "200": 22, 181 "404": 4500, 182 "403": 4500, 183 }) 184 // run the em.String() function b.N times 185 for n := 0; n < b.N; n++ { 186 em.String() 187 } 188 } 189 190 func TestAllocsPerRun(t *testing.T) { 191 respCodesVal := NewMap("code", NewInt(0)) 192 for k, v := range map[string]int64{ 193 "200": 22, 194 "404": 4500, 195 "403": 4500, 196 } { 197 respCodesVal.IncKeyBy(k, NewInt(v)) 198 } 199 200 var em *EventMetrics 201 newAvg := testing.AllocsPerRun(100, func() { 202 em = NewEventMetrics(time.Now()). 203 AddMetric("sent", NewInt(32)). 204 AddMetric("rcvd", NewInt(22)). 205 AddMetric("rtt", NewInt(220100)). 206 AddMetric("resp-code", respCodesVal) 207 }) 208 209 stringAvg := testing.AllocsPerRun(100, func() { 210 _ = em.String() 211 }) 212 213 t.Logf("Average allocations per run: ForNew=%v, ForString=%v", newAvg, stringAvg) 214 }