github.com/GoogleCloudPlatform/testgrid@v0.0.174/util/metrics/logmetrics/log_test.go (about) 1 /* 2 Copyright 2021 The TestGrid Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package logmetrics 18 19 import ( 20 "testing" 21 "time" 22 23 "github.com/google/go-cmp/cmp" 24 "github.com/sirupsen/logrus" 25 ) 26 27 func TestInt64Set(t *testing.T) { 28 cases := []struct { 29 name string 30 fields []string 31 sets []map[int64][]string 32 want map[string]map[string]interface{} 33 }{ 34 { 35 name: "zero", 36 want: map[string]map[string]interface{}{}, 37 }, 38 { 39 name: "basic", 40 fields: []string{"component"}, 41 sets: []map[int64][]string{ 42 {64: {"updater"}}, 43 }, 44 want: map[string]map[string]interface{}{ 45 "component": { 46 "updater": mean{[]int64{64}}, 47 }, 48 }, 49 }, 50 { 51 name: "fields", 52 fields: []string{"component", "source"}, 53 sets: []map[int64][]string{ 54 {64: {"updater", "prow"}}, 55 }, 56 want: map[string]map[string]interface{}{ 57 "component": { 58 "updater": mean{[]int64{64}}, 59 }, 60 "source": { 61 "prow": mean{[]int64{64}}, 62 }, 63 }, 64 }, 65 { 66 name: "values", 67 fields: []string{"component"}, 68 sets: []map[int64][]string{ 69 {64: {"updater"}}, 70 {32: {"updater"}}, 71 }, 72 want: map[string]map[string]interface{}{ 73 "component": { 74 "updater": mean{[]int64{64, 32}}, 75 }, 76 }, 77 }, 78 { 79 name: "fields and values", 80 fields: []string{"component", "source"}, 81 sets: []map[int64][]string{ 82 {64: {"updater", "prow"}}, 83 {32: {"updater", "prow"}}, 84 }, 85 want: map[string]map[string]interface{}{ 86 "component": { 87 "updater": mean{[]int64{64, 32}}, 88 }, 89 "source": { 90 "prow": mean{[]int64{64, 32}}, 91 }, 92 }, 93 }, 94 { 95 name: "complex", 96 fields: []string{"component", "source"}, 97 sets: []map[int64][]string{ 98 {64: {"updater", "prow"}}, 99 {66: {"updater", "google"}}, 100 {32: {"summarizer", "google"}}, 101 }, 102 want: map[string]map[string]interface{}{ 103 "component": { 104 "updater": mean{[]int64{64, 66}}, 105 "summarizer": mean{[]int64{32}}, 106 }, 107 "source": { 108 "prow": mean{[]int64{64}}, 109 "google": mean{[]int64{66, 32}}, 110 }, 111 }, 112 }, 113 } 114 115 for _, tc := range cases { 116 t.Run(tc.name, func(t *testing.T) { 117 var r Reporter 118 m := r.Int64("fake metric", "fake desc", logrus.WithField("name", tc.name), tc.fields...) 119 for _, set := range tc.sets { 120 for n, fields := range set { 121 m.Set(n, fields...) 122 } 123 } 124 got := m.(Valuer).Values() 125 if diff := cmp.Diff(tc.want, got, cmp.AllowUnexported(mean{}, gauge{})); diff != "" { 126 t.Errorf("Set() got unexpected diff (-want +got):\n%s", diff) 127 } 128 }) 129 } 130 } 131 132 func TestCounterAdd(t *testing.T) { 133 when := time.Now().Add(-10 * time.Minute) 134 cases := []struct { 135 name string 136 fields []string 137 adds []map[int64][]string 138 want map[string]map[string]interface{} 139 }{ 140 { 141 name: "zero", 142 want: map[string]map[string]interface{}{}, 143 }, 144 { 145 name: "basic", 146 fields: []string{"component"}, 147 adds: []map[int64][]string{ 148 { 149 12: {"updater"}, 150 }, 151 }, 152 want: map[string]map[string]interface{}{ 153 "component": {"updater": gauge{12, 12, 10 * time.Minute}}, 154 }, 155 }, 156 { 157 name: "fields", 158 fields: []string{"component", "source"}, 159 adds: []map[int64][]string{ 160 {64: {"updater", "prow"}}, 161 }, 162 want: map[string]map[string]interface{}{ 163 "component": { 164 "updater": gauge{64, 64, 10 * time.Minute}, 165 }, 166 "source": { 167 "prow": gauge{64, 64, 10 * time.Minute}, 168 }, 169 }, 170 }, 171 { 172 name: "values", 173 fields: []string{"component"}, 174 adds: []map[int64][]string{ 175 {64: {"updater"}}, 176 {32: {"updater"}}, 177 }, 178 want: map[string]map[string]interface{}{ 179 "component": { 180 "updater": gauge{64 + 32, 64 + 32, 10 * time.Minute}, 181 }, 182 }, 183 }, 184 { 185 name: "fields and values", 186 fields: []string{"component", "source"}, 187 adds: []map[int64][]string{ 188 {64: {"updater", "prow"}}, 189 {32: {"updater", "prow"}}, 190 }, 191 want: map[string]map[string]interface{}{ 192 "component": { 193 "updater": gauge{64 + 32, 64 + 32, 10 * time.Minute}, 194 }, 195 "source": { 196 "prow": gauge{64 + 32, 64 + 32, 10 * time.Minute}, 197 }, 198 }, 199 }, 200 { 201 name: "complex", 202 fields: []string{"component", "source"}, 203 adds: []map[int64][]string{ 204 {64: {"updater", "prow"}}, 205 {66: {"updater", "google"}}, 206 {32: {"summarizer", "google"}}, 207 }, 208 want: map[string]map[string]interface{}{ 209 "component": { 210 "updater": gauge{64 + 66, 64 + 66, 10 * time.Minute}, 211 "summarizer": gauge{32, 32, 10 * time.Minute}, 212 }, 213 "source": { 214 "prow": gauge{64, 64, 10 * time.Minute}, 215 "google": gauge{66 + 32, 66 + 32, 10 * time.Minute}, 216 }, 217 }, 218 }, 219 } 220 221 for _, tc := range cases { 222 t.Run(tc.name, func(t *testing.T) { 223 var r Reporter 224 m := r.Counter("fake metric", "fake desc", logrus.WithField("name", tc.name), tc.fields...) 225 m.(*logCounter).last = when 226 for _, add := range tc.adds { 227 for n, values := range add { 228 m.Add(n, values...) 229 } 230 } 231 232 got := m.(Valuer).Values() 233 for _, got := range got { 234 for key, value := range got { 235 g := value.(gauge) 236 g.dur = g.dur.Round(time.Minute) 237 got[key] = g 238 } 239 } 240 if diff := cmp.Diff(tc.want, got, cmp.AllowUnexported(gauge{})); diff != "" { 241 t.Errorf("Add() got unexpected diff (-want +got):\n%s", diff) 242 } 243 }) 244 } 245 } 246 247 func TestMean(t *testing.T) { 248 cases := []struct { 249 name string 250 m mean 251 want string 252 }{ 253 { 254 name: "basic", 255 want: "0 values", 256 }, 257 { 258 name: "single", 259 m: mean{values: []int64{7}}, 260 want: "7", 261 }, 262 { 263 name: "average", 264 m: mean{values: []int64{7, 8, 9}}, 265 want: "8 average (3 values)", 266 }, 267 } 268 269 for _, tc := range cases { 270 t.Run(tc.name, func(t *testing.T) { 271 if got := tc.m.String(); got != tc.want { 272 t.Errorf("mean.String() got %q want %q", got, tc.want) 273 } 274 }) 275 } 276 } 277 278 func TestQPS(t *testing.T) { 279 cases := []struct { 280 name string 281 g gauge 282 want string 283 }{ 284 { 285 name: "instant", 286 g: gauge{ 287 delta: 100, 288 }, 289 want: "0 per second", 290 }, 291 { 292 name: "constant", 293 g: gauge{ 294 dur: 5 * time.Second, 295 }, 296 want: "0 per second", 297 }, 298 { 299 name: "slow", 300 g: gauge{ 301 delta: 1, 302 dur: 5*time.Second + 200*time.Millisecond, 303 }, 304 want: "once per 5.2s", 305 }, 306 { 307 name: "fast", 308 g: gauge{ 309 delta: 100, 310 dur: 5 * time.Second, 311 }, 312 want: "20.00 per second", 313 }, 314 } 315 316 for _, tc := range cases { 317 t.Run(tc.name, func(t *testing.T) { 318 if got := tc.g.qps(); got != tc.want { 319 t.Errorf("gauge.qps() got %q want %q", got, tc.want) 320 } 321 }) 322 } 323 }