github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/metric/metric_test.go (about) 1 // Copyright 2018 The gVisor 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 metric 16 17 import ( 18 "testing" 19 20 "google.golang.org/protobuf/proto" 21 "github.com/SagerNet/gvisor/pkg/eventchannel" 22 pb "github.com/SagerNet/gvisor/pkg/metric/metric_go_proto" 23 ) 24 25 // sliceEmitter implements eventchannel.Emitter by appending all messages to a 26 // slice. 27 type sliceEmitter []proto.Message 28 29 // Emit implements eventchannel.Emitter.Emit. 30 func (s *sliceEmitter) Emit(msg proto.Message) (bool, error) { 31 *s = append(*s, msg) 32 return false, nil 33 } 34 35 // Emit implements eventchannel.Emitter.Close. 36 func (s *sliceEmitter) Close() error { 37 return nil 38 } 39 40 // Reset clears all events in s. 41 func (s *sliceEmitter) Reset() { 42 *s = nil 43 } 44 45 // emitter is the eventchannel.Emitter used for all tests. Package eventchannel 46 // doesn't allow removing Emitters, so we must use one global emitter for all 47 // test cases. 48 var emitter sliceEmitter 49 50 func init() { 51 reset() 52 53 eventchannel.AddEmitter(&emitter) 54 } 55 56 // reset clears all global state in the metric package. 57 func reset() { 58 initialized = false 59 allMetrics = makeMetricSet() 60 emitter.Reset() 61 } 62 63 const ( 64 fooDescription = "Foo!" 65 barDescription = "Bar Baz" 66 counterDescription = "Counter" 67 ) 68 69 func TestInitialize(t *testing.T) { 70 defer reset() 71 72 _, err := NewUint64Metric("/foo", false, pb.MetricMetadata_UNITS_NONE, fooDescription) 73 if err != nil { 74 t.Fatalf("NewUint64Metric got err %v want nil", err) 75 } 76 77 _, err = NewUint64Metric("/bar", true, pb.MetricMetadata_UNITS_NANOSECONDS, barDescription) 78 if err != nil { 79 t.Fatalf("NewUint64Metric got err %v want nil", err) 80 } 81 82 if err := Initialize(); err != nil { 83 t.Fatalf("Initialize(): %s", err) 84 } 85 86 if len(emitter) != 1 { 87 t.Fatalf("Initialize emitted %d events want 1", len(emitter)) 88 } 89 90 mr, ok := emitter[0].(*pb.MetricRegistration) 91 if !ok { 92 t.Fatalf("emitter %v got %T want pb.MetricRegistration", emitter[0], emitter[0]) 93 } 94 95 if len(mr.Metrics) != 2 { 96 t.Errorf("MetricRegistration got %d metrics want 2", len(mr.Metrics)) 97 } 98 99 foundFoo := false 100 foundBar := false 101 for _, m := range mr.Metrics { 102 if m.Type != pb.MetricMetadata_TYPE_UINT64 { 103 t.Errorf("Metadata %+v Type got %v want pb.MetricMetadata_TYPE_UINT64", m, m.Type) 104 } 105 if !m.Cumulative { 106 t.Errorf("Metadata %+v Cumulative got false want true", m) 107 } 108 109 switch m.Name { 110 case "/foo": 111 foundFoo = true 112 if m.Description != fooDescription { 113 t.Errorf("/foo %+v Description got %q want %q", m, m.Description, fooDescription) 114 } 115 if m.Sync { 116 t.Errorf("/foo %+v Sync got true want false", m) 117 } 118 if m.Units != pb.MetricMetadata_UNITS_NONE { 119 t.Errorf("/foo %+v Units got %v want %v", m, m.Units, pb.MetricMetadata_UNITS_NONE) 120 } 121 case "/bar": 122 foundBar = true 123 if m.Description != barDescription { 124 t.Errorf("/bar %+v Description got %q want %q", m, m.Description, barDescription) 125 } 126 if !m.Sync { 127 t.Errorf("/bar %+v Sync got true want false", m) 128 } 129 if m.Units != pb.MetricMetadata_UNITS_NANOSECONDS { 130 t.Errorf("/bar %+v Units got %v want %v", m, m.Units, pb.MetricMetadata_UNITS_NANOSECONDS) 131 } 132 } 133 } 134 135 if !foundFoo { 136 t.Errorf("/foo not found: %+v", emitter) 137 } 138 if !foundBar { 139 t.Errorf("/bar not found: %+v", emitter) 140 } 141 } 142 143 func TestDisable(t *testing.T) { 144 defer reset() 145 146 _, err := NewUint64Metric("/foo", false, pb.MetricMetadata_UNITS_NONE, fooDescription) 147 if err != nil { 148 t.Fatalf("NewUint64Metric got err %v want nil", err) 149 } 150 151 _, err = NewUint64Metric("/bar", true, pb.MetricMetadata_UNITS_NONE, barDescription) 152 if err != nil { 153 t.Fatalf("NewUint64Metric got err %v want nil", err) 154 } 155 156 if err := Disable(); err != nil { 157 t.Fatalf("Disable(): %s", err) 158 } 159 160 if len(emitter) != 1 { 161 t.Fatalf("Initialize emitted %d events want 1", len(emitter)) 162 } 163 164 mr, ok := emitter[0].(*pb.MetricRegistration) 165 if !ok { 166 t.Fatalf("emitter %v got %T want pb.MetricRegistration", emitter[0], emitter[0]) 167 } 168 169 if len(mr.Metrics) != 0 { 170 t.Errorf("MetricRegistration got %d metrics want 0", len(mr.Metrics)) 171 } 172 } 173 174 func TestEmitMetricUpdate(t *testing.T) { 175 defer reset() 176 177 foo, err := NewUint64Metric("/foo", false, pb.MetricMetadata_UNITS_NONE, fooDescription) 178 if err != nil { 179 t.Fatalf("NewUint64Metric got err %v want nil", err) 180 } 181 182 _, err = NewUint64Metric("/bar", true, pb.MetricMetadata_UNITS_NONE, barDescription) 183 if err != nil { 184 t.Fatalf("NewUint64Metric got err %v want nil", err) 185 } 186 187 if err := Initialize(); err != nil { 188 t.Fatalf("Initialize(): %s", err) 189 } 190 191 // Don't care about the registration metrics. 192 emitter.Reset() 193 EmitMetricUpdate() 194 195 if len(emitter) != 1 { 196 t.Fatalf("EmitMetricUpdate emitted %d events want 1", len(emitter)) 197 } 198 199 update, ok := emitter[0].(*pb.MetricUpdate) 200 if !ok { 201 t.Fatalf("emitter %v got %T want pb.MetricUpdate", emitter[0], emitter[0]) 202 } 203 204 if len(update.Metrics) != 2 { 205 t.Errorf("MetricUpdate got %d metrics want 2", len(update.Metrics)) 206 } 207 208 // Both are included for their initial values. 209 foundFoo := false 210 foundBar := false 211 for _, m := range update.Metrics { 212 switch m.Name { 213 case "/foo": 214 foundFoo = true 215 case "/bar": 216 foundBar = true 217 } 218 uv, ok := m.Value.(*pb.MetricValue_Uint64Value) 219 if !ok { 220 t.Errorf("%+v: value %v got %T want pb.MetricValue_Uint64Value", m, m.Value, m.Value) 221 continue 222 } 223 if uv.Uint64Value != 0 { 224 t.Errorf("%v: Value got %v want 0", m, uv.Uint64Value) 225 } 226 } 227 228 if !foundFoo { 229 t.Errorf("/foo not found: %+v", emitter) 230 } 231 if !foundBar { 232 t.Errorf("/bar not found: %+v", emitter) 233 } 234 235 // Increment foo. Only it is included in the next update. 236 foo.Increment() 237 238 emitter.Reset() 239 EmitMetricUpdate() 240 241 if len(emitter) != 1 { 242 t.Fatalf("EmitMetricUpdate emitted %d events want 1", len(emitter)) 243 } 244 245 update, ok = emitter[0].(*pb.MetricUpdate) 246 if !ok { 247 t.Fatalf("emitter %v got %T want pb.MetricUpdate", emitter[0], emitter[0]) 248 } 249 250 if len(update.Metrics) != 1 { 251 t.Errorf("MetricUpdate got %d metrics want 1", len(update.Metrics)) 252 } 253 254 m := update.Metrics[0] 255 256 if m.Name != "/foo" { 257 t.Errorf("Metric %+v name got %q want '/foo'", m, m.Name) 258 } 259 260 uv, ok := m.Value.(*pb.MetricValue_Uint64Value) 261 if !ok { 262 t.Errorf("%+v: value %v got %T want pb.MetricValue_Uint64Value", m, m.Value, m.Value) 263 } 264 if uv.Uint64Value != 1 { 265 t.Errorf("%v: Value got %v want 1", m, uv.Uint64Value) 266 } 267 } 268 269 func TestEmitMetricUpdateWithFields(t *testing.T) { 270 defer reset() 271 272 field := Field{ 273 name: "weirdness_type", 274 allowedValues: []string{"weird1", "weird2"}} 275 276 counter, err := NewUint64Metric("/weirdness", false, pb.MetricMetadata_UNITS_NONE, counterDescription, field) 277 if err != nil { 278 t.Fatalf("NewUint64Metric got err %v want nil", err) 279 } 280 281 if err := Initialize(); err != nil { 282 t.Fatalf("Initialize(): %s", err) 283 } 284 285 // Don't care about the registration metrics. 286 emitter.Reset() 287 EmitMetricUpdate() 288 289 // For metrics with fields, we do not emit data unless the value is 290 // incremented. 291 if len(emitter) != 0 { 292 t.Fatalf("EmitMetricUpdate emitted %d events want 0", len(emitter)) 293 } 294 295 counter.IncrementBy(4, "weird1") 296 counter.Increment("weird2") 297 298 emitter.Reset() 299 EmitMetricUpdate() 300 301 if len(emitter) != 1 { 302 t.Fatalf("EmitMetricUpdate emitted %d events want 1", len(emitter)) 303 } 304 305 update, ok := emitter[0].(*pb.MetricUpdate) 306 if !ok { 307 t.Fatalf("emitter %v got %T want pb.MetricUpdate", emitter[0], emitter[0]) 308 } 309 310 if len(update.Metrics) != 2 { 311 t.Errorf("MetricUpdate got %d metrics want 2", len(update.Metrics)) 312 } 313 314 foundWeird1 := false 315 foundWeird2 := false 316 for i := 0; i < len(update.Metrics); i++ { 317 m := update.Metrics[i] 318 319 if m.Name != "/weirdness" { 320 t.Errorf("Metric %+v name got %q want '/weirdness'", m, m.Name) 321 } 322 if len(m.FieldValues) != 1 { 323 t.Errorf("MetricUpdate got %d fields want 1", len(m.FieldValues)) 324 } 325 326 switch m.FieldValues[0] { 327 case "weird1": 328 uv, ok := m.Value.(*pb.MetricValue_Uint64Value) 329 if !ok { 330 t.Errorf("%+v: value %v got %T want pb.MetricValue_Uint64Value", m, m.Value, m.Value) 331 } 332 if uv.Uint64Value != 4 { 333 t.Errorf("%v: Value got %v want 4", m, uv.Uint64Value) 334 } 335 foundWeird1 = true 336 case "weird2": 337 uv, ok := m.Value.(*pb.MetricValue_Uint64Value) 338 if !ok { 339 t.Errorf("%+v: value %v got %T want pb.MetricValue_Uint64Value", m, m.Value, m.Value) 340 } 341 if uv.Uint64Value != 1 { 342 t.Errorf("%v: Value got %v want 1", m, uv.Uint64Value) 343 } 344 foundWeird2 = true 345 } 346 } 347 348 if !foundWeird1 { 349 t.Errorf("Field value weird1 not found: %+v", emitter) 350 } 351 if !foundWeird2 { 352 t.Errorf("Field value weird2 not found: %+v", emitter) 353 } 354 }