@@ -10,6 +10,7 @@ import (
10
10
11
11
. "github.com/onsi/gomega"
12
12
13
+ corev1 "k8s.io/api/core/v1"
13
14
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14
15
"sigs.k8s.io/controller-runtime/pkg/client"
15
16
@@ -75,14 +76,88 @@ func Test_ReconcilePolicy_UnknownPolicyIsIgnored(t *testing.T) {
75
76
tc .Expect (rg .Status .Tags ).To (HaveKeyWithValue ("tag1" , "value1" ))
76
77
}
77
78
78
- func Test_ReconcilePolicy_DetachOnDelete_SkipsDelete (t * testing.T ) {
79
+ func Test_ReconcilePolicy_SkipsDelete (t * testing.T ) {
79
80
t .Parallel ()
80
- testDeleteSkipped (t , "detach-on-delete" )
81
+
82
+ testCases := []struct {
83
+ name string
84
+ policy string
85
+ onNamespace bool
86
+ }{
87
+ {
88
+ name : "DetachOnDelete_OnResource" ,
89
+ policy : "detach-on-delete" ,
90
+ onNamespace : false ,
91
+ },
92
+ {
93
+ name : "Skip_OnResource" ,
94
+ policy : "skip" ,
95
+ onNamespace : false ,
96
+ },
97
+ {
98
+ name : "DetachOnDelete_OnNamespace" ,
99
+ policy : "detach-on-delete" ,
100
+ onNamespace : true ,
101
+ },
102
+ {
103
+ name : "Skip_OnNamespace" ,
104
+ policy : "skip" ,
105
+ onNamespace : true ,
106
+ },
107
+ }
108
+
109
+ for _ , tc := range testCases {
110
+ t .Run (tc .name , func (t * testing.T ) {
111
+ t .Parallel ()
112
+ testDeleteSkipped (
113
+ t ,
114
+ deleteSkippedOptions {
115
+ policy : tc .policy ,
116
+ onNamespace : tc .onNamespace ,
117
+ })
118
+ })
119
+ }
81
120
}
82
121
83
- func Test_ReconcilePolicy_Skip_SkipsDelete (t * testing.T ) {
122
+ func Test_ReconcilePolicy_SkipReconcileAddedToNamespace_ReconcileIsSkipped (t * testing.T ) {
84
123
t .Parallel ()
85
- testDeleteSkipped (t , "skip" )
124
+
125
+ tc := globalTestContext .ForTest (t )
126
+
127
+ // Create a resource group
128
+ rg := tc .CreateTestResourceGroupAndWait ()
129
+
130
+ // check properties
131
+ tc .Expect (rg .Status .Location ).To (Equal (tc .AzureRegion ))
132
+ tc .Expect (rg .Status .Properties .ProvisioningState ).To (Equal (to .Ptr ("Succeeded" )))
133
+ tc .Expect (rg .Status .Id ).ToNot (BeNil ())
134
+
135
+ // Update the namespace to skip reconcile
136
+ ns := & corev1.Namespace {}
137
+ tc .GetResource (client.ObjectKey {Name : tc .Namespace }, ns )
138
+ oldNS := ns .DeepCopy ()
139
+ ns .Annotations = make (map [string ]string )
140
+ ns .Annotations ["serviceoperator.azure.com/reconcile-policy" ] = "skip"
141
+ tc .Patch (oldNS , ns )
142
+
143
+ // Update the tags
144
+ old := rg .DeepCopy ()
145
+ rg .Spec .Tags ["tag1" ] = "value1"
146
+ tc .PatchResourceAndWait (old , rg )
147
+ tc .Expect (rg .Status .Tags ).ToNot (HaveKey ("tag1" ))
148
+
149
+ // Stop skipping reconcile
150
+ oldNS = ns .DeepCopy ()
151
+ delete (ns .Annotations , "serviceoperator.azure.com/reconcile-policy" )
152
+ tc .Patch (oldNS , ns )
153
+
154
+ // ensure the tags get updated
155
+ objectKey := client .ObjectKeyFromObject (rg )
156
+ tc .Eventually (func () map [string ]string {
157
+ newRG := & resources.ResourceGroup {}
158
+ tc .GetResource (objectKey , newRG )
159
+ return newRG .Status .Tags
160
+ }).Should (HaveKeyWithValue ("tag1" , "value1" ))
86
161
}
87
162
88
163
func Test_ReconcilePolicy_SkippedParentDeleted_ChildIssuesDeleteToAzure (t * testing.T ) {
@@ -198,7 +273,12 @@ func Test_ReconcilePolicySkip_CreatesSecretAndConfigMap(t *testing.T) {
198
273
tc .Patch (old , acct )
199
274
}
200
275
201
- func testDeleteSkipped (t * testing.T , policy string ) {
276
+ type deleteSkippedOptions struct {
277
+ policy string
278
+ onNamespace bool
279
+ }
280
+
281
+ func testDeleteSkipped (t * testing.T , opts deleteSkippedOptions ) {
202
282
tc := globalTestContext .ForTest (t )
203
283
204
284
// Create a resource group
@@ -211,23 +291,33 @@ func testDeleteSkipped(t *testing.T, policy string) {
211
291
tc .Expect (rg .Status .Id ).ToNot (BeNil ())
212
292
armId := * rg .Status .Id
213
293
214
- if policy == "skip" {
215
- // This is a hack so that we can tell when reconcile has happened to avoid a race in the recording.
216
- // It's only required in the skip case because for detach-on-delete we don't reconcile at all
217
- // See HasReconcilePolicyAnnotationChanged
294
+ if ! opts .onNamespace {
295
+ if opts .policy == "skip" {
296
+ // This is a hack so that we can tell when reconcile has happened to avoid a race in the recording.
297
+ // It's only required in the skip case because for detach-on-delete we don't reconcile at all
298
+ // See HasReconcilePolicyAnnotationChanged
299
+ old := rg .DeepCopy ()
300
+ rg .Status .Conditions [0 ].ObservedGeneration = - 1
301
+ tc .PatchStatus (old , rg )
302
+ }
303
+
304
+ // Update to skip reconcile
218
305
old := rg .DeepCopy ()
219
- rg .Status .Conditions [0 ].ObservedGeneration = - 1
220
- tc .PatchStatus (old , rg )
306
+ rg .Annotations ["serviceoperator.azure.com/reconcile-policy" ] = opts .policy
307
+ tc .Patch (old , rg )
308
+ // TODO: There may still be a race here where delete in the operator code gets the old cached value without the policy in the detach-on-delete case,
309
+ // TODO: since there is no reconcile after the annotation patch (see HasReconcilePolicyAnnotationChanged), so this eventually finishes quickly.
310
+ tc .Eventually (rg ).Should (tc .Match .BeProvisioned (- 1 ))
311
+ } else {
312
+ // Update the namespace to skip reconcile
313
+ ns := & corev1.Namespace {}
314
+ tc .GetResource (client.ObjectKey {Name : tc .Namespace }, ns )
315
+ oldNS := ns .DeepCopy ()
316
+ ns .Annotations = make (map [string ]string )
317
+ ns .Annotations ["serviceoperator.azure.com/reconcile-policy" ] = opts .policy
318
+ tc .Patch (oldNS , ns )
221
319
}
222
320
223
- // Update to skip reconcile
224
- old := rg .DeepCopy ()
225
- rg .Annotations ["serviceoperator.azure.com/reconcile-policy" ] = policy
226
- tc .Patch (old , rg )
227
- // TODO: There may still be a race here where delete in the operator code gets the old cached value without the policy in the detach-on-delete case,
228
- // TODO: since there is no reconcile after the annotation patch (see HasReconcilePolicyAnnotationChanged), so this eventually finishes quickly.
229
- tc .Eventually (rg ).Should (tc .Match .BeProvisioned (- 1 ))
230
-
231
321
tc .DeleteResourceAndWait (rg )
232
322
233
323
// Ensure that the resource group was NOT deleted in Azure
@@ -247,6 +337,16 @@ func testDeleteSkipped(t *testing.T, policy string) {
247
337
Spec : rg .Spec ,
248
338
}
249
339
tc .CreateResourceAndWait (newRG )
340
+
341
+ if opts .onNamespace {
342
+ // Remove skip reconcile annotation from the namespace
343
+ ns := & corev1.Namespace {}
344
+ tc .GetResource (client.ObjectKey {Name : tc .Namespace }, ns )
345
+ oldNS := ns .DeepCopy ()
346
+ delete (ns .Annotations , "serviceoperator.azure.com/reconcile-policy" )
347
+ tc .Patch (oldNS , ns )
348
+ }
349
+
250
350
// Delete it
251
351
tc .DeleteResourceAndWait (newRG )
252
352
0 commit comments