1// Copyright 2013 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package model
15
16import "testing"
17
18func testMetric(t testing.TB) {
19	var scenarios = []struct {
20		input           LabelSet
21		fingerprint     Fingerprint
22		fastFingerprint Fingerprint
23	}{
24		{
25			input:           LabelSet{},
26			fingerprint:     14695981039346656037,
27			fastFingerprint: 14695981039346656037,
28		},
29		{
30			input: LabelSet{
31				"first_name":   "electro",
32				"occupation":   "robot",
33				"manufacturer": "westinghouse",
34			},
35			fingerprint:     5911716720268894962,
36			fastFingerprint: 11310079640881077873,
37		},
38		{
39			input: LabelSet{
40				"x": "y",
41			},
42			fingerprint:     8241431561484471700,
43			fastFingerprint: 13948396922932177635,
44		},
45		{
46			input: LabelSet{
47				"a": "bb",
48				"b": "c",
49			},
50			fingerprint:     3016285359649981711,
51			fastFingerprint: 3198632812309449502,
52		},
53		{
54			input: LabelSet{
55				"a":  "b",
56				"bb": "c",
57			},
58			fingerprint:     7122421792099404749,
59			fastFingerprint: 5774953389407657638,
60		},
61	}
62
63	for i, scenario := range scenarios {
64		input := Metric(scenario.input)
65
66		if scenario.fingerprint != input.Fingerprint() {
67			t.Errorf("%d. expected %d, got %d", i, scenario.fingerprint, input.Fingerprint())
68		}
69		if scenario.fastFingerprint != input.FastFingerprint() {
70			t.Errorf("%d. expected %d, got %d", i, scenario.fastFingerprint, input.FastFingerprint())
71		}
72	}
73}
74
75func TestMetric(t *testing.T) {
76	testMetric(t)
77}
78
79func BenchmarkMetric(b *testing.B) {
80	for i := 0; i < b.N; i++ {
81		testMetric(b)
82	}
83}
84
85func TestMetricNameIsValid(t *testing.T) {
86	var scenarios = []struct {
87		mn    LabelValue
88		valid bool
89	}{
90		{
91			mn:    "Avalid_23name",
92			valid: true,
93		},
94		{
95			mn:    "_Avalid_23name",
96			valid: true,
97		},
98		{
99			mn:    "1valid_23name",
100			valid: false,
101		},
102		{
103			mn:    "avalid_23name",
104			valid: true,
105		},
106		{
107			mn:    "Ava:lid_23name",
108			valid: true,
109		},
110		{
111			mn:    "a lid_23name",
112			valid: false,
113		},
114		{
115			mn:    ":leading_colon",
116			valid: true,
117		},
118		{
119			mn:    "colon:in:the:middle",
120			valid: true,
121		},
122		{
123			mn:    "",
124			valid: false,
125		},
126	}
127
128	for _, s := range scenarios {
129		if IsValidMetricName(s.mn) != s.valid {
130			t.Errorf("Expected %v for %q using IsValidMetricName function", s.valid, s.mn)
131		}
132		if MetricNameRE.MatchString(string(s.mn)) != s.valid {
133			t.Errorf("Expected %v for %q using regexp matching", s.valid, s.mn)
134		}
135	}
136}
137
138func TestMetricClone(t *testing.T) {
139	m := Metric{
140		"first_name":   "electro",
141		"occupation":   "robot",
142		"manufacturer": "westinghouse",
143	}
144
145	m2 := m.Clone()
146
147	if len(m) != len(m2) {
148		t.Errorf("expected the length of the cloned metric to be equal to the input metric")
149	}
150
151	for ln, lv := range m2 {
152		expected := m[ln]
153		if expected != lv {
154			t.Errorf("expected label value %s but got %s for label name %s", expected, lv, ln)
155		}
156	}
157}
158
159func TestMetricToString(t *testing.T) {
160	scenarios := []struct {
161		name     string
162		input    Metric
163		expected string
164	}{
165		{
166			name: "valid metric without __name__ label",
167			input: Metric{
168				"first_name":   "electro",
169				"occupation":   "robot",
170				"manufacturer": "westinghouse",
171			},
172			expected: `{first_name="electro", manufacturer="westinghouse", occupation="robot"}`,
173		},
174		{
175			name: "valid metric with __name__ label",
176			input: Metric{
177				"__name__":     "electro",
178				"occupation":   "robot",
179				"manufacturer": "westinghouse",
180			},
181			expected: `electro{manufacturer="westinghouse", occupation="robot"}`,
182		},
183		{
184			name: "empty metric with __name__ label",
185			input: Metric{
186				"__name__": "fooname",
187			},
188			expected: "fooname",
189		},
190		{
191			name:     "empty metric",
192			input:    Metric{},
193			expected: "{}",
194		},
195	}
196
197	for _, scenario := range scenarios {
198		t.Run(scenario.name, func(t *testing.T) {
199			actual := scenario.input.String()
200			if actual != scenario.expected {
201				t.Errorf("expected string output %s but got %s", actual, scenario.expected)
202			}
203		})
204	}
205}
206