~/snippets/go-mock-k8s-controller-runtime-client
Published on

Mock controller-runtime client

1483 words8 min read

Note: It is purposefully not complete

package client

import (
	"context"
	"reflect"

	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type ListResponse struct {
	ObjectList client.ObjectList
	Error      error
}

type GetResponse struct {
	Object client.Object
	Error  error
}

type UpdateParamaters struct {
	Object client.Object
}

type ParameterCapture struct {
	UpdateParamaters UpdateParamaters
}

type MockClientOption func(*MockClient)

type MockClient struct {
	getResponse         GetResponse
	listResponse        ListResponse
	createResponse      error
	deleteResponse      error
	updateResponse      error
	patchResponse       error
	deleteAllOfResponse error
	statusResponse      *MockStatusWriter
	schemeResponse      *runtime.Scheme
	restMapperResponse  meta.RESTMapper

	parameterCapture ParameterCapture
}

func WithGetResponse(gr GetResponse) MockClientOption {
	return func(mc *MockClient) {
		mc.getResponse = gr
	}
}

func WithListResponse(lr ListResponse) MockClientOption {
	return func(mc *MockClient) {
		mc.listResponse = lr
	}
}

func WithCreateResponse(err error) MockClientOption {
	return func(mc *MockClient) {
		mc.createResponse = err
	}
}

func WithDeleteResponse(err error) MockClientOption {
	return func(mc *MockClient) {
		mc.deleteResponse = err
	}
}

func WithUpdateResponse(err error) MockClientOption {
	return func(mc *MockClient) {
		mc.updateResponse = err
	}
}

func WithPatchResponse(err error) MockClientOption {
	return func(mc *MockClient) {
		mc.patchResponse = err
	}
}

func WithDeleteAllOfResourceResponse(err error) MockClientOption {
	return func(mc *MockClient) {
		mc.deleteAllOfResponse = err
	}
}

func WithStatusResponse(msw *MockStatusWriter) MockClientOption {
	return func(mc *MockClient) {
		mc.statusResponse = msw
	}
}

func WithSchemeResponse(sr *runtime.Scheme) MockClientOption {
	return func(mc *MockClient) {
		mc.schemeResponse = sr
	}
}

func WithRestMapperResponse(rm meta.RESTMapper) MockClientOption {
	return func(mc *MockClient) {
		mc.restMapperResponse = rm
	}
}

func (c *MockClient) GetParameterCapture() ParameterCapture {
	return c.parameterCapture
}

func (c *MockClient) GetStatusResponse() *MockStatusWriter {
	return c.statusResponse
}

func NewMockClient(opts ...MockClientOption) *MockClient {
	c := &MockClient{}

	for _, opt := range opts {
		opt(c)
	}

	return c
}

func (m *MockClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
	v := reflect.ValueOf(obj).Elem()
	if reflect.ValueOf(m.getResponse.Object).Kind() == reflect.Pointer {
		v.Set(reflect.ValueOf(m.getResponse.Object).Elem())
	} else {
		v.Set(reflect.ValueOf(m.getResponse.Object))
	}

	return m.getResponse.Error
}

func (m *MockClient) List(ctx context.Context, ol client.ObjectList, opts ...client.ListOption) error {
	v := reflect.ValueOf(ol).Elem()
	if reflect.ValueOf(m.listResponse.ObjectList).Kind() == reflect.Pointer {
		v.Set(reflect.ValueOf(m.listResponse.ObjectList).Elem())
	} else {
		v.Set(reflect.ValueOf(m.listResponse.ObjectList))
	}

	return m.listResponse.Error
}

func (m *MockClient) Create(context.Context, client.Object, ...client.CreateOption) error {
	return m.createResponse
}

func (m *MockClient) Delete(context.Context, client.Object, ...client.DeleteOption) error {
	return m.deleteResponse
}

func (m *MockClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
	m.parameterCapture.UpdateParamaters = UpdateParamaters{Object: obj}

	return m.updateResponse
}

func (m *MockClient) Patch(context.Context, client.Object, client.Patch, ...client.PatchOption) error {
	return m.patchResponse
}

func (m *MockClient) DeleteAllOf(context.Context, client.Object, ...client.DeleteAllOfOption) error {
	return m.deleteAllOfResponse
}

func (m *MockClient) Status() client.StatusWriter {
	return m.statusResponse
}

func (m *MockClient) Scheme() *runtime.Scheme {
	return m.schemeResponse
}

func (m *MockClient) RESTMapper() meta.RESTMapper {
	return m.restMapperResponse
}

type MockStatusWriterOption func(*MockStatusWriter)

type MockStatusWriter struct {
	updateResponse error
	patchResponse  error

	parameterCapture ParameterCapture
}

func NewMockStatusWriter(opts ...MockStatusWriterOption) *MockStatusWriter {
	c := &MockStatusWriter{}

	for _, opt := range opts {
		opt(c)
	}

	return c
}

func (m *MockStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
	m.parameterCapture.UpdateParamaters = UpdateParamaters{Object: obj}

	return m.updateResponse
}

func (m *MockStatusWriter) Patch(context.Context, client.Object, client.Patch, ...client.PatchOption) error {
	return m.patchResponse
}

func (m *MockStatusWriter) GetParameterCapture() ParameterCapture {
	return m.parameterCapture
}