The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/promlib/admission_handler_test.go

247 lines
7.2 KiB

package promlib
import (
"context"
"fmt"
"net/http"
"testing"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/proto"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func Test_ValidateAdmission(t *testing.T) {
t.Run("should return error when MutateAdmission fails and response is nil", func(t *testing.T) {
httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]()
logger := backend.NewLoggerWith("logger", "test")
s := &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)),
logger: logger,
}
req := &backend.AdmissionRequest{
Kind: backend.GroupVersionKind{
Group: "grafana-plugin-sdk-go",
Kind: "DataSourceInstanceSettings",
},
ObjectBytes: []byte(`{"foo":"bar"}`),
}
actual, err := s.ValidateAdmission(context.Background(), req)
assert.ErrorContains(t, err, "cannot parse invalid")
assert.Nil(t, actual)
})
t.Run("should return ValidationResponse when MutateAdmission succeeds", func(t *testing.T) {
httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]()
logger := backend.NewLoggerWith("logger", "test")
s := &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)),
logger: logger,
}
pb := &pluginv2.DataSourceInstanceSettings{
ApiVersion: "v0alpha1",
Url: "https://grafana.example.com/",
}
data, err := proto.Marshal(pb)
assert.NoError(t, err)
expected := &backend.ValidationResponse{
Allowed: true,
}
req := &backend.AdmissionRequest{
Kind: backend.GroupVersionKind{
Group: "grafana-plugin-sdk-go",
Kind: "DataSourceInstanceSettings",
},
ObjectBytes: data,
}
actual, err := s.ValidateAdmission(context.Background(), req)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
})
}
func Test_MutateAdmission(t *testing.T) {
t.Run("should fail when Kind and Group do not match expected values", func(t *testing.T) {
httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]()
logger := backend.NewLoggerWith("logger", "test")
s := &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)),
logger: logger,
}
expected := getBadRequest("expected DataSourceInstanceSettings protobuf payload")
req := &backend.AdmissionRequest{
Kind: backend.GroupVersionKind{
Group: "example.k8s.io",
Kind: "Pod",
},
}
actual, err := s.MutateAdmission(context.Background(), req)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
})
t.Run("should return an error when object bytes is nil", func(t *testing.T) {
httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]()
logger := backend.NewLoggerWith("logger", "test")
s := &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)),
logger: logger,
}
expected := getBadRequest("missing datasource settings")
req := &backend.AdmissionRequest{
Kind: backend.GroupVersionKind{
Group: "grafana-plugin-sdk-go",
Kind: "DataSourceInstanceSettings",
},
}
actual, err := s.MutateAdmission(context.Background(), req)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
})
t.Run("should return an error when protobuf payload conversion fails", func(t *testing.T) {
httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]()
logger := backend.NewLoggerWith("logger", "test")
s := &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)),
logger: logger,
}
req := &backend.AdmissionRequest{
Kind: backend.GroupVersionKind{
Group: "grafana-plugin-sdk-go",
Kind: "DataSourceInstanceSettings",
},
ObjectBytes: []byte(`{"foo":"bar"}`),
}
actual, err := s.MutateAdmission(context.Background(), req)
assert.ErrorContains(t, err, "cannot parse invalid")
assert.Nil(t, actual)
})
t.Run("should return bad request error when settings APIVersion is invalid", func(t *testing.T) {
httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]()
logger := backend.NewLoggerWith("logger", "test")
s := &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)),
logger: logger,
}
pb := &pluginv2.DataSourceInstanceSettings{
ApiVersion: "v0alpha2",
}
data, err := proto.Marshal(pb)
assert.NoError(t, err)
expected := getBadRequest(fmt.Sprintf("expected apiVersion: v0alpha1, found: %s", pb.ApiVersion))
req := &backend.AdmissionRequest{
Kind: backend.GroupVersionKind{
Group: "grafana-plugin-sdk-go",
Kind: "DataSourceInstanceSettings",
},
ObjectBytes: data,
}
actual, err := s.MutateAdmission(context.Background(), req)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
})
t.Run("should return bad request error when settings URL is invalid", func(t *testing.T) {
httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]()
logger := backend.NewLoggerWith("logger", "test")
s := &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)),
logger: logger,
}
pb := &pluginv2.DataSourceInstanceSettings{
ApiVersion: "v0alpha1",
}
data, err := proto.Marshal(pb)
assert.NoError(t, err)
expected := getBadRequest("missing URL value")
req := &backend.AdmissionRequest{
Kind: backend.GroupVersionKind{
Group: "grafana-plugin-sdk-go",
Kind: "DataSourceInstanceSettings",
},
ObjectBytes: data,
}
actual, err := s.MutateAdmission(context.Background(), req)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
})
t.Run("should return successfully mutation response", func(t *testing.T) {
httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]()
logger := backend.NewLoggerWith("logger", "test")
s := &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)),
logger: logger,
}
pb := &pluginv2.DataSourceInstanceSettings{
ApiVersion: "v0alpha1",
Url: "https://grafana.example.com/",
}
data, err := proto.Marshal(pb)
assert.NoError(t, err)
expected := &backend.MutationResponse{
Allowed: true,
ObjectBytes: data,
}
req := &backend.AdmissionRequest{
Kind: backend.GroupVersionKind{
Group: "grafana-plugin-sdk-go",
Kind: "DataSourceInstanceSettings",
},
ObjectBytes: data,
}
actual, err := s.MutateAdmission(context.Background(), req)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
})
}
func Test_getBadRequest(t *testing.T) {
t.Run("should get a successful bad request", func(t *testing.T) {
msg := "missing URL value"
expected := &backend.MutationResponse{
Allowed: false,
Result: &backend.StatusResult{
Status: "Failure",
Message: "missing URL value",
Reason: string(metav1.StatusReasonBadRequest),
Code: http.StatusBadRequest,
},
}
actual := getBadRequest(msg)
assert.Equal(t, expected, actual)
})
}