Files
open-cluster-management/pkg/server/services/tokenrequest/tokenrequest_test.go
Wei Liu 8fd640694e enable grpc e2e (#1354)
Signed-off-by: Wei Liu <liuweixa@redhat.com>
2026-01-27 10:26:32 +00:00

255 lines
7.3 KiB
Go

package tokenrequest
import (
"context"
"fmt"
"strings"
"testing"
cloudevents "github.com/cloudevents/sdk-go/v2"
authenticationv1 "k8s.io/api/authentication/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
kubefake "k8s.io/client-go/kubernetes/fake"
clienttesting "k8s.io/client-go/testing"
sace "open-cluster-management.io/sdk-go/pkg/cloudevents/clients/serviceaccount"
"open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types"
testingcommon "open-cluster-management.io/ocm/pkg/common/testing"
)
func TestNewTokenRequestService(t *testing.T) {
kubeClient := kubefake.NewSimpleClientset()
service := NewTokenRequestService(kubeClient)
tokenService, ok := service.(*TokenRequestService)
if !ok {
t.Errorf("expected TokenRequestService, got %T", service)
}
if tokenService.client == nil {
t.Errorf("client should not be nil")
}
if tokenService.codec == nil {
t.Errorf("codec should not be nil")
}
}
func TestList(t *testing.T) {
kubeClient := kubefake.NewSimpleClientset()
service := NewTokenRequestService(kubeClient)
evts, err := service.List(context.Background(), types.ListOptions{})
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if evts != nil {
t.Errorf("expected nil events, got %v", evts)
}
}
func TestHandleStatusUpdate(t *testing.T) {
cases := []struct {
name string
serviceAccounts []runtime.Object
tokenRequestEvt *cloudevents.Event
validateActions func(t *testing.T, actions []clienttesting.Action)
validateHandler func(t *testing.T, handler *mockEventHandler)
reactorError error
expectedError bool
expectedErrorText string
}{
{
name: "invalid event type",
serviceAccounts: []runtime.Object{},
tokenRequestEvt: func() *cloudevents.Event {
evt := types.NewEventBuilder("test", types.CloudEventsType{}).NewEvent()
return &evt
}(),
expectedError: true,
expectedErrorText: "failed to parse cloud event type",
},
{
name: "invalid action",
serviceAccounts: []runtime.Object{},
tokenRequestEvt: func() *cloudevents.Event {
evt := types.NewEventBuilder("test", types.CloudEventsType{
CloudEventsDataType: sace.TokenRequestDataType,
SubResource: types.SubResourceSpec,
Action: types.DeleteRequestAction,
}).NewEvent()
tokenRequest := &authenticationv1.TokenRequest{
ObjectMeta: metav1.ObjectMeta{
Name: "test-sa",
Namespace: "test-namespace",
},
}
evt.SetData(cloudevents.ApplicationJSON, tokenRequest)
return &evt
}(),
expectedError: true,
expectedErrorText: "unsupported action",
},
{
name: "create token request successfully",
serviceAccounts: []runtime.Object{
&corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: "test-sa",
Namespace: "test-namespace",
},
},
},
tokenRequestEvt: func() *cloudevents.Event {
evt := types.NewEventBuilder("test", types.CloudEventsType{
CloudEventsDataType: sace.TokenRequestDataType,
SubResource: types.SubResourceSpec,
Action: types.CreateRequestAction,
}).NewEvent()
tokenRequest := &authenticationv1.TokenRequest{
ObjectMeta: metav1.ObjectMeta{
Name: "test-sa",
Namespace: "test-namespace",
},
Spec: authenticationv1.TokenRequestSpec{
Audiences: []string{"test-audience"},
},
}
tokenRequest.UID = "test-request-uid"
evt.SetData(cloudevents.ApplicationJSON, tokenRequest)
return &evt
}(),
validateActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "create")
if actions[0].GetSubresource() != "token" {
t.Errorf("expected subresource %s, got %s", "token", actions[0].GetSubresource())
}
},
validateHandler: func(t *testing.T, handler *mockEventHandler) {
if !handler.onCreateCalled {
t.Errorf("expected OnCreate to be called")
}
if handler.lastDataType != sace.TokenRequestDataType {
t.Errorf("expected data type %s, got %s", sace.TokenRequestDataType, handler.lastDataType)
}
},
},
{
name: "create token request with client error",
serviceAccounts: []runtime.Object{},
tokenRequestEvt: func() *cloudevents.Event {
evt := types.NewEventBuilder("test", types.CloudEventsType{
CloudEventsDataType: sace.TokenRequestDataType,
SubResource: types.SubResourceSpec,
Action: types.CreateRequestAction,
}).NewEvent()
tokenRequest := &authenticationv1.TokenRequest{
ObjectMeta: metav1.ObjectMeta{
Name: "test-sa",
Namespace: "test-namespace",
},
Spec: authenticationv1.TokenRequestSpec{
Audiences: []string{"test-audience"},
},
}
evt.SetData(cloudevents.ApplicationJSON, tokenRequest)
return &evt
}(),
reactorError: fmt.Errorf("simulated error"),
expectedError: true,
expectedErrorText: "simulated error",
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
kubeClient := kubefake.NewSimpleClientset(c.serviceAccounts...)
// Add reactor for error simulation
if c.reactorError != nil {
kubeClient.PrependReactor("create", "serviceaccounts", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, c.reactorError
})
}
service := NewTokenRequestService(kubeClient).(*TokenRequestService)
// Create and register a mock handler
mockHandler := &mockEventHandler{}
service.RegisterHandler(context.Background(), mockHandler)
err := service.HandleStatusUpdate(context.Background(), c.tokenRequestEvt)
if c.expectedError {
if err == nil {
t.Errorf("expected error, got nil")
return
}
if c.expectedErrorText != "" && !strings.HasPrefix(err.Error(), c.expectedErrorText) {
t.Errorf("expected error to start with %q, got %q", c.expectedErrorText, err.Error())
}
return
}
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
if c.validateActions != nil {
c.validateActions(t, kubeClient.Actions())
}
if c.validateHandler != nil {
c.validateHandler(t, mockHandler)
}
})
}
}
func TestRegisterHandler(t *testing.T) {
kubeClient := kubefake.NewSimpleClientset()
service := NewTokenRequestService(kubeClient).(*TokenRequestService)
mockHandler := &mockEventHandler{}
service.RegisterHandler(context.Background(), mockHandler)
if service.handler == nil {
t.Errorf("handler should not be nil after registration")
}
}
// mockEventHandler is a mock implementation of server.EventHandler for testing
type mockEventHandler struct {
onCreateCalled bool
onUpdateCalled bool
onDeleteCalled bool
lastDataType types.CloudEventsDataType
lastResourceID string
}
func (m *mockEventHandler) HandleEvent(ctx context.Context, evt *cloudevents.Event) error {
eventType, err := types.ParseCloudEventsType(evt.Type())
if err != nil {
return err
}
m.lastDataType = eventType.CloudEventsDataType
m.lastResourceID = evt.ID()
// Determine what kind of event it is based on the action type
switch eventType.Action {
case types.CreateRequestAction:
m.onCreateCalled = true
case types.UpdateRequestAction:
m.onUpdateCalled = true
case types.DeleteRequestAction:
m.onDeleteCalled = true
}
return nil
}