Skip to content

Commit 528c4ad

Browse files
committed
fix validate_test
Signed-off-by: 7h3-3mp7y-m4n <[email protected]>
1 parent 30ac251 commit 528c4ad

File tree

3 files changed

+138
-1
lines changed

3 files changed

+138
-1
lines changed

pkg/util/validation/limits.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ type Limits struct {
151151
MetricRelabelConfigs []*relabel.Config `yaml:"metric_relabel_configs,omitempty" json:"metric_relabel_configs,omitempty" doc:"nocli|description=List of metric relabel configurations. Note that in most situations, it is more effective to use metrics relabeling directly in the Prometheus server, e.g. remote_write.write_relabel_configs."`
152152
MaxNativeHistogramBuckets int `yaml:"max_native_histogram_buckets" json:"max_native_histogram_buckets"`
153153
PromoteResourceAttributes []string `yaml:"promote_resource_attributes" json:"promote_resource_attributes"`
154-
154+
UseUTF8Validation bool `yaml:"use_utf8_validation" json:"use_utf8_validation"`
155155
// Ingester enforced limits.
156156
// Series
157157
MaxLocalSeriesPerUser int `yaml:"max_series_per_user" json:"max_series_per_user"`

pkg/util/validation/validate.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,12 @@ func ValidateExemplar(validateMetrics *ValidateMetrics, userID string, ls []cort
250250
// ValidateLabels returns an err if the labels are invalid.
251251
// The returned error may retain the provided series labels.
252252
func ValidateLabels(validateMetrics *ValidateMetrics, limits *Limits, userID string, ls []cortexpb.LabelAdapter, skipLabelNameValidation bool) ValidationError {
253+
//nolint:staticcheck // SA1019: using deprecated NameValidationScheme intentionally as a temporary compatibility workaround for UTF-8 migration issues
254+
if limits.UseUTF8Validation {
255+
model.NameValidationScheme = model.UTF8Validation
256+
} else {
257+
model.NameValidationScheme = model.LegacyValidation
258+
}
253259
if limits.EnforceMetricName {
254260
unsafeMetricName, err := extract.UnsafeMetricNameFromLabelAdapters(ls)
255261
if err != nil {

pkg/util/validation/validate_test.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,137 @@ func TestValidateLabels(t *testing.T) {
151151
`), "cortex_discarded_samples_total"))
152152
}
153153

154+
// same test
155+
func TestValidateLabels_Legacy(t *testing.T) {
156+
cfg := new(Limits)
157+
userID := "testUser"
158+
159+
reg := prometheus.NewRegistry()
160+
validateMetrics := NewValidateMetrics(reg)
161+
162+
cfg.MaxLabelValueLength = 25
163+
cfg.MaxLabelNameLength = 25
164+
cfg.MaxLabelNamesPerSeries = 2
165+
cfg.MaxLabelsSizeBytes = 90
166+
cfg.EnforceMetricName = true
167+
cfg.UseUTF8Validation = false // Legacy validation
168+
cfg.LimitsPerLabelSet = []LimitsPerLabelSet{
169+
{
170+
Limits: LimitsPerLabelSetEntry{MaxSeries: 0},
171+
LabelSet: labels.FromMap(map[string]string{
172+
model.MetricNameLabel: "foo",
173+
}),
174+
Hash: 0,
175+
},
176+
{
177+
Limits: LimitsPerLabelSetEntry{MaxSeries: 0},
178+
LabelSet: labels.EmptyLabels(),
179+
Hash: 1,
180+
},
181+
}
182+
183+
for i, c := range []struct {
184+
metric model.Metric
185+
skipLabelNameValidation bool
186+
expectedErr error
187+
}{
188+
{map[model.LabelName]model.LabelValue{}, false, newNoMetricNameError()},
189+
{map[model.LabelName]model.LabelValue{model.MetricNameLabel: " "}, false, newInvalidMetricNameError(" ")},
190+
{map[model.LabelName]model.LabelValue{model.MetricNameLabel: "valid", "foo ": "bar"}, false,
191+
newInvalidLabelError([]cortexpb.LabelAdapter{
192+
{Name: model.MetricNameLabel, Value: "valid"},
193+
{Name: "foo ", Value: "bar"},
194+
}, "foo ")},
195+
{map[model.LabelName]model.LabelValue{model.MetricNameLabel: "valid"}, false, nil},
196+
{
197+
map[model.LabelName]model.LabelValue{model.MetricNameLabel: "badLabelName", "this_is_a_really_really_long_name_that_should_cause_an_error": "test_value_please_ignore"},
198+
false,
199+
newLabelNameTooLongError([]cortexpb.LabelAdapter{
200+
{Name: model.MetricNameLabel, Value: "badLabelName"},
201+
{Name: "this_is_a_really_really_long_name_that_should_cause_an_error", Value: "test_value_please_ignore"},
202+
}, "this_is_a_really_really_long_name_that_should_cause_an_error", cfg.MaxLabelNameLength),
203+
},
204+
{
205+
map[model.LabelName]model.LabelValue{model.MetricNameLabel: "badLabelValue", "much_shorter_name": "test_value_please_ignore_no_really_nothing_to_see_here"},
206+
false,
207+
newLabelValueTooLongError([]cortexpb.LabelAdapter{
208+
{Name: model.MetricNameLabel, Value: "badLabelValue"},
209+
{Name: "much_shorter_name", Value: "test_value_please_ignore_no_really_nothing_to_see_here"},
210+
}, "much_shorter_name", "test_value_please_ignore_no_really_nothing_to_see_here", cfg.MaxLabelValueLength),
211+
},
212+
{
213+
map[model.LabelName]model.LabelValue{model.MetricNameLabel: "foo", "bar": "baz", "blip": "blop"},
214+
false,
215+
newTooManyLabelsError([]cortexpb.LabelAdapter{
216+
{Name: model.MetricNameLabel, Value: "foo"},
217+
{Name: "bar", Value: "baz"},
218+
{Name: "blip", Value: "blop"},
219+
}, 2),
220+
},
221+
{
222+
map[model.LabelName]model.LabelValue{model.MetricNameLabel: "exactly_twenty_five_chars", "exactly_twenty_five_chars": "exactly_twenty_five_chars"},
223+
false,
224+
labelSizeBytesExceededError([]cortexpb.LabelAdapter{
225+
{Name: model.MetricNameLabel, Value: "exactly_twenty_five_chars"},
226+
{Name: "exactly_twenty_five_chars", Value: "exactly_twenty_five_chars"},
227+
}, 91, cfg.MaxLabelsSizeBytes),
228+
},
229+
{map[model.LabelName]model.LabelValue{model.MetricNameLabel: "foo", "invalid%label&name": "bar"}, true, nil},
230+
} {
231+
convertedLabels := cortexpb.FromMetricsToLabelAdapters(c.metric)
232+
233+
t.Logf("Case %d:\n Input Metric: %+v\n SkipLabelNameValidation: %v", i, c.metric, c.skipLabelNameValidation)
234+
235+
err := ValidateLabels(validateMetrics, cfg, userID, convertedLabels, c.skipLabelNameValidation)
236+
237+
if err != nil {
238+
t.Logf(" Got Error: %v", err)
239+
} else {
240+
t.Log(" Got Error: <nil>")
241+
}
242+
243+
if c.expectedErr != nil {
244+
t.Logf(" Expected Error: %v", c.expectedErr)
245+
} else {
246+
t.Log(" Expected Error: <nil>")
247+
}
248+
249+
assert.Equal(t, c.expectedErr, err, "wrong error (case %d)", i)
250+
}
251+
252+
// Metrics validation
253+
validateMetrics.DiscardedSamples.WithLabelValues("random reason", "different user").Inc()
254+
255+
require.NoError(t, testutil.GatherAndCompare(reg, strings.NewReader(`
256+
# HELP cortex_discarded_samples_total The total number of samples that were discarded.
257+
# TYPE cortex_discarded_samples_total counter
258+
cortex_discarded_samples_total{reason="label_invalid",user="testUser"} 1
259+
cortex_discarded_samples_total{reason="label_name_too_long",user="testUser"} 1
260+
cortex_discarded_samples_total{reason="label_value_too_long",user="testUser"} 1
261+
cortex_discarded_samples_total{reason="max_label_names_per_series",user="testUser"} 1
262+
cortex_discarded_samples_total{reason="metric_name_invalid",user="testUser"} 1
263+
cortex_discarded_samples_total{reason="missing_metric_name",user="testUser"} 1
264+
cortex_discarded_samples_total{reason="labels_size_bytes_exceeded",user="testUser"} 1
265+
cortex_discarded_samples_total{reason="random reason",user="different user"} 1
266+
`), "cortex_discarded_samples_total"))
267+
268+
require.NoError(t, testutil.GatherAndCompare(reg, strings.NewReader(`
269+
# HELP cortex_label_size_bytes The combined size in bytes of all labels and label values for a time series.
270+
# TYPE cortex_label_size_bytes histogram
271+
cortex_label_size_bytes_bucket{user="testUser",le="+Inf"} 3
272+
cortex_label_size_bytes_sum{user="testUser"} 148
273+
cortex_label_size_bytes_count{user="testUser"} 3
274+
`), "cortex_label_size_bytes"))
275+
276+
DeletePerUserValidationMetrics(validateMetrics, userID, util_log.Logger)
277+
278+
require.NoError(t, testutil.GatherAndCompare(reg, strings.NewReader(`
279+
# HELP cortex_discarded_samples_total The total number of samples that were discarded.
280+
# TYPE cortex_discarded_samples_total counter
281+
cortex_discarded_samples_total{reason="random reason",user="different user"} 1
282+
`), "cortex_discarded_samples_total"))
283+
}
284+
154285
func TestValidateExemplars(t *testing.T) {
155286
userID := "testUser"
156287
reg := prometheus.NewRegistry()

0 commit comments

Comments
 (0)