...

Source file src/sigs.k8s.io/controller-runtime/pkg/client/client_test.go

Documentation: sigs.k8s.io/controller-runtime/pkg/client

     1  /*
     2  Copyright 2018 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 client_test
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"reflect"
    25  	"sync/atomic"
    26  	"time"
    27  
    28  	. "github.com/onsi/ginkgo/v2"
    29  	. "github.com/onsi/gomega"
    30  	appsv1 "k8s.io/api/apps/v1"
    31  	authenticationv1 "k8s.io/api/authentication/v1"
    32  	autoscalingv1 "k8s.io/api/autoscaling/v1"
    33  	certificatesv1 "k8s.io/api/certificates/v1"
    34  	corev1 "k8s.io/api/core/v1"
    35  	policyv1 "k8s.io/api/policy/v1"
    36  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    37  	"k8s.io/apimachinery/pkg/api/meta"
    38  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    39  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    40  	"k8s.io/apimachinery/pkg/runtime"
    41  	"k8s.io/apimachinery/pkg/runtime/schema"
    42  	"k8s.io/apimachinery/pkg/types"
    43  	kscheme "k8s.io/client-go/kubernetes/scheme"
    44  	"k8s.io/utils/ptr"
    45  
    46  	"sigs.k8s.io/controller-runtime/examples/crd/pkg"
    47  	"sigs.k8s.io/controller-runtime/pkg/cache"
    48  	"sigs.k8s.io/controller-runtime/pkg/client"
    49  )
    50  
    51  func deleteDeployment(ctx context.Context, dep *appsv1.Deployment, ns string) {
    52  	_, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
    53  	if err == nil {
    54  		err = clientset.AppsV1().Deployments(ns).Delete(ctx, dep.Name, metav1.DeleteOptions{})
    55  		Expect(err).NotTo(HaveOccurred())
    56  	}
    57  }
    58  
    59  func deleteNamespace(ctx context.Context, ns *corev1.Namespace) {
    60  	ns, err := clientset.CoreV1().Namespaces().Get(ctx, ns.Name, metav1.GetOptions{})
    61  	if err != nil {
    62  		return
    63  	}
    64  
    65  	err = clientset.CoreV1().Namespaces().Delete(ctx, ns.Name, metav1.DeleteOptions{})
    66  	Expect(err).NotTo(HaveOccurred())
    67  
    68  	// finalize if necessary
    69  	pos := -1
    70  	finalizers := ns.Spec.Finalizers
    71  	for i, fin := range finalizers {
    72  		if fin == "kubernetes" {
    73  			pos = i
    74  			break
    75  		}
    76  	}
    77  	if pos == -1 {
    78  		// no need to finalize
    79  		return
    80  	}
    81  
    82  	// re-get in order to finalize
    83  	ns, err = clientset.CoreV1().Namespaces().Get(ctx, ns.Name, metav1.GetOptions{})
    84  	if err != nil {
    85  		return
    86  	}
    87  
    88  	ns.Spec.Finalizers = append(finalizers[:pos], finalizers[pos+1:]...)
    89  	_, err = clientset.CoreV1().Namespaces().Finalize(ctx, ns, metav1.UpdateOptions{})
    90  	Expect(err).NotTo(HaveOccurred())
    91  
    92  WAIT_LOOP:
    93  	for i := 0; i < 10; i++ {
    94  		ns, err = clientset.CoreV1().Namespaces().Get(ctx, ns.Name, metav1.GetOptions{})
    95  		if apierrors.IsNotFound(err) {
    96  			// success!
    97  			return
    98  		}
    99  		select {
   100  		case <-ctx.Done():
   101  			break WAIT_LOOP
   102  			// failed to delete in time, see failure below
   103  		case <-time.After(100 * time.Millisecond):
   104  			// do nothing, try again
   105  		}
   106  	}
   107  	Fail(fmt.Sprintf("timed out waiting for namespace %q to be deleted", ns.Name))
   108  }
   109  
   110  type mockPatchOption struct {
   111  	applied bool
   112  }
   113  
   114  func (o *mockPatchOption) ApplyToPatch(_ *client.PatchOptions) {
   115  	o.applied = true
   116  }
   117  
   118  // metaOnlyFromObj returns PartialObjectMetadata from a concrete Go struct that
   119  // returns a concrete *metav1.ObjectMeta from GetObjectMeta (yes, that plays a
   120  // bit fast and loose, but the only other options are serializing and then
   121  // deserializing, or manually calling all the accessor funcs, which are both a bit annoying).
   122  func metaOnlyFromObj(obj interface {
   123  	runtime.Object
   124  	metav1.ObjectMetaAccessor
   125  }, scheme *runtime.Scheme) *metav1.PartialObjectMetadata {
   126  	metaObj := metav1.PartialObjectMetadata{}
   127  	obj.GetObjectMeta().(*metav1.ObjectMeta).DeepCopyInto(&metaObj.ObjectMeta)
   128  	kinds, _, err := scheme.ObjectKinds(obj)
   129  	if err != nil {
   130  		panic(err)
   131  	}
   132  	metaObj.SetGroupVersionKind(kinds[0])
   133  	return &metaObj
   134  }
   135  
   136  var _ = Describe("Client", func() {
   137  
   138  	var scheme *runtime.Scheme
   139  	var depGvk schema.GroupVersionKind
   140  	var dep *appsv1.Deployment
   141  	var pod *corev1.Pod
   142  	var node *corev1.Node
   143  	var serviceAccount *corev1.ServiceAccount
   144  	var csr *certificatesv1.CertificateSigningRequest
   145  	var count uint64 = 0
   146  	var replicaCount int32 = 2
   147  	var ns = "default"
   148  	var errNotCached *cache.ErrResourceNotCached
   149  	ctx := context.TODO()
   150  
   151  	BeforeEach(func() {
   152  		atomic.AddUint64(&count, 1)
   153  		dep = &appsv1.Deployment{
   154  			ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("deployment-name-%v", count), Namespace: ns, Labels: map[string]string{"app": fmt.Sprintf("bar-%v", count)}},
   155  			Spec: appsv1.DeploymentSpec{
   156  				Replicas: &replicaCount,
   157  				Selector: &metav1.LabelSelector{
   158  					MatchLabels: map[string]string{"foo": "bar"},
   159  				},
   160  				Template: corev1.PodTemplateSpec{
   161  					ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
   162  					Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
   163  				},
   164  			},
   165  		}
   166  		depGvk = schema.GroupVersionKind{
   167  			Group:   "apps",
   168  			Kind:    "Deployment",
   169  			Version: "v1",
   170  		}
   171  		// Pod is invalid without a container field in the PodSpec
   172  		pod = &corev1.Pod{
   173  			ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("pod-%v", count), Namespace: ns},
   174  			Spec:       corev1.PodSpec{},
   175  		}
   176  		node = &corev1.Node{
   177  			ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("node-name-%v", count)},
   178  			Spec:       corev1.NodeSpec{},
   179  		}
   180  		serviceAccount = &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("sa-%v", count), Namespace: ns}}
   181  		csr = &certificatesv1.CertificateSigningRequest{
   182  			ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("csr-%v", count)},
   183  			Spec: certificatesv1.CertificateSigningRequestSpec{
   184  				SignerName: "org.io/my-signer",
   185  				Request: []byte(`-----BEGIN CERTIFICATE REQUEST-----
   186  MIIChzCCAW8CAQAwQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0
   187  eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDCCASIwDQYJKoZIhvcNAQEB
   188  BQADggEPADCCAQoCggEBANe06dLX/bDNm6mVEnKdJexcJM6WKMFSt5o6BEdD1+Ki
   189  WyUcvfNgIBbwAZjkF9U1r7+KuDcc6XYFnb6ky1wPo4C+XwcIIx7Nnbf8IdWJukPb
   190  2BCsqO4NCsG6kKFavmH9J3q//nwKUvlQE+AJ2MPuOAZTwZ4KskghiGuS8hyk6/PZ
   191  XH9QhV7Jma43bDzQozd2C7OujRBhLsuP94KSu839RRFWd9ms3XHgTxLxb7nxwZDx
   192  9l7/ZVAObJoQYlHENqs12NCVP4gpJfbcY8/rd+IG4ftcZEmpeO4kKO+d2TpRKQqw
   193  bjCMoAdD5Y43iLTtyql4qRnbMe3nxYG2+1inEryuV/cCAwEAAaAAMA0GCSqGSIb3
   194  DQEBCwUAA4IBAQDH5hDByRN7wERQtC/o6uc8Y+yhjq9YcBJjjbnD6Vwru5pOdWtx
   195  qfKkkXI5KNOdEhWzLnJyOcWHjj8UoHqI3AjxGC7dTM95eGjxQGUpsUOX8JSd4MiZ
   196  cct4g4BKBj02AGqZLiEgN+PLCYAmEaYU7oZc4OAh6WzMrljNRsj66awMQpw8O1eY
   197  YuBa8vwz8ko8vn/pn7IrFu8cZ+EA3rluJ+budX/QrEGi1hijg27q7/Qr0wNI9f1v
   198  086mLKdqaBTkblXWEvF3WP4CcLNyrSNi4eu+G0fcAgGp1F/Nqh0MuWKSOLprv5Om
   199  U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC
   200  -----END CERTIFICATE REQUEST-----`),
   201  				Usages: []certificatesv1.KeyUsage{certificatesv1.UsageClientAuth},
   202  			},
   203  		}
   204  		scheme = kscheme.Scheme
   205  	})
   206  
   207  	var delOptions *metav1.DeleteOptions
   208  	AfterEach(func() {
   209  		// Cleanup
   210  		var zero int64 = 0
   211  		policy := metav1.DeletePropagationForeground
   212  		delOptions = &metav1.DeleteOptions{
   213  			GracePeriodSeconds: &zero,
   214  			PropagationPolicy:  &policy,
   215  		}
   216  		deleteDeployment(ctx, dep, ns)
   217  		_, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
   218  		if err == nil {
   219  			err = clientset.CoreV1().Nodes().Delete(ctx, node.Name, *delOptions)
   220  			Expect(err).NotTo(HaveOccurred())
   221  		}
   222  		err = clientset.CoreV1().ServiceAccounts(ns).Delete(ctx, serviceAccount.Name, *delOptions)
   223  		Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
   224  
   225  		err = clientset.CertificatesV1().CertificateSigningRequests().Delete(ctx, csr.Name, *delOptions)
   226  		Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
   227  	})
   228  
   229  	Describe("New", func() {
   230  		It("should return a new Client", func() {
   231  			cl, err := client.New(cfg, client.Options{})
   232  			Expect(err).NotTo(HaveOccurred())
   233  			Expect(cl).NotTo(BeNil())
   234  		})
   235  
   236  		It("should fail if the config is nil", func() {
   237  			cl, err := client.New(nil, client.Options{})
   238  			Expect(err).To(HaveOccurred())
   239  			Expect(cl).To(BeNil())
   240  		})
   241  
   242  		It("should use the provided Scheme if provided", func() {
   243  			cl, err := client.New(cfg, client.Options{Scheme: scheme})
   244  			Expect(err).NotTo(HaveOccurred())
   245  			Expect(cl).NotTo(BeNil())
   246  			Expect(cl.Scheme()).ToNot(BeNil())
   247  			Expect(cl.Scheme()).To(Equal(scheme))
   248  		})
   249  
   250  		It("should default the Scheme if not provided", func() {
   251  			cl, err := client.New(cfg, client.Options{})
   252  			Expect(err).NotTo(HaveOccurred())
   253  			Expect(cl).NotTo(BeNil())
   254  			Expect(cl.Scheme()).ToNot(BeNil())
   255  			Expect(cl.Scheme()).To(Equal(kscheme.Scheme))
   256  		})
   257  
   258  		It("should use the provided Mapper if provided", func() {
   259  			mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{})
   260  			cl, err := client.New(cfg, client.Options{Mapper: mapper})
   261  			Expect(err).NotTo(HaveOccurred())
   262  			Expect(cl).NotTo(BeNil())
   263  			Expect(cl.RESTMapper()).ToNot(BeNil())
   264  			Expect(cl.RESTMapper()).To(Equal(mapper))
   265  		})
   266  
   267  		It("should create a Mapper if not provided", func() {
   268  			cl, err := client.New(cfg, client.Options{})
   269  			Expect(err).NotTo(HaveOccurred())
   270  			Expect(cl).NotTo(BeNil())
   271  			Expect(cl.RESTMapper()).ToNot(BeNil())
   272  		})
   273  
   274  		It("should use the provided reader cache if provided, on get and list", func() {
   275  			cache := &fakeReader{}
   276  			cl, err := client.New(cfg, client.Options{Cache: &client.CacheOptions{Reader: cache}})
   277  			Expect(err).NotTo(HaveOccurred())
   278  			Expect(cl).NotTo(BeNil())
   279  			Expect(cl.Get(ctx, client.ObjectKey{Name: "test"}, &appsv1.Deployment{})).To(Succeed())
   280  			Expect(cl.List(ctx, &appsv1.DeploymentList{})).To(Succeed())
   281  			Expect(cache.Called).To(Equal(2))
   282  		})
   283  
   284  		It("should propagate ErrResourceNotCached errors", func() {
   285  			c := &fakeUncachedReader{}
   286  			cl, err := client.New(cfg, client.Options{Cache: &client.CacheOptions{Reader: c}})
   287  			Expect(err).NotTo(HaveOccurred())
   288  			Expect(cl).NotTo(BeNil())
   289  			Expect(errors.As(cl.Get(ctx, client.ObjectKey{Name: "test"}, &appsv1.Deployment{}), &errNotCached)).To(BeTrue())
   290  			Expect(errors.As(cl.List(ctx, &appsv1.DeploymentList{}), &errNotCached)).To(BeTrue())
   291  			Expect(c.Called).To(Equal(2))
   292  		})
   293  
   294  		It("should not use the provided reader cache if provided, on get and list for uncached GVKs", func() {
   295  			cache := &fakeReader{}
   296  			cl, err := client.New(cfg, client.Options{Cache: &client.CacheOptions{Reader: cache, DisableFor: []client.Object{&corev1.Namespace{}}}})
   297  			Expect(err).NotTo(HaveOccurred())
   298  			Expect(cl).NotTo(BeNil())
   299  			Expect(cl.Get(ctx, client.ObjectKey{Name: "default"}, &corev1.Namespace{})).To(Succeed())
   300  			Expect(cl.List(ctx, &corev1.NamespaceList{})).To(Succeed())
   301  			Expect(cache.Called).To(Equal(0))
   302  		})
   303  	})
   304  
   305  	Describe("Create", func() {
   306  		Context("with structured objects", func() {
   307  			It("should create a new object from a go struct", func() {
   308  				cl, err := client.New(cfg, client.Options{})
   309  				Expect(err).NotTo(HaveOccurred())
   310  				Expect(cl).NotTo(BeNil())
   311  
   312  				By("creating the object")
   313  				err = cl.Create(context.TODO(), dep)
   314  				Expect(err).NotTo(HaveOccurred())
   315  
   316  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   317  				Expect(err).NotTo(HaveOccurred())
   318  				Expect(actual).NotTo(BeNil())
   319  
   320  				By("writing the result back to the go struct")
   321  				Expect(dep).To(Equal(actual))
   322  			})
   323  
   324  			It("should create a new object non-namespace object from a go struct", func() {
   325  				cl, err := client.New(cfg, client.Options{})
   326  				Expect(err).NotTo(HaveOccurred())
   327  				Expect(cl).NotTo(BeNil())
   328  
   329  				By("creating the object")
   330  				err = cl.Create(context.TODO(), node)
   331  				Expect(err).NotTo(HaveOccurred())
   332  
   333  				actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
   334  				Expect(err).NotTo(HaveOccurred())
   335  				Expect(actual).NotTo(BeNil())
   336  
   337  				By("writing the result back to the go struct")
   338  				Expect(node).To(Equal(actual))
   339  			})
   340  
   341  			It("should fail if the object already exists", func() {
   342  				cl, err := client.New(cfg, client.Options{})
   343  				Expect(err).NotTo(HaveOccurred())
   344  				Expect(cl).NotTo(BeNil())
   345  
   346  				old := dep.DeepCopy()
   347  
   348  				By("creating the object")
   349  				err = cl.Create(context.TODO(), dep)
   350  				Expect(err).NotTo(HaveOccurred())
   351  
   352  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   353  				Expect(err).NotTo(HaveOccurred())
   354  				Expect(actual).NotTo(BeNil())
   355  
   356  				By("creating the object a second time")
   357  				err = cl.Create(context.TODO(), old)
   358  				Expect(err).To(HaveOccurred())
   359  				Expect(apierrors.IsAlreadyExists(err)).To(BeTrue())
   360  			})
   361  
   362  			It("should fail if the object does not pass server-side validation", func() {
   363  				cl, err := client.New(cfg, client.Options{})
   364  				Expect(err).NotTo(HaveOccurred())
   365  				Expect(cl).NotTo(BeNil())
   366  
   367  				By("creating the pod, since required field Containers is empty")
   368  				err = cl.Create(context.TODO(), pod)
   369  				Expect(err).To(HaveOccurred())
   370  				// TODO(seans): Add test to validate the returned error. Problems currently with
   371  				// different returned error locally versus travis.
   372  			})
   373  
   374  			It("should fail if the object cannot be mapped to a GVK", func() {
   375  				By("creating client with empty Scheme")
   376  				emptyScheme := runtime.NewScheme()
   377  				cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
   378  				Expect(err).NotTo(HaveOccurred())
   379  				Expect(cl).NotTo(BeNil())
   380  
   381  				By("creating the object fails")
   382  				err = cl.Create(context.TODO(), dep)
   383  				Expect(err).To(HaveOccurred())
   384  				Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
   385  			})
   386  
   387  			PIt("should fail if the GVK cannot be mapped to a Resource", func() {
   388  				// TODO(seans3): implement these
   389  				// Example: ListOptions
   390  			})
   391  
   392  			Context("with the DryRun option", func() {
   393  				It("should not create a new object, global option", func() {
   394  					cl, err := client.New(cfg, client.Options{DryRun: ptr.To(true)})
   395  					Expect(err).NotTo(HaveOccurred())
   396  					Expect(cl).NotTo(BeNil())
   397  
   398  					By("creating the object (with DryRun)")
   399  					err = cl.Create(context.TODO(), dep)
   400  					Expect(err).NotTo(HaveOccurred())
   401  
   402  					actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   403  					Expect(err).To(HaveOccurred())
   404  					Expect(apierrors.IsNotFound(err)).To(BeTrue())
   405  					Expect(actual).To(Equal(&appsv1.Deployment{}))
   406  				})
   407  
   408  				It("should not create a new object, inline option", func() {
   409  					cl, err := client.New(cfg, client.Options{})
   410  					Expect(err).NotTo(HaveOccurred())
   411  					Expect(cl).NotTo(BeNil())
   412  
   413  					By("creating the object (with DryRun)")
   414  					err = cl.Create(context.TODO(), dep, client.DryRunAll)
   415  					Expect(err).NotTo(HaveOccurred())
   416  
   417  					actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   418  					Expect(err).To(HaveOccurred())
   419  					Expect(apierrors.IsNotFound(err)).To(BeTrue())
   420  					Expect(actual).To(Equal(&appsv1.Deployment{}))
   421  				})
   422  			})
   423  		})
   424  
   425  		Context("with unstructured objects", func() {
   426  			It("should create a new object from a go struct", func() {
   427  				cl, err := client.New(cfg, client.Options{})
   428  				Expect(err).NotTo(HaveOccurred())
   429  				Expect(cl).NotTo(BeNil())
   430  
   431  				By("encoding the deployment as unstructured")
   432  				u := &unstructured.Unstructured{}
   433  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
   434  				u.SetGroupVersionKind(schema.GroupVersionKind{
   435  					Group:   "apps",
   436  					Kind:    "Deployment",
   437  					Version: "v1",
   438  				})
   439  
   440  				By("creating the object")
   441  				err = cl.Create(context.TODO(), u)
   442  				Expect(err).NotTo(HaveOccurred())
   443  
   444  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   445  				Expect(err).NotTo(HaveOccurred())
   446  				Expect(actual).NotTo(BeNil())
   447  			})
   448  
   449  			It("should create a new non-namespace object ", func() {
   450  				cl, err := client.New(cfg, client.Options{})
   451  				Expect(err).NotTo(HaveOccurred())
   452  				Expect(cl).NotTo(BeNil())
   453  
   454  				By("encoding the deployment as unstructured")
   455  				u := &unstructured.Unstructured{}
   456  				Expect(scheme.Convert(node, u, nil)).To(Succeed())
   457  				u.SetGroupVersionKind(schema.GroupVersionKind{
   458  					Group:   "",
   459  					Kind:    "Node",
   460  					Version: "v1",
   461  				})
   462  
   463  				By("creating the object")
   464  				err = cl.Create(context.TODO(), node)
   465  				Expect(err).NotTo(HaveOccurred())
   466  
   467  				actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
   468  				Expect(err).NotTo(HaveOccurred())
   469  				Expect(actual).NotTo(BeNil())
   470  				au := &unstructured.Unstructured{}
   471  				Expect(scheme.Convert(actual, au, nil)).To(Succeed())
   472  				Expect(scheme.Convert(node, u, nil)).To(Succeed())
   473  				By("writing the result back to the go struct")
   474  
   475  				Expect(u).To(Equal(au))
   476  			})
   477  
   478  			It("should fail if the object already exists", func() {
   479  				cl, err := client.New(cfg, client.Options{})
   480  				Expect(err).NotTo(HaveOccurred())
   481  				Expect(cl).NotTo(BeNil())
   482  
   483  				old := dep.DeepCopy()
   484  
   485  				By("creating the object")
   486  				err = cl.Create(context.TODO(), dep)
   487  				Expect(err).NotTo(HaveOccurred())
   488  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   489  				Expect(err).NotTo(HaveOccurred())
   490  				Expect(actual).NotTo(BeNil())
   491  
   492  				By("encoding the deployment as unstructured")
   493  				u := &unstructured.Unstructured{}
   494  				Expect(scheme.Convert(old, u, nil)).To(Succeed())
   495  				u.SetGroupVersionKind(schema.GroupVersionKind{
   496  					Group:   "apps",
   497  					Kind:    "Deployment",
   498  					Version: "v1",
   499  				})
   500  
   501  				By("creating the object a second time")
   502  				err = cl.Create(context.TODO(), u)
   503  				Expect(err).To(HaveOccurred())
   504  				Expect(apierrors.IsAlreadyExists(err)).To(BeTrue())
   505  			})
   506  
   507  			It("should fail if the object does not pass server-side validation", func() {
   508  				cl, err := client.New(cfg, client.Options{})
   509  				Expect(err).NotTo(HaveOccurred())
   510  				Expect(cl).NotTo(BeNil())
   511  
   512  				By("creating the pod, since required field Containers is empty")
   513  				u := &unstructured.Unstructured{}
   514  				Expect(scheme.Convert(pod, u, nil)).To(Succeed())
   515  				u.SetGroupVersionKind(schema.GroupVersionKind{
   516  					Group:   "",
   517  					Version: "v1",
   518  					Kind:    "Pod",
   519  				})
   520  				err = cl.Create(context.TODO(), u)
   521  				Expect(err).To(HaveOccurred())
   522  				// TODO(seans): Add test to validate the returned error. Problems currently with
   523  				// different returned error locally versus travis.
   524  			})
   525  
   526  		})
   527  
   528  		Context("with metadata objects", func() {
   529  			It("should fail with an error", func() {
   530  				cl, err := client.New(cfg, client.Options{})
   531  				Expect(err).NotTo(HaveOccurred())
   532  
   533  				obj := metaOnlyFromObj(dep, scheme)
   534  				Expect(cl.Create(context.TODO(), obj)).NotTo(Succeed())
   535  			})
   536  		})
   537  
   538  		Context("with the DryRun option", func() {
   539  			It("should not create a new object from a go struct", func() {
   540  				cl, err := client.New(cfg, client.Options{})
   541  				Expect(err).NotTo(HaveOccurred())
   542  				Expect(cl).NotTo(BeNil())
   543  
   544  				By("encoding the deployment as unstructured")
   545  				u := &unstructured.Unstructured{}
   546  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
   547  				u.SetGroupVersionKind(schema.GroupVersionKind{
   548  					Group:   "apps",
   549  					Kind:    "Deployment",
   550  					Version: "v1",
   551  				})
   552  
   553  				By("creating the object")
   554  				err = cl.Create(context.TODO(), u, client.DryRunAll)
   555  				Expect(err).NotTo(HaveOccurred())
   556  
   557  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   558  				Expect(err).To(HaveOccurred())
   559  				Expect(apierrors.IsNotFound(err)).To(BeTrue())
   560  				Expect(actual).To(Equal(&appsv1.Deployment{}))
   561  			})
   562  		})
   563  	})
   564  
   565  	Describe("Update", func() {
   566  		Context("with structured objects", func() {
   567  			It("should update an existing object from a go struct", func() {
   568  				cl, err := client.New(cfg, client.Options{})
   569  				Expect(err).NotTo(HaveOccurred())
   570  				Expect(cl).NotTo(BeNil())
   571  
   572  				By("initially creating a Deployment")
   573  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
   574  				Expect(err).NotTo(HaveOccurred())
   575  
   576  				By("updating the Deployment")
   577  				dep.Annotations = map[string]string{"foo": "bar"}
   578  				err = cl.Update(context.TODO(), dep)
   579  				Expect(err).NotTo(HaveOccurred())
   580  
   581  				By("validating updated Deployment has new annotation")
   582  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   583  				Expect(err).NotTo(HaveOccurred())
   584  				Expect(actual).NotTo(BeNil())
   585  				Expect(actual.Annotations["foo"]).To(Equal("bar"))
   586  			})
   587  
   588  			It("should update and preserve type information", func() {
   589  				cl, err := client.New(cfg, client.Options{})
   590  				Expect(err).NotTo(HaveOccurred())
   591  				Expect(cl).NotTo(BeNil())
   592  
   593  				By("initially creating a Deployment")
   594  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
   595  				Expect(err).NotTo(HaveOccurred())
   596  
   597  				By("updating the Deployment")
   598  				dep.SetGroupVersionKind(depGvk)
   599  				err = cl.Update(context.TODO(), dep)
   600  				Expect(err).NotTo(HaveOccurred())
   601  
   602  				By("validating updated Deployment has type information")
   603  				Expect(dep.GroupVersionKind()).To(Equal(depGvk))
   604  			})
   605  
   606  			It("should update an existing object non-namespace object from a go struct", func() {
   607  				cl, err := client.New(cfg, client.Options{})
   608  				Expect(err).NotTo(HaveOccurred())
   609  				Expect(cl).NotTo(BeNil())
   610  
   611  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
   612  				Expect(err).NotTo(HaveOccurred())
   613  
   614  				By("updating the object")
   615  				node.Annotations = map[string]string{"foo": "bar"}
   616  				err = cl.Update(context.TODO(), node)
   617  				Expect(err).NotTo(HaveOccurred())
   618  
   619  				By("validate updated Node had new annotation")
   620  				actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
   621  				Expect(err).NotTo(HaveOccurred())
   622  				Expect(actual).NotTo(BeNil())
   623  				Expect(actual.Annotations["foo"]).To(Equal("bar"))
   624  			})
   625  
   626  			It("should fail if the object does not exist", func() {
   627  				cl, err := client.New(cfg, client.Options{})
   628  				Expect(err).NotTo(HaveOccurred())
   629  				Expect(cl).NotTo(BeNil())
   630  
   631  				By("updating non-existent object")
   632  				err = cl.Update(context.TODO(), dep)
   633  				Expect(err).To(HaveOccurred())
   634  			})
   635  
   636  			PIt("should fail if the object does not pass server-side validation", func() {
   637  
   638  			})
   639  
   640  			PIt("should fail if the object doesn't have meta", func() {
   641  
   642  			})
   643  
   644  			It("should fail if the object cannot be mapped to a GVK", func() {
   645  				By("creating client with empty Scheme")
   646  				emptyScheme := runtime.NewScheme()
   647  				cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
   648  				Expect(err).NotTo(HaveOccurred())
   649  				Expect(cl).NotTo(BeNil())
   650  
   651  				By("initially creating a Deployment")
   652  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
   653  				Expect(err).NotTo(HaveOccurred())
   654  
   655  				By("updating the Deployment")
   656  				dep.Annotations = map[string]string{"foo": "bar"}
   657  				err = cl.Update(context.TODO(), dep)
   658  				Expect(err).To(HaveOccurred())
   659  				Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
   660  			})
   661  
   662  			PIt("should fail if the GVK cannot be mapped to a Resource", func() {
   663  
   664  			})
   665  		})
   666  		Context("with unstructured objects", func() {
   667  			It("should update an existing object from a go struct", func() {
   668  				cl, err := client.New(cfg, client.Options{})
   669  				Expect(err).NotTo(HaveOccurred())
   670  				Expect(cl).NotTo(BeNil())
   671  
   672  				By("initially creating a Deployment")
   673  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
   674  				Expect(err).NotTo(HaveOccurred())
   675  
   676  				By("updating the Deployment")
   677  				u := &unstructured.Unstructured{}
   678  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
   679  				u.SetGroupVersionKind(schema.GroupVersionKind{
   680  					Group:   "apps",
   681  					Kind:    "Deployment",
   682  					Version: "v1",
   683  				})
   684  				u.SetAnnotations(map[string]string{"foo": "bar"})
   685  				err = cl.Update(context.TODO(), u)
   686  				Expect(err).NotTo(HaveOccurred())
   687  
   688  				By("validating updated Deployment has new annotation")
   689  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   690  				Expect(err).NotTo(HaveOccurred())
   691  				Expect(actual).NotTo(BeNil())
   692  				Expect(actual.Annotations["foo"]).To(Equal("bar"))
   693  			})
   694  
   695  			It("should update and preserve type information", func() {
   696  				cl, err := client.New(cfg, client.Options{})
   697  				Expect(err).NotTo(HaveOccurred())
   698  				Expect(cl).NotTo(BeNil())
   699  
   700  				By("initially creating a Deployment")
   701  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
   702  				Expect(err).NotTo(HaveOccurred())
   703  
   704  				By("updating the Deployment")
   705  				u := &unstructured.Unstructured{}
   706  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
   707  				u.SetGroupVersionKind(depGvk)
   708  				u.SetAnnotations(map[string]string{"foo": "bar"})
   709  				err = cl.Update(context.TODO(), u)
   710  				Expect(err).NotTo(HaveOccurred())
   711  
   712  				By("validating updated Deployment has type information")
   713  				Expect(u.GroupVersionKind()).To(Equal(depGvk))
   714  			})
   715  
   716  			It("should update an existing object non-namespace object from a go struct", func() {
   717  				cl, err := client.New(cfg, client.Options{})
   718  				Expect(err).NotTo(HaveOccurred())
   719  				Expect(cl).NotTo(BeNil())
   720  
   721  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
   722  				Expect(err).NotTo(HaveOccurred())
   723  
   724  				By("updating the object")
   725  				u := &unstructured.Unstructured{}
   726  				Expect(scheme.Convert(node, u, nil)).To(Succeed())
   727  				u.SetGroupVersionKind(schema.GroupVersionKind{
   728  					Group:   "",
   729  					Kind:    "Node",
   730  					Version: "v1",
   731  				})
   732  				u.SetAnnotations(map[string]string{"foo": "bar"})
   733  				err = cl.Update(context.TODO(), u)
   734  				Expect(err).NotTo(HaveOccurred())
   735  
   736  				By("validate updated Node had new annotation")
   737  				actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
   738  				Expect(err).NotTo(HaveOccurred())
   739  				Expect(actual).NotTo(BeNil())
   740  				Expect(actual.Annotations["foo"]).To(Equal("bar"))
   741  			})
   742  			It("should fail if the object does not exist", func() {
   743  				cl, err := client.New(cfg, client.Options{})
   744  				Expect(err).NotTo(HaveOccurred())
   745  				Expect(cl).NotTo(BeNil())
   746  
   747  				By("updating non-existent object")
   748  				u := &unstructured.Unstructured{}
   749  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
   750  				u.SetGroupVersionKind(depGvk)
   751  				err = cl.Update(context.TODO(), dep)
   752  				Expect(err).To(HaveOccurred())
   753  			})
   754  		})
   755  		Context("with metadata objects", func() {
   756  			It("should fail with an error", func() {
   757  				cl, err := client.New(cfg, client.Options{})
   758  				Expect(err).NotTo(HaveOccurred())
   759  
   760  				obj := metaOnlyFromObj(dep, scheme)
   761  
   762  				Expect(cl.Update(context.TODO(), obj)).NotTo(Succeed())
   763  			})
   764  		})
   765  	})
   766  
   767  	Describe("Patch", func() {
   768  		Context("Metadata Client", func() {
   769  			It("should merge patch with options", func() {
   770  				cl, err := client.New(cfg, client.Options{})
   771  				Expect(err).NotTo(HaveOccurred())
   772  				Expect(cl).NotTo(BeNil())
   773  
   774  				By("initially creating a Deployment")
   775  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
   776  				Expect(err).NotTo(HaveOccurred())
   777  
   778  				metadata := metaOnlyFromObj(dep, scheme)
   779  				if metadata.Labels == nil {
   780  					metadata.Labels = make(map[string]string)
   781  				}
   782  				metadata.Labels["foo"] = "bar"
   783  
   784  				testOption := &mockPatchOption{}
   785  				Expect(cl.Patch(context.TODO(), metadata, client.Merge, testOption)).To(Succeed())
   786  
   787  				By("validating that patched metadata has new labels")
   788  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   789  				Expect(err).NotTo(HaveOccurred())
   790  				Expect(actual).NotTo(BeNil())
   791  				Expect(actual.Labels["foo"]).To(Equal("bar"))
   792  
   793  				By("validating patch options were applied")
   794  				Expect(testOption.applied).To(BeTrue())
   795  			})
   796  		})
   797  	})
   798  
   799  	Describe("SubResourceClient", func() {
   800  		Context("with structured objects", func() {
   801  			It("should be able to read the Scale subresource", func() {
   802  				cl, err := client.New(cfg, client.Options{})
   803  				Expect(err).NotTo(HaveOccurred())
   804  				Expect(cl).NotTo(BeNil())
   805  
   806  				By("Creating a deployment")
   807  				dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
   808  				Expect(err).NotTo(HaveOccurred())
   809  
   810  				By("reading the scale subresource")
   811  				scale := &autoscalingv1.Scale{}
   812  				err = cl.SubResource("scale").Get(ctx, dep, scale, &client.SubResourceGetOptions{})
   813  				Expect(err).NotTo(HaveOccurred())
   814  				Expect(scale.Spec.Replicas).To(Equal(*dep.Spec.Replicas))
   815  			})
   816  			It("should be able to create ServiceAccount tokens", func() {
   817  				cl, err := client.New(cfg, client.Options{})
   818  				Expect(err).NotTo(HaveOccurred())
   819  				Expect(cl).NotTo(BeNil())
   820  
   821  				By("Creating the serviceAccount")
   822  				_, err = clientset.CoreV1().ServiceAccounts(serviceAccount.Namespace).Create(ctx, serviceAccount, metav1.CreateOptions{})
   823  				Expect((err)).NotTo(HaveOccurred())
   824  
   825  				token := &authenticationv1.TokenRequest{}
   826  				err = cl.SubResource("token").Create(ctx, serviceAccount, token, &client.SubResourceCreateOptions{})
   827  				Expect(err).NotTo(HaveOccurred())
   828  
   829  				Expect(token.Status.Token).NotTo(Equal(""))
   830  			})
   831  
   832  			It("should be able to create Pod evictions", func() {
   833  				cl, err := client.New(cfg, client.Options{})
   834  				Expect(err).NotTo(HaveOccurred())
   835  				Expect(cl).NotTo(BeNil())
   836  
   837  				// Make the pod valid
   838  				pod.Spec.Containers = []corev1.Container{{Name: "foo", Image: "busybox"}}
   839  
   840  				By("Creating the pod")
   841  				pod, err = clientset.CoreV1().Pods(pod.Namespace).Create(ctx, pod, metav1.CreateOptions{})
   842  				Expect(err).NotTo(HaveOccurred())
   843  
   844  				By("Creating the eviction")
   845  				eviction := &policyv1.Eviction{
   846  					DeleteOptions: &metav1.DeleteOptions{GracePeriodSeconds: ptr.To(int64(0))},
   847  				}
   848  				err = cl.SubResource("eviction").Create(ctx, pod, eviction, &client.SubResourceCreateOptions{})
   849  				Expect((err)).NotTo(HaveOccurred())
   850  
   851  				By("Asserting the pod is gone")
   852  				_, err = clientset.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
   853  				Expect(apierrors.IsNotFound(err)).To(BeTrue())
   854  			})
   855  
   856  			It("should be able to create Pod bindings", func() {
   857  				cl, err := client.New(cfg, client.Options{})
   858  				Expect(err).NotTo(HaveOccurred())
   859  				Expect(cl).NotTo(BeNil())
   860  
   861  				// Make the pod valid
   862  				pod.Spec.Containers = []corev1.Container{{Name: "foo", Image: "busybox"}}
   863  
   864  				By("Creating the pod")
   865  				pod, err = clientset.CoreV1().Pods(pod.Namespace).Create(ctx, pod, metav1.CreateOptions{})
   866  				Expect(err).NotTo(HaveOccurred())
   867  
   868  				By("Creating the binding")
   869  				binding := &corev1.Binding{
   870  					Target: corev1.ObjectReference{Name: node.Name},
   871  				}
   872  				err = cl.SubResource("binding").Create(ctx, pod, binding, &client.SubResourceCreateOptions{})
   873  				Expect((err)).NotTo(HaveOccurred())
   874  
   875  				By("Asserting the pod is bound")
   876  				pod, err = clientset.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
   877  				Expect(err).NotTo(HaveOccurred())
   878  				Expect(pod.Spec.NodeName).To(Equal(node.Name))
   879  			})
   880  
   881  			It("should be able to approve CSRs", func() {
   882  				cl, err := client.New(cfg, client.Options{})
   883  				Expect(err).NotTo(HaveOccurred())
   884  				Expect(cl).NotTo(BeNil())
   885  
   886  				By("Creating the CSR")
   887  				csr, err := clientset.CertificatesV1().CertificateSigningRequests().Create(ctx, csr, metav1.CreateOptions{})
   888  				Expect(err).NotTo(HaveOccurred())
   889  
   890  				By("Approving the CSR")
   891  				csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
   892  					Type:   certificatesv1.CertificateApproved,
   893  					Status: corev1.ConditionTrue,
   894  				})
   895  				err = cl.SubResource("approval").Update(ctx, csr, &client.SubResourceUpdateOptions{})
   896  				Expect(err).NotTo(HaveOccurred())
   897  
   898  				By("Asserting the CSR is approved")
   899  				csr, err = clientset.CertificatesV1().CertificateSigningRequests().Get(ctx, csr.Name, metav1.GetOptions{})
   900  				Expect(err).NotTo(HaveOccurred())
   901  				Expect(csr.Status.Conditions[0].Type).To(Equal(certificatesv1.CertificateApproved))
   902  				Expect(csr.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue))
   903  			})
   904  
   905  			It("should be able to approve CSRs using Patch", func() {
   906  				cl, err := client.New(cfg, client.Options{})
   907  				Expect(err).NotTo(HaveOccurred())
   908  				Expect(cl).NotTo(BeNil())
   909  
   910  				By("Creating the CSR")
   911  				csr, err := clientset.CertificatesV1().CertificateSigningRequests().Create(ctx, csr, metav1.CreateOptions{})
   912  				Expect(err).NotTo(HaveOccurred())
   913  
   914  				By("Approving the CSR")
   915  				patch := client.MergeFrom(csr.DeepCopy())
   916  				csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
   917  					Type:   certificatesv1.CertificateApproved,
   918  					Status: corev1.ConditionTrue,
   919  				})
   920  				err = cl.SubResource("approval").Patch(ctx, csr, patch, &client.SubResourcePatchOptions{})
   921  				Expect(err).NotTo(HaveOccurred())
   922  
   923  				By("Asserting the CSR is approved")
   924  				csr, err = clientset.CertificatesV1().CertificateSigningRequests().Get(ctx, csr.Name, metav1.GetOptions{})
   925  				Expect(err).NotTo(HaveOccurred())
   926  				Expect(csr.Status.Conditions[0].Type).To(Equal(certificatesv1.CertificateApproved))
   927  				Expect(csr.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue))
   928  			})
   929  
   930  			It("should be able to update the scale subresource", func() {
   931  				cl, err := client.New(cfg, client.Options{})
   932  				Expect(err).NotTo(HaveOccurred())
   933  				Expect(cl).NotTo(BeNil())
   934  
   935  				By("Creating a deployment")
   936  				dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
   937  				Expect(err).NotTo(HaveOccurred())
   938  
   939  				By("Updating the scale subresource")
   940  				replicaCount := *dep.Spec.Replicas
   941  				scale := &autoscalingv1.Scale{Spec: autoscalingv1.ScaleSpec{Replicas: replicaCount}}
   942  				err = cl.SubResource("scale").Update(ctx, dep, client.WithSubResourceBody(scale), &client.SubResourceUpdateOptions{})
   943  				Expect(err).NotTo(HaveOccurred())
   944  
   945  				By("Asserting replicas got updated")
   946  				dep, err = clientset.AppsV1().Deployments(dep.Namespace).Get(ctx, dep.Name, metav1.GetOptions{})
   947  				Expect(err).NotTo(HaveOccurred())
   948  				Expect(*dep.Spec.Replicas).To(Equal(replicaCount))
   949  			})
   950  
   951  			It("should be able to patch the scale subresource", func() {
   952  				cl, err := client.New(cfg, client.Options{})
   953  				Expect(err).NotTo(HaveOccurred())
   954  				Expect(cl).NotTo(BeNil())
   955  
   956  				By("Creating a deployment")
   957  				dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
   958  				Expect(err).NotTo(HaveOccurred())
   959  
   960  				By("Updating the scale subresurce")
   961  				replicaCount := *dep.Spec.Replicas
   962  				patch := client.MergeFrom(&autoscalingv1.Scale{})
   963  				scale := &autoscalingv1.Scale{Spec: autoscalingv1.ScaleSpec{Replicas: replicaCount}}
   964  				err = cl.SubResource("scale").Patch(ctx, dep, patch, client.WithSubResourceBody(scale), &client.SubResourcePatchOptions{})
   965  				Expect(err).NotTo(HaveOccurred())
   966  
   967  				By("Asserting replicas got updated")
   968  				dep, err = clientset.AppsV1().Deployments(dep.Namespace).Get(ctx, dep.Name, metav1.GetOptions{})
   969  				Expect(err).NotTo(HaveOccurred())
   970  				Expect(*dep.Spec.Replicas).To(Equal(replicaCount))
   971  			})
   972  		})
   973  
   974  		Context("with unstructured objects", func() {
   975  			It("should be able to read the Scale subresource", func() {
   976  				cl, err := client.New(cfg, client.Options{})
   977  				Expect(err).NotTo(HaveOccurred())
   978  				Expect(cl).NotTo(BeNil())
   979  
   980  				By("Creating a deployment")
   981  				dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
   982  				Expect(err).NotTo(HaveOccurred())
   983  				dep.APIVersion = appsv1.SchemeGroupVersion.String()
   984  				dep.Kind = reflect.TypeOf(dep).Elem().Name()
   985  				depUnstructured, err := toUnstructured(dep)
   986  				Expect(err).NotTo(HaveOccurred())
   987  
   988  				By("reading the scale subresource")
   989  				scale := &unstructured.Unstructured{}
   990  				scale.SetAPIVersion("autoscaling/v1")
   991  				scale.SetKind("Scale")
   992  				err = cl.SubResource("scale").Get(ctx, depUnstructured, scale)
   993  				Expect(err).NotTo(HaveOccurred())
   994  
   995  				val, found, err := unstructured.NestedInt64(scale.UnstructuredContent(), "spec", "replicas")
   996  				Expect(err).NotTo(HaveOccurred())
   997  				Expect(found).To(BeTrue())
   998  				Expect(int32(val)).To(Equal(*dep.Spec.Replicas))
   999  			})
  1000  			It("should be able to create ServiceAccount tokens", func() {
  1001  				cl, err := client.New(cfg, client.Options{})
  1002  				Expect(err).NotTo(HaveOccurred())
  1003  				Expect(cl).NotTo(BeNil())
  1004  
  1005  				By("Creating the serviceAccount")
  1006  				_, err = clientset.CoreV1().ServiceAccounts(serviceAccount.Namespace).Create(ctx, serviceAccount, metav1.CreateOptions{})
  1007  				Expect((err)).NotTo(HaveOccurred())
  1008  
  1009  				serviceAccount.APIVersion = "v1"
  1010  				serviceAccount.Kind = "ServiceAccount"
  1011  				serviceAccountUnstructured, err := toUnstructured(serviceAccount)
  1012  				Expect(err).NotTo(HaveOccurred())
  1013  
  1014  				token := &unstructured.Unstructured{}
  1015  				token.SetAPIVersion("authentication.k8s.io/v1")
  1016  				token.SetKind("TokenRequest")
  1017  				err = cl.SubResource("token").Create(ctx, serviceAccountUnstructured, token)
  1018  				Expect(err).NotTo(HaveOccurred())
  1019  				Expect(token.GetAPIVersion()).To(Equal("authentication.k8s.io/v1"))
  1020  				Expect(token.GetKind()).To(Equal("TokenRequest"))
  1021  
  1022  				val, found, err := unstructured.NestedString(token.UnstructuredContent(), "status", "token")
  1023  				Expect(err).NotTo(HaveOccurred())
  1024  				Expect(found).To(BeTrue())
  1025  				Expect(val).NotTo(Equal(""))
  1026  			})
  1027  
  1028  			It("should be able to create Pod evictions", func() {
  1029  				cl, err := client.New(cfg, client.Options{})
  1030  				Expect(err).NotTo(HaveOccurred())
  1031  				Expect(cl).NotTo(BeNil())
  1032  
  1033  				// Make the pod valid
  1034  				pod.Spec.Containers = []corev1.Container{{Name: "foo", Image: "busybox"}}
  1035  
  1036  				By("Creating the pod")
  1037  				pod, err = clientset.CoreV1().Pods(pod.Namespace).Create(ctx, pod, metav1.CreateOptions{})
  1038  				Expect(err).NotTo(HaveOccurred())
  1039  
  1040  				pod.APIVersion = "v1"
  1041  				pod.Kind = "Pod"
  1042  				podUnstructured, err := toUnstructured(pod)
  1043  				Expect(err).NotTo(HaveOccurred())
  1044  
  1045  				By("Creating the eviction")
  1046  				eviction := &unstructured.Unstructured{}
  1047  				eviction.SetAPIVersion("policy/v1")
  1048  				eviction.SetKind("Eviction")
  1049  				err = unstructured.SetNestedField(eviction.UnstructuredContent(), int64(0), "deleteOptions", "gracePeriodSeconds")
  1050  				Expect(err).NotTo(HaveOccurred())
  1051  				err = cl.SubResource("eviction").Create(ctx, podUnstructured, eviction)
  1052  				Expect(err).NotTo(HaveOccurred())
  1053  				Expect(eviction.GetAPIVersion()).To(Equal("policy/v1"))
  1054  				Expect(eviction.GetKind()).To(Equal("Eviction"))
  1055  
  1056  				By("Asserting the pod is gone")
  1057  				_, err = clientset.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
  1058  				Expect(apierrors.IsNotFound(err)).To(BeTrue())
  1059  			})
  1060  
  1061  			It("should be able to create Pod bindings", func() {
  1062  				cl, err := client.New(cfg, client.Options{})
  1063  				Expect(err).NotTo(HaveOccurred())
  1064  				Expect(cl).NotTo(BeNil())
  1065  
  1066  				// Make the pod valid
  1067  				pod.Spec.Containers = []corev1.Container{{Name: "foo", Image: "busybox"}}
  1068  
  1069  				By("Creating the pod")
  1070  				pod, err = clientset.CoreV1().Pods(pod.Namespace).Create(ctx, pod, metav1.CreateOptions{})
  1071  				Expect(err).NotTo(HaveOccurred())
  1072  
  1073  				pod.APIVersion = "v1"
  1074  				pod.Kind = "Pod"
  1075  				podUnstructured, err := toUnstructured(pod)
  1076  				Expect(err).NotTo(HaveOccurred())
  1077  
  1078  				By("Creating the binding")
  1079  				binding := &unstructured.Unstructured{}
  1080  				binding.SetAPIVersion("v1")
  1081  				binding.SetKind("Binding")
  1082  				err = unstructured.SetNestedField(binding.UnstructuredContent(), node.Name, "target", "name")
  1083  				Expect(err).NotTo(HaveOccurred())
  1084  
  1085  				err = cl.SubResource("binding").Create(ctx, podUnstructured, binding)
  1086  				Expect((err)).NotTo(HaveOccurred())
  1087  				Expect(binding.GetAPIVersion()).To(Equal("v1"))
  1088  				Expect(binding.GetKind()).To(Equal("Binding"))
  1089  
  1090  				By("Asserting the pod is bound")
  1091  				pod, err = clientset.CoreV1().Pods(pod.Namespace).Get(ctx, pod.Name, metav1.GetOptions{})
  1092  				Expect(err).NotTo(HaveOccurred())
  1093  				Expect(pod.Spec.NodeName).To(Equal(node.Name))
  1094  			})
  1095  
  1096  			It("should be able to approve CSRs", func() {
  1097  				cl, err := client.New(cfg, client.Options{})
  1098  				Expect(err).NotTo(HaveOccurred())
  1099  				Expect(cl).NotTo(BeNil())
  1100  
  1101  				By("Creating the CSR")
  1102  				csr, err := clientset.CertificatesV1().CertificateSigningRequests().Create(ctx, csr, metav1.CreateOptions{})
  1103  				Expect(err).NotTo(HaveOccurred())
  1104  
  1105  				By("Approving the CSR")
  1106  				csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
  1107  					Type:   certificatesv1.CertificateApproved,
  1108  					Status: corev1.ConditionTrue,
  1109  				})
  1110  				csr.APIVersion = "certificates.k8s.io/v1"
  1111  				csr.Kind = "CertificateSigningRequest"
  1112  				csrUnstructured, err := toUnstructured(csr)
  1113  				Expect(err).NotTo(HaveOccurred())
  1114  
  1115  				err = cl.SubResource("approval").Update(ctx, csrUnstructured)
  1116  				Expect(err).NotTo(HaveOccurred())
  1117  				Expect(csrUnstructured.GetAPIVersion()).To(Equal("certificates.k8s.io/v1"))
  1118  				Expect(csrUnstructured.GetKind()).To(Equal("CertificateSigningRequest"))
  1119  
  1120  				By("Asserting the CSR is approved")
  1121  				csr, err = clientset.CertificatesV1().CertificateSigningRequests().Get(ctx, csr.Name, metav1.GetOptions{})
  1122  				Expect(err).NotTo(HaveOccurred())
  1123  				Expect(csr.Status.Conditions[0].Type).To(Equal(certificatesv1.CertificateApproved))
  1124  				Expect(csr.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue))
  1125  			})
  1126  
  1127  			It("should be able to approve CSRs using Patch", func() {
  1128  				cl, err := client.New(cfg, client.Options{})
  1129  				Expect(err).NotTo(HaveOccurred())
  1130  				Expect(cl).NotTo(BeNil())
  1131  
  1132  				By("Creating the CSR")
  1133  				csr, err := clientset.CertificatesV1().CertificateSigningRequests().Create(ctx, csr, metav1.CreateOptions{})
  1134  				Expect(err).NotTo(HaveOccurred())
  1135  
  1136  				By("Approving the CSR")
  1137  				patch := client.MergeFrom(csr.DeepCopy())
  1138  				csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
  1139  					Type:   certificatesv1.CertificateApproved,
  1140  					Status: corev1.ConditionTrue,
  1141  				})
  1142  				csr.APIVersion = "certificates.k8s.io/v1"
  1143  				csr.Kind = "CertificateSigningRequest"
  1144  				csrUnstructured, err := toUnstructured(csr)
  1145  				Expect(err).NotTo(HaveOccurred())
  1146  
  1147  				err = cl.SubResource("approval").Patch(ctx, csrUnstructured, patch)
  1148  				Expect(err).NotTo(HaveOccurred())
  1149  				Expect(csrUnstructured.GetAPIVersion()).To(Equal("certificates.k8s.io/v1"))
  1150  				Expect(csrUnstructured.GetKind()).To(Equal("CertificateSigningRequest"))
  1151  
  1152  				By("Asserting the CSR is approved")
  1153  				csr, err = clientset.CertificatesV1().CertificateSigningRequests().Get(ctx, csr.Name, metav1.GetOptions{})
  1154  				Expect(err).NotTo(HaveOccurred())
  1155  				Expect(csr.Status.Conditions[0].Type).To(Equal(certificatesv1.CertificateApproved))
  1156  				Expect(csr.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue))
  1157  			})
  1158  
  1159  			It("should be able to update the scale subresource", func() {
  1160  				cl, err := client.New(cfg, client.Options{})
  1161  				Expect(err).NotTo(HaveOccurred())
  1162  				Expect(cl).NotTo(BeNil())
  1163  
  1164  				By("Creating a deployment")
  1165  				dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
  1166  				Expect(err).NotTo(HaveOccurred())
  1167  				dep.APIVersion = "apps/v1"
  1168  				dep.Kind = "Deployment"
  1169  				depUnstructured, err := toUnstructured(dep)
  1170  				Expect(err).NotTo(HaveOccurred())
  1171  
  1172  				By("Updating the scale subresurce")
  1173  				replicaCount := *dep.Spec.Replicas
  1174  				scale := &unstructured.Unstructured{}
  1175  				scale.SetAPIVersion("autoscaling/v1")
  1176  				scale.SetKind("Scale")
  1177  				Expect(unstructured.SetNestedField(scale.Object, int64(replicaCount), "spec", "replicas")).NotTo(HaveOccurred())
  1178  				err = cl.SubResource("scale").Update(ctx, depUnstructured, client.WithSubResourceBody(scale))
  1179  				Expect(err).NotTo(HaveOccurred())
  1180  				Expect(scale.GetAPIVersion()).To(Equal("autoscaling/v1"))
  1181  				Expect(scale.GetKind()).To(Equal("Scale"))
  1182  
  1183  				By("Asserting replicas got updated")
  1184  				dep, err = clientset.AppsV1().Deployments(dep.Namespace).Get(ctx, dep.Name, metav1.GetOptions{})
  1185  				Expect(err).NotTo(HaveOccurred())
  1186  				Expect(*dep.Spec.Replicas).To(Equal(replicaCount))
  1187  			})
  1188  
  1189  			It("should be able to patch the scale subresource", func() {
  1190  				cl, err := client.New(cfg, client.Options{})
  1191  				Expect(err).NotTo(HaveOccurred())
  1192  				Expect(cl).NotTo(BeNil())
  1193  
  1194  				By("Creating a deployment")
  1195  				dep, err := clientset.AppsV1().Deployments(dep.Namespace).Create(ctx, dep, metav1.CreateOptions{})
  1196  				Expect(err).NotTo(HaveOccurred())
  1197  				dep.APIVersion = "apps/v1"
  1198  				dep.Kind = "Deployment"
  1199  				depUnstructured, err := toUnstructured(dep)
  1200  				Expect(err).NotTo(HaveOccurred())
  1201  
  1202  				By("Updating the scale subresurce")
  1203  				replicaCount := *dep.Spec.Replicas
  1204  				scale := &unstructured.Unstructured{}
  1205  				scale.SetAPIVersion("autoscaling/v1")
  1206  				scale.SetKind("Scale")
  1207  				patch := client.MergeFrom(scale.DeepCopy())
  1208  				Expect(unstructured.SetNestedField(scale.Object, int64(replicaCount), "spec", "replicas")).NotTo(HaveOccurred())
  1209  				err = cl.SubResource("scale").Patch(ctx, depUnstructured, patch, client.WithSubResourceBody(scale))
  1210  				Expect(err).NotTo(HaveOccurred())
  1211  				Expect(scale.GetAPIVersion()).To(Equal("autoscaling/v1"))
  1212  				Expect(scale.GetKind()).To(Equal("Scale"))
  1213  
  1214  				By("Asserting replicas got updated")
  1215  				dep, err = clientset.AppsV1().Deployments(dep.Namespace).Get(ctx, dep.Name, metav1.GetOptions{})
  1216  				Expect(err).NotTo(HaveOccurred())
  1217  				Expect(*dep.Spec.Replicas).To(Equal(replicaCount))
  1218  			})
  1219  		})
  1220  
  1221  	})
  1222  
  1223  	Describe("StatusClient", func() {
  1224  		Context("with structured objects", func() {
  1225  			It("should update status of an existing object", func() {
  1226  				cl, err := client.New(cfg, client.Options{})
  1227  				Expect(err).NotTo(HaveOccurred())
  1228  				Expect(cl).NotTo(BeNil())
  1229  
  1230  				By("initially creating a Deployment")
  1231  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1232  				Expect(err).NotTo(HaveOccurred())
  1233  
  1234  				By("updating the status of Deployment")
  1235  				dep.Status.Replicas = 1
  1236  				err = cl.Status().Update(context.TODO(), dep)
  1237  				Expect(err).NotTo(HaveOccurred())
  1238  
  1239  				By("validating updated Deployment has new status")
  1240  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
  1241  				Expect(err).NotTo(HaveOccurred())
  1242  				Expect(actual).NotTo(BeNil())
  1243  				Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
  1244  			})
  1245  
  1246  			It("should update status and preserve type information", func() {
  1247  				cl, err := client.New(cfg, client.Options{})
  1248  				Expect(err).NotTo(HaveOccurred())
  1249  				Expect(cl).NotTo(BeNil())
  1250  
  1251  				By("initially creating a Deployment")
  1252  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1253  				Expect(err).NotTo(HaveOccurred())
  1254  
  1255  				By("updating the status of Deployment")
  1256  				dep.SetGroupVersionKind(depGvk)
  1257  				dep.Status.Replicas = 1
  1258  				err = cl.Status().Update(context.TODO(), dep)
  1259  				Expect(err).NotTo(HaveOccurred())
  1260  
  1261  				By("validating updated Deployment has type information")
  1262  				Expect(dep.GroupVersionKind()).To(Equal(depGvk))
  1263  			})
  1264  
  1265  			It("should patch status and preserve type information", func() {
  1266  				cl, err := client.New(cfg, client.Options{})
  1267  				Expect(err).NotTo(HaveOccurred())
  1268  				Expect(cl).NotTo(BeNil())
  1269  
  1270  				By("initially creating a Deployment")
  1271  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1272  				Expect(err).NotTo(HaveOccurred())
  1273  
  1274  				By("patching the status of Deployment")
  1275  				dep.SetGroupVersionKind(depGvk)
  1276  				depPatch := client.MergeFrom(dep.DeepCopy())
  1277  				dep.Status.Replicas = 1
  1278  				err = cl.Status().Patch(context.TODO(), dep, depPatch)
  1279  				Expect(err).NotTo(HaveOccurred())
  1280  
  1281  				By("validating updated Deployment has type information")
  1282  				Expect(dep.GroupVersionKind()).To(Equal(depGvk))
  1283  			})
  1284  
  1285  			It("should not update spec of an existing object", func() {
  1286  				cl, err := client.New(cfg, client.Options{})
  1287  				Expect(err).NotTo(HaveOccurred())
  1288  				Expect(cl).NotTo(BeNil())
  1289  
  1290  				By("initially creating a Deployment")
  1291  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1292  				Expect(err).NotTo(HaveOccurred())
  1293  
  1294  				By("updating the spec and status of Deployment")
  1295  				var rc int32 = 1
  1296  				dep.Status.Replicas = 1
  1297  				dep.Spec.Replicas = &rc
  1298  				err = cl.Status().Update(context.TODO(), dep)
  1299  				Expect(err).NotTo(HaveOccurred())
  1300  
  1301  				By("validating updated Deployment has new status and unchanged spec")
  1302  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
  1303  				Expect(err).NotTo(HaveOccurred())
  1304  				Expect(actual).NotTo(BeNil())
  1305  				Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
  1306  				Expect(*actual.Spec.Replicas).To(BeEquivalentTo(replicaCount))
  1307  			})
  1308  
  1309  			It("should update an existing object non-namespace object", func() {
  1310  				cl, err := client.New(cfg, client.Options{})
  1311  				Expect(err).NotTo(HaveOccurred())
  1312  				Expect(cl).NotTo(BeNil())
  1313  
  1314  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
  1315  				Expect(err).NotTo(HaveOccurred())
  1316  
  1317  				By("updating status of the object")
  1318  				node.Status.Phase = corev1.NodeRunning
  1319  				err = cl.Status().Update(context.TODO(), node)
  1320  				Expect(err).NotTo(HaveOccurred())
  1321  
  1322  				By("validate updated Node had new annotation")
  1323  				actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
  1324  				Expect(err).NotTo(HaveOccurred())
  1325  				Expect(actual).NotTo(BeNil())
  1326  				Expect(actual.Status.Phase).To(Equal(corev1.NodeRunning))
  1327  			})
  1328  
  1329  			It("should fail if the object does not exist", func() {
  1330  				cl, err := client.New(cfg, client.Options{})
  1331  				Expect(err).NotTo(HaveOccurred())
  1332  				Expect(cl).NotTo(BeNil())
  1333  
  1334  				By("updating status of a non-existent object")
  1335  				err = cl.Status().Update(context.TODO(), dep)
  1336  				Expect(err).To(HaveOccurred())
  1337  			})
  1338  
  1339  			It("should fail if the object cannot be mapped to a GVK", func() {
  1340  				By("creating client with empty Scheme")
  1341  				emptyScheme := runtime.NewScheme()
  1342  				cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
  1343  				Expect(err).NotTo(HaveOccurred())
  1344  				Expect(cl).NotTo(BeNil())
  1345  
  1346  				By("initially creating a Deployment")
  1347  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1348  				Expect(err).NotTo(HaveOccurred())
  1349  
  1350  				By("updating status of the Deployment")
  1351  				dep.Status.Replicas = 1
  1352  				err = cl.Status().Update(context.TODO(), dep)
  1353  				Expect(err).To(HaveOccurred())
  1354  				Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
  1355  			})
  1356  
  1357  			PIt("should fail if the GVK cannot be mapped to a Resource", func() {
  1358  
  1359  			})
  1360  
  1361  			PIt("should fail if an API does not implement Status subresource", func() {
  1362  
  1363  			})
  1364  		})
  1365  
  1366  		Context("with unstructured objects", func() {
  1367  			It("should update status of an existing object", func() {
  1368  				cl, err := client.New(cfg, client.Options{})
  1369  				Expect(err).NotTo(HaveOccurred())
  1370  				Expect(cl).NotTo(BeNil())
  1371  
  1372  				By("initially creating a Deployment")
  1373  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1374  				Expect(err).NotTo(HaveOccurred())
  1375  
  1376  				By("updating the status of Deployment")
  1377  				u := &unstructured.Unstructured{}
  1378  				dep.Status.Replicas = 1
  1379  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
  1380  				err = cl.Status().Update(context.TODO(), u)
  1381  				Expect(err).NotTo(HaveOccurred())
  1382  
  1383  				By("validating updated Deployment has new status")
  1384  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
  1385  				Expect(err).NotTo(HaveOccurred())
  1386  				Expect(actual).NotTo(BeNil())
  1387  				Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
  1388  			})
  1389  
  1390  			It("should update status and preserve type information", func() {
  1391  				cl, err := client.New(cfg, client.Options{})
  1392  				Expect(err).NotTo(HaveOccurred())
  1393  				Expect(cl).NotTo(BeNil())
  1394  
  1395  				By("initially creating a Deployment")
  1396  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1397  				Expect(err).NotTo(HaveOccurred())
  1398  
  1399  				By("updating the status of Deployment")
  1400  				u := &unstructured.Unstructured{}
  1401  				dep.Status.Replicas = 1
  1402  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
  1403  				err = cl.Status().Update(context.TODO(), u)
  1404  				Expect(err).NotTo(HaveOccurred())
  1405  
  1406  				By("validating updated Deployment has type information")
  1407  				Expect(u.GroupVersionKind()).To(Equal(depGvk))
  1408  			})
  1409  
  1410  			It("should patch status and preserve type information", func() {
  1411  				cl, err := client.New(cfg, client.Options{})
  1412  				Expect(err).NotTo(HaveOccurred())
  1413  				Expect(cl).NotTo(BeNil())
  1414  
  1415  				By("initially creating a Deployment")
  1416  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1417  				Expect(err).NotTo(HaveOccurred())
  1418  
  1419  				By("patching the status of Deployment")
  1420  				u := &unstructured.Unstructured{}
  1421  				depPatch := client.MergeFrom(dep.DeepCopy())
  1422  				dep.Status.Replicas = 1
  1423  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
  1424  				err = cl.Status().Patch(context.TODO(), u, depPatch)
  1425  				Expect(err).NotTo(HaveOccurred())
  1426  
  1427  				By("validating updated Deployment has type information")
  1428  				Expect(u.GroupVersionKind()).To(Equal(depGvk))
  1429  
  1430  				By("validating patched Deployment has new status")
  1431  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
  1432  				Expect(err).NotTo(HaveOccurred())
  1433  				Expect(actual).NotTo(BeNil())
  1434  				Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
  1435  			})
  1436  
  1437  			It("should not update spec of an existing object", func() {
  1438  				cl, err := client.New(cfg, client.Options{})
  1439  				Expect(err).NotTo(HaveOccurred())
  1440  				Expect(cl).NotTo(BeNil())
  1441  
  1442  				By("initially creating a Deployment")
  1443  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1444  				Expect(err).NotTo(HaveOccurred())
  1445  
  1446  				By("updating the spec and status of Deployment")
  1447  				u := &unstructured.Unstructured{}
  1448  				var rc int32 = 1
  1449  				dep.Status.Replicas = 1
  1450  				dep.Spec.Replicas = &rc
  1451  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
  1452  				err = cl.Status().Update(context.TODO(), u)
  1453  				Expect(err).NotTo(HaveOccurred())
  1454  
  1455  				By("validating updated Deployment has new status and unchanged spec")
  1456  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
  1457  				Expect(err).NotTo(HaveOccurred())
  1458  				Expect(actual).NotTo(BeNil())
  1459  				Expect(actual.Status.Replicas).To(BeEquivalentTo(1))
  1460  				Expect(*actual.Spec.Replicas).To(BeEquivalentTo(replicaCount))
  1461  			})
  1462  
  1463  			It("should update an existing object non-namespace object", func() {
  1464  				cl, err := client.New(cfg, client.Options{})
  1465  				Expect(err).NotTo(HaveOccurred())
  1466  				Expect(cl).NotTo(BeNil())
  1467  
  1468  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
  1469  				Expect(err).NotTo(HaveOccurred())
  1470  
  1471  				By("updating status of the object")
  1472  				u := &unstructured.Unstructured{}
  1473  				node.Status.Phase = corev1.NodeRunning
  1474  				Expect(scheme.Convert(node, u, nil)).To(Succeed())
  1475  				err = cl.Status().Update(context.TODO(), u)
  1476  				Expect(err).NotTo(HaveOccurred())
  1477  
  1478  				By("validate updated Node had new annotation")
  1479  				actual, err := clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
  1480  				Expect(err).NotTo(HaveOccurred())
  1481  				Expect(actual).NotTo(BeNil())
  1482  				Expect(actual.Status.Phase).To(Equal(corev1.NodeRunning))
  1483  			})
  1484  
  1485  			It("should fail if the object does not exist", func() {
  1486  				cl, err := client.New(cfg, client.Options{})
  1487  				Expect(err).NotTo(HaveOccurred())
  1488  				Expect(cl).NotTo(BeNil())
  1489  
  1490  				By("updating status of a non-existent object")
  1491  				u := &unstructured.Unstructured{}
  1492  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
  1493  				err = cl.Status().Update(context.TODO(), u)
  1494  				Expect(err).To(HaveOccurred())
  1495  			})
  1496  
  1497  			PIt("should fail if the GVK cannot be mapped to a Resource", func() {
  1498  
  1499  			})
  1500  
  1501  			PIt("should fail if an API does not implement Status subresource", func() {
  1502  
  1503  			})
  1504  
  1505  		})
  1506  
  1507  		Context("with metadata objects", func() {
  1508  			It("should fail to update with an error", func() {
  1509  				cl, err := client.New(cfg, client.Options{})
  1510  				Expect(err).NotTo(HaveOccurred())
  1511  
  1512  				obj := metaOnlyFromObj(dep, scheme)
  1513  				Expect(cl.Status().Update(context.TODO(), obj)).NotTo(Succeed())
  1514  			})
  1515  
  1516  			It("should patch status and preserve type information", func() {
  1517  				cl, err := client.New(cfg, client.Options{})
  1518  				Expect(err).NotTo(HaveOccurred())
  1519  				Expect(cl).NotTo(BeNil())
  1520  
  1521  				By("initially creating a Deployment")
  1522  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1523  				Expect(err).NotTo(HaveOccurred())
  1524  
  1525  				By("patching the status of Deployment")
  1526  				objPatch := client.MergeFrom(metaOnlyFromObj(dep, scheme))
  1527  				dep.Annotations = map[string]string{"some-new-annotation": "some-new-value"}
  1528  				obj := metaOnlyFromObj(dep, scheme)
  1529  				err = cl.Status().Patch(context.TODO(), obj, objPatch)
  1530  				Expect(err).NotTo(HaveOccurred())
  1531  
  1532  				By("validating updated Deployment has type information")
  1533  				Expect(obj.GroupVersionKind()).To(Equal(depGvk))
  1534  
  1535  				By("validating patched Deployment has new status")
  1536  				actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
  1537  				Expect(err).NotTo(HaveOccurred())
  1538  				Expect(actual).NotTo(BeNil())
  1539  				Expect(actual.Annotations).To(HaveKeyWithValue("some-new-annotation", "some-new-value"))
  1540  			})
  1541  		})
  1542  	})
  1543  
  1544  	Describe("Delete", func() {
  1545  		Context("with structured objects", func() {
  1546  			It("should delete an existing object from a go struct", func() {
  1547  				cl, err := client.New(cfg, client.Options{})
  1548  				Expect(err).NotTo(HaveOccurred())
  1549  				Expect(cl).NotTo(BeNil())
  1550  
  1551  				By("initially creating a Deployment")
  1552  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1553  				Expect(err).NotTo(HaveOccurred())
  1554  
  1555  				By("deleting the Deployment")
  1556  				depName := dep.Name
  1557  				err = cl.Delete(context.TODO(), dep)
  1558  				Expect(err).NotTo(HaveOccurred())
  1559  
  1560  				By("validating the Deployment no longer exists")
  1561  				_, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
  1562  				Expect(err).To(HaveOccurred())
  1563  			})
  1564  
  1565  			It("should delete an existing object non-namespace object from a go struct", func() {
  1566  				cl, err := client.New(cfg, client.Options{})
  1567  				Expect(err).NotTo(HaveOccurred())
  1568  				Expect(cl).NotTo(BeNil())
  1569  
  1570  				By("initially creating a Node")
  1571  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
  1572  				Expect(err).NotTo(HaveOccurred())
  1573  
  1574  				By("deleting the Node")
  1575  				nodeName := node.Name
  1576  				err = cl.Delete(context.TODO(), node)
  1577  				Expect(err).NotTo(HaveOccurred())
  1578  
  1579  				By("validating the Node no longer exists")
  1580  				_, err = clientset.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
  1581  				Expect(err).To(HaveOccurred())
  1582  			})
  1583  
  1584  			It("should fail if the object does not exist", func() {
  1585  				cl, err := client.New(cfg, client.Options{})
  1586  				Expect(err).NotTo(HaveOccurred())
  1587  				Expect(cl).NotTo(BeNil())
  1588  
  1589  				By("Deleting node before it is ever created")
  1590  				err = cl.Delete(context.TODO(), node)
  1591  				Expect(err).To(HaveOccurred())
  1592  			})
  1593  
  1594  			PIt("should fail if the object doesn't have meta", func() {
  1595  
  1596  			})
  1597  
  1598  			It("should fail if the object cannot be mapped to a GVK", func() {
  1599  				By("creating client with empty Scheme")
  1600  				emptyScheme := runtime.NewScheme()
  1601  				cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
  1602  				Expect(err).NotTo(HaveOccurred())
  1603  				Expect(cl).NotTo(BeNil())
  1604  
  1605  				By("initially creating a Deployment")
  1606  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1607  				Expect(err).NotTo(HaveOccurred())
  1608  
  1609  				By("deleting the Deployment fails")
  1610  				err = cl.Delete(context.TODO(), dep)
  1611  				Expect(err).To(HaveOccurred())
  1612  				Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
  1613  			})
  1614  
  1615  			PIt("should fail if the GVK cannot be mapped to a Resource", func() {
  1616  
  1617  			})
  1618  
  1619  			It("should delete a collection of objects", func() {
  1620  				cl, err := client.New(cfg, client.Options{})
  1621  				Expect(err).NotTo(HaveOccurred())
  1622  				Expect(cl).NotTo(BeNil())
  1623  
  1624  				By("initially creating two Deployments")
  1625  
  1626  				dep2 := dep.DeepCopy()
  1627  				dep2.Name += "-2"
  1628  
  1629  				dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1630  				Expect(err).NotTo(HaveOccurred())
  1631  				dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
  1632  				Expect(err).NotTo(HaveOccurred())
  1633  
  1634  				depName := dep.Name
  1635  				dep2Name := dep2.Name
  1636  
  1637  				By("deleting Deployments")
  1638  				err = cl.DeleteAllOf(context.TODO(), dep, client.InNamespace(ns), client.MatchingLabels(dep.ObjectMeta.Labels))
  1639  				Expect(err).NotTo(HaveOccurred())
  1640  
  1641  				By("validating the Deployment no longer exists")
  1642  				_, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
  1643  				Expect(err).To(HaveOccurred())
  1644  				_, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep2Name, metav1.GetOptions{})
  1645  				Expect(err).To(HaveOccurred())
  1646  			})
  1647  		})
  1648  		Context("with unstructured objects", func() {
  1649  			It("should delete an existing object from a go struct", func() {
  1650  				cl, err := client.New(cfg, client.Options{})
  1651  				Expect(err).NotTo(HaveOccurred())
  1652  				Expect(cl).NotTo(BeNil())
  1653  
  1654  				By("initially creating a Deployment")
  1655  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1656  				Expect(err).NotTo(HaveOccurred())
  1657  
  1658  				By("deleting the Deployment")
  1659  				depName := dep.Name
  1660  				u := &unstructured.Unstructured{}
  1661  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
  1662  				u.SetGroupVersionKind(schema.GroupVersionKind{
  1663  					Group:   "apps",
  1664  					Kind:    "Deployment",
  1665  					Version: "v1",
  1666  				})
  1667  				err = cl.Delete(context.TODO(), u)
  1668  				Expect(err).NotTo(HaveOccurred())
  1669  
  1670  				By("validating the Deployment no longer exists")
  1671  				_, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
  1672  				Expect(err).To(HaveOccurred())
  1673  			})
  1674  
  1675  			It("should delete an existing object non-namespace object from a go struct", func() {
  1676  				cl, err := client.New(cfg, client.Options{})
  1677  				Expect(err).NotTo(HaveOccurred())
  1678  				Expect(cl).NotTo(BeNil())
  1679  
  1680  				By("initially creating a Node")
  1681  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
  1682  				Expect(err).NotTo(HaveOccurred())
  1683  
  1684  				By("deleting the Node")
  1685  				nodeName := node.Name
  1686  				u := &unstructured.Unstructured{}
  1687  				Expect(scheme.Convert(node, u, nil)).To(Succeed())
  1688  				u.SetGroupVersionKind(schema.GroupVersionKind{
  1689  					Group:   "",
  1690  					Kind:    "Node",
  1691  					Version: "v1",
  1692  				})
  1693  				err = cl.Delete(context.TODO(), u)
  1694  				Expect(err).NotTo(HaveOccurred())
  1695  
  1696  				By("validating the Node no longer exists")
  1697  				_, err = clientset.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
  1698  				Expect(err).To(HaveOccurred())
  1699  			})
  1700  
  1701  			It("should fail if the object does not exist", func() {
  1702  				cl, err := client.New(cfg, client.Options{})
  1703  				Expect(err).NotTo(HaveOccurred())
  1704  				Expect(cl).NotTo(BeNil())
  1705  
  1706  				By("Deleting node before it is ever created")
  1707  				u := &unstructured.Unstructured{}
  1708  				Expect(scheme.Convert(node, u, nil)).To(Succeed())
  1709  				u.SetGroupVersionKind(schema.GroupVersionKind{
  1710  					Group:   "",
  1711  					Kind:    "Node",
  1712  					Version: "v1",
  1713  				})
  1714  				err = cl.Delete(context.TODO(), node)
  1715  				Expect(err).To(HaveOccurred())
  1716  			})
  1717  
  1718  			It("should delete a collection of object", func() {
  1719  				cl, err := client.New(cfg, client.Options{})
  1720  				Expect(err).NotTo(HaveOccurred())
  1721  				Expect(cl).NotTo(BeNil())
  1722  
  1723  				By("initially creating two Deployments")
  1724  
  1725  				dep2 := dep.DeepCopy()
  1726  				dep2.Name += "-2"
  1727  
  1728  				dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1729  				Expect(err).NotTo(HaveOccurred())
  1730  				dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
  1731  				Expect(err).NotTo(HaveOccurred())
  1732  
  1733  				depName := dep.Name
  1734  				dep2Name := dep2.Name
  1735  
  1736  				By("deleting Deployments")
  1737  				u := &unstructured.Unstructured{}
  1738  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
  1739  				u.SetGroupVersionKind(schema.GroupVersionKind{
  1740  					Group:   "apps",
  1741  					Kind:    "Deployment",
  1742  					Version: "v1",
  1743  				})
  1744  				err = cl.DeleteAllOf(context.TODO(), u, client.InNamespace(ns), client.MatchingLabels(dep.ObjectMeta.Labels))
  1745  				Expect(err).NotTo(HaveOccurred())
  1746  
  1747  				By("validating the Deployment no longer exists")
  1748  				_, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
  1749  				Expect(err).To(HaveOccurred())
  1750  				_, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep2Name, metav1.GetOptions{})
  1751  				Expect(err).To(HaveOccurred())
  1752  			})
  1753  		})
  1754  		Context("with metadata objects", func() {
  1755  			It("should delete an existing object from a go struct", func() {
  1756  				cl, err := client.New(cfg, client.Options{})
  1757  				Expect(err).NotTo(HaveOccurred())
  1758  				Expect(cl).NotTo(BeNil())
  1759  
  1760  				By("initially creating a Deployment")
  1761  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1762  				Expect(err).NotTo(HaveOccurred())
  1763  
  1764  				By("deleting the Deployment")
  1765  				metaObj := metaOnlyFromObj(dep, scheme)
  1766  				err = cl.Delete(context.TODO(), metaObj)
  1767  				Expect(err).NotTo(HaveOccurred())
  1768  
  1769  				By("validating the Deployment no longer exists")
  1770  				_, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
  1771  				Expect(err).To(HaveOccurred())
  1772  			})
  1773  
  1774  			It("should delete an existing object non-namespace object from a go struct", func() {
  1775  				cl, err := client.New(cfg, client.Options{})
  1776  				Expect(err).NotTo(HaveOccurred())
  1777  				Expect(cl).NotTo(BeNil())
  1778  
  1779  				By("initially creating a Node")
  1780  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
  1781  				Expect(err).NotTo(HaveOccurred())
  1782  
  1783  				By("deleting the Node")
  1784  				metaObj := metaOnlyFromObj(node, scheme)
  1785  				err = cl.Delete(context.TODO(), metaObj)
  1786  				Expect(err).NotTo(HaveOccurred())
  1787  
  1788  				By("validating the Node no longer exists")
  1789  				_, err = clientset.CoreV1().Nodes().Get(ctx, node.Name, metav1.GetOptions{})
  1790  				Expect(err).To(HaveOccurred())
  1791  			})
  1792  
  1793  			It("should fail if the object does not exist", func() {
  1794  				cl, err := client.New(cfg, client.Options{})
  1795  				Expect(err).NotTo(HaveOccurred())
  1796  				Expect(cl).NotTo(BeNil())
  1797  
  1798  				By("Deleting node before it is ever created")
  1799  				metaObj := metaOnlyFromObj(node, scheme)
  1800  				err = cl.Delete(context.TODO(), metaObj)
  1801  				Expect(err).To(HaveOccurred())
  1802  			})
  1803  
  1804  			It("should delete a collection of object", func() {
  1805  				cl, err := client.New(cfg, client.Options{})
  1806  				Expect(err).NotTo(HaveOccurred())
  1807  				Expect(cl).NotTo(BeNil())
  1808  
  1809  				By("initially creating two Deployments")
  1810  
  1811  				dep2 := dep.DeepCopy()
  1812  				dep2.Name += "-2"
  1813  
  1814  				dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1815  				Expect(err).NotTo(HaveOccurred())
  1816  				dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
  1817  				Expect(err).NotTo(HaveOccurred())
  1818  
  1819  				depName := dep.Name
  1820  				dep2Name := dep2.Name
  1821  
  1822  				By("deleting Deployments")
  1823  				metaObj := metaOnlyFromObj(dep, scheme)
  1824  				err = cl.DeleteAllOf(context.TODO(), metaObj, client.InNamespace(ns), client.MatchingLabels(dep.ObjectMeta.Labels))
  1825  				Expect(err).NotTo(HaveOccurred())
  1826  
  1827  				By("validating the Deployment no longer exists")
  1828  				_, err = clientset.AppsV1().Deployments(ns).Get(ctx, depName, metav1.GetOptions{})
  1829  				Expect(err).To(HaveOccurred())
  1830  				_, err = clientset.AppsV1().Deployments(ns).Get(ctx, dep2Name, metav1.GetOptions{})
  1831  				Expect(err).To(HaveOccurred())
  1832  			})
  1833  		})
  1834  	})
  1835  
  1836  	Describe("Get", func() {
  1837  		Context("with structured objects", func() {
  1838  			It("should fetch an existing object for a go struct", func() {
  1839  				By("first creating the Deployment")
  1840  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1841  				Expect(err).NotTo(HaveOccurred())
  1842  
  1843  				cl, err := client.New(cfg, client.Options{})
  1844  				Expect(err).NotTo(HaveOccurred())
  1845  				Expect(cl).NotTo(BeNil())
  1846  
  1847  				By("fetching the created Deployment")
  1848  				var actual appsv1.Deployment
  1849  				key := client.ObjectKey{Namespace: ns, Name: dep.Name}
  1850  				err = cl.Get(context.TODO(), key, &actual)
  1851  				Expect(err).NotTo(HaveOccurred())
  1852  				Expect(actual).NotTo(BeNil())
  1853  
  1854  				By("validating the fetched deployment equals the created one")
  1855  				Expect(dep).To(Equal(&actual))
  1856  			})
  1857  
  1858  			It("should fetch an existing non-namespace object for a go struct", func() {
  1859  				By("first creating the object")
  1860  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
  1861  				Expect(err).NotTo(HaveOccurred())
  1862  
  1863  				cl, err := client.New(cfg, client.Options{})
  1864  				Expect(err).NotTo(HaveOccurred())
  1865  				Expect(cl).NotTo(BeNil())
  1866  
  1867  				By("retrieving node through client")
  1868  				var actual corev1.Node
  1869  				key := client.ObjectKey{Namespace: ns, Name: node.Name}
  1870  				err = cl.Get(context.TODO(), key, &actual)
  1871  				Expect(err).NotTo(HaveOccurred())
  1872  				Expect(actual).NotTo(BeNil())
  1873  
  1874  				Expect(node).To(Equal(&actual))
  1875  			})
  1876  
  1877  			It("should fail if the object does not exist", func() {
  1878  				cl, err := client.New(cfg, client.Options{})
  1879  				Expect(err).NotTo(HaveOccurred())
  1880  				Expect(cl).NotTo(BeNil())
  1881  
  1882  				By("fetching object that has not been created yet")
  1883  				key := client.ObjectKey{Namespace: ns, Name: dep.Name}
  1884  				var actual appsv1.Deployment
  1885  				err = cl.Get(context.TODO(), key, &actual)
  1886  				Expect(err).To(HaveOccurred())
  1887  			})
  1888  
  1889  			PIt("should fail if the object doesn't have meta", func() {
  1890  
  1891  			})
  1892  
  1893  			It("should fail if the object cannot be mapped to a GVK", func() {
  1894  				By("first creating the Deployment")
  1895  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1896  				Expect(err).NotTo(HaveOccurred())
  1897  
  1898  				By("creating a client with an empty Scheme")
  1899  				emptyScheme := runtime.NewScheme()
  1900  				cl, err := client.New(cfg, client.Options{Scheme: emptyScheme})
  1901  				Expect(err).NotTo(HaveOccurred())
  1902  				Expect(cl).NotTo(BeNil())
  1903  
  1904  				By("fetching the created Deployment fails")
  1905  				var actual appsv1.Deployment
  1906  				key := client.ObjectKey{Namespace: ns, Name: dep.Name}
  1907  				err = cl.Get(context.TODO(), key, &actual)
  1908  				Expect(err).To(HaveOccurred())
  1909  				Expect(err.Error()).To(ContainSubstring("no kind is registered for the type"))
  1910  			})
  1911  
  1912  			PIt("should fail if the GVK cannot be mapped to a Resource", func() {
  1913  
  1914  			})
  1915  
  1916  			// Test this with an integrated type and a CRD to make sure it covers both proto
  1917  			// and json deserialization.
  1918  			for idx, object := range []client.Object{&corev1.ConfigMap{}, &pkg.ChaosPod{}} {
  1919  				idx, object := idx, object
  1920  				It(fmt.Sprintf("should not retain any data in the obj variable that is not on the server for %T", object), func() {
  1921  					cl, err := client.New(cfg, client.Options{})
  1922  					Expect(err).NotTo(HaveOccurred())
  1923  					Expect(cl).NotTo(BeNil())
  1924  
  1925  					object.SetName(fmt.Sprintf("retain-test-%d", idx))
  1926  					object.SetNamespace(ns)
  1927  
  1928  					By("First creating the object")
  1929  					toCreate := object.DeepCopyObject().(client.Object)
  1930  					Expect(cl.Create(ctx, toCreate)).NotTo(HaveOccurred())
  1931  
  1932  					By("Fetching it into a variable that has finalizers set")
  1933  					toGetInto := object.DeepCopyObject().(client.Object)
  1934  					toGetInto.SetFinalizers([]string{"some-finalizer"})
  1935  					Expect(cl.Get(ctx, client.ObjectKeyFromObject(object), toGetInto)).NotTo(HaveOccurred())
  1936  
  1937  					By("Ensuring the created and the received object are equal")
  1938  					Expect(toCreate).Should(Equal(toGetInto))
  1939  				})
  1940  			}
  1941  
  1942  		})
  1943  
  1944  		Context("with unstructured objects", func() {
  1945  			It("should fetch an existing object", func() {
  1946  				By("first creating the Deployment")
  1947  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  1948  				Expect(err).NotTo(HaveOccurred())
  1949  
  1950  				cl, err := client.New(cfg, client.Options{})
  1951  				Expect(err).NotTo(HaveOccurred())
  1952  				Expect(cl).NotTo(BeNil())
  1953  
  1954  				By("encoding the Deployment as unstructured")
  1955  				var u runtime.Unstructured = &unstructured.Unstructured{}
  1956  				Expect(scheme.Convert(dep, u, nil)).To(Succeed())
  1957  
  1958  				By("fetching the created Deployment")
  1959  				var actual unstructured.Unstructured
  1960  				actual.SetGroupVersionKind(schema.GroupVersionKind{
  1961  					Group:   "apps",
  1962  					Kind:    "Deployment",
  1963  					Version: "v1",
  1964  				})
  1965  				key := client.ObjectKey{Namespace: ns, Name: dep.Name}
  1966  				err = cl.Get(context.TODO(), key, &actual)
  1967  				Expect(err).NotTo(HaveOccurred())
  1968  				Expect(actual).NotTo(BeNil())
  1969  
  1970  				By("validating the fetched Deployment equals the created one")
  1971  				Expect(u).To(Equal(&actual))
  1972  			})
  1973  
  1974  			It("should fetch an existing non-namespace object", func() {
  1975  				By("first creating the Node")
  1976  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
  1977  				Expect(err).NotTo(HaveOccurred())
  1978  
  1979  				By("encoding the Node as unstructured")
  1980  				var u runtime.Unstructured = &unstructured.Unstructured{}
  1981  				Expect(scheme.Convert(node, u, nil)).To(Succeed())
  1982  
  1983  				cl, err := client.New(cfg, client.Options{})
  1984  				Expect(err).NotTo(HaveOccurred())
  1985  				Expect(cl).NotTo(BeNil())
  1986  
  1987  				By("fetching the created Node")
  1988  				var actual unstructured.Unstructured
  1989  				actual.SetGroupVersionKind(schema.GroupVersionKind{
  1990  					Group:   "",
  1991  					Kind:    "Node",
  1992  					Version: "v1",
  1993  				})
  1994  				key := client.ObjectKey{Namespace: ns, Name: node.Name}
  1995  				err = cl.Get(context.TODO(), key, &actual)
  1996  				Expect(err).NotTo(HaveOccurred())
  1997  				Expect(actual).NotTo(BeNil())
  1998  
  1999  				By("validating the fetched Node equals the created one")
  2000  				Expect(u).To(Equal(&actual))
  2001  			})
  2002  
  2003  			It("should fail if the object does not exist", func() {
  2004  				cl, err := client.New(cfg, client.Options{})
  2005  				Expect(err).NotTo(HaveOccurred())
  2006  				Expect(cl).NotTo(BeNil())
  2007  
  2008  				By("fetching object that has not been created yet")
  2009  				key := client.ObjectKey{Namespace: ns, Name: dep.Name}
  2010  				u := &unstructured.Unstructured{}
  2011  				err = cl.Get(context.TODO(), key, u)
  2012  				Expect(err).To(HaveOccurred())
  2013  			})
  2014  
  2015  			It("should not retain any data in the obj variable that is not on the server", func() {
  2016  				object := &unstructured.Unstructured{}
  2017  				cl, err := client.New(cfg, client.Options{})
  2018  				Expect(err).NotTo(HaveOccurred())
  2019  				Expect(cl).NotTo(BeNil())
  2020  
  2021  				object.SetName("retain-unstructured")
  2022  				object.SetNamespace(ns)
  2023  				object.SetAPIVersion("chaosapps.metamagical.io/v1")
  2024  				object.SetKind("ChaosPod")
  2025  
  2026  				By("First creating the object")
  2027  				toCreate := object.DeepCopyObject().(client.Object)
  2028  				Expect(cl.Create(ctx, toCreate)).NotTo(HaveOccurred())
  2029  
  2030  				By("Fetching it into a variable that has finalizers set")
  2031  				toGetInto := object.DeepCopyObject().(client.Object)
  2032  				toGetInto.SetFinalizers([]string{"some-finalizer"})
  2033  				Expect(cl.Get(ctx, client.ObjectKeyFromObject(object), toGetInto)).NotTo(HaveOccurred())
  2034  
  2035  				By("Ensuring the created and the received object are equal")
  2036  				Expect(toCreate).Should(Equal(toGetInto))
  2037  			})
  2038  		})
  2039  		Context("with metadata objects", func() {
  2040  			It("should fetch an existing object for a go struct", func() {
  2041  				By("first creating the Deployment")
  2042  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  2043  				Expect(err).NotTo(HaveOccurred())
  2044  
  2045  				cl, err := client.New(cfg, client.Options{})
  2046  				Expect(err).NotTo(HaveOccurred())
  2047  				Expect(cl).NotTo(BeNil())
  2048  
  2049  				By("fetching the created Deployment")
  2050  				var actual metav1.PartialObjectMetadata
  2051  				gvk := schema.GroupVersionKind{
  2052  					Group:   "apps",
  2053  					Version: "v1",
  2054  					Kind:    "Deployment",
  2055  				}
  2056  				actual.SetGroupVersionKind(gvk)
  2057  				key := client.ObjectKey{Namespace: ns, Name: dep.Name}
  2058  				err = cl.Get(context.TODO(), key, &actual)
  2059  				Expect(err).NotTo(HaveOccurred())
  2060  				Expect(actual).NotTo(BeNil())
  2061  
  2062  				By("validating that the GVK has been preserved")
  2063  				Expect(actual.GroupVersionKind()).To(Equal(gvk))
  2064  
  2065  				By("validating the fetched deployment equals the created one")
  2066  				Expect(metaOnlyFromObj(dep, scheme)).To(Equal(&actual))
  2067  			})
  2068  
  2069  			It("should fetch an existing non-namespace object for a go struct", func() {
  2070  				By("first creating the object")
  2071  				node, err := clientset.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{})
  2072  				Expect(err).NotTo(HaveOccurred())
  2073  
  2074  				cl, err := client.New(cfg, client.Options{})
  2075  				Expect(err).NotTo(HaveOccurred())
  2076  				Expect(cl).NotTo(BeNil())
  2077  
  2078  				By("retrieving node through client")
  2079  				var actual metav1.PartialObjectMetadata
  2080  				actual.SetGroupVersionKind(schema.GroupVersionKind{
  2081  					Version: "v1",
  2082  					Kind:    "Node",
  2083  				})
  2084  				key := client.ObjectKey{Namespace: ns, Name: node.Name}
  2085  				err = cl.Get(context.TODO(), key, &actual)
  2086  				Expect(err).NotTo(HaveOccurred())
  2087  				Expect(actual).NotTo(BeNil())
  2088  
  2089  				Expect(metaOnlyFromObj(node, scheme)).To(Equal(&actual))
  2090  			})
  2091  
  2092  			It("should fail if the object does not exist", func() {
  2093  				cl, err := client.New(cfg, client.Options{})
  2094  				Expect(err).NotTo(HaveOccurred())
  2095  				Expect(cl).NotTo(BeNil())
  2096  
  2097  				By("fetching object that has not been created yet")
  2098  				key := client.ObjectKey{Namespace: ns, Name: dep.Name}
  2099  				var actual metav1.PartialObjectMetadata
  2100  				actual.SetGroupVersionKind(schema.GroupVersionKind{
  2101  					Group:   "apps",
  2102  					Version: "v1",
  2103  					Kind:    "Deployment",
  2104  				})
  2105  				err = cl.Get(context.TODO(), key, &actual)
  2106  				Expect(err).To(HaveOccurred())
  2107  			})
  2108  
  2109  			PIt("should fail if the object doesn't have meta", func() {
  2110  
  2111  			})
  2112  
  2113  			PIt("should fail if the GVK cannot be mapped to a Resource", func() {
  2114  
  2115  			})
  2116  
  2117  			It("should not retain any data in the obj variable that is not on the server", func() {
  2118  				cl, err := client.New(cfg, client.Options{})
  2119  				Expect(err).NotTo(HaveOccurred())
  2120  				Expect(cl).NotTo(BeNil())
  2121  
  2122  				By("First creating the object")
  2123  				toCreate := &pkg.ChaosPod{ObjectMeta: metav1.ObjectMeta{Name: "retain-metadata", Namespace: ns}}
  2124  				Expect(cl.Create(ctx, toCreate)).NotTo(HaveOccurred())
  2125  
  2126  				By("Fetching it into a variable that has finalizers set")
  2127  				toGetInto := &metav1.PartialObjectMetadata{
  2128  					TypeMeta:   metav1.TypeMeta{APIVersion: "chaosapps.metamagical.io/v1", Kind: "ChaosPod"},
  2129  					ObjectMeta: metav1.ObjectMeta{Namespace: ns, Name: "retain-metadata"},
  2130  				}
  2131  				toGetInto.SetFinalizers([]string{"some-finalizer"})
  2132  				Expect(cl.Get(ctx, client.ObjectKeyFromObject(toGetInto), toGetInto)).NotTo(HaveOccurred())
  2133  
  2134  				By("Ensuring the created and the received objects metadata are equal")
  2135  				Expect(toCreate.ObjectMeta).Should(Equal(toGetInto.ObjectMeta))
  2136  			})
  2137  		})
  2138  	})
  2139  
  2140  	Describe("List", func() {
  2141  		Context("with structured objects", func() {
  2142  			It("should fetch collection of objects", func() {
  2143  				By("creating an initial object")
  2144  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  2145  				Expect(err).NotTo(HaveOccurred())
  2146  
  2147  				cl, err := client.New(cfg, client.Options{})
  2148  				Expect(err).NotTo(HaveOccurred())
  2149  
  2150  				By("listing all objects of that type in the cluster")
  2151  				deps := &appsv1.DeploymentList{}
  2152  				Expect(cl.List(context.Background(), deps)).NotTo(HaveOccurred())
  2153  
  2154  				Expect(deps.Items).NotTo(BeEmpty())
  2155  				hasDep := false
  2156  				for _, item := range deps.Items {
  2157  					if item.Name == dep.Name && item.Namespace == dep.Namespace {
  2158  						hasDep = true
  2159  						break
  2160  					}
  2161  				}
  2162  				Expect(hasDep).To(BeTrue())
  2163  			})
  2164  
  2165  			It("should fetch unstructured collection of objects", func() {
  2166  				By("create an initial object")
  2167  				_, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  2168  				Expect(err).NotTo(HaveOccurred())
  2169  
  2170  				cl, err := client.New(cfg, client.Options{})
  2171  				Expect(err).NotTo(HaveOccurred())
  2172  
  2173  				By("listing all objects of that type in the cluster")
  2174  				deps := &unstructured.UnstructuredList{}
  2175  				deps.SetGroupVersionKind(schema.GroupVersionKind{
  2176  					Group:   "apps",
  2177  					Kind:    "DeploymentList",
  2178  					Version: "v1",
  2179  				})
  2180  				err = cl.List(context.Background(), deps)
  2181  				Expect(err).NotTo(HaveOccurred())
  2182  
  2183  				Expect(deps.Items).NotTo(BeEmpty())
  2184  				hasDep := false
  2185  				for _, item := range deps.Items {
  2186  					Expect(item.GroupVersionKind()).To(Equal(schema.GroupVersionKind{
  2187  						Group:   "apps",
  2188  						Kind:    "Deployment",
  2189  						Version: "v1",
  2190  					}))
  2191  					if item.GetName() == dep.Name && item.GetNamespace() == dep.Namespace {
  2192  						hasDep = true
  2193  						break
  2194  					}
  2195  				}
  2196  				Expect(hasDep).To(BeTrue())
  2197  			})
  2198  
  2199  			It("should fetch unstructured collection of objects, even if scheme is empty", func() {
  2200  				By("create an initial object")
  2201  				_, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  2202  				Expect(err).NotTo(HaveOccurred())
  2203  
  2204  				cl, err := client.New(cfg, client.Options{Scheme: runtime.NewScheme()})
  2205  				Expect(err).NotTo(HaveOccurred())
  2206  
  2207  				By("listing all objects of that type in the cluster")
  2208  				deps := &unstructured.UnstructuredList{}
  2209  				deps.SetGroupVersionKind(schema.GroupVersionKind{
  2210  					Group:   "apps",
  2211  					Kind:    "DeploymentList",
  2212  					Version: "v1",
  2213  				})
  2214  				err = cl.List(context.Background(), deps)
  2215  				Expect(err).NotTo(HaveOccurred())
  2216  
  2217  				Expect(deps.Items).NotTo(BeEmpty())
  2218  				hasDep := false
  2219  				for _, item := range deps.Items {
  2220  					if item.GetName() == dep.Name && item.GetNamespace() == dep.Namespace {
  2221  						hasDep = true
  2222  						break
  2223  					}
  2224  				}
  2225  				Expect(hasDep).To(BeTrue())
  2226  			})
  2227  
  2228  			It("should return an empty list if there are no matching objects", func() {
  2229  				cl, err := client.New(cfg, client.Options{})
  2230  				Expect(err).NotTo(HaveOccurred())
  2231  
  2232  				By("listing all Deployments in the cluster")
  2233  				deps := &appsv1.DeploymentList{}
  2234  				Expect(cl.List(context.Background(), deps)).NotTo(HaveOccurred())
  2235  
  2236  				By("validating no Deployments are returned")
  2237  				Expect(deps.Items).To(BeEmpty())
  2238  			})
  2239  
  2240  			// TODO(seans): get label selector test working
  2241  			It("should filter results by label selector", func() {
  2242  				By("creating a Deployment with the app=frontend label")
  2243  				depFrontend := &appsv1.Deployment{
  2244  					ObjectMeta: metav1.ObjectMeta{
  2245  						Name:      "deployment-frontend",
  2246  						Namespace: ns,
  2247  						Labels:    map[string]string{"app": "frontend"},
  2248  					},
  2249  					Spec: appsv1.DeploymentSpec{
  2250  						Selector: &metav1.LabelSelector{
  2251  							MatchLabels: map[string]string{"app": "frontend"},
  2252  						},
  2253  						Template: corev1.PodTemplateSpec{
  2254  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2255  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2256  						},
  2257  					},
  2258  				}
  2259  				depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
  2260  				Expect(err).NotTo(HaveOccurred())
  2261  
  2262  				By("creating a Deployment with the app=backend label")
  2263  				depBackend := &appsv1.Deployment{
  2264  					ObjectMeta: metav1.ObjectMeta{
  2265  						Name:      "deployment-backend",
  2266  						Namespace: ns,
  2267  						Labels:    map[string]string{"app": "backend"},
  2268  					},
  2269  					Spec: appsv1.DeploymentSpec{
  2270  						Selector: &metav1.LabelSelector{
  2271  							MatchLabels: map[string]string{"app": "backend"},
  2272  						},
  2273  						Template: corev1.PodTemplateSpec{
  2274  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  2275  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2276  						},
  2277  					},
  2278  				}
  2279  				depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
  2280  				Expect(err).NotTo(HaveOccurred())
  2281  
  2282  				cl, err := client.New(cfg, client.Options{})
  2283  				Expect(err).NotTo(HaveOccurred())
  2284  
  2285  				By("listing all Deployments with label app=backend")
  2286  				deps := &appsv1.DeploymentList{}
  2287  				labels := map[string]string{"app": "backend"}
  2288  				err = cl.List(context.Background(), deps, client.MatchingLabels(labels))
  2289  				Expect(err).NotTo(HaveOccurred())
  2290  
  2291  				By("only the Deployment with the backend label is returned")
  2292  				Expect(deps.Items).NotTo(BeEmpty())
  2293  				Expect(1).To(Equal(len(deps.Items)))
  2294  				actual := deps.Items[0]
  2295  				Expect(actual.Name).To(Equal("deployment-backend"))
  2296  
  2297  				deleteDeployment(ctx, depFrontend, ns)
  2298  				deleteDeployment(ctx, depBackend, ns)
  2299  			})
  2300  
  2301  			It("should filter results by namespace selector", func() {
  2302  				By("creating a Deployment in test-namespace-1")
  2303  				tns1 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-1"}}
  2304  				_, err := clientset.CoreV1().Namespaces().Create(ctx, tns1, metav1.CreateOptions{})
  2305  				Expect(err).NotTo(HaveOccurred())
  2306  				depFrontend := &appsv1.Deployment{
  2307  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: "test-namespace-1"},
  2308  					Spec: appsv1.DeploymentSpec{
  2309  						Selector: &metav1.LabelSelector{
  2310  							MatchLabels: map[string]string{"app": "frontend"},
  2311  						},
  2312  						Template: corev1.PodTemplateSpec{
  2313  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2314  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2315  						},
  2316  					},
  2317  				}
  2318  				depFrontend, err = clientset.AppsV1().Deployments("test-namespace-1").Create(ctx, depFrontend, metav1.CreateOptions{})
  2319  				Expect(err).NotTo(HaveOccurred())
  2320  
  2321  				By("creating a Deployment in test-namespace-2")
  2322  				tns2 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-2"}}
  2323  				_, err = clientset.CoreV1().Namespaces().Create(ctx, tns2, metav1.CreateOptions{})
  2324  				Expect(err).NotTo(HaveOccurred())
  2325  				depBackend := &appsv1.Deployment{
  2326  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: "test-namespace-2"},
  2327  					Spec: appsv1.DeploymentSpec{
  2328  						Selector: &metav1.LabelSelector{
  2329  							MatchLabels: map[string]string{"app": "backend"},
  2330  						},
  2331  						Template: corev1.PodTemplateSpec{
  2332  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  2333  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2334  						},
  2335  					},
  2336  				}
  2337  				depBackend, err = clientset.AppsV1().Deployments("test-namespace-2").Create(ctx, depBackend, metav1.CreateOptions{})
  2338  				Expect(err).NotTo(HaveOccurred())
  2339  
  2340  				cl, err := client.New(cfg, client.Options{})
  2341  				Expect(err).NotTo(HaveOccurred())
  2342  
  2343  				By("listing all Deployments in test-namespace-1")
  2344  				deps := &appsv1.DeploymentList{}
  2345  				err = cl.List(context.Background(), deps, client.InNamespace("test-namespace-1"))
  2346  				Expect(err).NotTo(HaveOccurred())
  2347  
  2348  				By("only the Deployment in test-namespace-1 is returned")
  2349  				Expect(deps.Items).NotTo(BeEmpty())
  2350  				Expect(1).To(Equal(len(deps.Items)))
  2351  				actual := deps.Items[0]
  2352  				Expect(actual.Name).To(Equal("deployment-frontend"))
  2353  
  2354  				deleteDeployment(ctx, depFrontend, "test-namespace-1")
  2355  				deleteDeployment(ctx, depBackend, "test-namespace-2")
  2356  				deleteNamespace(ctx, tns1)
  2357  				deleteNamespace(ctx, tns2)
  2358  			})
  2359  
  2360  			It("should filter results by field selector", func() {
  2361  				By("creating a Deployment with name deployment-frontend")
  2362  				depFrontend := &appsv1.Deployment{
  2363  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: ns},
  2364  					Spec: appsv1.DeploymentSpec{
  2365  						Selector: &metav1.LabelSelector{
  2366  							MatchLabels: map[string]string{"app": "frontend"},
  2367  						},
  2368  						Template: corev1.PodTemplateSpec{
  2369  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2370  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2371  						},
  2372  					},
  2373  				}
  2374  				depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
  2375  				Expect(err).NotTo(HaveOccurred())
  2376  
  2377  				By("creating a Deployment with name deployment-backend")
  2378  				depBackend := &appsv1.Deployment{
  2379  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: ns},
  2380  					Spec: appsv1.DeploymentSpec{
  2381  						Selector: &metav1.LabelSelector{
  2382  							MatchLabels: map[string]string{"app": "backend"},
  2383  						},
  2384  						Template: corev1.PodTemplateSpec{
  2385  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  2386  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2387  						},
  2388  					},
  2389  				}
  2390  				depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
  2391  				Expect(err).NotTo(HaveOccurred())
  2392  
  2393  				cl, err := client.New(cfg, client.Options{})
  2394  				Expect(err).NotTo(HaveOccurred())
  2395  
  2396  				By("listing all Deployments with field metadata.name=deployment-backend")
  2397  				deps := &appsv1.DeploymentList{}
  2398  				err = cl.List(context.Background(), deps,
  2399  					client.MatchingFields{"metadata.name": "deployment-backend"})
  2400  				Expect(err).NotTo(HaveOccurred())
  2401  
  2402  				By("only the Deployment with the backend field is returned")
  2403  				Expect(deps.Items).NotTo(BeEmpty())
  2404  				Expect(1).To(Equal(len(deps.Items)))
  2405  				actual := deps.Items[0]
  2406  				Expect(actual.Name).To(Equal("deployment-backend"))
  2407  
  2408  				deleteDeployment(ctx, depFrontend, ns)
  2409  				deleteDeployment(ctx, depBackend, ns)
  2410  			})
  2411  
  2412  			It("should filter results by namespace selector and label selector", func() {
  2413  				By("creating a Deployment in test-namespace-3 with the app=frontend label")
  2414  				tns3 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-3"}}
  2415  				_, err := clientset.CoreV1().Namespaces().Create(ctx, tns3, metav1.CreateOptions{})
  2416  				Expect(err).NotTo(HaveOccurred())
  2417  				depFrontend3 := &appsv1.Deployment{
  2418  					ObjectMeta: metav1.ObjectMeta{
  2419  						Name:      "deployment-frontend",
  2420  						Namespace: "test-namespace-3",
  2421  						Labels:    map[string]string{"app": "frontend"},
  2422  					},
  2423  					Spec: appsv1.DeploymentSpec{
  2424  						Selector: &metav1.LabelSelector{
  2425  							MatchLabels: map[string]string{"app": "frontend"},
  2426  						},
  2427  						Template: corev1.PodTemplateSpec{
  2428  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2429  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2430  						},
  2431  					},
  2432  				}
  2433  				depFrontend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(ctx, depFrontend3, metav1.CreateOptions{})
  2434  				Expect(err).NotTo(HaveOccurred())
  2435  
  2436  				By("creating a Deployment in test-namespace-3 with the app=backend label")
  2437  				depBackend3 := &appsv1.Deployment{
  2438  					ObjectMeta: metav1.ObjectMeta{
  2439  						Name:      "deployment-backend",
  2440  						Namespace: "test-namespace-3",
  2441  						Labels:    map[string]string{"app": "backend"},
  2442  					},
  2443  					Spec: appsv1.DeploymentSpec{
  2444  						Selector: &metav1.LabelSelector{
  2445  							MatchLabels: map[string]string{"app": "backend"},
  2446  						},
  2447  						Template: corev1.PodTemplateSpec{
  2448  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  2449  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2450  						},
  2451  					},
  2452  				}
  2453  				depBackend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(ctx, depBackend3, metav1.CreateOptions{})
  2454  				Expect(err).NotTo(HaveOccurred())
  2455  
  2456  				By("creating a Deployment in test-namespace-4 with the app=frontend label")
  2457  				tns4 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-4"}}
  2458  				_, err = clientset.CoreV1().Namespaces().Create(ctx, tns4, metav1.CreateOptions{})
  2459  				Expect(err).NotTo(HaveOccurred())
  2460  				depFrontend4 := &appsv1.Deployment{
  2461  					ObjectMeta: metav1.ObjectMeta{
  2462  						Name:      "deployment-frontend",
  2463  						Namespace: "test-namespace-4",
  2464  						Labels:    map[string]string{"app": "frontend"},
  2465  					},
  2466  					Spec: appsv1.DeploymentSpec{
  2467  						Selector: &metav1.LabelSelector{
  2468  							MatchLabels: map[string]string{"app": "frontend"},
  2469  						},
  2470  						Template: corev1.PodTemplateSpec{
  2471  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2472  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2473  						},
  2474  					},
  2475  				}
  2476  				depFrontend4, err = clientset.AppsV1().Deployments("test-namespace-4").Create(ctx, depFrontend4, metav1.CreateOptions{})
  2477  				Expect(err).NotTo(HaveOccurred())
  2478  
  2479  				cl, err := client.New(cfg, client.Options{})
  2480  				Expect(err).NotTo(HaveOccurred())
  2481  
  2482  				By("listing all Deployments in test-namespace-3 with label app=frontend")
  2483  				deps := &appsv1.DeploymentList{}
  2484  				labels := map[string]string{"app": "frontend"}
  2485  				err = cl.List(context.Background(), deps,
  2486  					client.InNamespace("test-namespace-3"),
  2487  					client.MatchingLabels(labels),
  2488  				)
  2489  				Expect(err).NotTo(HaveOccurred())
  2490  
  2491  				By("only the Deployment in test-namespace-3 with label app=frontend is returned")
  2492  				Expect(deps.Items).NotTo(BeEmpty())
  2493  				Expect(1).To(Equal(len(deps.Items)))
  2494  				actual := deps.Items[0]
  2495  				Expect(actual.Name).To(Equal("deployment-frontend"))
  2496  				Expect(actual.Namespace).To(Equal("test-namespace-3"))
  2497  
  2498  				deleteDeployment(ctx, depFrontend3, "test-namespace-3")
  2499  				deleteDeployment(ctx, depBackend3, "test-namespace-3")
  2500  				deleteDeployment(ctx, depFrontend4, "test-namespace-4")
  2501  				deleteNamespace(ctx, tns3)
  2502  				deleteNamespace(ctx, tns4)
  2503  			})
  2504  
  2505  			It("should filter results using limit and continue options", func() {
  2506  
  2507  				makeDeployment := func(suffix string) *appsv1.Deployment {
  2508  					return &appsv1.Deployment{
  2509  						ObjectMeta: metav1.ObjectMeta{
  2510  							Name: fmt.Sprintf("deployment-%s", suffix),
  2511  						},
  2512  						Spec: appsv1.DeploymentSpec{
  2513  							Selector: &metav1.LabelSelector{
  2514  								MatchLabels: map[string]string{"foo": "bar"},
  2515  							},
  2516  							Template: corev1.PodTemplateSpec{
  2517  								ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
  2518  								Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2519  							},
  2520  						},
  2521  					}
  2522  				}
  2523  
  2524  				By("creating 4 deployments")
  2525  				dep1 := makeDeployment("1")
  2526  				dep1, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep1, metav1.CreateOptions{})
  2527  				Expect(err).NotTo(HaveOccurred())
  2528  				defer deleteDeployment(ctx, dep1, ns)
  2529  
  2530  				dep2 := makeDeployment("2")
  2531  				dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
  2532  				Expect(err).NotTo(HaveOccurred())
  2533  				defer deleteDeployment(ctx, dep2, ns)
  2534  
  2535  				dep3 := makeDeployment("3")
  2536  				dep3, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep3, metav1.CreateOptions{})
  2537  				Expect(err).NotTo(HaveOccurred())
  2538  				defer deleteDeployment(ctx, dep3, ns)
  2539  
  2540  				dep4 := makeDeployment("4")
  2541  				dep4, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep4, metav1.CreateOptions{})
  2542  				Expect(err).NotTo(HaveOccurred())
  2543  				defer deleteDeployment(ctx, dep4, ns)
  2544  
  2545  				cl, err := client.New(cfg, client.Options{})
  2546  				Expect(err).NotTo(HaveOccurred())
  2547  
  2548  				By("listing 1 deployment when limit=1 is used")
  2549  				deps := &appsv1.DeploymentList{}
  2550  				err = cl.List(context.Background(), deps,
  2551  					client.Limit(1),
  2552  				)
  2553  				Expect(err).NotTo(HaveOccurred())
  2554  
  2555  				Expect(deps.Items).To(HaveLen(1))
  2556  				Expect(deps.Continue).NotTo(BeEmpty())
  2557  				Expect(deps.Items[0].Name).To(Equal(dep1.Name))
  2558  
  2559  				continueToken := deps.Continue
  2560  
  2561  				By("listing the next deployment when previous continuation token is used and limit=1")
  2562  				deps = &appsv1.DeploymentList{}
  2563  				err = cl.List(context.Background(), deps,
  2564  					client.Limit(1),
  2565  					client.Continue(continueToken),
  2566  				)
  2567  				Expect(err).NotTo(HaveOccurred())
  2568  
  2569  				Expect(deps.Items).To(HaveLen(1))
  2570  				Expect(deps.Continue).NotTo(BeEmpty())
  2571  				Expect(deps.Items[0].Name).To(Equal(dep2.Name))
  2572  
  2573  				continueToken = deps.Continue
  2574  
  2575  				By("listing the 2 remaining deployments when previous continuation token is used without a limit")
  2576  				deps = &appsv1.DeploymentList{}
  2577  				err = cl.List(context.Background(), deps,
  2578  					client.Continue(continueToken),
  2579  				)
  2580  				Expect(err).NotTo(HaveOccurred())
  2581  
  2582  				Expect(deps.Items).To(HaveLen(2))
  2583  				Expect(deps.Continue).To(BeEmpty())
  2584  				Expect(deps.Items[0].Name).To(Equal(dep3.Name))
  2585  				Expect(deps.Items[1].Name).To(Equal(dep4.Name))
  2586  			})
  2587  
  2588  			PIt("should fail if the object doesn't have meta", func() {
  2589  
  2590  			})
  2591  
  2592  			PIt("should fail if the object cannot be mapped to a GVK", func() {
  2593  
  2594  			})
  2595  
  2596  			PIt("should fail if the GVK cannot be mapped to a Resource", func() {
  2597  
  2598  			})
  2599  		})
  2600  
  2601  		Context("with unstructured objects", func() {
  2602  			It("should fetch collection of objects", func() {
  2603  				By("create an initial object")
  2604  				_, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  2605  				Expect(err).NotTo(HaveOccurred())
  2606  
  2607  				cl, err := client.New(cfg, client.Options{})
  2608  				Expect(err).NotTo(HaveOccurred())
  2609  
  2610  				By("listing all objects of that type in the cluster")
  2611  				deps := &unstructured.UnstructuredList{}
  2612  				deps.SetGroupVersionKind(schema.GroupVersionKind{
  2613  					Group:   "apps",
  2614  					Kind:    "DeploymentList",
  2615  					Version: "v1",
  2616  				})
  2617  				err = cl.List(context.Background(), deps)
  2618  				Expect(err).NotTo(HaveOccurred())
  2619  
  2620  				Expect(deps.Items).NotTo(BeEmpty())
  2621  				hasDep := false
  2622  				for _, item := range deps.Items {
  2623  					if item.GetName() == dep.Name && item.GetNamespace() == dep.Namespace {
  2624  						hasDep = true
  2625  						break
  2626  					}
  2627  				}
  2628  				Expect(hasDep).To(BeTrue())
  2629  			})
  2630  
  2631  			It("should return an empty list if there are no matching objects", func() {
  2632  				cl, err := client.New(cfg, client.Options{})
  2633  				Expect(err).NotTo(HaveOccurred())
  2634  
  2635  				By("listing all Deployments in the cluster")
  2636  				deps := &unstructured.UnstructuredList{}
  2637  				deps.SetGroupVersionKind(schema.GroupVersionKind{
  2638  					Group:   "apps",
  2639  					Kind:    "DeploymentList",
  2640  					Version: "v1",
  2641  				})
  2642  				Expect(cl.List(context.Background(), deps)).NotTo(HaveOccurred())
  2643  
  2644  				By("validating no Deployments are returned")
  2645  				Expect(deps.Items).To(BeEmpty())
  2646  			})
  2647  
  2648  			It("should filter results by namespace selector", func() {
  2649  				By("creating a Deployment in test-namespace-5")
  2650  				tns1 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-5"}}
  2651  				_, err := clientset.CoreV1().Namespaces().Create(ctx, tns1, metav1.CreateOptions{})
  2652  				Expect(err).NotTo(HaveOccurred())
  2653  				depFrontend := &appsv1.Deployment{
  2654  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: "test-namespace-5"},
  2655  					Spec: appsv1.DeploymentSpec{
  2656  						Selector: &metav1.LabelSelector{
  2657  							MatchLabels: map[string]string{"app": "frontend"},
  2658  						},
  2659  						Template: corev1.PodTemplateSpec{
  2660  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2661  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2662  						},
  2663  					},
  2664  				}
  2665  				depFrontend, err = clientset.AppsV1().Deployments("test-namespace-5").Create(ctx, depFrontend, metav1.CreateOptions{})
  2666  				Expect(err).NotTo(HaveOccurred())
  2667  
  2668  				By("creating a Deployment in test-namespace-6")
  2669  				tns2 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-6"}}
  2670  				_, err = clientset.CoreV1().Namespaces().Create(ctx, tns2, metav1.CreateOptions{})
  2671  				Expect(err).NotTo(HaveOccurred())
  2672  				depBackend := &appsv1.Deployment{
  2673  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: "test-namespace-6"},
  2674  					Spec: appsv1.DeploymentSpec{
  2675  						Selector: &metav1.LabelSelector{
  2676  							MatchLabels: map[string]string{"app": "backend"},
  2677  						},
  2678  						Template: corev1.PodTemplateSpec{
  2679  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  2680  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2681  						},
  2682  					},
  2683  				}
  2684  				depBackend, err = clientset.AppsV1().Deployments("test-namespace-6").Create(ctx, depBackend, metav1.CreateOptions{})
  2685  				Expect(err).NotTo(HaveOccurred())
  2686  
  2687  				cl, err := client.New(cfg, client.Options{})
  2688  				Expect(err).NotTo(HaveOccurred())
  2689  
  2690  				By("listing all Deployments in test-namespace-5")
  2691  				deps := &unstructured.UnstructuredList{}
  2692  				deps.SetGroupVersionKind(schema.GroupVersionKind{
  2693  					Group:   "apps",
  2694  					Kind:    "DeploymentList",
  2695  					Version: "v1",
  2696  				})
  2697  				err = cl.List(context.Background(), deps, client.InNamespace("test-namespace-5"))
  2698  				Expect(err).NotTo(HaveOccurred())
  2699  
  2700  				By("only the Deployment in test-namespace-5 is returned")
  2701  				Expect(deps.Items).NotTo(BeEmpty())
  2702  				Expect(1).To(Equal(len(deps.Items)))
  2703  				actual := deps.Items[0]
  2704  				Expect(actual.GetName()).To(Equal("deployment-frontend"))
  2705  
  2706  				deleteDeployment(ctx, depFrontend, "test-namespace-5")
  2707  				deleteDeployment(ctx, depBackend, "test-namespace-6")
  2708  				deleteNamespace(ctx, tns1)
  2709  				deleteNamespace(ctx, tns2)
  2710  			})
  2711  
  2712  			It("should filter results by field selector", func() {
  2713  				By("creating a Deployment with name deployment-frontend")
  2714  				depFrontend := &appsv1.Deployment{
  2715  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: ns},
  2716  					Spec: appsv1.DeploymentSpec{
  2717  						Selector: &metav1.LabelSelector{
  2718  							MatchLabels: map[string]string{"app": "frontend"},
  2719  						},
  2720  						Template: corev1.PodTemplateSpec{
  2721  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2722  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2723  						},
  2724  					},
  2725  				}
  2726  				depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
  2727  				Expect(err).NotTo(HaveOccurred())
  2728  
  2729  				By("creating a Deployment with name deployment-backend")
  2730  				depBackend := &appsv1.Deployment{
  2731  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: ns},
  2732  					Spec: appsv1.DeploymentSpec{
  2733  						Selector: &metav1.LabelSelector{
  2734  							MatchLabels: map[string]string{"app": "backend"},
  2735  						},
  2736  						Template: corev1.PodTemplateSpec{
  2737  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  2738  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2739  						},
  2740  					},
  2741  				}
  2742  				depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
  2743  				Expect(err).NotTo(HaveOccurred())
  2744  
  2745  				cl, err := client.New(cfg, client.Options{})
  2746  				Expect(err).NotTo(HaveOccurred())
  2747  
  2748  				By("listing all Deployments with field metadata.name=deployment-backend")
  2749  				deps := &unstructured.UnstructuredList{}
  2750  				deps.SetGroupVersionKind(schema.GroupVersionKind{
  2751  					Group:   "apps",
  2752  					Kind:    "DeploymentList",
  2753  					Version: "v1",
  2754  				})
  2755  				err = cl.List(context.Background(), deps,
  2756  					client.MatchingFields{"metadata.name": "deployment-backend"})
  2757  				Expect(err).NotTo(HaveOccurred())
  2758  
  2759  				By("only the Deployment with the backend field is returned")
  2760  				Expect(deps.Items).NotTo(BeEmpty())
  2761  				Expect(1).To(Equal(len(deps.Items)))
  2762  				actual := deps.Items[0]
  2763  				Expect(actual.GetName()).To(Equal("deployment-backend"))
  2764  
  2765  				deleteDeployment(ctx, depFrontend, ns)
  2766  				deleteDeployment(ctx, depBackend, ns)
  2767  			})
  2768  
  2769  			It("should filter results by namespace selector and label selector", func() {
  2770  				By("creating a Deployment in test-namespace-7 with the app=frontend label")
  2771  				tns3 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-7"}}
  2772  				_, err := clientset.CoreV1().Namespaces().Create(ctx, tns3, metav1.CreateOptions{})
  2773  				Expect(err).NotTo(HaveOccurred())
  2774  				depFrontend3 := &appsv1.Deployment{
  2775  					ObjectMeta: metav1.ObjectMeta{
  2776  						Name:      "deployment-frontend",
  2777  						Namespace: "test-namespace-7",
  2778  						Labels:    map[string]string{"app": "frontend"},
  2779  					},
  2780  					Spec: appsv1.DeploymentSpec{
  2781  						Selector: &metav1.LabelSelector{
  2782  							MatchLabels: map[string]string{"app": "frontend"},
  2783  						},
  2784  						Template: corev1.PodTemplateSpec{
  2785  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2786  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2787  						},
  2788  					},
  2789  				}
  2790  				depFrontend3, err = clientset.AppsV1().Deployments("test-namespace-7").Create(ctx, depFrontend3, metav1.CreateOptions{})
  2791  				Expect(err).NotTo(HaveOccurred())
  2792  
  2793  				By("creating a Deployment in test-namespace-7 with the app=backend label")
  2794  				depBackend3 := &appsv1.Deployment{
  2795  					ObjectMeta: metav1.ObjectMeta{
  2796  						Name:      "deployment-backend",
  2797  						Namespace: "test-namespace-7",
  2798  						Labels:    map[string]string{"app": "backend"},
  2799  					},
  2800  					Spec: appsv1.DeploymentSpec{
  2801  						Selector: &metav1.LabelSelector{
  2802  							MatchLabels: map[string]string{"app": "backend"},
  2803  						},
  2804  						Template: corev1.PodTemplateSpec{
  2805  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  2806  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2807  						},
  2808  					},
  2809  				}
  2810  				depBackend3, err = clientset.AppsV1().Deployments("test-namespace-7").Create(ctx, depBackend3, metav1.CreateOptions{})
  2811  				Expect(err).NotTo(HaveOccurred())
  2812  
  2813  				By("creating a Deployment in test-namespace-8 with the app=frontend label")
  2814  				tns4 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-8"}}
  2815  				_, err = clientset.CoreV1().Namespaces().Create(ctx, tns4, metav1.CreateOptions{})
  2816  				Expect(err).NotTo(HaveOccurred())
  2817  				depFrontend4 := &appsv1.Deployment{
  2818  					ObjectMeta: metav1.ObjectMeta{
  2819  						Name:      "deployment-frontend",
  2820  						Namespace: "test-namespace-8",
  2821  						Labels:    map[string]string{"app": "frontend"},
  2822  					},
  2823  					Spec: appsv1.DeploymentSpec{
  2824  						Selector: &metav1.LabelSelector{
  2825  							MatchLabels: map[string]string{"app": "frontend"},
  2826  						},
  2827  						Template: corev1.PodTemplateSpec{
  2828  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2829  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2830  						},
  2831  					},
  2832  				}
  2833  				depFrontend4, err = clientset.AppsV1().Deployments("test-namespace-8").Create(ctx, depFrontend4, metav1.CreateOptions{})
  2834  				Expect(err).NotTo(HaveOccurred())
  2835  
  2836  				cl, err := client.New(cfg, client.Options{})
  2837  				Expect(err).NotTo(HaveOccurred())
  2838  
  2839  				By("listing all Deployments in test-namespace-8 with label app=frontend")
  2840  				deps := &unstructured.UnstructuredList{}
  2841  				deps.SetGroupVersionKind(schema.GroupVersionKind{
  2842  					Group:   "apps",
  2843  					Kind:    "DeploymentList",
  2844  					Version: "v1",
  2845  				})
  2846  				labels := map[string]string{"app": "frontend"}
  2847  				err = cl.List(context.Background(), deps,
  2848  					client.InNamespace("test-namespace-7"), client.MatchingLabels(labels))
  2849  				Expect(err).NotTo(HaveOccurred())
  2850  
  2851  				By("only the Deployment in test-namespace-7 with label app=frontend is returned")
  2852  				Expect(deps.Items).NotTo(BeEmpty())
  2853  				Expect(1).To(Equal(len(deps.Items)))
  2854  				actual := deps.Items[0]
  2855  				Expect(actual.GetName()).To(Equal("deployment-frontend"))
  2856  				Expect(actual.GetNamespace()).To(Equal("test-namespace-7"))
  2857  
  2858  				deleteDeployment(ctx, depFrontend3, "test-namespace-7")
  2859  				deleteDeployment(ctx, depBackend3, "test-namespace-7")
  2860  				deleteDeployment(ctx, depFrontend4, "test-namespace-8")
  2861  				deleteNamespace(ctx, tns3)
  2862  				deleteNamespace(ctx, tns4)
  2863  			})
  2864  
  2865  			PIt("should fail if the object doesn't have meta", func() {
  2866  
  2867  			})
  2868  
  2869  			PIt("should filter results by namespace selector", func() {
  2870  
  2871  			})
  2872  		})
  2873  		Context("with metadata objects", func() {
  2874  			It("should fetch collection of objects", func() {
  2875  				By("creating an initial object")
  2876  				dep, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
  2877  				Expect(err).NotTo(HaveOccurred())
  2878  
  2879  				cl, err := client.New(cfg, client.Options{})
  2880  				Expect(err).NotTo(HaveOccurred())
  2881  
  2882  				By("listing all objects of that type in the cluster")
  2883  				gvk := schema.GroupVersionKind{
  2884  					Group:   "apps",
  2885  					Version: "v1",
  2886  					Kind:    "DeploymentList",
  2887  				}
  2888  				metaList := &metav1.PartialObjectMetadataList{}
  2889  				metaList.SetGroupVersionKind(gvk)
  2890  				Expect(cl.List(context.Background(), metaList)).NotTo(HaveOccurred())
  2891  
  2892  				By("validating that the list GVK has been preserved")
  2893  				Expect(metaList.GroupVersionKind()).To(Equal(gvk))
  2894  
  2895  				By("validating that the list has the expected deployment")
  2896  				Expect(metaList.Items).NotTo(BeEmpty())
  2897  				hasDep := false
  2898  				for _, item := range metaList.Items {
  2899  					Expect(item.GroupVersionKind()).To(Equal(schema.GroupVersionKind{
  2900  						Group:   "apps",
  2901  						Version: "v1",
  2902  						Kind:    "Deployment",
  2903  					}))
  2904  
  2905  					if item.Name == dep.Name && item.Namespace == dep.Namespace {
  2906  						hasDep = true
  2907  						break
  2908  					}
  2909  				}
  2910  				Expect(hasDep).To(BeTrue())
  2911  			})
  2912  
  2913  			It("should return an empty list if there are no matching objects", func() {
  2914  				cl, err := client.New(cfg, client.Options{})
  2915  				Expect(err).NotTo(HaveOccurred())
  2916  
  2917  				By("listing all Deployments in the cluster")
  2918  				metaList := &metav1.PartialObjectMetadataList{}
  2919  				metaList.SetGroupVersionKind(schema.GroupVersionKind{
  2920  					Group:   "apps",
  2921  					Version: "v1",
  2922  					Kind:    "DeploymentList",
  2923  				})
  2924  				Expect(cl.List(context.Background(), metaList)).NotTo(HaveOccurred())
  2925  
  2926  				By("validating no Deployments are returned")
  2927  				Expect(metaList.Items).To(BeEmpty())
  2928  			})
  2929  
  2930  			// TODO(seans): get label selector test working
  2931  			It("should filter results by label selector", func() {
  2932  				By("creating a Deployment with the app=frontend label")
  2933  				depFrontend := &appsv1.Deployment{
  2934  					ObjectMeta: metav1.ObjectMeta{
  2935  						Name:      "deployment-frontend",
  2936  						Namespace: ns,
  2937  						Labels:    map[string]string{"app": "frontend"},
  2938  					},
  2939  					Spec: appsv1.DeploymentSpec{
  2940  						Selector: &metav1.LabelSelector{
  2941  							MatchLabels: map[string]string{"app": "frontend"},
  2942  						},
  2943  						Template: corev1.PodTemplateSpec{
  2944  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  2945  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2946  						},
  2947  					},
  2948  				}
  2949  				depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
  2950  				Expect(err).NotTo(HaveOccurred())
  2951  
  2952  				By("creating a Deployment with the app=backend label")
  2953  				depBackend := &appsv1.Deployment{
  2954  					ObjectMeta: metav1.ObjectMeta{
  2955  						Name:      "deployment-backend",
  2956  						Namespace: ns,
  2957  						Labels:    map[string]string{"app": "backend"},
  2958  					},
  2959  					Spec: appsv1.DeploymentSpec{
  2960  						Selector: &metav1.LabelSelector{
  2961  							MatchLabels: map[string]string{"app": "backend"},
  2962  						},
  2963  						Template: corev1.PodTemplateSpec{
  2964  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  2965  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  2966  						},
  2967  					},
  2968  				}
  2969  				depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
  2970  				Expect(err).NotTo(HaveOccurred())
  2971  
  2972  				cl, err := client.New(cfg, client.Options{})
  2973  				Expect(err).NotTo(HaveOccurred())
  2974  
  2975  				By("listing all Deployments with label app=backend")
  2976  				metaList := &metav1.PartialObjectMetadataList{}
  2977  				metaList.SetGroupVersionKind(schema.GroupVersionKind{
  2978  					Group:   "apps",
  2979  					Version: "v1",
  2980  					Kind:    "DeploymentList",
  2981  				})
  2982  				labels := map[string]string{"app": "backend"}
  2983  				err = cl.List(context.Background(), metaList, client.MatchingLabels(labels))
  2984  				Expect(err).NotTo(HaveOccurred())
  2985  
  2986  				By("only the Deployment with the backend label is returned")
  2987  				Expect(metaList.Items).NotTo(BeEmpty())
  2988  				Expect(1).To(Equal(len(metaList.Items)))
  2989  				actual := metaList.Items[0]
  2990  				Expect(actual.Name).To(Equal("deployment-backend"))
  2991  
  2992  				deleteDeployment(ctx, depFrontend, ns)
  2993  				deleteDeployment(ctx, depBackend, ns)
  2994  			})
  2995  
  2996  			It("should filter results by namespace selector", func() {
  2997  				By("creating a Deployment in test-namespace-1")
  2998  				tns1 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-1"}}
  2999  				_, err := clientset.CoreV1().Namespaces().Create(ctx, tns1, metav1.CreateOptions{})
  3000  				Expect(err).NotTo(HaveOccurred())
  3001  				depFrontend := &appsv1.Deployment{
  3002  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: "test-namespace-1"},
  3003  					Spec: appsv1.DeploymentSpec{
  3004  						Selector: &metav1.LabelSelector{
  3005  							MatchLabels: map[string]string{"app": "frontend"},
  3006  						},
  3007  						Template: corev1.PodTemplateSpec{
  3008  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  3009  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  3010  						},
  3011  					},
  3012  				}
  3013  				depFrontend, err = clientset.AppsV1().Deployments("test-namespace-1").Create(ctx, depFrontend, metav1.CreateOptions{})
  3014  				Expect(err).NotTo(HaveOccurred())
  3015  
  3016  				By("creating a Deployment in test-namespace-2")
  3017  				tns2 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-2"}}
  3018  				_, err = clientset.CoreV1().Namespaces().Create(ctx, tns2, metav1.CreateOptions{})
  3019  				Expect(err).NotTo(HaveOccurred())
  3020  				depBackend := &appsv1.Deployment{
  3021  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: "test-namespace-2"},
  3022  					Spec: appsv1.DeploymentSpec{
  3023  						Selector: &metav1.LabelSelector{
  3024  							MatchLabels: map[string]string{"app": "backend"},
  3025  						},
  3026  						Template: corev1.PodTemplateSpec{
  3027  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  3028  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  3029  						},
  3030  					},
  3031  				}
  3032  				depBackend, err = clientset.AppsV1().Deployments("test-namespace-2").Create(ctx, depBackend, metav1.CreateOptions{})
  3033  				Expect(err).NotTo(HaveOccurred())
  3034  
  3035  				cl, err := client.New(cfg, client.Options{})
  3036  				Expect(err).NotTo(HaveOccurred())
  3037  
  3038  				By("listing all Deployments in test-namespace-1")
  3039  				metaList := &metav1.PartialObjectMetadataList{}
  3040  				metaList.SetGroupVersionKind(schema.GroupVersionKind{
  3041  					Group:   "apps",
  3042  					Version: "v1",
  3043  					Kind:    "DeploymentList",
  3044  				})
  3045  				err = cl.List(context.Background(), metaList, client.InNamespace("test-namespace-1"))
  3046  				Expect(err).NotTo(HaveOccurred())
  3047  
  3048  				By("only the Deployment in test-namespace-1 is returned")
  3049  				Expect(metaList.Items).NotTo(BeEmpty())
  3050  				Expect(1).To(Equal(len(metaList.Items)))
  3051  				actual := metaList.Items[0]
  3052  				Expect(actual.Name).To(Equal("deployment-frontend"))
  3053  
  3054  				deleteDeployment(ctx, depFrontend, "test-namespace-1")
  3055  				deleteDeployment(ctx, depBackend, "test-namespace-2")
  3056  				deleteNamespace(ctx, tns1)
  3057  				deleteNamespace(ctx, tns2)
  3058  			})
  3059  
  3060  			It("should filter results by field selector", func() {
  3061  				By("creating a Deployment with name deployment-frontend")
  3062  				depFrontend := &appsv1.Deployment{
  3063  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-frontend", Namespace: ns},
  3064  					Spec: appsv1.DeploymentSpec{
  3065  						Selector: &metav1.LabelSelector{
  3066  							MatchLabels: map[string]string{"app": "frontend"},
  3067  						},
  3068  						Template: corev1.PodTemplateSpec{
  3069  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  3070  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  3071  						},
  3072  					},
  3073  				}
  3074  				depFrontend, err := clientset.AppsV1().Deployments(ns).Create(ctx, depFrontend, metav1.CreateOptions{})
  3075  				Expect(err).NotTo(HaveOccurred())
  3076  
  3077  				By("creating a Deployment with name deployment-backend")
  3078  				depBackend := &appsv1.Deployment{
  3079  					ObjectMeta: metav1.ObjectMeta{Name: "deployment-backend", Namespace: ns},
  3080  					Spec: appsv1.DeploymentSpec{
  3081  						Selector: &metav1.LabelSelector{
  3082  							MatchLabels: map[string]string{"app": "backend"},
  3083  						},
  3084  						Template: corev1.PodTemplateSpec{
  3085  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  3086  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  3087  						},
  3088  					},
  3089  				}
  3090  				depBackend, err = clientset.AppsV1().Deployments(ns).Create(ctx, depBackend, metav1.CreateOptions{})
  3091  				Expect(err).NotTo(HaveOccurred())
  3092  
  3093  				cl, err := client.New(cfg, client.Options{})
  3094  				Expect(err).NotTo(HaveOccurred())
  3095  
  3096  				By("listing all Deployments with field metadata.name=deployment-backend")
  3097  				metaList := &metav1.PartialObjectMetadataList{}
  3098  				metaList.SetGroupVersionKind(schema.GroupVersionKind{
  3099  					Group:   "apps",
  3100  					Version: "v1",
  3101  					Kind:    "DeploymentList",
  3102  				})
  3103  				err = cl.List(context.Background(), metaList,
  3104  					client.MatchingFields{"metadata.name": "deployment-backend"})
  3105  				Expect(err).NotTo(HaveOccurred())
  3106  
  3107  				By("only the Deployment with the backend field is returned")
  3108  				Expect(metaList.Items).NotTo(BeEmpty())
  3109  				Expect(1).To(Equal(len(metaList.Items)))
  3110  				actual := metaList.Items[0]
  3111  				Expect(actual.Name).To(Equal("deployment-backend"))
  3112  
  3113  				deleteDeployment(ctx, depFrontend, ns)
  3114  				deleteDeployment(ctx, depBackend, ns)
  3115  			})
  3116  
  3117  			It("should filter results by namespace selector and label selector", func() {
  3118  				By("creating a Deployment in test-namespace-3 with the app=frontend label")
  3119  				tns3 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-3"}}
  3120  				_, err := clientset.CoreV1().Namespaces().Create(ctx, tns3, metav1.CreateOptions{})
  3121  				Expect(err).NotTo(HaveOccurred())
  3122  				depFrontend3 := &appsv1.Deployment{
  3123  					ObjectMeta: metav1.ObjectMeta{
  3124  						Name:      "deployment-frontend",
  3125  						Namespace: "test-namespace-3",
  3126  						Labels:    map[string]string{"app": "frontend"},
  3127  					},
  3128  					Spec: appsv1.DeploymentSpec{
  3129  						Selector: &metav1.LabelSelector{
  3130  							MatchLabels: map[string]string{"app": "frontend"},
  3131  						},
  3132  						Template: corev1.PodTemplateSpec{
  3133  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  3134  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  3135  						},
  3136  					},
  3137  				}
  3138  				depFrontend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(ctx, depFrontend3, metav1.CreateOptions{})
  3139  				Expect(err).NotTo(HaveOccurred())
  3140  
  3141  				By("creating a Deployment in test-namespace-3 with the app=backend label")
  3142  				depBackend3 := &appsv1.Deployment{
  3143  					ObjectMeta: metav1.ObjectMeta{
  3144  						Name:      "deployment-backend",
  3145  						Namespace: "test-namespace-3",
  3146  						Labels:    map[string]string{"app": "backend"},
  3147  					},
  3148  					Spec: appsv1.DeploymentSpec{
  3149  						Selector: &metav1.LabelSelector{
  3150  							MatchLabels: map[string]string{"app": "backend"},
  3151  						},
  3152  						Template: corev1.PodTemplateSpec{
  3153  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "backend"}},
  3154  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  3155  						},
  3156  					},
  3157  				}
  3158  				depBackend3, err = clientset.AppsV1().Deployments("test-namespace-3").Create(ctx, depBackend3, metav1.CreateOptions{})
  3159  				Expect(err).NotTo(HaveOccurred())
  3160  
  3161  				By("creating a Deployment in test-namespace-4 with the app=frontend label")
  3162  				tns4 := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace-4"}}
  3163  				_, err = clientset.CoreV1().Namespaces().Create(ctx, tns4, metav1.CreateOptions{})
  3164  				Expect(err).NotTo(HaveOccurred())
  3165  				depFrontend4 := &appsv1.Deployment{
  3166  					ObjectMeta: metav1.ObjectMeta{
  3167  						Name:      "deployment-frontend",
  3168  						Namespace: "test-namespace-4",
  3169  						Labels:    map[string]string{"app": "frontend"},
  3170  					},
  3171  					Spec: appsv1.DeploymentSpec{
  3172  						Selector: &metav1.LabelSelector{
  3173  							MatchLabels: map[string]string{"app": "frontend"},
  3174  						},
  3175  						Template: corev1.PodTemplateSpec{
  3176  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  3177  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  3178  						},
  3179  					},
  3180  				}
  3181  				depFrontend4, err = clientset.AppsV1().Deployments("test-namespace-4").Create(ctx, depFrontend4, metav1.CreateOptions{})
  3182  				Expect(err).NotTo(HaveOccurred())
  3183  
  3184  				cl, err := client.New(cfg, client.Options{})
  3185  				Expect(err).NotTo(HaveOccurred())
  3186  
  3187  				By("listing all Deployments in test-namespace-3 with label app=frontend")
  3188  				metaList := &metav1.PartialObjectMetadataList{}
  3189  				metaList.SetGroupVersionKind(schema.GroupVersionKind{
  3190  					Group:   "apps",
  3191  					Version: "v1",
  3192  					Kind:    "DeploymentList",
  3193  				})
  3194  				labels := map[string]string{"app": "frontend"}
  3195  				err = cl.List(context.Background(), metaList,
  3196  					client.InNamespace("test-namespace-3"),
  3197  					client.MatchingLabels(labels),
  3198  				)
  3199  				Expect(err).NotTo(HaveOccurred())
  3200  
  3201  				By("only the Deployment in test-namespace-3 with label app=frontend is returned")
  3202  				Expect(metaList.Items).NotTo(BeEmpty())
  3203  				Expect(1).To(Equal(len(metaList.Items)))
  3204  				actual := metaList.Items[0]
  3205  				Expect(actual.Name).To(Equal("deployment-frontend"))
  3206  				Expect(actual.Namespace).To(Equal("test-namespace-3"))
  3207  
  3208  				deleteDeployment(ctx, depFrontend3, "test-namespace-3")
  3209  				deleteDeployment(ctx, depBackend3, "test-namespace-3")
  3210  				deleteDeployment(ctx, depFrontend4, "test-namespace-4")
  3211  				deleteNamespace(ctx, tns3)
  3212  				deleteNamespace(ctx, tns4)
  3213  			})
  3214  
  3215  			It("should filter results using limit and continue options", func() {
  3216  
  3217  				makeDeployment := func(suffix string) *appsv1.Deployment {
  3218  					return &appsv1.Deployment{
  3219  						ObjectMeta: metav1.ObjectMeta{
  3220  							Name: fmt.Sprintf("deployment-%s", suffix),
  3221  						},
  3222  						Spec: appsv1.DeploymentSpec{
  3223  							Selector: &metav1.LabelSelector{
  3224  								MatchLabels: map[string]string{"foo": "bar"},
  3225  							},
  3226  							Template: corev1.PodTemplateSpec{
  3227  								ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
  3228  								Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
  3229  							},
  3230  						},
  3231  					}
  3232  				}
  3233  
  3234  				By("creating 4 deployments")
  3235  				dep1 := makeDeployment("1")
  3236  				dep1, err := clientset.AppsV1().Deployments(ns).Create(ctx, dep1, metav1.CreateOptions{})
  3237  				Expect(err).NotTo(HaveOccurred())
  3238  				defer deleteDeployment(ctx, dep1, ns)
  3239  
  3240  				dep2 := makeDeployment("2")
  3241  				dep2, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep2, metav1.CreateOptions{})
  3242  				Expect(err).NotTo(HaveOccurred())
  3243  				defer deleteDeployment(ctx, dep2, ns)
  3244  
  3245  				dep3 := makeDeployment("3")
  3246  				dep3, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep3, metav1.CreateOptions{})
  3247  				Expect(err).NotTo(HaveOccurred())
  3248  				defer deleteDeployment(ctx, dep3, ns)
  3249  
  3250  				dep4 := makeDeployment("4")
  3251  				dep4, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep4, metav1.CreateOptions{})
  3252  				Expect(err).NotTo(HaveOccurred())
  3253  				defer deleteDeployment(ctx, dep4, ns)
  3254  
  3255  				cl, err := client.New(cfg, client.Options{})
  3256  				Expect(err).NotTo(HaveOccurred())
  3257  
  3258  				By("listing 1 deployment when limit=1 is used")
  3259  				metaList := &metav1.PartialObjectMetadataList{}
  3260  				metaList.SetGroupVersionKind(schema.GroupVersionKind{
  3261  					Group:   "apps",
  3262  					Version: "v1",
  3263  					Kind:    "DeploymentList",
  3264  				})
  3265  				err = cl.List(context.Background(), metaList,
  3266  					client.Limit(1),
  3267  				)
  3268  				Expect(err).NotTo(HaveOccurred())
  3269  
  3270  				Expect(metaList.Items).To(HaveLen(1))
  3271  				Expect(metaList.Continue).NotTo(BeEmpty())
  3272  				Expect(metaList.Items[0].Name).To(Equal(dep1.Name))
  3273  
  3274  				continueToken := metaList.Continue
  3275  
  3276  				By("listing the next deployment when previous continuation token is used and limit=1")
  3277  				metaList = &metav1.PartialObjectMetadataList{}
  3278  				metaList.SetGroupVersionKind(schema.GroupVersionKind{
  3279  					Group:   "apps",
  3280  					Version: "v1",
  3281  					Kind:    "DeploymentList",
  3282  				})
  3283  				err = cl.List(context.Background(), metaList,
  3284  					client.Limit(1),
  3285  					client.Continue(continueToken),
  3286  				)
  3287  				Expect(err).NotTo(HaveOccurred())
  3288  
  3289  				Expect(metaList.Items).To(HaveLen(1))
  3290  				Expect(metaList.Continue).NotTo(BeEmpty())
  3291  				Expect(metaList.Items[0].Name).To(Equal(dep2.Name))
  3292  
  3293  				continueToken = metaList.Continue
  3294  
  3295  				By("listing the 2 remaining deployments when previous continuation token is used without a limit")
  3296  				metaList = &metav1.PartialObjectMetadataList{}
  3297  				metaList.SetGroupVersionKind(schema.GroupVersionKind{
  3298  					Group:   "apps",
  3299  					Version: "v1",
  3300  					Kind:    "DeploymentList",
  3301  				})
  3302  				err = cl.List(context.Background(), metaList,
  3303  					client.Continue(continueToken),
  3304  				)
  3305  				Expect(err).NotTo(HaveOccurred())
  3306  
  3307  				Expect(metaList.Items).To(HaveLen(2))
  3308  				Expect(metaList.Continue).To(BeEmpty())
  3309  				Expect(metaList.Items[0].Name).To(Equal(dep3.Name))
  3310  				Expect(metaList.Items[1].Name).To(Equal(dep4.Name))
  3311  			})
  3312  
  3313  			PIt("should fail if the object doesn't have meta", func() {
  3314  
  3315  			})
  3316  
  3317  			PIt("should fail if the object cannot be mapped to a GVK", func() {
  3318  
  3319  			})
  3320  
  3321  			PIt("should fail if the GVK cannot be mapped to a Resource", func() {
  3322  
  3323  			})
  3324  		})
  3325  	})
  3326  
  3327  	Describe("CreateOptions", func() {
  3328  		It("should allow setting DryRun to 'all'", func() {
  3329  			co := &client.CreateOptions{}
  3330  			client.DryRunAll.ApplyToCreate(co)
  3331  			all := []string{metav1.DryRunAll}
  3332  			Expect(co.AsCreateOptions().DryRun).To(Equal(all))
  3333  		})
  3334  
  3335  		It("should allow setting the field manager", func() {
  3336  			po := &client.CreateOptions{}
  3337  			client.FieldOwner("some-owner").ApplyToCreate(po)
  3338  			Expect(po.AsCreateOptions().FieldManager).To(Equal("some-owner"))
  3339  		})
  3340  
  3341  		It("should produce empty metav1.CreateOptions if nil", func() {
  3342  			var co *client.CreateOptions
  3343  			Expect(co.AsCreateOptions()).To(Equal(&metav1.CreateOptions{}))
  3344  			co = &client.CreateOptions{}
  3345  			Expect(co.AsCreateOptions()).To(Equal(&metav1.CreateOptions{}))
  3346  		})
  3347  	})
  3348  
  3349  	Describe("DeleteOptions", func() {
  3350  		It("should allow setting GracePeriodSeconds", func() {
  3351  			do := &client.DeleteOptions{}
  3352  			client.GracePeriodSeconds(1).ApplyToDelete(do)
  3353  			gp := int64(1)
  3354  			Expect(do.AsDeleteOptions().GracePeriodSeconds).To(Equal(&gp))
  3355  		})
  3356  
  3357  		It("should allow setting Precondition", func() {
  3358  			do := &client.DeleteOptions{}
  3359  			pc := metav1.NewUIDPreconditions("uid")
  3360  			client.Preconditions(*pc).ApplyToDelete(do)
  3361  			Expect(do.AsDeleteOptions().Preconditions).To(Equal(pc))
  3362  			Expect(do.Preconditions).To(Equal(pc))
  3363  		})
  3364  
  3365  		It("should allow setting PropagationPolicy", func() {
  3366  			do := &client.DeleteOptions{}
  3367  			client.PropagationPolicy(metav1.DeletePropagationForeground).ApplyToDelete(do)
  3368  			dp := metav1.DeletePropagationForeground
  3369  			Expect(do.AsDeleteOptions().PropagationPolicy).To(Equal(&dp))
  3370  		})
  3371  
  3372  		It("should allow setting DryRun", func() {
  3373  			do := &client.DeleteOptions{}
  3374  			client.DryRunAll.ApplyToDelete(do)
  3375  			all := []string{metav1.DryRunAll}
  3376  			Expect(do.AsDeleteOptions().DryRun).To(Equal(all))
  3377  		})
  3378  
  3379  		It("should produce empty metav1.DeleteOptions if nil", func() {
  3380  			var do *client.DeleteOptions
  3381  			Expect(do.AsDeleteOptions()).To(Equal(&metav1.DeleteOptions{}))
  3382  			do = &client.DeleteOptions{}
  3383  			Expect(do.AsDeleteOptions()).To(Equal(&metav1.DeleteOptions{}))
  3384  		})
  3385  
  3386  		It("should merge multiple options together", func() {
  3387  			gp := int64(1)
  3388  			pc := metav1.NewUIDPreconditions("uid")
  3389  			dp := metav1.DeletePropagationForeground
  3390  			do := &client.DeleteOptions{}
  3391  			do.ApplyOptions([]client.DeleteOption{
  3392  				client.GracePeriodSeconds(gp),
  3393  				client.Preconditions(*pc),
  3394  				client.PropagationPolicy(dp),
  3395  			})
  3396  			Expect(do.GracePeriodSeconds).To(Equal(&gp))
  3397  			Expect(do.Preconditions).To(Equal(pc))
  3398  			Expect(do.PropagationPolicy).To(Equal(&dp))
  3399  		})
  3400  	})
  3401  
  3402  	Describe("DeleteCollectionOptions", func() {
  3403  		It("should be convertable to list options", func() {
  3404  			gp := int64(1)
  3405  			do := &client.DeleteAllOfOptions{}
  3406  			do.ApplyOptions([]client.DeleteAllOfOption{
  3407  				client.GracePeriodSeconds(gp),
  3408  				client.MatchingLabels{"foo": "bar"},
  3409  			})
  3410  
  3411  			listOpts := do.AsListOptions()
  3412  			Expect(listOpts).NotTo(BeNil())
  3413  			Expect(listOpts.LabelSelector).To(Equal("foo=bar"))
  3414  		})
  3415  
  3416  		It("should be convertable to delete options", func() {
  3417  			gp := int64(1)
  3418  			do := &client.DeleteAllOfOptions{}
  3419  			do.ApplyOptions([]client.DeleteAllOfOption{
  3420  				client.GracePeriodSeconds(gp),
  3421  				client.MatchingLabels{"foo": "bar"},
  3422  			})
  3423  
  3424  			deleteOpts := do.AsDeleteOptions()
  3425  			Expect(deleteOpts).NotTo(BeNil())
  3426  			Expect(deleteOpts.GracePeriodSeconds).To(Equal(&gp))
  3427  		})
  3428  	})
  3429  
  3430  	Describe("GetOptions", func() {
  3431  		It("should be convertable to metav1.GetOptions", func() {
  3432  			o := (&client.GetOptions{}).ApplyOptions([]client.GetOption{
  3433  				&client.GetOptions{Raw: &metav1.GetOptions{ResourceVersion: "RV0"}},
  3434  			})
  3435  			mo := o.AsGetOptions()
  3436  			Expect(mo).NotTo(BeNil())
  3437  			Expect(mo.ResourceVersion).To(Equal("RV0"))
  3438  		})
  3439  
  3440  		It("should produce empty metav1.GetOptions if nil", func() {
  3441  			var o *client.GetOptions
  3442  			Expect(o.AsGetOptions()).To(Equal(&metav1.GetOptions{}))
  3443  			o = &client.GetOptions{}
  3444  			Expect(o.AsGetOptions()).To(Equal(&metav1.GetOptions{}))
  3445  		})
  3446  	})
  3447  
  3448  	Describe("ListOptions", func() {
  3449  		It("should be convertable to metav1.ListOptions", func() {
  3450  			lo := (&client.ListOptions{}).ApplyOptions([]client.ListOption{
  3451  				client.MatchingFields{"field1": "bar"},
  3452  				client.InNamespace("test-namespace"),
  3453  				client.MatchingLabels{"foo": "bar"},
  3454  				client.Limit(1),
  3455  				client.Continue("foo"),
  3456  			})
  3457  			mlo := lo.AsListOptions()
  3458  			Expect(mlo).NotTo(BeNil())
  3459  			Expect(mlo.LabelSelector).To(Equal("foo=bar"))
  3460  			Expect(mlo.FieldSelector).To(Equal("field1=bar"))
  3461  			Expect(mlo.Limit).To(Equal(int64(1)))
  3462  			Expect(mlo.Continue).To(Equal("foo"))
  3463  		})
  3464  
  3465  		It("should be populated by MatchingLabels", func() {
  3466  			lo := &client.ListOptions{}
  3467  			client.MatchingLabels{"foo": "bar"}.ApplyToList(lo)
  3468  			Expect(lo).NotTo(BeNil())
  3469  			Expect(lo.LabelSelector.String()).To(Equal("foo=bar"))
  3470  		})
  3471  
  3472  		It("should be populated by MatchingField", func() {
  3473  			lo := &client.ListOptions{}
  3474  			client.MatchingFields{"field1": "bar"}.ApplyToList(lo)
  3475  			Expect(lo).NotTo(BeNil())
  3476  			Expect(lo.FieldSelector.String()).To(Equal("field1=bar"))
  3477  		})
  3478  
  3479  		It("should be populated by InNamespace", func() {
  3480  			lo := &client.ListOptions{}
  3481  			client.InNamespace("test").ApplyToList(lo)
  3482  			Expect(lo).NotTo(BeNil())
  3483  			Expect(lo.Namespace).To(Equal("test"))
  3484  		})
  3485  
  3486  		It("should produce empty metav1.ListOptions if nil", func() {
  3487  			var do *client.ListOptions
  3488  			Expect(do.AsListOptions()).To(Equal(&metav1.ListOptions{}))
  3489  			do = &client.ListOptions{}
  3490  			Expect(do.AsListOptions()).To(Equal(&metav1.ListOptions{}))
  3491  		})
  3492  
  3493  		It("should be populated by Limit", func() {
  3494  			lo := &client.ListOptions{}
  3495  			client.Limit(1).ApplyToList(lo)
  3496  			Expect(lo).NotTo(BeNil())
  3497  			Expect(lo.Limit).To(Equal(int64(1)))
  3498  		})
  3499  
  3500  		It("should ignore Limit when converted to metav1.ListOptions and watch is true", func() {
  3501  			lo := &client.ListOptions{
  3502  				Raw: &metav1.ListOptions{Watch: true},
  3503  			}
  3504  			lo.ApplyOptions([]client.ListOption{
  3505  				client.Limit(1),
  3506  			})
  3507  			mlo := lo.AsListOptions()
  3508  			Expect(mlo).NotTo(BeNil())
  3509  			Expect(mlo.Limit).To(BeZero())
  3510  		})
  3511  
  3512  		It("should be populated by Continue", func() {
  3513  			lo := &client.ListOptions{}
  3514  			client.Continue("foo").ApplyToList(lo)
  3515  			Expect(lo).NotTo(BeNil())
  3516  			Expect(lo.Continue).To(Equal("foo"))
  3517  		})
  3518  
  3519  		It("should ignore Continue token when converted to metav1.ListOptions and watch is true", func() {
  3520  			lo := &client.ListOptions{
  3521  				Raw: &metav1.ListOptions{Watch: true},
  3522  			}
  3523  			lo.ApplyOptions([]client.ListOption{
  3524  				client.Continue("foo"),
  3525  			})
  3526  			mlo := lo.AsListOptions()
  3527  			Expect(mlo).NotTo(BeNil())
  3528  			Expect(mlo.Continue).To(BeEmpty())
  3529  		})
  3530  
  3531  		It("should ignore both Limit and Continue token when converted to metav1.ListOptions and watch is true", func() {
  3532  			lo := &client.ListOptions{
  3533  				Raw: &metav1.ListOptions{Watch: true},
  3534  			}
  3535  			lo.ApplyOptions([]client.ListOption{
  3536  				client.Limit(1),
  3537  				client.Continue("foo"),
  3538  			})
  3539  			mlo := lo.AsListOptions()
  3540  			Expect(mlo).NotTo(BeNil())
  3541  			Expect(mlo.Limit).To(BeZero())
  3542  			Expect(mlo.Continue).To(BeEmpty())
  3543  		})
  3544  	})
  3545  
  3546  	Describe("UpdateOptions", func() {
  3547  		It("should allow setting DryRun to 'all'", func() {
  3548  			uo := &client.UpdateOptions{}
  3549  			client.DryRunAll.ApplyToUpdate(uo)
  3550  			all := []string{metav1.DryRunAll}
  3551  			Expect(uo.AsUpdateOptions().DryRun).To(Equal(all))
  3552  		})
  3553  
  3554  		It("should allow setting the field manager", func() {
  3555  			po := &client.UpdateOptions{}
  3556  			client.FieldOwner("some-owner").ApplyToUpdate(po)
  3557  			Expect(po.AsUpdateOptions().FieldManager).To(Equal("some-owner"))
  3558  		})
  3559  
  3560  		It("should produce empty metav1.UpdateOptions if nil", func() {
  3561  			var co *client.UpdateOptions
  3562  			Expect(co.AsUpdateOptions()).To(Equal(&metav1.UpdateOptions{}))
  3563  			co = &client.UpdateOptions{}
  3564  			Expect(co.AsUpdateOptions()).To(Equal(&metav1.UpdateOptions{}))
  3565  		})
  3566  	})
  3567  
  3568  	Describe("PatchOptions", func() {
  3569  		It("should allow setting DryRun to 'all'", func() {
  3570  			po := &client.PatchOptions{}
  3571  			client.DryRunAll.ApplyToPatch(po)
  3572  			all := []string{metav1.DryRunAll}
  3573  			Expect(po.AsPatchOptions().DryRun).To(Equal(all))
  3574  		})
  3575  
  3576  		It("should allow setting Force to 'true'", func() {
  3577  			po := &client.PatchOptions{}
  3578  			client.ForceOwnership.ApplyToPatch(po)
  3579  			mpo := po.AsPatchOptions()
  3580  			Expect(mpo.Force).NotTo(BeNil())
  3581  			Expect(*mpo.Force).To(BeTrue())
  3582  		})
  3583  
  3584  		It("should allow setting the field manager", func() {
  3585  			po := &client.PatchOptions{}
  3586  			client.FieldOwner("some-owner").ApplyToPatch(po)
  3587  			Expect(po.AsPatchOptions().FieldManager).To(Equal("some-owner"))
  3588  		})
  3589  
  3590  		It("should produce empty metav1.PatchOptions if nil", func() {
  3591  			var po *client.PatchOptions
  3592  			Expect(po.AsPatchOptions()).To(Equal(&metav1.PatchOptions{}))
  3593  			po = &client.PatchOptions{}
  3594  			Expect(po.AsPatchOptions()).To(Equal(&metav1.PatchOptions{}))
  3595  		})
  3596  	})
  3597  })
  3598  
  3599  var _ = Describe("ClientWithCache", func() {
  3600  	Describe("Get", func() {
  3601  		It("should call cache reader when structured object", func() {
  3602  			cachedReader := &fakeReader{}
  3603  			cl, err := client.New(cfg, client.Options{
  3604  				Cache: &client.CacheOptions{
  3605  					Reader: cachedReader,
  3606  				},
  3607  			})
  3608  			Expect(err).NotTo(HaveOccurred())
  3609  			var actual appsv1.Deployment
  3610  			key := client.ObjectKey{Namespace: "ns", Name: "name"}
  3611  			Expect(cl.Get(context.TODO(), key, &actual)).To(Succeed())
  3612  			Expect(1).To(Equal(cachedReader.Called))
  3613  		})
  3614  
  3615  		When("getting unstructured objects", func() {
  3616  			var dep *appsv1.Deployment
  3617  
  3618  			BeforeEach(func() {
  3619  				dep = &appsv1.Deployment{
  3620  					ObjectMeta: metav1.ObjectMeta{
  3621  						Name:   "deployment1",
  3622  						Labels: map[string]string{"app": "frontend"},
  3623  					},
  3624  					Spec: appsv1.DeploymentSpec{
  3625  						Selector: &metav1.LabelSelector{
  3626  							MatchLabels: map[string]string{"app": "frontend"},
  3627  						},
  3628  						Template: corev1.PodTemplateSpec{
  3629  							ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "frontend"}},
  3630  							Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "x", Image: "x"}}},
  3631  						},
  3632  					},
  3633  				}
  3634  				var err error
  3635  				dep, err = clientset.AppsV1().Deployments("default").Create(context.Background(), dep, metav1.CreateOptions{})
  3636  				Expect(err).NotTo(HaveOccurred())
  3637  			})
  3638  			AfterEach(func() {
  3639  				Expect(clientset.AppsV1().Deployments("default").Delete(
  3640  					context.Background(),
  3641  					dep.Name,
  3642  					metav1.DeleteOptions{},
  3643  				)).To(Succeed())
  3644  			})
  3645  			It("should call client reader when not cached", func() {
  3646  				cachedReader := &fakeReader{}
  3647  				cl, err := client.New(cfg, client.Options{
  3648  					Cache: &client.CacheOptions{
  3649  						Reader: cachedReader,
  3650  					},
  3651  				})
  3652  				Expect(err).NotTo(HaveOccurred())
  3653  
  3654  				actual := &unstructured.Unstructured{}
  3655  				actual.SetGroupVersionKind(schema.GroupVersionKind{
  3656  					Group:   "apps",
  3657  					Kind:    "Deployment",
  3658  					Version: "v1",
  3659  				})
  3660  				actual.SetName(dep.Name)
  3661  				key := client.ObjectKey{Namespace: dep.Namespace, Name: dep.Name}
  3662  				Expect(cl.Get(context.TODO(), key, actual)).To(Succeed())
  3663  				Expect(0).To(Equal(cachedReader.Called))
  3664  			})
  3665  			It("should call cache reader when cached", func() {
  3666  				cachedReader := &fakeReader{}
  3667  				cl, err := client.New(cfg, client.Options{
  3668  					Cache: &client.CacheOptions{
  3669  						Reader:       cachedReader,
  3670  						Unstructured: true,
  3671  					},
  3672  				})
  3673  				Expect(err).NotTo(HaveOccurred())
  3674  
  3675  				actual := &unstructured.Unstructured{}
  3676  				actual.SetGroupVersionKind(schema.GroupVersionKind{
  3677  					Group:   "apps",
  3678  					Kind:    "Deployment",
  3679  					Version: "v1",
  3680  				})
  3681  				actual.SetName(dep.Name)
  3682  				key := client.ObjectKey{Namespace: dep.Namespace, Name: dep.Name}
  3683  				Expect(cl.Get(context.TODO(), key, actual)).To(Succeed())
  3684  				Expect(1).To(Equal(cachedReader.Called))
  3685  			})
  3686  		})
  3687  	})
  3688  	Describe("List", func() {
  3689  		It("should call cache reader when structured object", func() {
  3690  			cachedReader := &fakeReader{}
  3691  			cl, err := client.New(cfg, client.Options{
  3692  				Cache: &client.CacheOptions{
  3693  					Reader: cachedReader,
  3694  				},
  3695  			})
  3696  			Expect(err).NotTo(HaveOccurred())
  3697  			var actual appsv1.DeploymentList
  3698  			Expect(cl.List(context.Background(), &actual)).To(Succeed())
  3699  			Expect(1).To(Equal(cachedReader.Called))
  3700  		})
  3701  
  3702  		When("listing unstructured objects", func() {
  3703  			It("should call client reader when not cached", func() {
  3704  				cachedReader := &fakeReader{}
  3705  				cl, err := client.New(cfg, client.Options{
  3706  					Cache: &client.CacheOptions{
  3707  						Reader: cachedReader,
  3708  					},
  3709  				})
  3710  				Expect(err).NotTo(HaveOccurred())
  3711  
  3712  				actual := &unstructured.UnstructuredList{}
  3713  				actual.SetGroupVersionKind(schema.GroupVersionKind{
  3714  					Group:   "apps",
  3715  					Kind:    "DeploymentList",
  3716  					Version: "v1",
  3717  				})
  3718  				Expect(cl.List(context.Background(), actual)).To(Succeed())
  3719  				Expect(0).To(Equal(cachedReader.Called))
  3720  			})
  3721  			It("should call cache reader when cached", func() {
  3722  				cachedReader := &fakeReader{}
  3723  				cl, err := client.New(cfg, client.Options{
  3724  					Cache: &client.CacheOptions{
  3725  						Reader:       cachedReader,
  3726  						Unstructured: true,
  3727  					},
  3728  				})
  3729  				Expect(err).NotTo(HaveOccurred())
  3730  
  3731  				actual := &unstructured.UnstructuredList{}
  3732  				actual.SetGroupVersionKind(schema.GroupVersionKind{
  3733  					Group:   "apps",
  3734  					Kind:    "DeploymentList",
  3735  					Version: "v1",
  3736  				})
  3737  				Expect(cl.List(context.Background(), actual)).To(Succeed())
  3738  				Expect(1).To(Equal(cachedReader.Called))
  3739  			})
  3740  		})
  3741  	})
  3742  })
  3743  
  3744  var _ = Describe("Patch", func() {
  3745  	Describe("MergeFrom", func() {
  3746  		var cm *corev1.ConfigMap
  3747  
  3748  		BeforeEach(func() {
  3749  			cm = &corev1.ConfigMap{
  3750  				ObjectMeta: metav1.ObjectMeta{
  3751  					Namespace:       metav1.NamespaceDefault,
  3752  					Name:            "cm",
  3753  					ResourceVersion: "10",
  3754  				},
  3755  			}
  3756  		})
  3757  
  3758  		It("creates a merge patch with the modifications applied during the mutation", func() {
  3759  			const (
  3760  				annotationKey   = "test"
  3761  				annotationValue = "foo"
  3762  			)
  3763  
  3764  			By("creating a merge patch")
  3765  			patch := client.MergeFrom(cm.DeepCopy())
  3766  
  3767  			By("returning a patch with type MergePatch")
  3768  			Expect(patch.Type()).To(Equal(types.MergePatchType))
  3769  
  3770  			By("retrieving modifying the config map")
  3771  			metav1.SetMetaDataAnnotation(&cm.ObjectMeta, annotationKey, annotationValue)
  3772  
  3773  			By("computing the patch data")
  3774  			data, err := patch.Data(cm)
  3775  
  3776  			By("returning no error")
  3777  			Expect(err).NotTo(HaveOccurred())
  3778  
  3779  			By("returning a patch with data only containing the annotation change")
  3780  			Expect(data).To(Equal([]byte(fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, annotationKey, annotationValue))))
  3781  		})
  3782  
  3783  		It("creates a merge patch with the modifications applied during the mutation, using optimistic locking", func() {
  3784  			const (
  3785  				annotationKey   = "test"
  3786  				annotationValue = "foo"
  3787  			)
  3788  
  3789  			By("creating a merge patch")
  3790  			patch := client.MergeFromWithOptions(cm.DeepCopy(), client.MergeFromWithOptimisticLock{})
  3791  
  3792  			By("returning a patch with type MergePatch")
  3793  			Expect(patch.Type()).To(Equal(types.MergePatchType))
  3794  
  3795  			By("retrieving modifying the config map")
  3796  			metav1.SetMetaDataAnnotation(&cm.ObjectMeta, annotationKey, annotationValue)
  3797  
  3798  			By("computing the patch data")
  3799  			data, err := patch.Data(cm)
  3800  
  3801  			By("returning no error")
  3802  			Expect(err).NotTo(HaveOccurred())
  3803  
  3804  			By("returning a patch with data containing the annotation change and the resourceVersion change")
  3805  			Expect(data).To(Equal([]byte(fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"},"resourceVersion":"%s"}}`, annotationKey, annotationValue, cm.ResourceVersion))))
  3806  		})
  3807  	})
  3808  
  3809  	Describe("StrategicMergeFrom", func() {
  3810  		var dep *appsv1.Deployment
  3811  
  3812  		BeforeEach(func() {
  3813  			dep = &appsv1.Deployment{
  3814  				ObjectMeta: metav1.ObjectMeta{
  3815  					Namespace:       metav1.NamespaceDefault,
  3816  					Name:            "dep",
  3817  					ResourceVersion: "10",
  3818  				},
  3819  				Spec: appsv1.DeploymentSpec{
  3820  					Template: corev1.PodTemplateSpec{
  3821  						Spec: corev1.PodSpec{Containers: []corev1.Container{{
  3822  							Name:  "main",
  3823  							Image: "foo:v1",
  3824  						}, {
  3825  							Name:  "sidecar",
  3826  							Image: "bar:v1",
  3827  						}}},
  3828  					},
  3829  				},
  3830  			}
  3831  		})
  3832  
  3833  		It("creates a strategic merge patch with the modifications applied during the mutation", func() {
  3834  			By("creating a strategic merge patch")
  3835  			patch := client.StrategicMergeFrom(dep.DeepCopy())
  3836  
  3837  			By("returning a patch with type StrategicMergePatchType")
  3838  			Expect(patch.Type()).To(Equal(types.StrategicMergePatchType))
  3839  
  3840  			By("updating the main container's image")
  3841  			for i, c := range dep.Spec.Template.Spec.Containers {
  3842  				if c.Name == "main" {
  3843  					c.Image = "foo:v2"
  3844  				}
  3845  				dep.Spec.Template.Spec.Containers[i] = c
  3846  			}
  3847  
  3848  			By("computing the patch data")
  3849  			data, err := patch.Data(dep)
  3850  
  3851  			By("returning no error")
  3852  			Expect(err).NotTo(HaveOccurred())
  3853  
  3854  			By("returning a patch with data only containing the image change")
  3855  			Expect(data).To(Equal([]byte(`{"spec":{"template":{"spec":{"$setElementOrder/containers":[{"name":"main"},` +
  3856  				`{"name":"sidecar"}],"containers":[{"image":"foo:v2","name":"main"}]}}}}`)))
  3857  		})
  3858  
  3859  		It("creates a strategic merge patch with the modifications applied during the mutation, using optimistic locking", func() {
  3860  			By("creating a strategic merge patch")
  3861  			patch := client.StrategicMergeFrom(dep.DeepCopy(), client.MergeFromWithOptimisticLock{})
  3862  
  3863  			By("returning a patch with type StrategicMergePatchType")
  3864  			Expect(patch.Type()).To(Equal(types.StrategicMergePatchType))
  3865  
  3866  			By("updating the main container's image")
  3867  			for i, c := range dep.Spec.Template.Spec.Containers {
  3868  				if c.Name == "main" {
  3869  					c.Image = "foo:v2"
  3870  				}
  3871  				dep.Spec.Template.Spec.Containers[i] = c
  3872  			}
  3873  
  3874  			By("computing the patch data")
  3875  			data, err := patch.Data(dep)
  3876  
  3877  			By("returning no error")
  3878  			Expect(err).NotTo(HaveOccurred())
  3879  
  3880  			By("returning a patch with data containing the image change and the resourceVersion change")
  3881  			Expect(data).To(Equal([]byte(fmt.Sprintf(`{"metadata":{"resourceVersion":"%s"},`+
  3882  				`"spec":{"template":{"spec":{"$setElementOrder/containers":[{"name":"main"},{"name":"sidecar"}],"containers":[{"image":"foo:v2","name":"main"}]}}}}`,
  3883  				dep.ResourceVersion))))
  3884  		})
  3885  	})
  3886  })
  3887  
  3888  var _ = Describe("IgnoreNotFound", func() {
  3889  	It("should return nil on a 'NotFound' error", func() {
  3890  		By("creating a NotFound error")
  3891  		err := apierrors.NewNotFound(schema.GroupResource{}, "")
  3892  
  3893  		By("returning no error")
  3894  		Expect(client.IgnoreNotFound(err)).To(Succeed())
  3895  	})
  3896  
  3897  	It("should return the error on a status other than not found", func() {
  3898  		By("creating a BadRequest error")
  3899  		err := apierrors.NewBadRequest("")
  3900  
  3901  		By("returning an error")
  3902  		Expect(client.IgnoreNotFound(err)).To(HaveOccurred())
  3903  	})
  3904  
  3905  	It("should return the error on a non-status error", func() {
  3906  		By("creating an fmt error")
  3907  		err := fmt.Errorf("arbitrary error")
  3908  
  3909  		By("returning an error")
  3910  		Expect(client.IgnoreNotFound(err)).To(HaveOccurred())
  3911  	})
  3912  })
  3913  
  3914  var _ = Describe("IgnoreAlreadyExists", func() {
  3915  	It("should return nil on a 'AlreadyExists' error", func() {
  3916  		By("creating a AlreadyExists error")
  3917  		err := apierrors.NewAlreadyExists(schema.GroupResource{}, "")
  3918  
  3919  		By("returning no error")
  3920  		Expect(client.IgnoreAlreadyExists(err)).To(Succeed())
  3921  	})
  3922  
  3923  	It("should return the error on a status other than already exists", func() {
  3924  		By("creating a BadRequest error")
  3925  		err := apierrors.NewBadRequest("")
  3926  
  3927  		By("returning an error")
  3928  		Expect(client.IgnoreAlreadyExists(err)).To(HaveOccurred())
  3929  	})
  3930  
  3931  	It("should return the error on a non-status error", func() {
  3932  		By("creating an fmt error")
  3933  		err := fmt.Errorf("arbitrary error")
  3934  
  3935  		By("returning an error")
  3936  		Expect(client.IgnoreAlreadyExists(err)).To(HaveOccurred())
  3937  	})
  3938  })
  3939  
  3940  type fakeReader struct {
  3941  	Called int
  3942  }
  3943  
  3944  func (f *fakeReader) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
  3945  	f.Called++
  3946  	return nil
  3947  }
  3948  
  3949  func (f *fakeReader) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
  3950  	f.Called++
  3951  	return nil
  3952  }
  3953  
  3954  type fakeUncachedReader struct {
  3955  	Called int
  3956  }
  3957  
  3958  func (f *fakeUncachedReader) Get(_ context.Context, _ client.ObjectKey, _ client.Object, opts ...client.GetOption) error {
  3959  	f.Called++
  3960  	return &cache.ErrResourceNotCached{}
  3961  }
  3962  
  3963  func (f *fakeUncachedReader) List(_ context.Context, _ client.ObjectList, _ ...client.ListOption) error {
  3964  	f.Called++
  3965  	return &cache.ErrResourceNotCached{}
  3966  }
  3967  
  3968  func toUnstructured(o client.Object) (*unstructured.Unstructured, error) {
  3969  	serialized, err := json.Marshal(o)
  3970  	if err != nil {
  3971  		return nil, err
  3972  	}
  3973  	u := &unstructured.Unstructured{}
  3974  	return u, json.Unmarshal(serialized, u)
  3975  }
  3976  

View as plain text