Files
grafana/pkg/promlib/resource/resource_test.go
Tobias Skarhed bd83646bd4 PromLib: Take AdHoc filters into account when requesting suggestions without label (#101555)
* Check for adhoc filters, even when no timeserie name is used

* Add test
2025-03-06 12:21:10 +01:00

190 lines
4.8 KiB
Go

package resource_test
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"net/url"
"testing"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/promlib/models"
"github.com/grafana/grafana/pkg/promlib/resource"
)
type mockRoundTripper struct {
Response *http.Response
Err error
customRoundTrip func(req *http.Request) (*http.Response, error)
}
func (m *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if m.customRoundTrip != nil {
return m.customRoundTrip(req)
}
return m.Response, m.Err
}
func setup() (*http.Client, backend.DataSourceInstanceSettings, log.Logger) {
// Mock HTTP Response
mockResponse := &http.Response{
StatusCode: 200,
Body: io.NopCloser(bytes.NewReader([]byte(`{"message": "success"}`))),
Header: make(http.Header),
}
// Create a mock RoundTripper
mockTransport := &mockRoundTripper{
Response: mockResponse,
}
// Create a mock HTTP client using the mock RoundTripper
mockClient := &http.Client{
Transport: mockTransport,
}
settings := backend.DataSourceInstanceSettings{
ID: 1,
URL: "http://mock-server",
JSONData: []byte(`{}`),
}
logger := log.DefaultLogger
return mockClient, settings, logger
}
func TestNewResource(t *testing.T) {
mockClient, settings, logger := setup()
res, err := resource.New(mockClient, settings, logger)
require.NoError(t, err)
assert.NotNil(t, res)
}
func TestResource_Execute(t *testing.T) {
mockClient, settings, logger := setup()
res, err := resource.New(mockClient, settings, logger)
require.NoError(t, err)
req := &backend.CallResourceRequest{
URL: "/test",
}
ctx := context.Background()
resp, err := res.Execute(ctx, req)
require.NoError(t, err)
assert.NotNil(t, resp)
}
func TestResource_GetSuggestions(t *testing.T) {
mockClient, _, logger := setup()
settings := backend.DataSourceInstanceSettings{
ID: 1,
URL: "http://localhost:9090",
JSONData: []byte(`{"httpMethod": "GET"}`),
}
res, err := resource.New(mockClient, settings, logger)
require.NoError(t, err)
suggestionReq := resource.SuggestionRequest{
LabelName: "instance",
Queries: []string{"up"},
Start: "1609459200",
End: "1609462800",
Limit: 10,
}
body, err := json.Marshal(suggestionReq)
require.NoError(t, err)
req := &backend.CallResourceRequest{
Body: body,
}
ctx := context.Background()
resp, err := res.GetSuggestions(ctx, req)
require.NoError(t, err)
assert.NotNil(t, resp)
}
func TestResource_GetSuggestionsWithEmptyQueriesButFilters(t *testing.T) {
var capturedURL string
// Create a mock transport that captures the request URL
mockTransport := &mockRoundTripper{
Response: &http.Response{
StatusCode: 200,
Body: io.NopCloser(bytes.NewReader([]byte(`{"status":"success","data":[]}`))),
Header: make(http.Header),
},
customRoundTrip: func(req *http.Request) (*http.Response, error) {
capturedURL = req.URL.String()
return &http.Response{
StatusCode: 200,
Body: io.NopCloser(bytes.NewReader([]byte(`{"status":"success","data":[]}`))),
Header: make(http.Header),
}, nil
},
}
// Create a client with the mock transport
mockClient := &http.Client{
Transport: mockTransport,
}
settings := backend.DataSourceInstanceSettings{
ID: 1,
URL: "http://localhost:9090",
JSONData: []byte(`{"httpMethod": "GET"}`),
}
res, err := resource.New(mockClient, settings, log.DefaultLogger)
require.NoError(t, err)
// Create a request with empty queries but with filters
suggestionReq := resource.SuggestionRequest{
Queries: []string{}, // Empty queries
Scopes: []models.ScopeFilter{
{Key: "job", Operator: models.FilterOperatorEquals, Value: "testjob"},
},
AdhocFilters: []models.ScopeFilter{
{Key: "instance", Operator: models.FilterOperatorEquals, Value: "localhost:9090"},
},
}
body, err := json.Marshal(suggestionReq)
require.NoError(t, err)
req := &backend.CallResourceRequest{
Body: body,
}
ctx := context.Background()
resp, err := res.GetSuggestions(ctx, req)
require.NoError(t, err)
assert.NotNil(t, resp)
// Parse the captured URL to get the query parameters
parsedURL, err := url.Parse(capturedURL)
require.NoError(t, err)
// Get the match[] parameter
matchValues := parsedURL.Query()["match[]"]
require.Len(t, matchValues, 1, "Expected exactly one match[] parameter")
// The actual filter expression should match our expectation, regardless of URL encoding
decodedMatch, err := url.QueryUnescape(matchValues[0])
require.NoError(t, err)
// Check that both label matchers are present with their correct values
assert.Contains(t, decodedMatch, `job="testjob"`)
assert.Contains(t, decodedMatch, `instance="localhost:9090"`)
}