istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/kube/kclient/clienttest/test_helpers.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package clienttest
    16  
    17  import (
    18  	klabels "k8s.io/apimachinery/pkg/labels"
    19  
    20  	"istio.io/istio/pkg/kube/controllers"
    21  	"istio.io/istio/pkg/kube/kclient"
    22  	"istio.io/istio/pkg/slices"
    23  	"istio.io/istio/pkg/test"
    24  	"istio.io/istio/pkg/test/util/assert"
    25  	"istio.io/istio/pkg/util/sets"
    26  )
    27  
    28  type TestClient[T controllers.Object] struct {
    29  	c kclient.ReadWriter[T]
    30  	t test.Failer
    31  	TestWriter[T]
    32  }
    33  
    34  type TestWriter[T controllers.Object] struct {
    35  	c kclient.Writer[T]
    36  	t test.Failer
    37  }
    38  
    39  func (t TestClient[T]) Get(name, namespace string) T {
    40  	return t.c.Get(name, namespace)
    41  }
    42  
    43  func (t TestClient[T]) List(namespace string, selector klabels.Selector) []T {
    44  	return t.c.List(namespace, selector)
    45  }
    46  
    47  func (t TestWriter[T]) Create(object T) T {
    48  	t.t.Helper()
    49  	res, err := t.c.Create(object)
    50  	if err != nil {
    51  		t.t.Fatalf("create %v/%v: %v", object.GetNamespace(), object.GetName(), err)
    52  	}
    53  	return res
    54  }
    55  
    56  func (t TestWriter[T]) Update(object T) T {
    57  	t.t.Helper()
    58  	res, err := t.c.Update(object)
    59  	if err != nil {
    60  		t.t.Fatalf("update %v/%v: %v", object.GetNamespace(), object.GetName(), err)
    61  	}
    62  	return res
    63  }
    64  
    65  func (t TestWriter[T]) UpdateStatus(object T) T {
    66  	t.t.Helper()
    67  	res, err := t.c.UpdateStatus(object)
    68  	if err != nil {
    69  		t.t.Fatalf("update status %v/%v: %v", object.GetNamespace(), object.GetName(), err)
    70  	}
    71  	return res
    72  }
    73  
    74  func (t TestWriter[T]) CreateOrUpdate(object T) T {
    75  	t.t.Helper()
    76  	res, err := kclient.CreateOrUpdate[T](t.c, object)
    77  	if err != nil {
    78  		t.t.Fatalf("createOrUpdate %v/%v: %v", object.GetNamespace(), object.GetName(), err)
    79  	}
    80  	return res
    81  }
    82  
    83  func (t TestWriter[T]) CreateOrUpdateStatus(object T) T {
    84  	t.t.Helper()
    85  	_, err := kclient.CreateOrUpdate(t.c, object)
    86  	if err != nil {
    87  		t.t.Fatalf("createOrUpdate %v/%v: %v", object.GetNamespace(), object.GetName(), err)
    88  	}
    89  	return t.UpdateStatus(object)
    90  }
    91  
    92  func (t TestWriter[T]) Delete(name, namespace string) {
    93  	t.t.Helper()
    94  	err := t.c.Delete(name, namespace)
    95  	if err != nil {
    96  		t.t.Fatalf("delete %v/%v: %v", namespace, name, err)
    97  	}
    98  }
    99  
   100  // WrapReadWriter returns a client that calls t.Fatal on errors.
   101  // Reads may be cached or uncached, depending on the input client.
   102  func WrapReadWriter[T controllers.Object](t test.Failer, c kclient.ReadWriter[T]) TestClient[T] {
   103  	return TestClient[T]{
   104  		c: c,
   105  		t: t,
   106  		TestWriter: TestWriter[T]{
   107  			c: c,
   108  			t: t,
   109  		},
   110  	}
   111  }
   112  
   113  // Wrap returns a client that calls t.Fatal on errors.
   114  // Reads may be cached or uncached, depending on the input client.
   115  // Note: this is identical to WrapReadWriter but works around Go limitations, allowing calling w/o specifying
   116  // generic parameters in the common case.
   117  func Wrap[T controllers.Object](t test.Failer, c kclient.Client[T]) TestClient[T] {
   118  	return WrapReadWriter[T](t, c)
   119  }
   120  
   121  // TrackerHandler returns an object handler that records each event
   122  func TrackerHandler(tracker *assert.Tracker[string]) controllers.EventHandler[controllers.Object] {
   123  	return controllers.EventHandler[controllers.Object]{
   124  		AddFunc: func(obj controllers.Object) {
   125  			tracker.Record("add/" + obj.GetName())
   126  		},
   127  		UpdateFunc: func(oldObj, newObj controllers.Object) {
   128  			tracker.Record("update/" + newObj.GetName())
   129  		},
   130  		DeleteFunc: func(obj controllers.Object) {
   131  			tracker.Record("delete/" + obj.GetName())
   132  		},
   133  	}
   134  }
   135  
   136  func Names[T controllers.Object](list []T) sets.String {
   137  	return sets.New(slices.Map(list, func(a T) string { return a.GetName() })...)
   138  }