github.com/aristanetworks/goarista@v0.0.0-20240514173732-cca2755bbd44/cmd/ocprometheus/config_test.go (about) 1 // Copyright (c) 2017 Arista Networks, Inc. 2 // Use of this source code is governed by the Apache License 2.0 3 // that can be found in the COPYING file. 4 5 package main 6 7 import ( 8 "regexp" 9 "testing" 10 11 "github.com/aristanetworks/goarista/test" 12 13 "github.com/prometheus/client_golang/prometheus" 14 ) 15 16 func TestParseConfig(t *testing.T) { 17 tCases := []struct { 18 input []byte 19 config Config 20 }{ 21 { 22 input: []byte(` 23 devicelabels: 24 10.1.1.1: 25 lab1: val1 26 lab2: val2 27 '*': 28 lab1: val3 29 lab2: val4 30 subscriptions: 31 - /Sysdb/environment/cooling/status 32 - /Sysdb/environment/power/status 33 description-label-subscriptions: 34 - /interfaces/interface/state/description 35 - /network-instances/network-instance/protocols/protocol/state/description 36 - /interfaces/interface/invalid 37 metrics: 38 - name: fanName 39 path: /Sysdb/environment/cooling/status/fan/name 40 help: Fan Name 41 valuelabel: name 42 defaultvalue: 25 43 - name: intfCounter 44 path: /Sysdb/(lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter 45 help: Per-Interface Bytes/Errors/Discards Counters 46 - name: fanSpeed 47 path: /Sysdb/environment/cooling/fan/speed/value 48 help: Fan Speed`), 49 config: Config{ 50 DeviceLabels: map[string]prometheus.Labels{ 51 "10.1.1.1": { 52 "lab1": "val1", 53 "lab2": "val2", 54 }, 55 "*": { 56 "lab1": "val3", 57 "lab2": "val4", 58 }, 59 }, 60 Subscriptions: []string{ 61 "/Sysdb/environment/cooling/status", 62 "/Sysdb/environment/power/status", 63 }, 64 DescriptionLabelSubscriptions: []string{"/interfaces/interface/state/description", 65 "/network-instances/network-instance/protocols/protocol/state/description"}, 66 Metrics: []*MetricDef{ 67 { 68 Path: "/Sysdb/environment/cooling/status/fan/name", 69 re: regexp.MustCompile( 70 "/Sysdb/environment/cooling/status/fan/name"), 71 Name: "fanName", 72 Help: "Fan Name", 73 ValueLabel: "name", 74 DefaultValue: 25, 75 stringMetric: true, 76 devDesc: map[string]*promDesc{ 77 "10.1.1.1": { 78 fqName: "fanName", 79 help: "Fan Name", 80 varLabels: []string{"name"}, 81 devPermLabels: map[string]string{ 82 "lab1": "val1", 83 "lab2": "val2", 84 }, 85 }, 86 }, 87 desc: &promDesc{ 88 fqName: "fanName", 89 help: "Fan Name", 90 varLabels: []string{"name"}, 91 devPermLabels: map[string]string{ 92 "lab1": "val3", 93 "lab2": "val4", 94 }, 95 }, 96 }, 97 { 98 Path: "/Sysdb/(lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter", 99 re: regexp.MustCompile( 100 "/Sysdb/(lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter"), 101 Name: "intfCounter", 102 Help: "Per-Interface Bytes/Errors/Discards Counters", 103 devDesc: map[string]*promDesc{ 104 "10.1.1.1": { 105 fqName: "intfCounter", 106 help: "Per-Interface Bytes/Errors/Discards Counters", 107 varLabels: []string{"unnamedLabel1", "intf"}, 108 devPermLabels: map[string]string{"lab1": "val1", "lab2": "val2"}, 109 }, 110 }, 111 desc: &promDesc{ 112 fqName: "intfCounter", 113 help: "Per-Interface Bytes/Errors/Discards Counters", 114 varLabels: []string{"unnamedLabel1", "intf"}, 115 devPermLabels: map[string]string{"lab1": "val3", "lab2": "val4"}, 116 }, 117 }, 118 { 119 Path: "/Sysdb/environment/cooling/fan/speed/value", 120 re: regexp.MustCompile("/Sysdb/environment/cooling/fan/speed/value"), 121 Name: "fanSpeed", 122 Help: "Fan Speed", 123 devDesc: map[string]*promDesc{ 124 "10.1.1.1": { 125 fqName: "fanSpeed", 126 help: "Fan Speed", 127 varLabels: []string{}, 128 devPermLabels: map[string]string{"lab1": "val1", "lab2": "val2"}, 129 }, 130 }, 131 desc: &promDesc{ 132 fqName: "fanSpeed", 133 help: "Fan Speed", 134 varLabels: []string{}, 135 devPermLabels: map[string]string{"lab1": "val3", "lab2": "val4"}, 136 }, 137 }, 138 }, 139 subsByOrigin: map[string][]string{ 140 "": []string{ 141 "/Sysdb/environment/cooling/status", 142 "/Sysdb/environment/power/status", 143 }, 144 }, 145 }, 146 }, 147 { 148 input: []byte(` 149 devicelabels: 150 '*': 151 lab1: val3 152 lab2: val4 153 subscriptions: 154 - /Sysdb/environment/cooling/status 155 - /Sysdb/environment/power/status 156 metrics: 157 - name: intfCounter 158 path: /Sysdb/(?:lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter 159 help: Per-Interface Bytes/Errors/Discards Counters 160 - name: fanSpeed 161 path: /Sysdb/environment/cooling/fan/speed/value 162 help: Fan Speed`), 163 config: Config{ 164 DeviceLabels: map[string]prometheus.Labels{ 165 "*": { 166 "lab1": "val3", 167 "lab2": "val4", 168 }, 169 }, 170 Subscriptions: []string{ 171 "/Sysdb/environment/cooling/status", 172 "/Sysdb/environment/power/status", 173 }, 174 Metrics: []*MetricDef{ 175 { 176 Path: "/Sysdb/(?:lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter", 177 re: regexp.MustCompile( 178 "/Sysdb/(?:lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter"), 179 Name: "intfCounter", 180 Help: "Per-Interface Bytes/Errors/Discards Counters", 181 devDesc: map[string]*promDesc{}, 182 desc: &promDesc{ 183 fqName: "intfCounter", 184 help: "Per-Interface Bytes/Errors/Discards Counters", 185 varLabels: []string{"intf"}, 186 devPermLabels: map[string]string{ 187 "lab1": "val3", 188 "lab2": "val4", 189 }, 190 }, 191 }, 192 { 193 Path: "/Sysdb/environment/cooling/fan/speed/value", 194 re: regexp.MustCompile( 195 "/Sysdb/environment/cooling/fan/speed/value"), 196 Name: "fanSpeed", 197 Help: "Fan Speed", 198 devDesc: map[string]*promDesc{}, 199 desc: &promDesc{ 200 fqName: "fanSpeed", 201 help: "Fan Speed", 202 devPermLabels: map[string]string{ 203 "lab1": "val3", 204 "lab2": "val4", 205 }, 206 }, 207 }, 208 }, 209 subsByOrigin: map[string][]string{ 210 "": []string{ 211 "/Sysdb/environment/cooling/status", 212 "/Sysdb/environment/power/status", 213 }, 214 }, 215 }, 216 }, 217 { 218 input: []byte(` 219 devicelabels: 220 10.1.1.1: 221 lab1: val1 222 lab2: val2 223 subscriptions: 224 - eos_native:/Sysdb/environment/cooling/status 225 - /Sysdb/environment/power/status 226 metrics: 227 - name: intfCounter 228 path: /Sysdb/(?:lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter 229 help: Per-Interface Bytes/Errors/Discards Counters 230 - name: fanSpeed 231 path: /Sysdb/environment/cooling/fan/speed/value 232 help: Fan Speed`), 233 config: Config{ 234 DeviceLabels: map[string]prometheus.Labels{ 235 "10.1.1.1": { 236 "lab1": "val1", 237 "lab2": "val2", 238 }, 239 }, 240 Subscriptions: []string{ 241 "eos_native:/Sysdb/environment/cooling/status", 242 "/Sysdb/environment/power/status", 243 }, 244 Metrics: []*MetricDef{ 245 { 246 Path: "/Sysdb/(?:lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter", 247 re: regexp.MustCompile( 248 "/Sysdb/(?:lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter"), 249 Name: "intfCounter", 250 Help: "Per-Interface Bytes/Errors/Discards Counters", 251 devDesc: map[string]*promDesc{ 252 "10.1.1.1": { 253 fqName: "intfCounter", 254 help: "Per-Interface Bytes/Errors/Discards Counters", 255 varLabels: []string{"intf"}, 256 devPermLabels: map[string]string{ 257 "lab1": "val1", 258 "lab2": "val2", 259 }, 260 }, 261 }, 262 }, 263 { 264 Path: "/Sysdb/environment/cooling/fan/speed/value", 265 re: regexp.MustCompile( 266 "/Sysdb/environment/cooling/fan/speed/value"), 267 Name: "fanSpeed", 268 Help: "Fan Speed", 269 devDesc: map[string]*promDesc{ 270 "10.1.1.1": { 271 fqName: "fanSpeed", 272 help: "Fan Speed", 273 devPermLabels: map[string]string{ 274 "lab1": "val1", 275 "lab2": "val2", 276 }, 277 }, 278 }, 279 }, 280 }, 281 subsByOrigin: map[string][]string{ 282 "": []string{ 283 "/Sysdb/environment/power/status", 284 }, 285 "eos_native": []string{ 286 "/Sysdb/environment/cooling/status", 287 }, 288 }, 289 }, 290 }, 291 { 292 input: []byte(` 293 subscriptions: 294 - /Sysdb/environment/cooling/status 295 - /Sysdb/environment/power/status 296 metrics: 297 - name: intfCounter 298 path: /Sysdb/(?:lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter 299 help: Per-Interface Bytes/Errors/Discards Counters 300 - name: fanSpeed 301 path: /Sysdb/environment/cooling/fan/speed/value 302 help: Fan Speed`), 303 config: Config{ 304 DeviceLabels: map[string]prometheus.Labels{}, 305 Subscriptions: []string{ 306 "/Sysdb/environment/cooling/status", 307 "/Sysdb/environment/power/status", 308 }, 309 Metrics: []*MetricDef{ 310 { 311 Path: "/Sysdb/(?:lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter", 312 re: regexp.MustCompile( 313 "/Sysdb/(?:lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter"), 314 Name: "intfCounter", 315 Help: "Per-Interface Bytes/Errors/Discards Counters", 316 devDesc: map[string]*promDesc{}, 317 desc: &promDesc{ 318 fqName: "intfCounter", 319 help: "Per-Interface Bytes/Errors/Discards Counters", 320 varLabels: []string{"intf"}, 321 }, 322 }, 323 { 324 Path: "/Sysdb/environment/cooling/fan/speed/value", 325 re: regexp.MustCompile( 326 "/Sysdb/environment/cooling/fan/speed/value"), 327 Name: "fanSpeed", 328 Help: "Fan Speed", 329 devDesc: map[string]*promDesc{}, 330 desc: &promDesc{fqName: "fanSpeed", help: "Fan Speed"}, 331 }}, 332 subsByOrigin: map[string][]string{ 333 "": []string{ 334 "/Sysdb/environment/cooling/status", 335 "/Sysdb/environment/power/status", 336 }, 337 }, 338 }, 339 }, 340 } 341 342 for i, c := range tCases { 343 cfg, err := parseConfig(c.input) 344 if err != nil { 345 t.Errorf("Unexpected error in case %d: %v", i+1, err) 346 continue 347 } 348 if !test.DeepEqual(*cfg, c.config) { 349 t.Errorf("Test case %d: mismatch %v", i+1, test.Diff(*cfg, c.config)) 350 } 351 } 352 } 353 354 func TestGetMetricValues(t *testing.T) { 355 config := []byte(` 356 devicelabels: 357 10.1.1.1: 358 lab1: val1 359 lab2: val2 360 '*': 361 lab1: val3 362 lab2: val4 363 subscriptions: 364 - /Sysdb/environment/cooling/status 365 - /Sysdb/environment/power/status 366 metrics: 367 - name: intfCounter 368 path: /Sysdb/(lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter 369 help: Per-Interface Bytes/Errors/Discards Counters 370 - name: fanSpeed 371 path: /Sysdb/environment/cooling/status/fan/speed/value 372 help: Fan Speed`) 373 cfg, err := parseConfig(config) 374 if err != nil { 375 t.Fatalf("Unexpected error: %v", err) 376 } 377 378 tCases := []struct { 379 src source 380 desc *prometheus.Desc 381 labels []string 382 }{ 383 { 384 src: source{ 385 addr: "10.1.1.1", 386 path: "/Sysdb/lag/intfCounterDir/Ethernet1/intfCounter", 387 }, 388 desc: prometheus.NewDesc("intfCounter", "Per-Interface Bytes/Errors/Discards Counters", 389 []string{"unnamedLabel1", "intf"}, 390 prometheus.Labels{"lab1": "val1", "lab2": "val2"}), 391 labels: []string{"lag", "Ethernet1"}, 392 }, 393 { 394 src: source{ 395 addr: "10.2.2.2", 396 path: "/Sysdb/lag/intfCounterDir/Ethernet1/intfCounter", 397 }, 398 desc: prometheus.NewDesc("intfCounter", "Per-Interface Bytes/Errors/Discards Counters", 399 []string{"unnamedLabel1", "intf"}, 400 prometheus.Labels{"lab1": "val3", "lab2": "val4"}), 401 labels: []string{"lag", "Ethernet1"}, 402 }, 403 { 404 src: source{ 405 addr: "10.2.2.2", 406 path: "/Sysdb/environment/cooling/status/fan/speed/value", 407 }, 408 desc: prometheus.NewDesc("fanSpeed", "Fan Speed", 409 []string{}, 410 prometheus.Labels{"lab1": "val3", "lab2": "val4"}), 411 labels: []string{}, 412 }, 413 { 414 src: source{ 415 addr: "10.2.2.2", 416 path: "/Sysdb/environment/nonexistent", 417 }, 418 desc: nil, 419 labels: nil, 420 }, 421 } 422 descLabels := make(map[string]map[string]string) 423 for i, c := range tCases { 424 metric := cfg.getMetricValues(c.src, descLabels) 425 if metric == nil { 426 // Avoids error from trying to access metric.desc when metric is nil 427 metric = &metricValues{} 428 } 429 if !test.DeepEqual(metric.desc, c.desc) { 430 t.Errorf("Test case %d: desc mismatch %v", i+1, test.Diff(metric.desc, c.desc)) 431 } 432 if !test.DeepEqual(metric.labels, c.labels) { 433 t.Errorf("Test case %d: labels mismatch %v", i+1, test.Diff(metric.labels, c.labels)) 434 } 435 } 436 } 437 438 func TestGetAllDescs(t *testing.T) { 439 tCases := []struct { 440 config []byte 441 descs []*prometheus.Desc 442 }{ 443 { 444 config: []byte(` 445 devicelabels: 446 10.1.1.1: 447 lab1: val1 448 lab2: val2 449 '*': 450 lab1: val3 451 lab2: val4 452 subscriptions: 453 - /Sysdb/environment/cooling/status 454 - /Sysdb/environment/power/status 455 metrics: 456 - name: intfCounter 457 path: /Sysdb/(lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter 458 help: Per-Interface Bytes/Errors/Discards Counters 459 - name: fanSpeed 460 path: /Sysdb/environment/cooling/status/fan/speed/value 461 help: Fan Speed`), 462 descs: []*prometheus.Desc{ 463 prometheus.NewDesc("intfCounter", "Per-Interface Bytes/Errors/Discards Counters", 464 []string{"unnamedLabel1", "intf"}, 465 prometheus.Labels{"lab1": "val3", "lab2": "val4"}), 466 prometheus.NewDesc("intfCounter", "Per-Interface Bytes/Errors/Discards Counters", 467 []string{"unnamedLabel1", "intf"}, 468 prometheus.Labels{"lab1": "val1", "lab2": "val2"}), 469 prometheus.NewDesc("fanSpeed", "Fan Speed", []string{}, 470 prometheus.Labels{"lab1": "val3", "lab2": "val4"}), 471 prometheus.NewDesc("fanSpeed", "Fan Speed", []string{}, 472 prometheus.Labels{"lab1": "val1", "lab2": "val2"}), 473 }, 474 }, 475 { 476 config: []byte(` 477 devicelabels: 478 10.1.1.1: 479 lab1: val1 480 lab2: val2 481 subscriptions: 482 - /Sysdb/environment/cooling/status 483 - /Sysdb/environment/power/status 484 metrics: 485 - name: intfCounter 486 path: /Sysdb/(lag|slice/phy/.+)/intfCounterDir/(?P<intf>.+)/intfCounter 487 help: Per-Interface Bytes/Errors/Discards Counters 488 - name: fanSpeed 489 path: /Sysdb/environment/cooling/status/fan/speed/value 490 help: Fan Speed`), 491 descs: []*prometheus.Desc{ 492 prometheus.NewDesc("intfCounter", "Per-Interface Bytes/Errors/Discards Counters", 493 []string{"unnamedLabel1", "intf"}, 494 prometheus.Labels{"lab1": "val1", "lab2": "val2"}), 495 prometheus.NewDesc("fanSpeed", "Fan Speed", []string{}, 496 prometheus.Labels{"lab1": "val1", "lab2": "val2"}), 497 }, 498 }, 499 } 500 501 for i, c := range tCases { 502 cfg, err := parseConfig(c.config) 503 if err != nil { 504 t.Fatalf("Unexpected error: %v", err) 505 } 506 507 ch := make(chan *prometheus.Desc, 10) 508 cfg.getAllDescs(ch) 509 j := 0 510 for d := range ch { 511 if !test.DeepEqual(c.descs[j], d) { 512 t.Errorf("Test case %d: desc %d mismatch %v", i+1, j+1, test.Diff(c.descs[j], d)) 513 } 514 j++ 515 if j == len(c.descs) { 516 break 517 } 518 } 519 select { 520 case <-ch: 521 t.Errorf("Test case %d: too many descs", i+1) 522 default: 523 } 524 } 525 }