mirror of
https://github.com/rancher/steve.git
synced 2025-08-31 06:46:25 +00:00
added delegate error / improve delegate coverage / add new mocks
This commit is contained in:
@@ -239,20 +239,22 @@ func InstallStore[T runtime.Object, TList runtime.Object](
|
||||
apiGroup.VersionedResourcesStorageMap[gvk.Version] = make(map[string]rest.Storage)
|
||||
}
|
||||
|
||||
delegate := &delegate[T, TList]{
|
||||
scheme: s.scheme,
|
||||
delegate := &delegateError[T, TList]{
|
||||
inner: &delegate[T, TList]{
|
||||
scheme: s.scheme,
|
||||
|
||||
t: t,
|
||||
tList: tList,
|
||||
singularName: singularName,
|
||||
gvk: gvk,
|
||||
gvr: schema.GroupVersionResource{
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Resource: resourceName,
|
||||
t: t,
|
||||
tList: tList,
|
||||
singularName: singularName,
|
||||
gvk: gvk,
|
||||
gvr: schema.GroupVersionResource{
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Resource: resourceName,
|
||||
},
|
||||
authorizer: s.authorizer,
|
||||
store: store,
|
||||
},
|
||||
authorizer: s.authorizer,
|
||||
store: store,
|
||||
}
|
||||
|
||||
apiGroup.VersionedResourcesStorageMap[gvk.Version][resourceName] = delegate
|
||||
|
@@ -2,6 +2,7 @@ package ext
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
@@ -16,6 +17,10 @@ import (
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
)
|
||||
|
||||
var (
|
||||
errMissingUserInfo error = errors.New("missing user info")
|
||||
)
|
||||
|
||||
// delegate is the bridge between k8s.io/apiserver's [rest.Storage] interface and
|
||||
// our own Store interface we want developers to use
|
||||
//
|
||||
@@ -328,7 +333,7 @@ func (s *delegate[T, TList]) GetSingularName() string {
|
||||
func (s *delegate[T, TList]) makeContext(parentCtx context.Context) (Context, error) {
|
||||
userInfo, ok := request.UserFrom(parentCtx)
|
||||
if !ok {
|
||||
return Context{}, fmt.Errorf("missing user info")
|
||||
return Context{}, errMissingUserInfo
|
||||
}
|
||||
|
||||
ctx := Context{
|
||||
|
110
pkg/ext/delegate_error.go
Normal file
110
pkg/ext/delegate_error.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package ext
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
)
|
||||
|
||||
// delegateError wraps an inner delegate and converts unknown errors.
|
||||
type delegateError[T runtime.Object, TList runtime.Object] struct {
|
||||
inner *delegate[T, TList]
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) convertError(err error) error {
|
||||
if _, ok := err.(errors.APIStatus); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.NewInternalError(err)
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) New() runtime.Object {
|
||||
return d.inner.New()
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) Destroy() {
|
||||
d.inner.Destroy()
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) NewList() runtime.Object {
|
||||
return d.inner.NewList()
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) List(parentCtx context.Context, internaloptions *metainternalversion.ListOptions) (runtime.Object, error) {
|
||||
result, err := d.inner.List(parentCtx, internaloptions)
|
||||
if err != nil {
|
||||
return nil, d.convertError(err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
|
||||
result, err := d.inner.ConvertToTable(ctx, object, tableOptions)
|
||||
if err != nil {
|
||||
return nil, d.convertError(err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) Get(parentCtx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||
result, err := d.inner.Get(parentCtx, name, options)
|
||||
if err != nil {
|
||||
return nil, d.convertError(err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) Delete(parentCtx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
|
||||
result, completed, err := d.inner.Delete(parentCtx, name, deleteValidation, options)
|
||||
if err != nil {
|
||||
return nil, false, d.convertError(err)
|
||||
}
|
||||
return result, completed, nil
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) Create(parentCtx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
|
||||
result, err := d.inner.Create(parentCtx, obj, createValidation, options)
|
||||
if err != nil {
|
||||
return nil, d.convertError(err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) Update(parentCtx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
|
||||
result, created, err := d.inner.Update(parentCtx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options)
|
||||
if err != nil {
|
||||
return nil, false, d.convertError(err)
|
||||
}
|
||||
return result, created, nil
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) Watch(parentCtx context.Context, internaloptions *metainternalversion.ListOptions) (watch.Interface, error) {
|
||||
result, err := d.inner.Watch(parentCtx, internaloptions)
|
||||
if err != nil {
|
||||
return nil, d.convertError(err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) GroupVersionKind(groupVersion schema.GroupVersion) schema.GroupVersionKind {
|
||||
return d.inner.GroupVersionKind(groupVersion)
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) NamespaceScoped() bool {
|
||||
return d.inner.NamespaceScoped()
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) Kind() string {
|
||||
return d.inner.Kind()
|
||||
}
|
||||
|
||||
func (d *delegateError[T, TList]) GetSingularName() string {
|
||||
return d.inner.GetSingularName()
|
||||
}
|
60
pkg/ext/delegate_error_test.go
Normal file
60
pkg/ext/delegate_error_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package ext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestDelegateError_convertError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input error
|
||||
output error
|
||||
}{
|
||||
{
|
||||
name: "api status error",
|
||||
input: &apierrors.StatusError{
|
||||
ErrStatus: metav1.Status{
|
||||
Code: http.StatusNotFound,
|
||||
Reason: metav1.StatusReasonNotFound,
|
||||
},
|
||||
},
|
||||
output: &apierrors.StatusError{
|
||||
ErrStatus: metav1.Status{
|
||||
Code: http.StatusNotFound,
|
||||
Reason: metav1.StatusReasonNotFound,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "generic error",
|
||||
input: assert.AnError,
|
||||
output: &apierrors.StatusError{ErrStatus: metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusInternalServerError,
|
||||
Reason: metav1.StatusReasonInternalError,
|
||||
Details: &metav1.StatusDetails{
|
||||
Causes: []metav1.StatusCause{{Message: assert.AnError.Error()}},
|
||||
},
|
||||
Message: fmt.Sprintf("Internal error occurred: %v", assert.AnError),
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
delegateError := delegateError[*TestType, *TestTypeList]{
|
||||
inner: &delegate[*TestType, *TestTypeList]{},
|
||||
}
|
||||
|
||||
output := delegateError.convertError(tt.input)
|
||||
assert.Equal(t, tt.output, output)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
1012
pkg/ext/delegate_test.go
Normal file
1012
pkg/ext/delegate_test.go
Normal file
File diff suppressed because it is too large
Load Diff
66
pkg/ext/rest_mock.go
Normal file
66
pkg/ext/rest_mock.go
Normal file
@@ -0,0 +1,66 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
|
||||
// Package ext is a generated GoMock package.
|
||||
package ext
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// MockUpdatedObjectInfo is a mock of UpdatedObjectInfo interface.
|
||||
type MockUpdatedObjectInfo struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockUpdatedObjectInfoMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockUpdatedObjectInfoMockRecorder is the mock recorder for MockUpdatedObjectInfo.
|
||||
type MockUpdatedObjectInfoMockRecorder struct {
|
||||
mock *MockUpdatedObjectInfo
|
||||
}
|
||||
|
||||
// NewMockUpdatedObjectInfo creates a new mock instance.
|
||||
func NewMockUpdatedObjectInfo(ctrl *gomock.Controller) *MockUpdatedObjectInfo {
|
||||
mock := &MockUpdatedObjectInfo{ctrl: ctrl}
|
||||
mock.recorder = &MockUpdatedObjectInfoMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockUpdatedObjectInfo) EXPECT() *MockUpdatedObjectInfoMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Preconditions mocks base method.
|
||||
func (m *MockUpdatedObjectInfo) Preconditions() *v1.Preconditions {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Preconditions")
|
||||
ret0, _ := ret[0].(*v1.Preconditions)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Preconditions indicates an expected call of Preconditions.
|
||||
func (mr *MockUpdatedObjectInfoMockRecorder) Preconditions() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Preconditions", reflect.TypeOf((*MockUpdatedObjectInfo)(nil).Preconditions))
|
||||
}
|
||||
|
||||
// UpdatedObject mocks base method.
|
||||
func (m *MockUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj runtime.Object) (runtime.Object, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdatedObject", ctx, oldObj)
|
||||
ret0, _ := ret[0].(runtime.Object)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpdatedObject indicates an expected call of UpdatedObject.
|
||||
func (mr *MockUpdatedObjectInfoMockRecorder) UpdatedObject(ctx, oldObj any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatedObject", reflect.TypeOf((*MockUpdatedObjectInfo)(nil).UpdatedObject), ctx, oldObj)
|
||||
}
|
131
pkg/ext/store_mock.go
Normal file
131
pkg/ext/store_mock.go
Normal file
@@ -0,0 +1,131 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: ./pkg/ext/store.go
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -source=./pkg/ext/store.go -destination=./pkg/ext/store_mock.go -package=ext
|
||||
//
|
||||
|
||||
// Package ext is a generated GoMock package.
|
||||
package ext
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// MockStore is a mock of Store interface.
|
||||
type MockStore[T runtime.Object, TList runtime.Object] struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockStoreMockRecorder[T, TList]
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockStoreMockRecorder is the mock recorder for MockStore.
|
||||
type MockStoreMockRecorder[T runtime.Object, TList runtime.Object] struct {
|
||||
mock *MockStore[T, TList]
|
||||
}
|
||||
|
||||
// NewMockStore creates a new mock instance.
|
||||
func NewMockStore[T runtime.Object, TList runtime.Object](ctrl *gomock.Controller) *MockStore[T, TList] {
|
||||
mock := &MockStore[T, TList]{ctrl: ctrl}
|
||||
mock.recorder = &MockStoreMockRecorder[T, TList]{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockStore[T, TList]) EXPECT() *MockStoreMockRecorder[T, TList] {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Create mocks base method.
|
||||
func (m *MockStore[T, TList]) Create(ctx Context, obj T, opts *v1.CreateOptions) (T, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Create", ctx, obj, opts)
|
||||
ret0, _ := ret[0].(T)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Create indicates an expected call of Create.
|
||||
func (mr *MockStoreMockRecorder[T, TList]) Create(ctx, obj, opts any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockStore[T, TList])(nil).Create), ctx, obj, opts)
|
||||
}
|
||||
|
||||
// Delete mocks base method.
|
||||
func (m *MockStore[T, TList]) Delete(ctx Context, name string, opts *v1.DeleteOptions) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Delete", ctx, name, opts)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Delete indicates an expected call of Delete.
|
||||
func (mr *MockStoreMockRecorder[T, TList]) Delete(ctx, name, opts any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockStore[T, TList])(nil).Delete), ctx, name, opts)
|
||||
}
|
||||
|
||||
// Get mocks base method.
|
||||
func (m *MockStore[T, TList]) Get(ctx Context, name string, opts *v1.GetOptions) (T, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Get", ctx, name, opts)
|
||||
ret0, _ := ret[0].(T)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Get indicates an expected call of Get.
|
||||
func (mr *MockStoreMockRecorder[T, TList]) Get(ctx, name, opts any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockStore[T, TList])(nil).Get), ctx, name, opts)
|
||||
}
|
||||
|
||||
// List mocks base method.
|
||||
func (m *MockStore[T, TList]) List(ctx Context, opts *v1.ListOptions) (TList, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "List", ctx, opts)
|
||||
ret0, _ := ret[0].(TList)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// List indicates an expected call of List.
|
||||
func (mr *MockStoreMockRecorder[T, TList]) List(ctx, opts any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockStore[T, TList])(nil).List), ctx, opts)
|
||||
}
|
||||
|
||||
// Update mocks base method.
|
||||
func (m *MockStore[T, TList]) Update(ctx Context, obj T, opts *v1.UpdateOptions) (T, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Update", ctx, obj, opts)
|
||||
ret0, _ := ret[0].(T)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Update indicates an expected call of Update.
|
||||
func (mr *MockStoreMockRecorder[T, TList]) Update(ctx, obj, opts any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockStore[T, TList])(nil).Update), ctx, obj, opts)
|
||||
}
|
||||
|
||||
// Watch mocks base method.
|
||||
func (m *MockStore[T, TList]) Watch(ctx Context, opts *v1.ListOptions) (<-chan WatchEvent[T], error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Watch", ctx, opts)
|
||||
ret0, _ := ret[0].(<-chan WatchEvent[T])
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Watch indicates an expected call of Watch.
|
||||
func (mr *MockStoreMockRecorder[T, TList]) Watch(ctx, opts any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Watch", reflect.TypeOf((*MockStore[T, TList])(nil).Watch), ctx, opts)
|
||||
}
|
Reference in New Issue
Block a user