mirror of
https://github.com/rancher/steve.git
synced 2025-06-30 00:32:07 +00:00
845 lines
21 KiB
Go
845 lines
21 KiB
Go
package proxy
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
schema2 "k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/client-go/dynamic"
|
|
|
|
"github.com/rancher/wrangler/v3/pkg/schemas/validation"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/assert"
|
|
"golang.org/x/sync/errgroup"
|
|
v1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
"k8s.io/apimachinery/pkg/watch"
|
|
"k8s.io/client-go/dynamic/fake"
|
|
"k8s.io/client-go/rest"
|
|
clientgotesting "k8s.io/client-go/testing"
|
|
|
|
"github.com/rancher/apiserver/pkg/apierror"
|
|
"github.com/rancher/apiserver/pkg/types"
|
|
"github.com/rancher/wrangler/v3/pkg/schemas"
|
|
|
|
"github.com/rancher/steve/pkg/client"
|
|
)
|
|
|
|
var c *watch.FakeWatcher
|
|
|
|
type testFactory struct {
|
|
*client.Factory
|
|
|
|
fakeClient *fake.FakeDynamicClient
|
|
}
|
|
|
|
func (t *testFactory) TableAdminClientForWatch(ctx *types.APIRequest, schema *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
|
|
return t.fakeClient.Resource(schema2.GroupVersionResource{}), nil
|
|
}
|
|
|
|
func (t *testFactory) TableClient(ctx *types.APIRequest, schema *types.APISchema, namespace string, warningHandler rest.WarningHandler) (dynamic.ResourceInterface, error) {
|
|
return t.fakeClient.Resource(schema2.GroupVersionResource{}).Namespace(namespace), nil
|
|
}
|
|
|
|
func TestWatchNamesErrReceive(t *testing.T) {
|
|
testClientFactory, err := client.NewFactory(&rest.Config{}, false)
|
|
assert.Nil(t, err)
|
|
|
|
fakeClient := fake.NewSimpleDynamicClient(runtime.NewScheme())
|
|
c = watch.NewFakeWithChanSize(5, true)
|
|
defer c.Stop()
|
|
errMsgsToSend := []string{"err1", "err2", "err3"}
|
|
c.Add(&v1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "testsecret1"}})
|
|
for index := range errMsgsToSend {
|
|
c.Error(&metav1.Status{
|
|
Message: errMsgsToSend[index],
|
|
})
|
|
}
|
|
c.Add(&v1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "testsecret2"}})
|
|
fakeClient.PrependWatchReactor("*", func(action clientgotesting.Action) (handled bool, ret watch.Interface, err error) {
|
|
return true, c, nil
|
|
})
|
|
testStore := Store{
|
|
clientGetter: &testFactory{Factory: testClientFactory,
|
|
fakeClient: fakeClient,
|
|
},
|
|
}
|
|
apiSchema := &types.APISchema{Schema: &schemas.Schema{Attributes: map[string]interface{}{"table": "something"}}}
|
|
wc, err := testStore.WatchNames(&types.APIRequest{Namespace: "", Schema: apiSchema, Request: &http.Request{}}, apiSchema, types.WatchRequest{}, sets.NewString("testsecret1", "testsecret2"))
|
|
assert.Nil(t, err)
|
|
|
|
eg := errgroup.Group{}
|
|
eg.Go(func() error { return receiveUntil(wc, 5*time.Second) })
|
|
|
|
err = eg.Wait()
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, 0, len(c.ResultChan()), "Expected all secrets to have been received")
|
|
}
|
|
|
|
func TestByNames(t *testing.T) {
|
|
s := Store{}
|
|
apiSchema := &types.APISchema{Schema: &schemas.Schema{}}
|
|
apiOp := &types.APIRequest{Namespace: "*", Schema: apiSchema, Request: &http.Request{}}
|
|
names := sets.NewString("some-resource", "some-other-resource")
|
|
result, warn, err := s.ByNames(apiOp, apiSchema, names)
|
|
assert.NotNil(t, result)
|
|
assert.Len(t, result.Items, 0)
|
|
assert.Nil(t, err)
|
|
assert.Nil(t, warn)
|
|
}
|
|
|
|
func receiveUntil(wc chan watch.Event, d time.Duration) error {
|
|
timer := time.NewTicker(d)
|
|
defer timer.Stop()
|
|
secretNames := []string{"testsecret1", "testsecret2"}
|
|
errMsgs := []string{"err1", "err2", "err3"}
|
|
for {
|
|
select {
|
|
case event, ok := <-wc:
|
|
if !ok {
|
|
return errors.New("watch chan should not have been closed")
|
|
}
|
|
|
|
if event.Type == watch.Error {
|
|
status, ok := event.Object.(*metav1.Status)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if strings.HasSuffix(status.Message, errMsgs[0]) {
|
|
errMsgs = errMsgs[1:]
|
|
}
|
|
}
|
|
secret, ok := event.Object.(*v1.Secret)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if secret.Name == secretNames[0] {
|
|
secretNames = secretNames[1:]
|
|
}
|
|
if len(secretNames) == 0 && len(errMsgs) == 0 {
|
|
return nil
|
|
}
|
|
continue
|
|
case <-timer.C:
|
|
return errors.New("timed out waiting to receiving objects from chan")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCreate(t *testing.T) {
|
|
type input struct {
|
|
apiOp *types.APIRequest
|
|
schema *types.APISchema
|
|
params types.APIObject
|
|
}
|
|
|
|
type expected struct {
|
|
value *unstructured.Unstructured
|
|
warning []types.Warning
|
|
err error
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
namespace string
|
|
input input
|
|
expected expected
|
|
createReactorFunc clientgotesting.ReactionFunc
|
|
}{
|
|
{
|
|
name: "creating resource - namespace scoped",
|
|
input: input{
|
|
apiOp: &types.APIRequest{
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Request: &http.Request{URL: &url.URL{}},
|
|
},
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v1",
|
|
"kind": "Secret",
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
createReactorFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return false, ret, nil
|
|
},
|
|
expected: expected{
|
|
value: &unstructured.Unstructured{Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
},
|
|
}},
|
|
warning: []types.Warning{},
|
|
err: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "creating resource - cluster scoped",
|
|
input: input{
|
|
apiOp: &types.APIRequest{
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Request: &http.Request{URL: &url.URL{}},
|
|
},
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v1",
|
|
"kind": "Secret",
|
|
"namespaced": false,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
createReactorFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return false, ret, nil
|
|
},
|
|
expected: expected{
|
|
value: &unstructured.Unstructured{Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
},
|
|
}},
|
|
warning: []types.Warning{},
|
|
err: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "missing name",
|
|
input: input{
|
|
apiOp: &types.APIRequest{
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Request: &http.Request{URL: &url.URL{}},
|
|
},
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v1",
|
|
"kind": "Secret",
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"namespace": "testing-ns",
|
|
"generateName": "testing-gen-name",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
createReactorFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return false, ret, nil
|
|
},
|
|
expected: expected{
|
|
value: &unstructured.Unstructured{Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"generateName": "testing-gen-name",
|
|
"namespace": "testing-ns",
|
|
},
|
|
}},
|
|
warning: []types.Warning{},
|
|
err: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "missing name / generateName",
|
|
input: input{
|
|
apiOp: &types.APIRequest{
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Request: &http.Request{URL: &url.URL{}},
|
|
},
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v1",
|
|
"kind": "Secret",
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"namespace": "testing-ns",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
createReactorFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return false, ret, nil
|
|
},
|
|
expected: expected{
|
|
value: &unstructured.Unstructured{Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"generateName": "t-",
|
|
"namespace": "testing-ns",
|
|
},
|
|
}},
|
|
warning: []types.Warning{},
|
|
err: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "missing namespace in the params (should copy from apiOp)",
|
|
input: input{
|
|
apiOp: &types.APIRequest{
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Namespace: "testing-ns",
|
|
Request: &http.Request{URL: &url.URL{}},
|
|
},
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v1",
|
|
"kind": "Secret",
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
createReactorFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return false, ret, nil
|
|
},
|
|
expected: expected{
|
|
value: &unstructured.Unstructured{Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
},
|
|
}},
|
|
warning: []types.Warning{},
|
|
err: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "missing namespace - namespace scoped",
|
|
input: input{
|
|
apiOp: &types.APIRequest{
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Request: &http.Request{URL: &url.URL{}},
|
|
},
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{},
|
|
},
|
|
expected: expected{
|
|
value: nil,
|
|
warning: nil,
|
|
err: apierror.NewAPIError(
|
|
validation.InvalidBodyContent,
|
|
errNamespaceRequired,
|
|
),
|
|
},
|
|
},
|
|
{
|
|
name: "error response",
|
|
input: input{
|
|
apiOp: &types.APIRequest{
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Request: &http.Request{URL: &url.URL{}},
|
|
},
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v1",
|
|
"kind": "Secret",
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
createReactorFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return true, nil, apierrors.NewUnauthorized("sample reason")
|
|
},
|
|
expected: expected{
|
|
value: nil,
|
|
warning: []types.Warning{},
|
|
err: apierrors.NewUnauthorized("sample reason"),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range testCases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
testClientFactory, err := client.NewFactory(&rest.Config{}, false)
|
|
assert.NoError(t, err)
|
|
|
|
fakeClient := fake.NewSimpleDynamicClient(runtime.NewScheme())
|
|
|
|
if tt.createReactorFunc != nil {
|
|
fakeClient.PrependReactor("create", "*", tt.createReactorFunc)
|
|
}
|
|
|
|
testStore := Store{
|
|
clientGetter: &testFactory{Factory: testClientFactory,
|
|
fakeClient: fakeClient,
|
|
},
|
|
}
|
|
|
|
value, warning, err := testStore.Create(tt.input.apiOp, tt.input.schema, tt.input.params)
|
|
|
|
assert.Equal(t, tt.expected.value, value)
|
|
assert.Equal(t, tt.expected.warning, warning)
|
|
assert.Equal(t, tt.expected.err, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdate(t *testing.T) {
|
|
type input struct {
|
|
apiOp *types.APIRequest
|
|
schema *types.APISchema
|
|
params types.APIObject
|
|
id string
|
|
}
|
|
|
|
type expected struct {
|
|
value *unstructured.Unstructured
|
|
warning []types.Warning
|
|
err error
|
|
}
|
|
|
|
sampleCreateInput := input{
|
|
apiOp: &types.APIRequest{
|
|
Request: &http.Request{
|
|
URL: &url.URL{},
|
|
Method: http.MethodPost,
|
|
},
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Method: http.MethodPost,
|
|
},
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"kind": "Secret",
|
|
"version": "v1",
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"kind": "Secret",
|
|
"apiVersion": "v1",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
"resourceVersion": "1",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
updateCallbackFunc clientgotesting.ReactionFunc
|
|
createInput *input
|
|
updateInput input
|
|
expected expected
|
|
}{
|
|
{
|
|
name: "update - usual request",
|
|
updateCallbackFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return false, ret, nil
|
|
},
|
|
createInput: &sampleCreateInput,
|
|
updateInput: input{
|
|
apiOp: &types.APIRequest{
|
|
Request: &http.Request{
|
|
URL: &url.URL{},
|
|
Method: http.MethodPut,
|
|
},
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Method: http.MethodPut,
|
|
},
|
|
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v2",
|
|
"kind": "Secret",
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v2",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
"resourceVersion": "1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: expected{
|
|
value: &unstructured.Unstructured{Object: map[string]interface{}{
|
|
"apiVersion": "v2",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
"resourceVersion": "1",
|
|
},
|
|
}},
|
|
warning: []types.Warning{},
|
|
err: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "update - different apiVersion and kind (params and schema) - should copy from schema",
|
|
updateCallbackFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return false, ret, nil
|
|
},
|
|
createInput: &sampleCreateInput,
|
|
updateInput: input{
|
|
apiOp: &types.APIRequest{
|
|
Request: &http.Request{
|
|
URL: &url.URL{},
|
|
Method: http.MethodPut,
|
|
},
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Method: http.MethodPut,
|
|
},
|
|
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v2",
|
|
"kind": "Secret",
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "ConfigMap",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
"resourceVersion": "1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: expected{
|
|
value: &unstructured.Unstructured{Object: map[string]interface{}{
|
|
"apiVersion": "v2",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
"resourceVersion": "1",
|
|
},
|
|
}},
|
|
warning: []types.Warning{},
|
|
err: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "update - missing apiVersion and kind in params - should copy from schema",
|
|
updateCallbackFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return false, ret, nil
|
|
},
|
|
createInput: &sampleCreateInput,
|
|
updateInput: input{
|
|
apiOp: &types.APIRequest{
|
|
Request: &http.Request{
|
|
URL: &url.URL{},
|
|
Method: http.MethodPost,
|
|
},
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Method: http.MethodPost,
|
|
},
|
|
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v2",
|
|
"kind": "Secret",
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
"resourceVersion": "1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: expected{
|
|
value: &unstructured.Unstructured{Object: map[string]interface{}{
|
|
"apiVersion": "v2",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
"resourceVersion": "1",
|
|
},
|
|
}},
|
|
warning: []types.Warning{},
|
|
err: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "update - missing resource version",
|
|
updateCallbackFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return false, ret, nil
|
|
},
|
|
updateInput: input{
|
|
apiOp: &types.APIRequest{
|
|
Request: &http.Request{
|
|
URL: &url.URL{},
|
|
Method: http.MethodPut,
|
|
},
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Method: http.MethodPut,
|
|
},
|
|
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"version": "v1",
|
|
"kind": "Secret",
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "Secret",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: expected{
|
|
value: nil,
|
|
warning: nil,
|
|
err: errors.New(errResourceVersionRequired),
|
|
},
|
|
},
|
|
{
|
|
name: "update - error request",
|
|
updateCallbackFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) {
|
|
return true, nil, apierrors.NewUnauthorized("sample reason")
|
|
},
|
|
createInput: &sampleCreateInput,
|
|
updateInput: input{
|
|
apiOp: &types.APIRequest{
|
|
Request: &http.Request{
|
|
URL: &url.URL{},
|
|
Method: http.MethodPut,
|
|
},
|
|
Schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
},
|
|
},
|
|
Method: http.MethodPut,
|
|
},
|
|
|
|
schema: &types.APISchema{
|
|
Schema: &schemas.Schema{
|
|
ID: "testing",
|
|
Attributes: map[string]interface{}{
|
|
"kind": "Secret",
|
|
"namespaced": true,
|
|
},
|
|
},
|
|
},
|
|
params: types.APIObject{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "v2",
|
|
"metadata": map[string]interface{}{
|
|
"name": "testing-secret",
|
|
"namespace": "testing-ns",
|
|
"resourceVersion": "1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: expected{
|
|
value: nil,
|
|
warning: nil,
|
|
err: apierrors.NewUnauthorized("sample reason"),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range testCases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
testClientFactory, err := client.NewFactory(&rest.Config{}, false)
|
|
assert.NoError(t, err)
|
|
|
|
fakeClient := fake.NewSimpleDynamicClient(runtime.NewScheme())
|
|
|
|
if tt.updateCallbackFunc != nil {
|
|
fakeClient.PrependReactor("update", "*", tt.updateCallbackFunc)
|
|
}
|
|
|
|
testStore := Store{
|
|
clientGetter: &testFactory{Factory: testClientFactory,
|
|
fakeClient: fakeClient,
|
|
},
|
|
}
|
|
|
|
// Creating the object first, so we can update it later (this function is not the SUT)
|
|
if tt.createInput != nil {
|
|
_, _, err = testStore.Create(tt.createInput.apiOp, tt.createInput.schema, tt.createInput.params)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
value, warning, err := testStore.Update(tt.updateInput.apiOp, tt.updateInput.schema, tt.updateInput.params, tt.updateInput.id)
|
|
|
|
assert.Equal(t, tt.expected.value, value)
|
|
assert.Equal(t, tt.expected.warning, warning)
|
|
|
|
if tt.expected.err != nil {
|
|
assert.Equal(t, tt.expected.err.Error(), err.Error())
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|