From ccf576174cb5c95270a90b248ddfadd169d4c969 Mon Sep 17 00:00:00 2001 From: Sven Rebhan <36194019+srebhan@users.noreply.github.com> Date: Mon, 3 Mar 2025 16:27:31 +0100 Subject: [PATCH] test(outputs.prometheus_client): Add tests for content-type header (#16559) --- plugins/inputs/prometheus/README.md | 26 ++-- plugins/inputs/prometheus/sample.conf | 26 ++-- .../prometheus_client_test.go | 123 ++++++++++++++++++ .../prometheus_client_v1_test.go | 30 ----- 4 files changed, 149 insertions(+), 56 deletions(-) create mode 100644 plugins/outputs/prometheus_client/prometheus_client_test.go diff --git a/plugins/inputs/prometheus/README.md b/plugins/inputs/prometheus/README.md index 19e28b728..86145dac7 100644 --- a/plugins/inputs/prometheus/README.md +++ b/plugins/inputs/prometheus/README.md @@ -127,19 +127,6 @@ and `bearer_token_string` option. See the # Default is 60 minutes. # cache_refresh_interval = 60 - ## Scrape Services available in Consul Catalog - # [inputs.prometheus.consul] - # enabled = true - # agent = "http://localhost:8500" - # query_interval = "5m" - - # [[inputs.prometheus.consul.query]] - # name = "a service name" - # tag = "a service tag" - # url = 'http://{{if ne .ServiceAddress ""}}{{.ServiceAddress}}{{else}}{{.Address}}{{end}}:{{.ServicePort}}/{{with .ServiceMeta.metrics_path}}{{.}}{{else}}metrics{{end}}' - # [inputs.prometheus.consul.query.tags] - # host = "{{.Node}}" - ## Use bearer token for authorization. ('bearer_token' takes priority) # bearer_token = "/path/to/bearer/token" ## OR @@ -186,6 +173,19 @@ and `bearer_token_string` option. See the ## This option allows you to report the status of prometheus requests. # enable_request_metrics = false + ## Scrape Services available in Consul Catalog + # [inputs.prometheus.consul] + # enabled = true + # agent = "http://localhost:8500" + # query_interval = "5m" + + # [[inputs.prometheus.consul.query]] + # name = "a service name" + # tag = "a service tag" + # url = 'http://{{if ne .ServiceAddress ""}}{{.ServiceAddress}}{{else}}{{.Address}}{{end}}:{{.ServicePort}}/{{with .ServiceMeta.metrics_path}}{{.}}{{else}}metrics{{end}}' + # [inputs.prometheus.consul.query.tags] + # host = "{{.Node}}" + ## Control pod scraping based on pod namespace annotations ## Pass and drop here act like tagpass and tagdrop, but instead ## of filtering metrics they filters pod candidates for scraping diff --git a/plugins/inputs/prometheus/sample.conf b/plugins/inputs/prometheus/sample.conf index 425eba379..a770184fc 100644 --- a/plugins/inputs/prometheus/sample.conf +++ b/plugins/inputs/prometheus/sample.conf @@ -102,19 +102,6 @@ # Default is 60 minutes. # cache_refresh_interval = 60 - ## Scrape Services available in Consul Catalog - # [inputs.prometheus.consul] - # enabled = true - # agent = "http://localhost:8500" - # query_interval = "5m" - - # [[inputs.prometheus.consul.query]] - # name = "a service name" - # tag = "a service tag" - # url = 'http://{{if ne .ServiceAddress ""}}{{.ServiceAddress}}{{else}}{{.Address}}{{end}}:{{.ServicePort}}/{{with .ServiceMeta.metrics_path}}{{.}}{{else}}metrics{{end}}' - # [inputs.prometheus.consul.query.tags] - # host = "{{.Node}}" - ## Use bearer token for authorization. ('bearer_token' takes priority) # bearer_token = "/path/to/bearer/token" ## OR @@ -161,6 +148,19 @@ ## This option allows you to report the status of prometheus requests. # enable_request_metrics = false + ## Scrape Services available in Consul Catalog + # [inputs.prometheus.consul] + # enabled = true + # agent = "http://localhost:8500" + # query_interval = "5m" + + # [[inputs.prometheus.consul.query]] + # name = "a service name" + # tag = "a service tag" + # url = 'http://{{if ne .ServiceAddress ""}}{{.ServiceAddress}}{{else}}{{.Address}}{{end}}:{{.ServicePort}}/{{with .ServiceMeta.metrics_path}}{{.}}{{else}}metrics{{end}}' + # [inputs.prometheus.consul.query.tags] + # host = "{{.Node}}" + ## Control pod scraping based on pod namespace annotations ## Pass and drop here act like tagpass and tagdrop, but instead ## of filtering metrics they filters pod candidates for scraping diff --git a/plugins/outputs/prometheus_client/prometheus_client_test.go b/plugins/outputs/prometheus_client/prometheus_client_test.go new file mode 100644 index 000000000..c336d9d2e --- /dev/null +++ b/plugins/outputs/prometheus_client/prometheus_client_test.go @@ -0,0 +1,123 @@ +package prometheus_client + +import ( + "fmt" + "io" + "net/http" + "net/url" + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf/testutil" +) + +func TestLandingPage(t *testing.T) { + output := PrometheusClient{ + Listen: ":0", + CollectorsExclude: []string{"process"}, + MetricVersion: 1, + Log: &testutil.Logger{Name: "outputs.prometheus_client"}, + } + expected := "Telegraf Output Plugin: Prometheus Client" + + require.NoError(t, output.Init()) + require.NoError(t, output.Connect()) + + u, err := url.Parse(fmt.Sprintf("http://%s/", output.url.Host)) + require.NoError(t, err) + + resp, err := http.Get(u.String()) + require.NoError(t, err) + defer resp.Body.Close() + + actual, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, expected, strings.TrimSpace(string(actual))) +} + +func TestFormatHeader(t *testing.T) { + tests := []struct { + name string + accept string + expected string + }{ + { + name: "invalid accept ", + accept: "applications/json", + expected: "text/plain; version=0.0.4; charset=utf-8; escaping=underscores", + }, + { + name: "no accept header", + expected: "text/plain; version=0.0.4; charset=utf-8; escaping=underscores", + }, + { + name: "text no version", + accept: "text/plain", + expected: "text/plain; version=0.0.4; charset=utf-8; escaping=underscores", + }, + { + name: "text with version 0.0.4", + accept: "text/plain; version=0.0.4", + expected: "text/plain; version=0.0.4; charset=utf-8; escaping=underscores", + }, + { + name: "protobuf text format", + accept: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text", + expected: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text; escaping=underscores", + }, + { + name: "protobuf compact text format", + accept: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text", + expected: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text; escaping=underscores", + }, + { + name: "protobuf delimited format", + accept: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited", + expected: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited; escaping=underscores", + }, + { + name: "multiple accept preferring protobuf", + accept: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited, text/plain", + expected: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited; escaping=underscores", + }, + { + name: "multiple accept preferring text", + accept: "text/plain, application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited", + expected: "text/plain; version=0.0.4; charset=utf-8; escaping=underscores", + }, + } + + // Setup the plugin + plugin := PrometheusClient{ + Listen: ":0", + Log: testutil.Logger{Name: "outputs.prometheus_client"}, + } + require.NoError(t, plugin.Init()) + require.NoError(t, plugin.Connect()) + + // Get the plugin's address so we can send data to it + addr := fmt.Sprintf("http://%s/metrics", plugin.url.Host) + + // Run the actual tests + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Construct a request with the given "Accept" header + req, err := http.NewRequest("GET", addr, nil) + require.NoError(t, err) + if tt.accept != "" { + req.Header.Add("Accept", tt.accept) + } + + // Get the metrics + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + // Test the result + require.NotEmpty(t, resp.Body) + require.Equal(t, tt.expected, resp.Header.Get("Content-Type")) + }) + } +} diff --git a/plugins/outputs/prometheus_client/prometheus_client_v1_test.go b/plugins/outputs/prometheus_client/prometheus_client_v1_test.go index 82be5cfe2..a53a187d3 100644 --- a/plugins/outputs/prometheus_client/prometheus_client_v1_test.go +++ b/plugins/outputs/prometheus_client/prometheus_client_v1_test.go @@ -5,7 +5,6 @@ import ( "io" "net/http" "net/http/httptest" - "net/url" "regexp" "strings" "testing" @@ -496,32 +495,3 @@ rpc_duration_seconds_count 2693 }) } } - -func TestLandingPage(t *testing.T) { - logger := testutil.Logger{Name: "outputs.prometheus_client"} - output := PrometheusClient{ - Listen: ":0", - CollectorsExclude: []string{"process"}, - MetricVersion: 1, - Log: logger, - } - expected := "Telegraf Output Plugin: Prometheus Client" - - err := output.Init() - require.NoError(t, err) - - err = output.Connect() - require.NoError(t, err) - - u, err := url.Parse(fmt.Sprintf("http://%s/", output.url.Host)) - require.NoError(t, err) - - resp, err := http.Get(u.String()) - require.NoError(t, err) - defer resp.Body.Close() - - actual, err := io.ReadAll(resp.Body) - require.NoError(t, err) - - require.Equal(t, expected, strings.TrimSpace(string(actual))) -}