func TestHandlerRelabel(t *testing.T) {
	h := New(&Options{
		QueueCapacity: 3 * maxBatchSize,
		RelabelConfigs: []*config.RelabelConfig{
			{
				SourceLabels: model.LabelNames{"alertname"},
				Action:       "drop",
				Regex:        config.MustNewRegexp("drop"),
			},
			{
				SourceLabels: model.LabelNames{"alertname"},
				TargetLabel:  "alertname",
				Action:       "replace",
				Regex:        config.MustNewRegexp("rename"),
				Replacement:  "renamed",
			},
		},
	})

	// This alert should be dropped due to the configuration
	h.Send(&model.Alert{
		Labels: model.LabelSet{
			"alertname": "drop",
		},
	})

	// This alert should be replaced due to the configuration
	h.Send(&model.Alert{
		Labels: model.LabelSet{
			"alertname": "rename",
		},
	})

	expected := []*model.Alert{
		{
			Labels: model.LabelSet{
				"alertname": "renamed",
			},
		},
	}

	if !alertsEqual(expected, h.queue) {
		t.Errorf("Expected alerts %v, got %v", expected, h.queue)
	}
}
func TestExternalLabels(t *testing.T) {
	h := New(&Options{
		QueueCapacity:  3 * maxBatchSize,
		ExternalLabels: model.LabelSet{"a": "b"},
		RelabelConfigs: []*config.RelabelConfig{
			{
				SourceLabels: model.LabelNames{"alertname"},
				TargetLabel:  "a",
				Action:       "replace",
				Regex:        config.MustNewRegexp("externalrelabelthis"),
				Replacement:  "c",
			},
		},
	})

	// This alert should get the external label attached.
	h.Send(&model.Alert{
		Labels: model.LabelSet{
			"alertname": "test",
		},
	})

	// This alert should get the external label attached, but then set to "c"
	// through relabelling.
	h.Send(&model.Alert{
		Labels: model.LabelSet{
			"alertname": "externalrelabelthis",
		},
	})

	expected := []*model.Alert{
		{
			Labels: model.LabelSet{
				"alertname": "test",
				"a":         "b",
			},
		},
		{
			Labels: model.LabelSet{
				"alertname": "externalrelabelthis",
				"a":         "c",
			},
		},
	}

	if !alertsEqual(expected, h.queue) {
		t.Errorf("Expected alerts %v, got %v", expected, h.queue)
	}
}
func TestTargetManagerConfigUpdate(t *testing.T) {
	testJob1 := &config.ScrapeConfig{
		JobName:        "test_job1",
		ScrapeInterval: config.Duration(1 * time.Minute),
		Params: url.Values{
			"testParam": []string{"paramValue", "secondValue"},
		},
		TargetGroups: []*config.TargetGroup{{
			Targets: []model.LabelSet{
				{model.AddressLabel: "example.org:80"},
				{model.AddressLabel: "example.com:80"},
			},
		}},
		RelabelConfigs: []*config.RelabelConfig{
			{
				// Copy out the URL parameter.
				SourceLabels: model.LabelNames{"__param_testParam"},
				Regex:        config.MustNewRegexp("(.*)"),
				TargetLabel:  "testParam",
				Replacement:  "$1",
				Action:       config.RelabelReplace,
			},
		},
	}
	testJob2 := &config.ScrapeConfig{
		JobName:        "test_job2",
		ScrapeInterval: config.Duration(1 * time.Minute),
		TargetGroups: []*config.TargetGroup{
			{
				Targets: []model.LabelSet{
					{model.AddressLabel: "example.org:8080"},
					{model.AddressLabel: "example.com:8081"},
				},
				Labels: model.LabelSet{
					"foo":  "bar",
					"boom": "box",
				},
			},
			{
				Targets: []model.LabelSet{
					{model.AddressLabel: "test.com:1234"},
				},
			},
			{
				Targets: []model.LabelSet{
					{model.AddressLabel: "test.com:1235"},
				},
				Labels: model.LabelSet{"instance": "fixed"},
			},
		},
		RelabelConfigs: []*config.RelabelConfig{
			{
				SourceLabels: model.LabelNames{model.AddressLabel},
				Regex:        config.MustNewRegexp(`test\.(.*?):(.*)`),
				Replacement:  "foo.${1}:${2}",
				TargetLabel:  model.AddressLabel,
				Action:       config.RelabelReplace,
			},
			{
				// Add a new label for example.* targets.
				SourceLabels: model.LabelNames{model.AddressLabel, "boom", "foo"},
				Regex:        config.MustNewRegexp("example.*?-b([a-z-]+)r"),
				TargetLabel:  "new",
				Replacement:  "$1",
				Separator:    "-",
				Action:       config.RelabelReplace,
			},
			{
				// Drop an existing label.
				SourceLabels: model.LabelNames{"boom"},
				Regex:        config.MustNewRegexp(".*"),
				TargetLabel:  "boom",
				Replacement:  "",
				Action:       config.RelabelReplace,
			},
		},
	}

	sequence := []struct {
		scrapeConfigs []*config.ScrapeConfig
		expected      map[string][]model.LabelSet
	}{
		{
			scrapeConfigs: []*config.ScrapeConfig{testJob1},
			expected: map[string][]model.LabelSet{
				"test_job1:static:0:0": {
					{model.JobLabel: "test_job1", model.InstanceLabel: "example.org:80", "testParam": "paramValue",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.org:80", model.ParamLabelPrefix + "testParam": "paramValue"},
					{model.JobLabel: "test_job1", model.InstanceLabel: "example.com:80", "testParam": "paramValue",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.com:80", model.ParamLabelPrefix + "testParam": "paramValue"},
				},
			},
		}, {
			scrapeConfigs: []*config.ScrapeConfig{testJob1},
			expected: map[string][]model.LabelSet{
				"test_job1:static:0:0": {
					{model.JobLabel: "test_job1", model.InstanceLabel: "example.org:80", "testParam": "paramValue",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.org:80", model.ParamLabelPrefix + "testParam": "paramValue"},
					{model.JobLabel: "test_job1", model.InstanceLabel: "example.com:80", "testParam": "paramValue",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.com:80", model.ParamLabelPrefix + "testParam": "paramValue"},
				},
			},
		}, {
			scrapeConfigs: []*config.ScrapeConfig{testJob1, testJob2},
			expected: map[string][]model.LabelSet{
				"test_job1:static:0:0": {
					{model.JobLabel: "test_job1", model.InstanceLabel: "example.org:80", "testParam": "paramValue",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.org:80", model.ParamLabelPrefix + "testParam": "paramValue"},
					{model.JobLabel: "test_job1", model.InstanceLabel: "example.com:80", "testParam": "paramValue",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.com:80", model.ParamLabelPrefix + "testParam": "paramValue"},
				},
				"test_job2:static:0:0": {
					{model.JobLabel: "test_job2", model.InstanceLabel: "example.org:8080", "foo": "bar", "new": "ox-ba",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.org:8080"},
					{model.JobLabel: "test_job2", model.InstanceLabel: "example.com:8081", "foo": "bar", "new": "ox-ba",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.com:8081"},
				},
				"test_job2:static:0:1": {
					{model.JobLabel: "test_job2", model.InstanceLabel: "foo.com:1234",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "foo.com:1234"},
				},
				"test_job2:static:0:2": {
					{model.JobLabel: "test_job2", model.InstanceLabel: "fixed",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "foo.com:1235"},
				},
			},
		}, {
			scrapeConfigs: []*config.ScrapeConfig{},
			expected:      map[string][]model.LabelSet{},
		}, {
			scrapeConfigs: []*config.ScrapeConfig{testJob2},
			expected: map[string][]model.LabelSet{
				"test_job2:static:0:0": {
					{model.JobLabel: "test_job2", model.InstanceLabel: "example.org:8080", "foo": "bar", "new": "ox-ba",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.org:8080"},
					{model.JobLabel: "test_job2", model.InstanceLabel: "example.com:8081", "foo": "bar", "new": "ox-ba",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "example.com:8081"},
				},
				"test_job2:static:0:1": {
					{model.JobLabel: "test_job2", model.InstanceLabel: "foo.com:1234",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "foo.com:1234"},
				},
				"test_job2:static:0:2": {
					{model.JobLabel: "test_job2", model.InstanceLabel: "fixed",
						model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "foo.com:1235"},
				},
			},
		},
	}
	conf := &config.Config{}
	*conf = config.DefaultConfig

	targetManager := NewTargetManager(nopAppender{})
	targetManager.ApplyConfig(conf)

	targetManager.Run()
	defer targetManager.Stop()

	for i, step := range sequence {
		conf.ScrapeConfigs = step.scrapeConfigs
		targetManager.ApplyConfig(conf)

		time.Sleep(50 * time.Millisecond)

		if len(targetManager.targets) != len(step.expected) {
			t.Fatalf("step %d: sources mismatch: expected %v, got %v", i, step.expected, targetManager.targets)
		}

		for source, actTargets := range targetManager.targets {
			expTargets, ok := step.expected[source]
			if !ok {
				t.Fatalf("step %d: unexpected source %q: %v", i, source, actTargets)
			}
			for _, expt := range expTargets {
				found := false
				for _, actt := range actTargets {
					if reflect.DeepEqual(expt, actt.fullLabels()) {
						found = true
						break
					}
				}
				if !found {
					t.Errorf("step %d: expected target %v for %q not found in actual targets", i, expt, source)
				}
			}
		}
	}
}
Exemple #4
0
func TestTargetScrapeMetricRelabelConfigs(t *testing.T) {
	server := httptest.NewServer(
		http.HandlerFunc(
			func(w http.ResponseWriter, r *http.Request) {
				w.Header().Set("Content-Type", `text/plain; version=0.0.4`)
				w.Write([]byte("test_metric_drop 0\n"))
				w.Write([]byte("test_metric_relabel 1\n"))
			},
		),
	)
	defer server.Close()
	testTarget := newTestTarget(server.URL, 10*time.Millisecond, model.LabelSet{})
	testTarget.metricRelabelConfigs = []*config.RelabelConfig{
		{
			SourceLabels: model.LabelNames{"__name__"},
			Regex:        config.MustNewRegexp(".*drop.*"),
			Action:       config.RelabelDrop,
		},
		{
			SourceLabels: model.LabelNames{"__name__"},
			Regex:        config.MustNewRegexp(".*(relabel|up).*"),
			TargetLabel:  "foo",
			Replacement:  "bar",
			Action:       config.RelabelReplace,
		},
	}

	appender := &collectResultAppender{}
	testTarget.scrape(appender)

	// Remove variables part of result.
	for _, sample := range appender.result {
		sample.Timestamp = 0
		sample.Value = 0
	}

	expected := []*model.Sample{
		{
			Metric: model.Metric{
				model.MetricNameLabel: "test_metric_relabel",
				"foo":               "bar",
				model.InstanceLabel: model.LabelValue(testTarget.url.Host),
			},
			Timestamp: 0,
			Value:     0,
		},
		// The metrics about the scrape are not affected.
		{
			Metric: model.Metric{
				model.MetricNameLabel: scrapeHealthMetricName,
				model.InstanceLabel:   model.LabelValue(testTarget.url.Host),
			},
			Timestamp: 0,
			Value:     0,
		},
		{
			Metric: model.Metric{
				model.MetricNameLabel: scrapeDurationMetricName,
				model.InstanceLabel:   model.LabelValue(testTarget.url.Host),
			},
			Timestamp: 0,
			Value:     0,
		},
	}

	if !appender.result.Equal(expected) {
		t.Fatalf("Expected and actual samples not equal. Expected: %s, actual: %s", expected, appender.result)
	}

}
func TestRelabel(t *testing.T) {
	tests := []struct {
		input   model.LabelSet
		relabel []*config.RelabelConfig
		output  model.LabelSet
	}{
		{
			input: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f(.*)"),
					TargetLabel:  model.LabelName("d"),
					Separator:    ";",
					Replacement:  "ch${1}-ch${1}",
					Action:       config.RelabelReplace,
				},
			},
			output: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
				"d": "choo-choo",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a", "b"},
					Regex:        config.MustNewRegexp("f(.*);(.*)r"),
					TargetLabel:  model.LabelName("a"),
					Separator:    ";",
					Replacement:  "b${1}${2}m", // boobam
					Action:       config.RelabelReplace,
				},
				{
					SourceLabels: model.LabelNames{"c", "a"},
					Regex:        config.MustNewRegexp("(b).*b(.*)ba(.*)"),
					TargetLabel:  model.LabelName("d"),
					Separator:    ";",
					Replacement:  "$1$2$2$3",
					Action:       config.RelabelReplace,
				},
			},
			output: model.LabelSet{
				"a": "boobam",
				"b": "bar",
				"c": "baz",
				"d": "boooom",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp(".*o.*"),
					Action:       config.RelabelDrop,
				}, {
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f(.*)"),
					TargetLabel:  model.LabelName("d"),
					Separator:    ";",
					Replacement:  "ch$1-ch$1",
					Action:       config.RelabelReplace,
				},
			},
			output: nil,
		},
		{
			input: model.LabelSet{
				"a": "abc",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp(".*(b).*"),
					TargetLabel:  model.LabelName("d"),
					Separator:    ";",
					Replacement:  "$1",
					Action:       config.RelabelReplace,
				},
			},
			output: model.LabelSet{
				"a": "abc",
				"d": "b",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("no-match"),
					Action:       config.RelabelDrop,
				},
			},
			output: model.LabelSet{
				"a": "foo",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f|o"),
					Action:       config.RelabelDrop,
				},
			},
			output: model.LabelSet{
				"a": "foo",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("no-match"),
					Action:       config.RelabelKeep,
				},
			},
			output: nil,
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f.*"),
					Action:       config.RelabelKeep,
				},
			},
			output: model.LabelSet{
				"a": "foo",
			},
		},
		{
			// No replacement must be applied if there is no match.
			input: model.LabelSet{
				"a": "boo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f"),
					TargetLabel:  model.LabelName("b"),
					Replacement:  "bar",
					Action:       config.RelabelReplace,
				},
			},
			output: model.LabelSet{
				"a": "boo",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"c"},
					TargetLabel:  model.LabelName("d"),
					Separator:    ";",
					Action:       config.RelabelHashMod,
					Modulus:      1000,
				},
			},
			output: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
				"d": "976",
			},
		},
		{
			input: model.LabelSet{
				"a":  "foo",
				"b1": "bar",
				"b2": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					Regex:       config.MustNewRegexp("(b.*)"),
					Replacement: "bar_${1}",
					Action:      config.RelabelLabelMap,
				},
			},
			output: model.LabelSet{
				"a":      "foo",
				"b1":     "bar",
				"b2":     "baz",
				"bar_b1": "bar",
				"bar_b2": "baz",
			},
		},
		{
			input: model.LabelSet{
				"a":             "foo",
				"__meta_my_bar": "aaa",
				"__meta_my_baz": "bbb",
				"__meta_other":  "ccc",
			},
			relabel: []*config.RelabelConfig{
				{
					Regex:       config.MustNewRegexp("__meta_(my.*)"),
					Replacement: "${1}",
					Action:      config.RelabelLabelMap,
				},
			},
			output: model.LabelSet{
				"a":             "foo",
				"__meta_my_bar": "aaa",
				"__meta_my_baz": "bbb",
				"__meta_other":  "ccc",
				"my_bar":        "aaa",
				"my_baz":        "bbb",
			},
		},
	}

	for i, test := range tests {
		res, err := Relabel(test.input, test.relabel...)
		if err != nil {
			t.Errorf("Test %d: error relabeling: %s", i+1, err)
		}

		if !reflect.DeepEqual(res, test.output) {
			t.Errorf("Test %d: relabel output mismatch: expected %#v, got %#v", i+1, test.output, res)
		}
	}
}
func TestRelabel(t *testing.T) {
	tests := []struct {
		input   model.LabelSet
		relabel []*config.RelabelConfig
		output  model.LabelSet
	}{
		{
			input: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f(.*)"),
					TargetLabel:  "d",
					Separator:    ";",
					Replacement:  "ch${1}-ch${1}",
					Action:       config.RelabelReplace,
				},
			},
			output: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
				"d": "choo-choo",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a", "b"},
					Regex:        config.MustNewRegexp("f(.*);(.*)r"),
					TargetLabel:  "a",
					Separator:    ";",
					Replacement:  "b${1}${2}m", // boobam
					Action:       config.RelabelReplace,
				},
				{
					SourceLabels: model.LabelNames{"c", "a"},
					Regex:        config.MustNewRegexp("(b).*b(.*)ba(.*)"),
					TargetLabel:  "d",
					Separator:    ";",
					Replacement:  "$1$2$2$3",
					Action:       config.RelabelReplace,
				},
			},
			output: model.LabelSet{
				"a": "boobam",
				"b": "bar",
				"c": "baz",
				"d": "boooom",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp(".*o.*"),
					Action:       config.RelabelDrop,
				}, {
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f(.*)"),
					TargetLabel:  "d",
					Separator:    ";",
					Replacement:  "ch$1-ch$1",
					Action:       config.RelabelReplace,
				},
			},
			output: nil,
		},
		{
			input: model.LabelSet{
				"a": "foo",
				"b": "bar",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp(".*o.*"),
					Action:       config.RelabelDrop,
				},
			},
			output: nil,
		},
		{
			input: model.LabelSet{
				"a": "abc",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp(".*(b).*"),
					TargetLabel:  "d",
					Separator:    ";",
					Replacement:  "$1",
					Action:       config.RelabelReplace,
				},
			},
			output: model.LabelSet{
				"a": "abc",
				"d": "b",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("no-match"),
					Action:       config.RelabelDrop,
				},
			},
			output: model.LabelSet{
				"a": "foo",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f|o"),
					Action:       config.RelabelDrop,
				},
			},
			output: model.LabelSet{
				"a": "foo",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("no-match"),
					Action:       config.RelabelKeep,
				},
			},
			output: nil,
		},
		{
			input: model.LabelSet{
				"a": "foo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f.*"),
					Action:       config.RelabelKeep,
				},
			},
			output: model.LabelSet{
				"a": "foo",
			},
		},
		{
			// No replacement must be applied if there is no match.
			input: model.LabelSet{
				"a": "boo",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("f"),
					TargetLabel:  "b",
					Replacement:  "bar",
					Action:       config.RelabelReplace,
				},
			},
			output: model.LabelSet{
				"a": "boo",
			},
		},
		{
			input: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"c"},
					TargetLabel:  "d",
					Separator:    ";",
					Action:       config.RelabelHashMod,
					Modulus:      1000,
				},
			},
			output: model.LabelSet{
				"a": "foo",
				"b": "bar",
				"c": "baz",
				"d": "976",
			},
		},
		{
			input: model.LabelSet{
				"a":  "foo",
				"b1": "bar",
				"b2": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					Regex:       config.MustNewRegexp("(b.*)"),
					Replacement: "bar_${1}",
					Action:      config.RelabelLabelMap,
				},
			},
			output: model.LabelSet{
				"a":      "foo",
				"b1":     "bar",
				"b2":     "baz",
				"bar_b1": "bar",
				"bar_b2": "baz",
			},
		},
		{
			input: model.LabelSet{
				"a":             "foo",
				"__meta_my_bar": "aaa",
				"__meta_my_baz": "bbb",
				"__meta_other":  "ccc",
			},
			relabel: []*config.RelabelConfig{
				{
					Regex:       config.MustNewRegexp("__meta_(my.*)"),
					Replacement: "${1}",
					Action:      config.RelabelLabelMap,
				},
			},
			output: model.LabelSet{
				"a":             "foo",
				"__meta_my_bar": "aaa",
				"__meta_my_baz": "bbb",
				"__meta_other":  "ccc",
				"my_bar":        "aaa",
				"my_baz":        "bbb",
			},
		},
		{ // valid case
			input: model.LabelSet{
				"a": "some-name-value",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("some-([^-]+)-([^,]+)"),
					Action:       config.RelabelReplace,
					Replacement:  "${2}",
					TargetLabel:  "${1}",
				},
			},
			output: model.LabelSet{
				"a":    "some-name-value",
				"name": "value",
			},
		},
		{ // invalid replacement ""
			input: model.LabelSet{
				"a": "some-name-value",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("some-([^-]+)-([^,]+)"),
					Action:       config.RelabelReplace,
					Replacement:  "${3}",
					TargetLabel:  "${1}",
				},
			},
			output: model.LabelSet{
				"a": "some-name-value",
			},
		},
		{ // invalid target_labels
			input: model.LabelSet{
				"a": "some-name-value",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("some-([^-]+)-([^,]+)"),
					Action:       config.RelabelReplace,
					Replacement:  "${1}",
					TargetLabel:  "${3}",
				},
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("some-([^-]+)-([^,]+)"),
					Action:       config.RelabelReplace,
					Replacement:  "${1}",
					TargetLabel:  "0${3}",
				},
				{
					SourceLabels: model.LabelNames{"a"},
					Regex:        config.MustNewRegexp("some-([^-]+)-([^,]+)"),
					Action:       config.RelabelReplace,
					Replacement:  "${1}",
					TargetLabel:  "-${3}",
				},
			},
			output: model.LabelSet{
				"a": "some-name-value",
			},
		},
		{ // more complex real-life like usecase
			input: model.LabelSet{
				"__meta_sd_tags": "path:/secret,job:some-job,label:foo=bar",
			},
			relabel: []*config.RelabelConfig{
				{
					SourceLabels: model.LabelNames{"__meta_sd_tags"},
					Regex:        config.MustNewRegexp("(?:.+,|^)path:(/[^,]+).*"),
					Action:       config.RelabelReplace,
					Replacement:  "${1}",
					TargetLabel:  "__metrics_path__",
				},
				{
					SourceLabels: model.LabelNames{"__meta_sd_tags"},
					Regex:        config.MustNewRegexp("(?:.+,|^)job:([^,]+).*"),
					Action:       config.RelabelReplace,
					Replacement:  "${1}",
					TargetLabel:  "job",
				},
				{
					SourceLabels: model.LabelNames{"__meta_sd_tags"},
					Regex:        config.MustNewRegexp("(?:.+,|^)label:([^=]+)=([^,]+).*"),
					Action:       config.RelabelReplace,
					Replacement:  "${2}",
					TargetLabel:  "${1}",
				},
			},
			output: model.LabelSet{
				"__meta_sd_tags":   "path:/secret,job:some-job,label:foo=bar",
				"__metrics_path__": "/secret",
				"job":              "some-job",
				"foo":              "bar",
			},
		},
		{
			input: model.LabelSet{
				"a":  "foo",
				"b1": "bar",
				"b2": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					Regex:  config.MustNewRegexp("(b.*)"),
					Action: config.RelabelLabelKeep,
				},
			},
			output: model.LabelSet{
				"b1": "bar",
				"b2": "baz",
			},
		},
		{
			input: model.LabelSet{
				"a":  "foo",
				"b1": "bar",
				"b2": "baz",
			},
			relabel: []*config.RelabelConfig{
				{
					Regex:  config.MustNewRegexp("(b.*)"),
					Action: config.RelabelLabelDrop,
				},
			},
			output: model.LabelSet{
				"a": "foo",
			},
		},
	}

	for i, test := range tests {
		res := Process(test.input, test.relabel...)

		if !reflect.DeepEqual(res, test.output) {
			t.Errorf("Test %d: relabel output mismatch: expected %#v, got %#v", i+1, test.output, res)
		}
	}
}