sigs.k8s.io/cluster-api@v1.7.1/exp/addons/internal/controllers/clusterresourceset_scope_test.go (about)

     1  /*
     2  Copyright 2022 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 controllers
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	. "github.com/onsi/gomega"
    24  	corev1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    27  	"sigs.k8s.io/controller-runtime/pkg/client"
    28  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    29  
    30  	addonsv1 "sigs.k8s.io/cluster-api/exp/addons/api/v1beta1"
    31  )
    32  
    33  func TestReconcileStrategyScopeNeedsApply(t *testing.T) {
    34  	tests := []struct {
    35  		name  string
    36  		scope *reconcileStrategyScope
    37  		want  bool
    38  	}{
    39  		{
    40  			name: "no ResourceBinding",
    41  			scope: &reconcileStrategyScope{
    42  				baseResourceReconcileScope: baseResourceReconcileScope{
    43  					resourceSetBinding: &addonsv1.ResourceSetBinding{},
    44  					resourceRef: addonsv1.ResourceRef{
    45  						Name: "cp",
    46  						Kind: "ConfigMap",
    47  					},
    48  				},
    49  			},
    50  			want: true,
    51  		},
    52  		{
    53  			name: "not applied ResourceBinding",
    54  			scope: &reconcileStrategyScope{
    55  				baseResourceReconcileScope: baseResourceReconcileScope{
    56  					resourceSetBinding: &addonsv1.ResourceSetBinding{
    57  						Resources: []addonsv1.ResourceBinding{
    58  							{
    59  								ResourceRef: addonsv1.ResourceRef{
    60  									Name: "cp",
    61  									Kind: "ConfigMap",
    62  								},
    63  								Applied: false,
    64  							},
    65  						},
    66  					},
    67  					resourceRef: addonsv1.ResourceRef{
    68  						Name: "cp",
    69  						Kind: "ConfigMap",
    70  					},
    71  				},
    72  			},
    73  			want: true,
    74  		},
    75  		{
    76  			name: "applied ResourceBinding and different hash",
    77  			scope: &reconcileStrategyScope{
    78  				baseResourceReconcileScope: baseResourceReconcileScope{
    79  					resourceSetBinding: &addonsv1.ResourceSetBinding{
    80  						Resources: []addonsv1.ResourceBinding{
    81  							{
    82  								ResourceRef: addonsv1.ResourceRef{
    83  									Name: "cp",
    84  									Kind: "ConfigMap",
    85  								},
    86  								Applied: true,
    87  								Hash:    "111",
    88  							},
    89  						},
    90  					},
    91  					resourceRef: addonsv1.ResourceRef{
    92  						Name: "cp",
    93  						Kind: "ConfigMap",
    94  					},
    95  					computedHash: "222",
    96  				},
    97  			},
    98  			want: true,
    99  		},
   100  		{
   101  			name: "applied ResourceBinding and same hash",
   102  			scope: &reconcileStrategyScope{
   103  				baseResourceReconcileScope: baseResourceReconcileScope{
   104  					resourceSetBinding: &addonsv1.ResourceSetBinding{
   105  						Resources: []addonsv1.ResourceBinding{
   106  							{
   107  								ResourceRef: addonsv1.ResourceRef{
   108  									Name: "cp",
   109  									Kind: "ConfigMap",
   110  								},
   111  								Applied: true,
   112  								Hash:    "111",
   113  							},
   114  						},
   115  					},
   116  					resourceRef: addonsv1.ResourceRef{
   117  						Name: "cp",
   118  						Kind: "ConfigMap",
   119  					},
   120  					computedHash: "111",
   121  				},
   122  			},
   123  			want: false,
   124  		},
   125  	}
   126  	for _, tt := range tests {
   127  		t.Run(tt.name, func(t *testing.T) {
   128  			gs := NewWithT(t)
   129  			gs.Expect(tt.scope.needsApply()).To(Equal(tt.want))
   130  		})
   131  	}
   132  }
   133  
   134  func TestReconcileApplyOnceScopeNeedsApply(t *testing.T) {
   135  	tests := []struct {
   136  		name  string
   137  		scope *reconcileApplyOnceScope
   138  		want  bool
   139  	}{
   140  		{
   141  			name: "not applied ResourceBinding",
   142  			scope: &reconcileApplyOnceScope{
   143  				baseResourceReconcileScope: baseResourceReconcileScope{
   144  					resourceSetBinding: &addonsv1.ResourceSetBinding{
   145  						Resources: []addonsv1.ResourceBinding{
   146  							{
   147  								ResourceRef: addonsv1.ResourceRef{
   148  									Name: "cp",
   149  									Kind: "ConfigMap",
   150  								},
   151  								Applied: false,
   152  							},
   153  						},
   154  					},
   155  					resourceRef: addonsv1.ResourceRef{
   156  						Name: "cp",
   157  						Kind: "ConfigMap",
   158  					},
   159  				},
   160  			},
   161  			want: true,
   162  		},
   163  		{
   164  			name: "applied ResourceBinding",
   165  			scope: &reconcileApplyOnceScope{
   166  				baseResourceReconcileScope: baseResourceReconcileScope{
   167  					resourceSetBinding: &addonsv1.ResourceSetBinding{
   168  						Resources: []addonsv1.ResourceBinding{
   169  							{
   170  								ResourceRef: addonsv1.ResourceRef{
   171  									Name: "cp",
   172  									Kind: "ConfigMap",
   173  								},
   174  								Applied: true,
   175  							},
   176  						},
   177  					},
   178  					resourceRef: addonsv1.ResourceRef{
   179  						Name: "cp",
   180  						Kind: "ConfigMap",
   181  					},
   182  				},
   183  			},
   184  			want: false,
   185  		},
   186  	}
   187  	for _, tt := range tests {
   188  		t.Run(tt.name, func(t *testing.T) {
   189  			gs := NewWithT(t)
   190  			gs.Expect(tt.scope.needsApply()).To(Equal(tt.want))
   191  		})
   192  	}
   193  }
   194  
   195  func TestReconcileApplyOnceScopeApplyObj(t *testing.T) {
   196  	tests := []struct {
   197  		name         string
   198  		existingObjs []client.Object
   199  		obj          *unstructured.Unstructured
   200  		wantErr      string
   201  	}{
   202  		{
   203  			name: "object doesn't exist",
   204  			obj: &unstructured.Unstructured{
   205  				Object: map[string]interface{}{
   206  					"apiVersion": "v1",
   207  					"kind":       "ConfigMap",
   208  					"metadata": map[string]interface{}{
   209  						"name":      "my-cm",
   210  						"namespace": "that-ns",
   211  					},
   212  				},
   213  			},
   214  		},
   215  		{
   216  			name: "object exists",
   217  			existingObjs: []client.Object{
   218  				&corev1.ConfigMap{
   219  					ObjectMeta: metav1.ObjectMeta{
   220  						Name:      "my-cm",
   221  						Namespace: "that-ns",
   222  					},
   223  				},
   224  			},
   225  			obj: &unstructured.Unstructured{
   226  				Object: map[string]interface{}{
   227  					"apiVersion": "v1",
   228  					"kind":       "ConfigMap",
   229  					"metadata": map[string]interface{}{
   230  						"name":      "my-cm",
   231  						"namespace": "that-ns",
   232  					},
   233  				},
   234  			},
   235  		},
   236  	}
   237  	for _, tt := range tests {
   238  		t.Run(tt.name, func(t *testing.T) {
   239  			gs := NewWithT(t)
   240  			ctx := context.Background()
   241  			client := fake.NewClientBuilder().WithObjects(tt.existingObjs...).Build()
   242  			scope := &reconcileApplyOnceScope{}
   243  			err := scope.applyObj(ctx, client, tt.obj)
   244  			if tt.wantErr == "" {
   245  				gs.Expect(err).ToNot(HaveOccurred())
   246  			} else {
   247  				gs.Expect(err).To(MatchError(ContainSubstring(tt.wantErr)))
   248  			}
   249  		})
   250  	}
   251  }