Files
grafana/pkg/promlib/admission_handler_test.go
Yusuf Ali Koyuncu 8b2e0d80d0 chore: add unit tests for admission handler (#104650)
* refactor: remove unused code in the function

* test: add unit tests for admission handler

* Revert "refactor: remove unused code in the function"

This reverts commit b8f48dbdbff49a2860efe0257ba62378fc8227b2.

* revert: added again due to incorrectly made test scenario

* test: add unit tests for admission handler
2025-05-07 20:06:54 +02:00

248 lines
7.2 KiB
Go

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)
})
}