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  }