...

Source file src/k8s.io/component-base/metrics/counter_test.go

Documentation: k8s.io/component-base/metrics

     1  /*
     2  Copyright 2019 The Kubernetes 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 metrics
    18  
    19  import (
    20  	"bytes"
    21  	"testing"
    22  
    23  	"github.com/blang/semver/v4"
    24  	"github.com/prometheus/common/expfmt"
    25  	"github.com/stretchr/testify/assert"
    26  
    27  	apimachineryversion "k8s.io/apimachinery/pkg/version"
    28  )
    29  
    30  func TestCounter(t *testing.T) {
    31  	var tests = []struct {
    32  		desc string
    33  		*CounterOpts
    34  		expectedMetricCount int
    35  		expectedHelp        string
    36  	}{
    37  		{
    38  			desc: "Test non deprecated",
    39  			CounterOpts: &CounterOpts{
    40  				Namespace:      "namespace",
    41  				Name:           "metric_test_name",
    42  				Subsystem:      "subsystem",
    43  				StabilityLevel: ALPHA,
    44  				Help:           "counter help",
    45  			},
    46  			expectedMetricCount: 1,
    47  			expectedHelp:        "[ALPHA] counter help",
    48  		},
    49  		{
    50  			desc: "Test deprecated",
    51  			CounterOpts: &CounterOpts{
    52  				Namespace:         "namespace",
    53  				Name:              "metric_test_name",
    54  				Subsystem:         "subsystem",
    55  				Help:              "counter help",
    56  				StabilityLevel:    ALPHA,
    57  				DeprecatedVersion: "1.15.0",
    58  			},
    59  			expectedMetricCount: 1,
    60  			expectedHelp:        "[ALPHA] (Deprecated since 1.15.0) counter help",
    61  		},
    62  		{
    63  			desc: "Test hidden",
    64  			CounterOpts: &CounterOpts{
    65  				Namespace:         "namespace",
    66  				Name:              "metric_test_name",
    67  				Subsystem:         "subsystem",
    68  				Help:              "counter help",
    69  				StabilityLevel:    ALPHA,
    70  				DeprecatedVersion: "1.14.0",
    71  			},
    72  			expectedMetricCount: 0,
    73  		},
    74  	}
    75  
    76  	for _, test := range tests {
    77  		t.Run(test.desc, func(t *testing.T) {
    78  			registry := newKubeRegistry(apimachineryversion.Info{
    79  				Major:      "1",
    80  				Minor:      "15",
    81  				GitVersion: "v1.15.0-alpha-1.12345",
    82  			})
    83  			// c is a pointer to a Counter
    84  			c := NewCounter(test.CounterOpts)
    85  			registry.MustRegister(c)
    86  			// mfs is a pointer to a dto.MetricFamily slice
    87  			mfs, err := registry.Gather()
    88  			var buf bytes.Buffer
    89  			enc := expfmt.NewEncoder(&buf, "text/plain; version=0.0.4; charset=utf-8")
    90  			assert.Equalf(t, test.expectedMetricCount, len(mfs), "Got %v metrics, Want: %v metrics", len(mfs), test.expectedMetricCount)
    91  			assert.Nil(t, err, "Gather failed %v", err)
    92  			for _, metric := range mfs {
    93  				err := enc.Encode(metric)
    94  				assert.Nil(t, err, "Unexpected err %v in encoding the metric", err)
    95  				assert.Equalf(t, test.expectedHelp, metric.GetHelp(), "Got %s as help message, want %s", metric.GetHelp(), test.expectedHelp)
    96  			}
    97  
    98  			// increment the counter N number of times and verify that the metric retains the count correctly
    99  			numberOfTimesToIncrement := 3
   100  			for i := 0; i < numberOfTimesToIncrement; i++ {
   101  				c.Inc()
   102  			}
   103  			mfs, err = registry.Gather()
   104  			assert.Nil(t, err, "Gather failed %v", err)
   105  
   106  			for _, mf := range mfs {
   107  				mfMetric := mf.GetMetric()
   108  				for _, m := range mfMetric {
   109  					assert.Equalf(t, numberOfTimesToIncrement, int(m.GetCounter().GetValue()), "Got %v, wanted %v as the count", m.GetCounter().GetValue(), numberOfTimesToIncrement)
   110  				}
   111  			}
   112  		})
   113  	}
   114  }
   115  
   116  func TestCounterVec(t *testing.T) {
   117  	var tests = []struct {
   118  		desc string
   119  		*CounterOpts
   120  		labels                    []string
   121  		registryVersion           *semver.Version
   122  		expectedMetricFamilyCount int
   123  		expectedHelp              string
   124  	}{
   125  		{
   126  			desc: "Test non deprecated",
   127  			CounterOpts: &CounterOpts{
   128  				Namespace: "namespace",
   129  				Name:      "metric_test_name",
   130  				Subsystem: "subsystem",
   131  				Help:      "counter help",
   132  			},
   133  			labels:                    []string{"label_a", "label_b"},
   134  			expectedMetricFamilyCount: 1,
   135  			expectedHelp:              "[ALPHA] counter help",
   136  		},
   137  		{
   138  			desc: "Test deprecated",
   139  			CounterOpts: &CounterOpts{
   140  				Namespace:         "namespace",
   141  				Name:              "metric_test_name",
   142  				Subsystem:         "subsystem",
   143  				Help:              "counter help",
   144  				DeprecatedVersion: "1.15.0",
   145  			},
   146  			labels:                    []string{"label_a", "label_b"},
   147  			expectedMetricFamilyCount: 1,
   148  			expectedHelp:              "[ALPHA] (Deprecated since 1.15.0) counter help",
   149  		},
   150  		{
   151  			desc: "Test hidden",
   152  			CounterOpts: &CounterOpts{
   153  				Namespace:         "namespace",
   154  				Name:              "metric_test_name",
   155  				Subsystem:         "subsystem",
   156  				Help:              "counter help",
   157  				DeprecatedVersion: "1.14.0",
   158  			},
   159  			labels:                    []string{"label_a", "label_b"},
   160  			expectedMetricFamilyCount: 0,
   161  			expectedHelp:              "counter help",
   162  		},
   163  		{
   164  			desc: "Test alpha",
   165  			CounterOpts: &CounterOpts{
   166  				StabilityLevel: ALPHA,
   167  				Namespace:      "namespace",
   168  				Name:           "metric_test_name",
   169  				Subsystem:      "subsystem",
   170  				Help:           "counter help",
   171  			},
   172  			labels:                    []string{"label_a", "label_b"},
   173  			expectedMetricFamilyCount: 1,
   174  			expectedHelp:              "[ALPHA] counter help",
   175  		},
   176  	}
   177  
   178  	for _, test := range tests {
   179  		t.Run(test.desc, func(t *testing.T) {
   180  			registry := newKubeRegistry(apimachineryversion.Info{
   181  				Major:      "1",
   182  				Minor:      "15",
   183  				GitVersion: "v1.15.0-alpha-1.12345",
   184  			})
   185  			c := NewCounterVec(test.CounterOpts, test.labels)
   186  			registry.MustRegister(c)
   187  			c.WithLabelValues("1", "2").Inc()
   188  			mfs, err := registry.Gather()
   189  			assert.Equalf(t, test.expectedMetricFamilyCount, len(mfs), "Got %v metric families, Want: %v metric families", len(mfs), test.expectedMetricFamilyCount)
   190  			assert.Nil(t, err, "Gather failed %v", err)
   191  
   192  			// this no-opts here when there are no metric families (i.e. when the metric is hidden)
   193  			for _, mf := range mfs {
   194  				assert.Equalf(t, 1, len(mf.GetMetric()), "Got %v metrics, wanted 1 as the count", len(mf.GetMetric()))
   195  				assert.Equalf(t, test.expectedHelp, mf.GetHelp(), "Got %s as help message, want %s", mf.GetHelp(), test.expectedHelp)
   196  			}
   197  
   198  			// let's increment the counter and verify that the metric still works
   199  			c.WithLabelValues("1", "3").Inc()
   200  			c.WithLabelValues("2", "3").Inc()
   201  			mfs, err = registry.Gather()
   202  			assert.Nil(t, err, "Gather failed %v", err)
   203  
   204  			// this no-opts here when there are no metric families (i.e. when the metric is hidden)
   205  			for _, mf := range mfs {
   206  				assert.Equalf(t, 3, len(mf.GetMetric()), "Got %v metrics, wanted 3 as the count", len(mf.GetMetric()))
   207  			}
   208  		})
   209  	}
   210  }
   211  
   212  func TestCounterWithLabelValueAllowList(t *testing.T) {
   213  	labelAllowValues := map[string]string{
   214  		"namespace_subsystem_metric_allowlist_test,label_a": "allowed",
   215  	}
   216  	labels := []string{"label_a", "label_b"}
   217  	opts := &CounterOpts{
   218  		Namespace: "namespace",
   219  		Name:      "metric_allowlist_test",
   220  		Subsystem: "subsystem",
   221  	}
   222  	var tests = []struct {
   223  		desc               string
   224  		labelValues        [][]string
   225  		expectMetricValues map[string]int
   226  	}{
   227  		{
   228  			desc:        "Test no unexpected input",
   229  			labelValues: [][]string{{"allowed", "b1"}, {"allowed", "b2"}},
   230  			expectMetricValues: map[string]int{
   231  				"allowed b1": 1,
   232  				"allowed b2": 1,
   233  			},
   234  		},
   235  		{
   236  			desc:        "Test unexpected input",
   237  			labelValues: [][]string{{"allowed", "b1"}, {"not_allowed", "b1"}},
   238  			expectMetricValues: map[string]int{
   239  				"allowed b1":    1,
   240  				"unexpected b1": 1,
   241  			},
   242  		},
   243  	}
   244  
   245  	for _, test := range tests {
   246  		t.Run(test.desc, func(t *testing.T) {
   247  			SetLabelAllowListFromCLI(labelAllowValues)
   248  			registry := newKubeRegistry(apimachineryversion.Info{
   249  				Major:      "1",
   250  				Minor:      "15",
   251  				GitVersion: "v1.15.0-alpha-1.12345",
   252  			})
   253  			c := NewCounterVec(opts, labels)
   254  			registry.MustRegister(c)
   255  
   256  			for _, lv := range test.labelValues {
   257  				c.WithLabelValues(lv...).Inc()
   258  			}
   259  			mfs, err := registry.Gather()
   260  			assert.Nil(t, err, "Gather failed %v", err)
   261  
   262  			for _, mf := range mfs {
   263  				if *mf.Name != BuildFQName(opts.Namespace, opts.Subsystem, opts.Name) {
   264  					continue
   265  				}
   266  				mfMetric := mf.GetMetric()
   267  
   268  				for _, m := range mfMetric {
   269  					var aValue, bValue string
   270  					for _, l := range m.Label {
   271  						if *l.Name == "label_a" {
   272  							aValue = *l.Value
   273  						}
   274  						if *l.Name == "label_b" {
   275  							bValue = *l.Value
   276  						}
   277  					}
   278  					labelValuePair := aValue + " " + bValue
   279  					expectedValue, ok := test.expectMetricValues[labelValuePair]
   280  					assert.True(t, ok, "Got unexpected label values, lable_a is %v, label_b is %v", aValue, bValue)
   281  					actualValue := int(m.GetCounter().GetValue())
   282  					assert.Equalf(t, expectedValue, actualValue, "Got %v, wanted %v as the count while setting label_a to %v and label b to %v", actualValue, expectedValue, aValue, bValue)
   283  				}
   284  			}
   285  		})
   286  	}
   287  }
   288  

View as plain text