VictoriaMetrics/lib/promrelabel/config_test.go
2022-12-21 20:24:57 -08:00

580 lines
12 KiB
Go

package promrelabel
import (
"reflect"
"testing"
"gopkg.in/yaml.v2"
)
func TestMultiLineRegexUnmarshalMarshal(t *testing.T) {
f := func(data, resultExpected string) {
t.Helper()
var mlr MultiLineRegex
if err := yaml.UnmarshalStrict([]byte(data), &mlr); err != nil {
t.Fatalf("cannot unmarshal %q: %s", data, err)
}
result, err := yaml.Marshal(&mlr)
if err != nil {
t.Fatalf("cannot marshal %q: %s", data, err)
}
if string(result) != resultExpected {
t.Fatalf("unexpected marshaled data; got\n%q\nwant\n%q", result, resultExpected)
}
}
f(``, `""`+"\n")
f(`foo`, "foo\n")
f(`a|b||c`, "- a\n- b\n- \"\"\n- c\n")
f(`(a|b)`, "(a|b)\n")
f(`a|b[c|d]`, "a|b[c|d]\n")
f("- a\n- b", "- a\n- b\n")
f("- a\n- (b)", "a|(b)\n")
}
func TestRelabelConfigMarshalUnmarshal(t *testing.T) {
f := func(data, resultExpected string) {
t.Helper()
var rcs []RelabelConfig
if err := yaml.UnmarshalStrict([]byte(data), &rcs); err != nil {
t.Fatalf("cannot unmarshal %q: %s", data, err)
}
result, err := yaml.Marshal(&rcs)
if err != nil {
t.Fatalf("cannot marshal %q: %s", data, err)
}
if string(result) != resultExpected {
t.Fatalf("unexpected marshaled data; got\n%q\nwant\n%q", result, resultExpected)
}
}
f(``, "[]\n")
f(`
- action: keep
regex: foobar
`, "- action: keep\n regex: foobar\n")
f(`
- regex:
- 'fo.+'
- '.*ba[r-z]a'
`, "- regex: fo.+|.*ba[r-z]a\n")
f(`- regex: foo|bar`, "- regex:\n - foo\n - bar\n")
f(`- regex: True`, `- regex: "true"`+"\n")
f(`- regex: true`, `- regex: "true"`+"\n")
f(`- regex: 123`, `- regex: "123"`+"\n")
f(`- regex: 1.23`, `- regex: "1.23"`+"\n")
f(`- regex: [null]`, `- regex: "null"`+"\n")
f(`
- regex:
- -1.23
- False
- null
- nan
`, "- regex:\n - \"-1.23\"\n - \"false\"\n - \"null\"\n - nan\n")
f(`
- action: graphite
match: 'foo.*.*.aaa'
labels:
instance: '$1-abc'
job: '${2}'
`, "- action: graphite\n match: foo.*.*.aaa\n labels:\n instance: $1-abc\n job: ${2}\n")
}
func TestLoadRelabelConfigsSuccess(t *testing.T) {
path := "testdata/relabel_configs_valid.yml"
pcs, err := LoadRelabelConfigs(path)
if err != nil {
t.Fatalf("cannot load relabel configs from %q: %s", path, err)
}
nExpected := 18
if n := pcs.Len(); n != nExpected {
t.Fatalf("unexpected number of relabel configs loaded from %q; got %d; want %d", path, n, nExpected)
}
}
func TestLoadRelabelConfigsFailure(t *testing.T) {
f := func(path string) {
t.Helper()
rcs, err := LoadRelabelConfigs(path)
if err == nil {
t.Fatalf("expecting non-nil error")
}
if rcs.Len() != 0 {
t.Fatalf("unexpected non-empty rcs: %#v", rcs)
}
}
t.Run("non-existing-file", func(t *testing.T) {
f("testdata/non-exsiting-file")
})
t.Run("invalid-file", func(t *testing.T) {
f("testdata/invalid_config.yml")
})
}
func TestParsedConfigsString(t *testing.T) {
f := func(rcs []RelabelConfig, sExpected string) {
t.Helper()
pcs, err := ParseRelabelConfigs(rcs)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
s := pcs.String()
if s != sExpected {
t.Fatalf("unexpected string representation for ParsedConfigs;\ngot\n%s\nwant\n%s", s, sExpected)
}
}
f([]RelabelConfig{
{
TargetLabel: "foo",
SourceLabels: []string{"aaa"},
},
}, "- source_labels: [aaa]\n target_label: foo\n")
var ie IfExpression
if err := ie.Parse("{foo=~'bar'}"); err != nil {
t.Fatalf("unexpected error when parsing if expression: %s", err)
}
f([]RelabelConfig{
{
Action: "graphite",
Match: "foo.*.bar",
Labels: map[string]string{
"job": "$1-zz",
},
If: &ie,
},
}, "- if: '{foo=~''bar''}'\n action: graphite\n match: foo.*.bar\n labels:\n job: $1-zz\n")
replacement := "foo"
f([]RelabelConfig{
{
Action: "replace",
SourceLabels: []string{"foo", "bar"},
TargetLabel: "x",
If: &ie,
},
{
TargetLabel: "x",
Replacement: &replacement,
},
}, "- if: '{foo=~''bar''}'\n action: replace\n source_labels: [foo, bar]\n target_label: x\n- target_label: x\n replacement: foo\n")
}
func TestParseRelabelConfigsSuccess(t *testing.T) {
f := func(rcs []RelabelConfig, pcsExpected *ParsedConfigs) {
t.Helper()
pcs, err := ParseRelabelConfigs(rcs)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if pcs != nil {
for _, prc := range pcs.prcs {
prc.ruleOriginal = ""
prc.stringReplacer = nil
prc.submatchReplacer = nil
}
}
if !reflect.DeepEqual(pcs, pcsExpected) {
t.Fatalf("unexpected pcs; got\n%#v\nwant\n%#v", pcs, pcsExpected)
}
}
f(nil, nil)
f([]RelabelConfig{
{
SourceLabels: []string{"foo", "bar"},
TargetLabel: "xxx",
},
}, &ParsedConfigs{
prcs: []*parsedRelabelConfig{
{
SourceLabels: []string{"foo", "bar"},
Separator: ";",
TargetLabel: "xxx",
RegexAnchored: defaultRegexForRelabelConfig,
Replacement: "$1",
Action: "replace",
regex: defaultPromRegex,
regexOriginal: defaultOriginalRegexForRelabelConfig,
hasCaptureGroupInReplacement: true,
},
},
})
}
func TestParseRelabelConfigsFailure(t *testing.T) {
f := func(rcs []RelabelConfig) {
t.Helper()
pcs, err := ParseRelabelConfigs(rcs)
if err == nil {
t.Fatalf("expecting non-nil error")
}
if pcs.Len() > 0 {
t.Fatalf("unexpected non-empty pcs: %#v", pcs)
}
}
t.Run("invalid-regex", func(t *testing.T) {
f([]RelabelConfig{
{
SourceLabels: []string{"aaa"},
TargetLabel: "xxx",
Regex: &MultiLineRegex{
S: "foo[bar",
},
},
})
})
t.Run("replace-missing-target-label", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "replace",
SourceLabels: []string{"foo"},
},
})
})
t.Run("replace_all-missing-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "replace_all",
TargetLabel: "xxx",
},
})
})
t.Run("replace_all-missing-target-label", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "replace_all",
SourceLabels: []string{"foo"},
},
})
})
t.Run("keep-missing-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keep",
},
})
})
t.Run("keep_if_equal-missing-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keep_if_equal",
},
})
})
t.Run("keep_if_equal-single-source-label", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keep_if_equal",
SourceLabels: []string{"foo"},
},
})
})
t.Run("keep_if_equal-unused-target-label", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keep_if_equal",
SourceLabels: []string{"foo", "bar"},
TargetLabel: "foo",
},
})
})
t.Run("keep_if_equal-unused-regex", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keep_if_equal",
SourceLabels: []string{"foo", "bar"},
Regex: &MultiLineRegex{
S: "bar",
},
},
})
})
t.Run("drop_if_equal-missing-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "drop_if_equal",
},
})
})
t.Run("drop_if_equal-single-source-label", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "drop_if_equal",
SourceLabels: []string{"foo"},
},
})
})
t.Run("drop_if_equal-unused-target-label", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "drop_if_equal",
SourceLabels: []string{"foo", "bar"},
TargetLabel: "foo",
},
})
})
t.Run("drop_if_equal-unused-regex", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "drop_if_equal",
SourceLabels: []string{"foo", "bar"},
Regex: &MultiLineRegex{
S: "bar",
},
},
})
})
t.Run("keepequal-missing-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keepequal",
},
})
})
t.Run("keepequal-missing-target-label", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keepequal",
SourceLabels: []string{"foo"},
},
})
})
t.Run("keepequal-unused-regex", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keepequal",
SourceLabels: []string{"foo"},
TargetLabel: "foo",
Regex: &MultiLineRegex{
S: "bar",
},
},
})
})
t.Run("dropequal-missing-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "dropequal",
},
})
})
t.Run("dropequal-missing-target-label", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "dropequal",
SourceLabels: []string{"foo"},
},
})
})
t.Run("dropequal-unused-regex", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "dropequal",
SourceLabels: []string{"foo"},
TargetLabel: "foo",
Regex: &MultiLineRegex{
S: "bar",
},
},
})
})
t.Run("drop-missing-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "drop",
},
})
})
t.Run("hashmod-missing-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "hashmod",
TargetLabel: "aaa",
Modulus: 123,
},
})
})
t.Run("hashmod-missing-target-label", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "hashmod",
SourceLabels: []string{"aaa"},
Modulus: 123,
},
})
})
t.Run("hashmod-missing-modulus", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "hashmod",
SourceLabels: []string{"aaa"},
TargetLabel: "xxx",
},
})
})
t.Run("invalid-action", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "invalid-action",
},
})
})
t.Run("drop_metrics-missing-regex", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "drop_metrics",
},
})
})
t.Run("drop_metrics-non-empty-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "drop_metrics",
SourceLabels: []string{"foo"},
Regex: &MultiLineRegex{
S: "bar",
},
},
})
})
t.Run("keep_metrics-missing-regex", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keep_metrics",
},
})
})
t.Run("keep_metrics-non-empty-source-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "keep_metrics",
SourceLabels: []string{"foo"},
Regex: &MultiLineRegex{
S: "bar",
},
},
})
})
t.Run("uppercase-missing-sourceLabels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "uppercase",
TargetLabel: "foobar",
},
})
})
t.Run("lowercase-missing-targetLabel", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "lowercase",
SourceLabels: []string{"foobar"},
},
})
})
t.Run("graphite-missing-match", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "graphite",
Labels: map[string]string{
"foo": "bar",
},
},
})
})
t.Run("graphite-missing-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "graphite",
Match: "foo.*.bar",
},
})
})
t.Run("graphite-superflouous-sourceLabels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "graphite",
Match: "foo.*.bar",
Labels: map[string]string{
"foo": "bar",
},
SourceLabels: []string{"foo"},
},
})
})
t.Run("graphite-superflouous-targetLabel", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "graphite",
Match: "foo.*.bar",
Labels: map[string]string{
"foo": "bar",
},
TargetLabel: "foo",
},
})
})
replacement := "foo"
t.Run("graphite-superflouous-replacement", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "graphite",
Match: "foo.*.bar",
Labels: map[string]string{
"foo": "bar",
},
Replacement: &replacement,
},
})
})
var re MultiLineRegex
t.Run("graphite-superflouous-regex", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "graphite",
Match: "foo.*.bar",
Labels: map[string]string{
"foo": "bar",
},
Regex: &re,
},
})
})
t.Run("non-graphite-superflouos-match", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "uppercase",
SourceLabels: []string{"foo"},
TargetLabel: "foo",
Match: "aaa",
},
})
})
t.Run("non-graphite-superflouos-labels", func(t *testing.T) {
f([]RelabelConfig{
{
Action: "uppercase",
SourceLabels: []string{"foo"},
TargetLabel: "foo",
Labels: map[string]string{
"foo": "Bar",
},
},
})
})
}
func TestIsDefaultRegex(t *testing.T) {
f := func(s string, resultExpected bool) {
t.Helper()
result := isDefaultRegex(s)
if result != resultExpected {
t.Fatalf("unexpected result for isDefaultRegex(%q); got %v; want %v", s, result, resultExpected)
}
}
f("", false)
f("foo", false)
f(".+", false)
f("a.*", false)
f(".*", true)
f("(.*)", true)
f("^.*$", true)
f("(?:.*)", true)
}