...

Source file src/k8s.io/component-base/metrics/histogram_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  	"testing"
    21  
    22  	"github.com/blang/semver/v4"
    23  	"github.com/prometheus/client_golang/prometheus"
    24  	"github.com/stretchr/testify/assert"
    25  
    26  	apimachineryversion "k8s.io/apimachinery/pkg/version"
    27  )
    28  
    29  func TestHistogram(t *testing.T) {
    30  	v115 := semver.MustParse("1.15.0")
    31  	var tests = []struct {
    32  		desc string
    33  		*HistogramOpts
    34  		registryVersion     *semver.Version
    35  		expectedMetricCount int
    36  		expectedHelp        string
    37  	}{
    38  		{
    39  			desc: "Test non deprecated",
    40  			HistogramOpts: &HistogramOpts{
    41  				Namespace: "namespace",
    42  				Name:      "metric_test_name",
    43  				Subsystem: "subsystem",
    44  				Help:      "histogram help message",
    45  				Buckets:   prometheus.DefBuckets,
    46  			},
    47  			registryVersion:     &v115,
    48  			expectedMetricCount: 1,
    49  			expectedHelp:        "[ALPHA] histogram help message",
    50  		},
    51  		{
    52  			desc: "Test deprecated",
    53  			HistogramOpts: &HistogramOpts{
    54  				Namespace:         "namespace",
    55  				Name:              "metric_test_name",
    56  				Subsystem:         "subsystem",
    57  				Help:              "histogram help message",
    58  				DeprecatedVersion: "1.15.0",
    59  				Buckets:           prometheus.DefBuckets,
    60  			},
    61  			registryVersion:     &v115,
    62  			expectedMetricCount: 1,
    63  			expectedHelp:        "[ALPHA] (Deprecated since 1.15.0) histogram help message",
    64  		},
    65  		{
    66  			desc: "Test hidden",
    67  			HistogramOpts: &HistogramOpts{
    68  				Namespace:         "namespace",
    69  				Name:              "metric_test_name",
    70  				Subsystem:         "subsystem",
    71  				Help:              "histogram help message",
    72  				DeprecatedVersion: "1.14.0",
    73  				Buckets:           prometheus.DefBuckets,
    74  			},
    75  			registryVersion:     &v115,
    76  			expectedMetricCount: 0,
    77  			expectedHelp:        "histogram help message",
    78  		},
    79  	}
    80  
    81  	for _, test := range tests {
    82  		t.Run(test.desc, func(t *testing.T) {
    83  			registry := newKubeRegistry(apimachineryversion.Info{
    84  				Major:      "1",
    85  				Minor:      "15",
    86  				GitVersion: "v1.15.0-alpha-1.12345",
    87  			})
    88  			c := NewHistogram(test.HistogramOpts)
    89  			registry.MustRegister(c)
    90  			cm := c.ObserverMetric.(prometheus.Metric)
    91  
    92  			metricChan := make(chan prometheus.Metric, 2)
    93  			c.Collect(metricChan)
    94  			close(metricChan)
    95  			m1 := <-metricChan
    96  			if m1 != cm {
    97  				t.Error("Unexpected metric", m1, cm)
    98  			}
    99  			m2, ok := <-metricChan
   100  			if ok {
   101  				t.Error("Unexpected second metric", m2)
   102  			}
   103  
   104  			ms, err := registry.Gather()
   105  			assert.Equalf(t, test.expectedMetricCount, len(ms), "Got %v metrics, Want: %v metrics", len(ms), test.expectedMetricCount)
   106  			assert.Nil(t, err, "Gather failed %v", err)
   107  
   108  			for _, metric := range ms {
   109  				assert.Equalf(t, test.expectedHelp, metric.GetHelp(), "Got %s as help message, want %s", metric.GetHelp(), test.expectedHelp)
   110  			}
   111  
   112  			// let's increment the counter and verify that the metric still works
   113  			c.Observe(1)
   114  			c.Observe(2)
   115  			c.Observe(3)
   116  			c.Observe(1.5)
   117  			expected := 4
   118  			ms, err = registry.Gather()
   119  			assert.Nil(t, err, "Gather failed %v", err)
   120  
   121  			for _, mf := range ms {
   122  				for _, m := range mf.GetMetric() {
   123  					assert.Equalf(t, expected, int(m.GetHistogram().GetSampleCount()), "Got %v, want %v as the sample count", m.GetHistogram().GetSampleCount(), expected)
   124  				}
   125  			}
   126  		})
   127  	}
   128  }
   129  
   130  func TestHistogramVec(t *testing.T) {
   131  	v115 := semver.MustParse("1.15.0")
   132  	var tests = []struct {
   133  		desc string
   134  		*HistogramOpts
   135  		labels              []string
   136  		registryVersion     *semver.Version
   137  		expectedMetricCount int
   138  		expectedHelp        string
   139  	}{
   140  		{
   141  			desc: "Test non deprecated",
   142  			HistogramOpts: &HistogramOpts{
   143  				Namespace: "namespace",
   144  				Name:      "metric_test_name",
   145  				Subsystem: "subsystem",
   146  				Help:      "histogram help message",
   147  				Buckets:   prometheus.DefBuckets,
   148  			},
   149  			labels:              []string{"label_a", "label_b"},
   150  			registryVersion:     &v115,
   151  			expectedMetricCount: 1,
   152  			expectedHelp:        "[ALPHA] histogram help message",
   153  		},
   154  		{
   155  			desc: "Test deprecated",
   156  			HistogramOpts: &HistogramOpts{
   157  				Namespace:         "namespace",
   158  				Name:              "metric_test_name",
   159  				Subsystem:         "subsystem",
   160  				Help:              "histogram help message",
   161  				DeprecatedVersion: "1.15.0",
   162  				Buckets:           prometheus.DefBuckets,
   163  			},
   164  			labels:              []string{"label_a", "label_b"},
   165  			registryVersion:     &v115,
   166  			expectedMetricCount: 1,
   167  			expectedHelp:        "[ALPHA] (Deprecated since 1.15.0) histogram help message",
   168  		},
   169  		{
   170  			desc: "Test hidden",
   171  			HistogramOpts: &HistogramOpts{
   172  				Namespace:         "namespace",
   173  				Name:              "metric_test_name",
   174  				Subsystem:         "subsystem",
   175  				Help:              "histogram help message",
   176  				DeprecatedVersion: "1.14.0",
   177  				Buckets:           prometheus.DefBuckets,
   178  			},
   179  			labels:              []string{"label_a", "label_b"},
   180  			registryVersion:     &v115,
   181  			expectedMetricCount: 0,
   182  			expectedHelp:        "histogram help message",
   183  		},
   184  	}
   185  
   186  	for _, test := range tests {
   187  		t.Run(test.desc, func(t *testing.T) {
   188  			registry := newKubeRegistry(apimachineryversion.Info{
   189  				Major:      "1",
   190  				Minor:      "15",
   191  				GitVersion: "v1.15.0-alpha-1.12345",
   192  			})
   193  			c := NewHistogramVec(test.HistogramOpts, test.labels)
   194  			registry.MustRegister(c)
   195  			ov12 := c.WithLabelValues("1", "2")
   196  			cm1 := ov12.(prometheus.Metric)
   197  			ov12.Observe(1.0)
   198  
   199  			if test.expectedMetricCount > 0 {
   200  				metricChan := make(chan prometheus.Metric, 2)
   201  				c.Collect(metricChan)
   202  				close(metricChan)
   203  				m1 := <-metricChan
   204  				if m1 != cm1 {
   205  					t.Error("Unexpected metric", m1, cm1)
   206  				}
   207  				m2, ok := <-metricChan
   208  				if ok {
   209  					t.Error("Unexpected second metric", m2)
   210  				}
   211  			}
   212  
   213  			ms, err := registry.Gather()
   214  			assert.Equalf(t, test.expectedMetricCount, len(ms), "Got %v metrics, Want: %v metrics", len(ms), test.expectedMetricCount)
   215  			assert.Nil(t, err, "Gather failed %v", err)
   216  			for _, metric := range ms {
   217  				if metric.GetHelp() != test.expectedHelp {
   218  					assert.Equalf(t, test.expectedHelp, metric.GetHelp(), "Got %s as help message, want %s", metric.GetHelp(), test.expectedHelp)
   219  				}
   220  			}
   221  
   222  			// let's increment the counter and verify that the metric still works
   223  			c.WithLabelValues("1", "3").Observe(1.0)
   224  			c.WithLabelValues("2", "3").Observe(1.0)
   225  			ms, err = registry.Gather()
   226  			assert.Nil(t, err, "Gather failed %v", err)
   227  
   228  			for _, mf := range ms {
   229  				assert.Equalf(t, 3, len(mf.GetMetric()), "Got %v metrics, wanted 3 as the count", len(mf.GetMetric()))
   230  				for _, m := range mf.GetMetric() {
   231  					assert.Equalf(t, uint64(1), m.GetHistogram().GetSampleCount(), "Got %v metrics, expected histogram sample count to equal 1", m.GetHistogram().GetSampleCount())
   232  				}
   233  			}
   234  		})
   235  	}
   236  }
   237  
   238  func TestHistogramWithLabelValueAllowList(t *testing.T) {
   239  	labelAllowValues := map[string]string{
   240  		"namespace_subsystem_metric_allowlist_test,label_a": "allowed",
   241  	}
   242  	labels := []string{"label_a", "label_b"}
   243  	opts := &HistogramOpts{
   244  		Namespace: "namespace",
   245  		Name:      "metric_allowlist_test",
   246  		Subsystem: "subsystem",
   247  	}
   248  	var tests = []struct {
   249  		desc               string
   250  		labelValues        [][]string
   251  		expectMetricValues map[string]uint64
   252  	}{
   253  		{
   254  			desc:        "Test no unexpected input",
   255  			labelValues: [][]string{{"allowed", "b1"}, {"allowed", "b2"}},
   256  			expectMetricValues: map[string]uint64{
   257  				"allowed b1": 1.0,
   258  				"allowed b2": 1.0,
   259  			},
   260  		},
   261  		{
   262  			desc:        "Test unexpected input",
   263  			labelValues: [][]string{{"allowed", "b1"}, {"not_allowed", "b1"}},
   264  			expectMetricValues: map[string]uint64{
   265  				"allowed b1":    1.0,
   266  				"unexpected b1": 1.0,
   267  			},
   268  		},
   269  	}
   270  
   271  	for _, test := range tests {
   272  		t.Run(test.desc, func(t *testing.T) {
   273  			SetLabelAllowListFromCLI(labelAllowValues)
   274  			registry := newKubeRegistry(apimachineryversion.Info{
   275  				Major:      "1",
   276  				Minor:      "15",
   277  				GitVersion: "v1.15.0-alpha-1.12345",
   278  			})
   279  			c := NewHistogramVec(opts, labels)
   280  			registry.MustRegister(c)
   281  
   282  			for _, lv := range test.labelValues {
   283  				c.WithLabelValues(lv...).Observe(1.0)
   284  			}
   285  			mfs, err := registry.Gather()
   286  			assert.Nil(t, err, "Gather failed %v", err)
   287  
   288  			for _, mf := range mfs {
   289  				if *mf.Name != BuildFQName(opts.Namespace, opts.Subsystem, opts.Name) {
   290  					continue
   291  				}
   292  				mfMetric := mf.GetMetric()
   293  
   294  				for _, m := range mfMetric {
   295  					var aValue, bValue string
   296  					for _, l := range m.Label {
   297  						if *l.Name == "label_a" {
   298  							aValue = *l.Value
   299  						}
   300  						if *l.Name == "label_b" {
   301  							bValue = *l.Value
   302  						}
   303  					}
   304  					labelValuePair := aValue + " " + bValue
   305  					expectedValue, ok := test.expectMetricValues[labelValuePair]
   306  					assert.True(t, ok, "Got unexpected label values, lable_a is %v, label_b is %v", aValue, bValue)
   307  					actualValue := m.GetHistogram().GetSampleCount()
   308  					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)
   309  				}
   310  			}
   311  		})
   312  	}
   313  }
   314  

View as plain text