prometheus/cmd/promtool/metrics_test.go
Minh Nguyen 6bb367970e
feat(promtool): add RW2 support to promtool push metrics using client_golang library (#17280)
* Add WriteProto method and tests for promtool metrics

This commit adds:
1. WriteProto method to storage/remote/client.go that handles
   marshaling and compression of protobuf messages
2. Updated parseAndPushMetrics in cmd/promtool/metrics.go to use
   the new WriteProto method
3. Comprehensive tests for PushMetrics functionality

The WriteProto method provides a cleaner API for sending protobuf
messages without manually handling marshaling and compression.

Signed-off-by: pipiland2612 <nguyen.t.dang.minh@gmail.com>

* use Write method from exp/api/remote

Signed-off-by: pipiland2612 <nguyen.t.dang.minh@gmail.com>

* fix

Signed-off-by: pipiland2612 <nguyen.t.dang.minh@gmail.com>

* fix lint

Signed-off-by: pipiland2612 <nguyen.t.dang.minh@gmail.com>

* fix test

Signed-off-by: pipiland2612 <nguyen.t.dang.minh@gmail.com>

* fix

Signed-off-by: pipiland2612 <nguyen.t.dang.minh@gmail.com>

* nit fixed

Signed-off-by: pipiland2612 <nguyen.t.dang.minh@gmail.com>

* fix lint

Signed-off-by: pipiland2612 <nguyen.t.dang.minh@gmail.com>

---------

Signed-off-by: pipiland2612 <nguyen.t.dang.minh@gmail.com>
2025-10-27 13:56:48 +00:00

121 lines
3.2 KiB
Go

// Copyright 2025 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"io"
"net/http"
"net/http/httptest"
"net/url"
"os"
"testing"
"time"
remoteapi "github.com/prometheus/client_golang/exp/api/remote"
"github.com/stretchr/testify/require"
)
func TestPushMetrics(t *testing.T) {
tests := []struct {
name string
metricsData string
}{
{
name: "successful push with gauge metrics",
metricsData: `# HELP test_metric A test metric
# TYPE test_metric gauge
test_metric{label="value1"} 42.0
test_metric{label="value2"} 43.0
`,
},
{
name: "successful push with counter metrics",
metricsData: `# HELP test_counter A test counter
# TYPE test_counter counter
test_counter 100
`,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// Create test server using client_golang's remote write handler.
store := &mockStorage{}
handler := remoteapi.NewWriteHandler(
store,
remoteapi.MessageTypes{remoteapi.WriteV1MessageType},
)
server := httptest.NewServer(handler)
defer server.Close()
serverURL, err := url.Parse(server.URL)
require.NoError(t, err)
// Create a temp file with metrics data.
tmpFile := t.TempDir() + "/metrics.txt"
err = os.WriteFile(tmpFile, []byte(tc.metricsData), 0o644)
require.NoError(t, err)
// Call PushMetrics.
status := PushMetrics(
serverURL,
http.DefaultTransport,
map[string]string{},
30*time.Second,
map[string]string{"job": "test"},
tmpFile,
)
require.Equal(t, successExitCode, status)
// Verify that the handler received and processed the request.
require.True(t, store.called, "Handler should have been called")
require.NoError(t, store.lastErr, "Handler should not have returned an error")
// Verify proper data propagation.
require.NotEmpty(t, store.receivedData, "Request should contain data (compression and decompression successful)")
require.Contains(t, store.receivedContentType, "application/x-protobuf", "Content-Type should be protobuf")
})
}
}
// mockStorage is a simple mock for testing the remote write handler.
type mockStorage struct {
called bool
lastErr error
receivedData []byte
receivedContentType string
}
func (m *mockStorage) Store(req *http.Request, _ remoteapi.WriteMessageType) (*remoteapi.WriteResponse, error) {
m.called = true
// Capture content-type header.
m.receivedContentType = req.Header.Get("Content-Type")
if req.Body != nil {
data, err := io.ReadAll(req.Body)
if err == nil {
m.receivedData = data
}
}
if m.lastErr != nil {
return nil, m.lastErr
}
resp := remoteapi.NewWriteResponse()
resp.SetStatusCode(http.StatusNoContent)
return resp, nil
}