k8s.io/apiserver@v0.31.1/pkg/registry/generic/testing/tester.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tester
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"testing"
    23  
    24  	"k8s.io/apimachinery/pkg/api/errors"
    25  	"k8s.io/apimachinery/pkg/api/meta"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/fields"
    28  	"k8s.io/apimachinery/pkg/labels"
    29  	"k8s.io/apimachinery/pkg/runtime"
    30  	genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
    31  	"k8s.io/apiserver/pkg/registry/rest"
    32  	"k8s.io/apiserver/pkg/registry/rest/resttest"
    33  	storagetesting "k8s.io/apiserver/pkg/storage/testing"
    34  )
    35  
    36  type Tester struct {
    37  	tester  *resttest.Tester
    38  	storage *genericregistry.Store
    39  }
    40  type UpdateFunc func(runtime.Object) runtime.Object
    41  
    42  func New(t *testing.T, storage *genericregistry.Store) *Tester {
    43  	return &Tester{
    44  		tester:  resttest.New(t, storage),
    45  		storage: storage,
    46  	}
    47  }
    48  
    49  func (t *Tester) TestNamespace() string {
    50  	return t.tester.TestNamespace()
    51  }
    52  
    53  func (t *Tester) ClusterScope() *Tester {
    54  	t.tester = t.tester.ClusterScope()
    55  	return t
    56  }
    57  
    58  func (t *Tester) Namer(namer func(int) string) *Tester {
    59  	t.tester = t.tester.Namer(namer)
    60  	return t
    61  }
    62  
    63  func (t *Tester) AllowCreateOnUpdate() *Tester {
    64  	t.tester = t.tester.AllowCreateOnUpdate()
    65  	return t
    66  }
    67  
    68  func (t *Tester) GeneratesName() *Tester {
    69  	t.tester = t.tester.GeneratesName()
    70  	return t
    71  }
    72  
    73  func (t *Tester) ReturnDeletedObject() *Tester {
    74  	t.tester = t.tester.ReturnDeletedObject()
    75  	return t
    76  }
    77  
    78  func (t *Tester) TestCreate(valid runtime.Object, invalid ...runtime.Object) {
    79  	t.tester.TestCreate(
    80  		valid,
    81  		t.createObject,
    82  		t.getObject,
    83  		invalid...,
    84  	)
    85  }
    86  
    87  func (t *Tester) TestUpdate(valid runtime.Object, validUpdateFunc UpdateFunc, invalidUpdateFunc ...UpdateFunc) {
    88  	var invalidFuncs []resttest.UpdateFunc
    89  	for _, f := range invalidUpdateFunc {
    90  		invalidFuncs = append(invalidFuncs, resttest.UpdateFunc(f))
    91  	}
    92  	t.tester.TestUpdate(
    93  		valid,
    94  		t.createObject,
    95  		t.getObject,
    96  		resttest.UpdateFunc(validUpdateFunc),
    97  		invalidFuncs...,
    98  	)
    99  }
   100  
   101  func (t *Tester) TestDelete(valid runtime.Object) {
   102  	t.tester.TestDelete(
   103  		valid,
   104  		t.createObject,
   105  		t.getObject,
   106  		errors.IsNotFound,
   107  	)
   108  }
   109  
   110  func (t *Tester) TestDeleteGraceful(valid runtime.Object, expectedGrace int64) {
   111  	t.tester.TestDeleteGraceful(
   112  		valid,
   113  		t.createObject,
   114  		t.getObject,
   115  		expectedGrace,
   116  	)
   117  }
   118  
   119  func (t *Tester) TestGet(valid runtime.Object) {
   120  	t.tester.TestGet(valid)
   121  }
   122  
   123  func (t *Tester) TestList(valid runtime.Object) {
   124  	t.tester.TestList(
   125  		valid,
   126  		t.setObjectsForList,
   127  	)
   128  }
   129  
   130  func (t *Tester) TestWatch(valid runtime.Object, labelsPass, labelsFail []labels.Set, fieldsPass, fieldsFail []fields.Set) {
   131  	t.tester.TestWatch(
   132  		valid,
   133  		t.emitObject,
   134  		labelsPass,
   135  		labelsFail,
   136  		fieldsPass,
   137  		fieldsFail,
   138  		// TODO: This should be filtered, the registry should not be aware of this level of detail
   139  		[]string{"create", "delete"},
   140  	)
   141  }
   142  
   143  // Helper functions
   144  
   145  func (t *Tester) getObject(ctx context.Context, obj runtime.Object) (runtime.Object, error) {
   146  	accessor, err := meta.Accessor(obj)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	result, err := t.storage.Get(ctx, accessor.GetName(), &metav1.GetOptions{})
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	return result, nil
   156  }
   157  
   158  func (t *Tester) createObject(ctx context.Context, obj runtime.Object) error {
   159  	accessor, err := meta.Accessor(obj)
   160  	if err != nil {
   161  		return err
   162  	}
   163  	key, err := t.storage.KeyFunc(ctx, accessor.GetName())
   164  	if err != nil {
   165  		return err
   166  	}
   167  	return t.storage.Storage.Create(ctx, key, obj, nil, 0, false)
   168  }
   169  
   170  func (t *Tester) setObjectsForList(objects []runtime.Object) []runtime.Object {
   171  	key := t.storage.KeyRootFunc(t.tester.TestContext())
   172  	if _, err := t.storage.DeleteCollection(t.tester.TestContext(), rest.ValidateAllObjectFunc, nil, nil); err != nil {
   173  		t.tester.Errorf("unable to clear collection: %v", err)
   174  		return nil
   175  	}
   176  	if err := storagetesting.CreateObjList(key, t.storage.Storage.Storage, objects); err != nil {
   177  		t.tester.Errorf("unexpected error: %v", err)
   178  		return nil
   179  	}
   180  	return objects
   181  }
   182  
   183  func (t *Tester) emitObject(obj runtime.Object, action string) error {
   184  	ctx := t.tester.TestContext()
   185  	var err error
   186  
   187  	switch action {
   188  	case "create":
   189  		err = t.createObject(ctx, obj)
   190  	case "delete":
   191  		var accessor metav1.Object
   192  		accessor, err = meta.Accessor(obj)
   193  		if err != nil {
   194  			return err
   195  		}
   196  		_, _, err = t.storage.Delete(ctx, accessor.GetName(), rest.ValidateAllObjectFunc, nil)
   197  	default:
   198  		err = fmt.Errorf("unexpected action: %v", action)
   199  	}
   200  
   201  	return err
   202  }