1/*
2Copyright 2019 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package metrics
18
19import (
20	"bytes"
21	"testing"
22
23	"github.com/blang/semver"
24	"github.com/prometheus/common/expfmt"
25	"github.com/stretchr/testify/assert"
26
27	apimachineryversion "k8s.io/apimachinery/pkg/version"
28)
29
30func 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
116func 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