...

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

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

     1  /*
     2  Copyright 2020 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  	"fmt"
    22  	"sync/atomic"
    23  
    24  	. "github.com/onsi/ginkgo/v2"
    25  	. "github.com/onsi/gomega"
    26  	appsv1 "k8s.io/api/apps/v1"
    27  	corev1 "k8s.io/api/core/v1"
    28  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/types"
    31  	"k8s.io/utils/ptr"
    32  
    33  	"sigs.k8s.io/controller-runtime/pkg/client"
    34  )
    35  
    36  var _ = Describe("DryRunClient", func() {
    37  	var dep *appsv1.Deployment
    38  	var count uint64 = 0
    39  	var replicaCount int32 = 2
    40  	var ns = "default"
    41  	ctx := context.Background()
    42  
    43  	getClient := func() client.Client {
    44  		cl, err := client.New(cfg, client.Options{DryRun: ptr.To(true)})
    45  		Expect(err).NotTo(HaveOccurred())
    46  		Expect(cl).NotTo(BeNil())
    47  		return cl
    48  	}
    49  
    50  	BeforeEach(func() {
    51  		atomic.AddUint64(&count, 1)
    52  		dep = &appsv1.Deployment{
    53  			ObjectMeta: metav1.ObjectMeta{
    54  				Name:      fmt.Sprintf("dry-run-deployment-%v", count),
    55  				Namespace: ns,
    56  				Labels:    map[string]string{"name": fmt.Sprintf("dry-run-deployment-%v", count)},
    57  			},
    58  			Spec: appsv1.DeploymentSpec{
    59  				Replicas: &replicaCount,
    60  				Selector: &metav1.LabelSelector{
    61  					MatchLabels: map[string]string{"foo": "bar"},
    62  				},
    63  				Template: corev1.PodTemplateSpec{
    64  					ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
    65  					Spec:       corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
    66  				},
    67  			},
    68  		}
    69  
    70  		var err error
    71  		dep, err = clientset.AppsV1().Deployments(ns).Create(ctx, dep, metav1.CreateOptions{})
    72  		Expect(err).NotTo(HaveOccurred())
    73  	})
    74  
    75  	AfterEach(func() {
    76  		deleteDeployment(ctx, dep, ns)
    77  	})
    78  
    79  	It("should successfully Get an object", func() {
    80  		name := types.NamespacedName{Namespace: ns, Name: dep.Name}
    81  		result := &appsv1.Deployment{}
    82  
    83  		Expect(getClient().Get(ctx, name, result)).NotTo(HaveOccurred())
    84  		Expect(result).To(BeEquivalentTo(dep))
    85  	})
    86  
    87  	It("should successfully List objects", func() {
    88  		result := &appsv1.DeploymentList{}
    89  		opts := client.MatchingLabels(dep.Labels)
    90  
    91  		Expect(getClient().List(ctx, result, opts)).NotTo(HaveOccurred())
    92  
    93  		Expect(len(result.Items)).To(BeEquivalentTo(1))
    94  		Expect(result.Items[0]).To(BeEquivalentTo(*dep))
    95  	})
    96  
    97  	It("should not create an object", func() {
    98  		newDep := dep.DeepCopy()
    99  		newDep.Name = "new-deployment"
   100  
   101  		Expect(getClient().Create(ctx, newDep)).ToNot(HaveOccurred())
   102  
   103  		_, err := clientset.AppsV1().Deployments(ns).Get(ctx, newDep.Name, metav1.GetOptions{})
   104  		Expect(apierrors.IsNotFound(err)).To(BeTrue())
   105  	})
   106  
   107  	It("should not create an object with opts", func() {
   108  		newDep := dep.DeepCopy()
   109  		newDep.Name = "new-deployment"
   110  		opts := &client.CreateOptions{DryRun: []string{"Bye", "Pippa"}}
   111  
   112  		Expect(getClient().Create(ctx, newDep, opts)).ToNot(HaveOccurred())
   113  
   114  		_, err := clientset.AppsV1().Deployments(ns).Get(ctx, newDep.Name, metav1.GetOptions{})
   115  		Expect(apierrors.IsNotFound(err)).To(BeTrue())
   116  	})
   117  
   118  	It("should refuse a create request for an invalid object", func() {
   119  		changedDep := dep.DeepCopy()
   120  		changedDep.Spec.Template.Spec.Containers = nil
   121  
   122  		err := getClient().Create(ctx, changedDep)
   123  		Expect(apierrors.IsInvalid(err)).To(BeTrue())
   124  	})
   125  
   126  	It("should not change objects via update", func() {
   127  		changedDep := dep.DeepCopy()
   128  		*changedDep.Spec.Replicas = 2
   129  
   130  		Expect(getClient().Update(ctx, changedDep)).ToNot(HaveOccurred())
   131  
   132  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   133  		Expect(err).NotTo(HaveOccurred())
   134  		Expect(actual).NotTo(BeNil())
   135  		Expect(actual).To(BeEquivalentTo(dep))
   136  	})
   137  
   138  	It("should not change objects via update with opts", func() {
   139  		changedDep := dep.DeepCopy()
   140  		*changedDep.Spec.Replicas = 2
   141  		opts := &client.UpdateOptions{DryRun: []string{"Bye", "Pippa"}}
   142  
   143  		Expect(getClient().Update(ctx, changedDep, opts)).ToNot(HaveOccurred())
   144  
   145  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   146  		Expect(err).NotTo(HaveOccurred())
   147  		Expect(actual).NotTo(BeNil())
   148  		Expect(actual).To(BeEquivalentTo(dep))
   149  	})
   150  
   151  	It("should refuse an update request for an invalid change", func() {
   152  		changedDep := dep.DeepCopy()
   153  		changedDep.Spec.Template.Spec.Containers = nil
   154  
   155  		err := getClient().Update(ctx, changedDep)
   156  		Expect(apierrors.IsInvalid(err)).To(BeTrue())
   157  	})
   158  
   159  	It("should not change objects via patch", func() {
   160  		changedDep := dep.DeepCopy()
   161  		*changedDep.Spec.Replicas = 2
   162  
   163  		Expect(getClient().Patch(ctx, changedDep, client.MergeFrom(dep))).ToNot(HaveOccurred())
   164  
   165  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   166  		Expect(err).NotTo(HaveOccurred())
   167  		Expect(actual).NotTo(BeNil())
   168  		Expect(actual).To(BeEquivalentTo(dep))
   169  	})
   170  
   171  	It("should not change objects via patch with opts", func() {
   172  		changedDep := dep.DeepCopy()
   173  		*changedDep.Spec.Replicas = 2
   174  		opts := &client.PatchOptions{DryRun: []string{"Bye", "Pippa"}}
   175  
   176  		Expect(getClient().Patch(ctx, changedDep, client.MergeFrom(dep), opts)).ToNot(HaveOccurred())
   177  
   178  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   179  		Expect(err).NotTo(HaveOccurred())
   180  		Expect(actual).NotTo(BeNil())
   181  		Expect(actual).To(BeEquivalentTo(dep))
   182  	})
   183  
   184  	It("should not delete objects", func() {
   185  		Expect(getClient().Delete(ctx, dep)).NotTo(HaveOccurred())
   186  
   187  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   188  		Expect(err).NotTo(HaveOccurred())
   189  		Expect(actual).NotTo(BeNil())
   190  		Expect(actual).To(BeEquivalentTo(dep))
   191  	})
   192  
   193  	It("should not delete objects with opts", func() {
   194  		opts := &client.DeleteOptions{DryRun: []string{"Bye", "Pippa"}}
   195  
   196  		Expect(getClient().Delete(ctx, dep, opts)).NotTo(HaveOccurred())
   197  
   198  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   199  		Expect(err).NotTo(HaveOccurred())
   200  		Expect(actual).NotTo(BeNil())
   201  		Expect(actual).To(BeEquivalentTo(dep))
   202  	})
   203  
   204  	It("should not delete objects via deleteAllOf", func() {
   205  		opts := []client.DeleteAllOfOption{client.InNamespace(ns), client.MatchingLabels(dep.Labels)}
   206  
   207  		Expect(getClient().DeleteAllOf(ctx, dep, opts...)).NotTo(HaveOccurred())
   208  
   209  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   210  		Expect(err).NotTo(HaveOccurred())
   211  		Expect(actual).NotTo(BeNil())
   212  		Expect(actual).To(BeEquivalentTo(dep))
   213  	})
   214  
   215  	It("should not change objects via update status", func() {
   216  		changedDep := dep.DeepCopy()
   217  		changedDep.Status.Replicas = 99
   218  
   219  		Expect(getClient().Status().Update(ctx, changedDep)).NotTo(HaveOccurred())
   220  
   221  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   222  		Expect(err).NotTo(HaveOccurred())
   223  		Expect(actual).NotTo(BeNil())
   224  		Expect(actual).To(BeEquivalentTo(dep))
   225  	})
   226  
   227  	It("should not change objects via update status with opts", func() {
   228  		changedDep := dep.DeepCopy()
   229  		changedDep.Status.Replicas = 99
   230  		opts := &client.SubResourceUpdateOptions{UpdateOptions: client.UpdateOptions{DryRun: []string{"Bye", "Pippa"}}}
   231  
   232  		Expect(getClient().Status().Update(ctx, changedDep, opts)).NotTo(HaveOccurred())
   233  
   234  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   235  		Expect(err).NotTo(HaveOccurred())
   236  		Expect(actual).NotTo(BeNil())
   237  		Expect(actual).To(BeEquivalentTo(dep))
   238  	})
   239  
   240  	It("should not change objects via status patch", func() {
   241  		changedDep := dep.DeepCopy()
   242  		changedDep.Status.Replicas = 99
   243  
   244  		Expect(getClient().Status().Patch(ctx, changedDep, client.MergeFrom(dep))).ToNot(HaveOccurred())
   245  
   246  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   247  		Expect(err).NotTo(HaveOccurred())
   248  		Expect(actual).NotTo(BeNil())
   249  		Expect(actual).To(BeEquivalentTo(dep))
   250  	})
   251  
   252  	It("should not change objects via status patch with opts", func() {
   253  		changedDep := dep.DeepCopy()
   254  		changedDep.Status.Replicas = 99
   255  
   256  		opts := &client.SubResourcePatchOptions{PatchOptions: client.PatchOptions{DryRun: []string{"Bye", "Pippa"}}}
   257  
   258  		Expect(getClient().Status().Patch(ctx, changedDep, client.MergeFrom(dep), opts)).ToNot(HaveOccurred())
   259  
   260  		actual, err := clientset.AppsV1().Deployments(ns).Get(ctx, dep.Name, metav1.GetOptions{})
   261  		Expect(err).NotTo(HaveOccurred())
   262  		Expect(actual).NotTo(BeNil())
   263  		Expect(actual).To(BeEquivalentTo(dep))
   264  	})
   265  })
   266  

View as plain text