@@ -10,6 +10,7 @@ import (
10
10
"io/ioutil"
11
11
"net/http"
12
12
"path"
13
+ "reflect"
13
14
"regexp"
14
15
"testing"
15
16
"time"
@@ -23,7 +24,9 @@ import (
23
24
"k8s.io/apimachinery/pkg/runtime"
24
25
"k8s.io/apimachinery/pkg/runtime/schema"
25
26
"k8s.io/cli-runtime/pkg/resource"
27
+ dynamicfake "k8s.io/client-go/dynamic/fake"
26
28
"k8s.io/client-go/rest/fake"
29
+ clienttesting "k8s.io/client-go/testing"
27
30
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
28
31
"k8s.io/kubectl/pkg/scheme"
29
32
"sigs.k8s.io/cli-utils/pkg/apply/event"
66
69
}
67
70
)
68
71
72
+ var deploymentUnmatched = & unstructured.Unstructured {
73
+ Object : map [string ]interface {}{
74
+ "apiVersion" : "apps/v1" ,
75
+ "kind" : "Deployment" ,
76
+ "metadata" : map [string ]interface {}{
77
+ "name" : "foo" ,
78
+ "namespace" : "default" ,
79
+ "annotations" : map [string ]interface {}{
80
+ "config.k8s.io/owning-inventory" : "unmatched" ,
81
+ },
82
+ },
83
+ },
84
+ }
85
+
86
+ var deploymentMatched = & unstructured.Unstructured {
87
+ Object : map [string ]interface {}{
88
+ "apiVersion" : "apps/v1" ,
89
+ "kind" : "Deployment" ,
90
+ "metadata" : map [string ]interface {}{
91
+ "name" : "foo" ,
92
+ "namespace" : "default" ,
93
+ "annotations" : map [string ]interface {}{
94
+ "config.k8s.io/owning-inventory" : "test" ,
95
+ },
96
+ },
97
+ },
98
+ }
99
+
69
100
// resourceStatus contains information about a specific resource, such
70
101
// as the manifest yaml and the URL path for this resource in the
71
102
// client. It also contains a factory function for creating a new
@@ -83,6 +114,9 @@ type expectedEvent struct {
83
114
statusEventType event.StatusEventType
84
115
pruneEventType event.PruneEventType
85
116
deleteEventType event.DeleteEventType
117
+
118
+ applyErrorType error
119
+ pruneEventOp event.PruneEventOperation
86
120
}
87
121
88
122
func TestApplier (t * testing.T ) {
@@ -94,6 +128,7 @@ func TestApplier(t *testing.T) {
94
128
prune bool
95
129
statusEvents []pollevent.Event
96
130
expectedEventTypes []expectedEvent
131
+ clusterObj * unstructured.Unstructured
97
132
}{
98
133
"apply without status or prune" : {
99
134
namespace : "default" ,
@@ -158,14 +193,14 @@ func TestApplier(t *testing.T) {
158
193
{
159
194
EventType : pollevent .ResourceUpdateEvent ,
160
195
Resource : & pollevent.ResourceStatus {
161
- Identifier : toIdentifier (t , resources ["deployment" ], "default" ),
196
+ Identifier : toIdentifier (t , resources ["deployment" ]),
162
197
Status : status .InProgressStatus ,
163
198
},
164
199
},
165
200
{
166
201
EventType : pollevent .ResourceUpdateEvent ,
167
202
Resource : & pollevent.ResourceStatus {
168
- Identifier : toIdentifier (t , resources ["deployment" ], "default" ),
203
+ Identifier : toIdentifier (t , resources ["deployment" ]),
169
204
Status : status .CurrentStatus ,
170
205
},
171
206
},
@@ -200,6 +235,152 @@ func TestApplier(t *testing.T) {
200
235
},
201
236
},
202
237
},
238
+ "apply with inventory object and cluster object" : {
239
+ namespace : "default" ,
240
+ resources : []resourceInfo {
241
+ resources ["deployment" ],
242
+ resources ["inventoryObject" ],
243
+ },
244
+ handlers : []handler {
245
+ & nsHandler {},
246
+ & inventoryObjectHandler {},
247
+ & genericHandler {
248
+ resourceInfo : resources ["deployment" ],
249
+ namespace : "default" ,
250
+ },
251
+ },
252
+ reconcileTimeout : time .Minute ,
253
+ statusEvents : []pollevent.Event {
254
+ {
255
+ EventType : pollevent .ResourceUpdateEvent ,
256
+ Resource : & pollevent.ResourceStatus {
257
+ Identifier : object.ObjMetadata {
258
+ Name : "foo-dcf2c498" ,
259
+ Namespace : "default" ,
260
+ GroupKind : schema.GroupKind {
261
+ Group : "" ,
262
+ Kind : "ConfigMap" ,
263
+ },
264
+ },
265
+ Status : status .CurrentStatus ,
266
+ },
267
+ },
268
+ {
269
+ EventType : pollevent .ResourceUpdateEvent ,
270
+ Resource : & pollevent.ResourceStatus {
271
+ Identifier : toIdentifier (t , resources ["deployment" ]),
272
+ Status : status .InProgressStatus ,
273
+ },
274
+ },
275
+ {
276
+ EventType : pollevent .ResourceUpdateEvent ,
277
+ Resource : & pollevent.ResourceStatus {
278
+ Identifier : toIdentifier (t , resources ["deployment" ]),
279
+ Status : status .CurrentStatus ,
280
+ },
281
+ },
282
+ },
283
+ expectedEventTypes : []expectedEvent {
284
+ {
285
+ eventType : event .InitType ,
286
+ },
287
+ {
288
+ eventType : event .ApplyType ,
289
+ applyEventType : event .ApplyEventResourceUpdate ,
290
+ applyErrorType : inventory .NewInventoryOverlapError (fmt .Errorf ("" )),
291
+ },
292
+ {
293
+ eventType : event .ApplyType ,
294
+ applyEventType : event .ApplyEventCompleted ,
295
+ },
296
+ {
297
+ eventType : event .StatusType ,
298
+ statusEventType : event .StatusEventResourceUpdate ,
299
+ },
300
+ {
301
+ eventType : event .StatusType ,
302
+ statusEventType : event .StatusEventResourceUpdate ,
303
+ },
304
+ {
305
+ eventType : event .StatusType ,
306
+ statusEventType : event .StatusEventResourceUpdate ,
307
+ },
308
+ {
309
+ eventType : event .StatusType ,
310
+ statusEventType : event .StatusEventCompleted ,
311
+ },
312
+ },
313
+ clusterObj : deploymentUnmatched ,
314
+ },
315
+ "prune with inventory object annotation unmatched" : {
316
+ namespace : "default" ,
317
+ resources : []resourceInfo {
318
+ resources ["inventoryObject" ],
319
+ },
320
+ handlers : []handler {
321
+ & nsHandler {},
322
+ & inventoryObjectHandler {},
323
+ & genericHandler {
324
+ namespace : "default" ,
325
+ },
326
+ },
327
+ reconcileTimeout : 0 ,
328
+ expectedEventTypes : []expectedEvent {
329
+ {
330
+ eventType : event .InitType ,
331
+ },
332
+ {
333
+ eventType : event .ApplyType ,
334
+ applyEventType : event .ApplyEventCompleted ,
335
+ },
336
+ {
337
+ eventType : event .PruneType ,
338
+ pruneEventType : event .PruneEventResourceUpdate ,
339
+ pruneEventOp : event .PruneSkipped ,
340
+ },
341
+ {
342
+ eventType : event .PruneType ,
343
+ pruneEventType : event .PruneEventCompleted ,
344
+ },
345
+ },
346
+ clusterObj : deploymentUnmatched ,
347
+ prune : true ,
348
+ },
349
+ "prune with inventory object annotation matched" : {
350
+ namespace : "default" ,
351
+ resources : []resourceInfo {
352
+ resources ["inventoryObject" ],
353
+ },
354
+ handlers : []handler {
355
+ & nsHandler {},
356
+ & inventoryObjectHandler {},
357
+ & genericHandler {
358
+ resourceInfo : resources ["deployment" ],
359
+ namespace : "default" ,
360
+ },
361
+ },
362
+ reconcileTimeout : 0 ,
363
+ expectedEventTypes : []expectedEvent {
364
+ {
365
+ eventType : event .InitType ,
366
+ },
367
+ {
368
+ eventType : event .ApplyType ,
369
+ applyEventType : event .ApplyEventCompleted ,
370
+ },
371
+ {
372
+ eventType : event .PruneType ,
373
+ pruneEventType : event .PruneEventResourceUpdate ,
374
+ pruneEventOp : event .Pruned ,
375
+ },
376
+ {
377
+ eventType : event .PruneType ,
378
+ pruneEventType : event .PruneEventCompleted ,
379
+ },
380
+ },
381
+ clusterObj : deploymentMatched ,
382
+ prune : true ,
383
+ },
203
384
}
204
385
205
386
for tn , tc := range testCases {
@@ -211,6 +392,9 @@ func TestApplier(t *testing.T) {
211
392
defer tf .Cleanup ()
212
393
213
394
tf .UnstructuredClient = newFakeRESTClient (t , tc .handlers )
395
+ if tc .clusterObj != nil {
396
+ tf .FakeDynamicClient = fakeDynamicClient (tc .clusterObj )
397
+ }
214
398
215
399
cf := provider .NewProvider (tf )
216
400
applier := NewApplier (cf )
@@ -222,7 +406,17 @@ func TestApplier(t *testing.T) {
222
406
if ! assert .NoError (t , err ) {
223
407
return
224
408
}
225
- applier .invClient = inventory .NewFakeInventoryClient ([]object.ObjMetadata {})
409
+
410
+ objmeta := []object.ObjMetadata {}
411
+ if tc .clusterObj != nil {
412
+ objmeta = append (objmeta , object .UnstructuredToObjMeta (tc .clusterObj ))
413
+ }
414
+ invClient := inventory .NewFakeInventoryClient (objmeta )
415
+ applier .invClient = invClient
416
+ err = applier .PruneOptions .Initialize (cf .Factory (), invClient )
417
+ if ! assert .NoError (t , err ) {
418
+ return
419
+ }
226
420
227
421
poller := & fakePoller {
228
422
events : tc .statusEvents ,
@@ -255,10 +449,12 @@ func TestApplier(t *testing.T) {
255
449
case event .InitType :
256
450
case event .ApplyType :
257
451
assert .Equal (t , expected .applyEventType .String (), e .ApplyEvent .Type .String ())
452
+ assert .Equal (t , reflect .TypeOf (expected .applyErrorType ), reflect .TypeOf (e .ApplyEvent .Error ))
258
453
case event .StatusType :
259
454
assert .Equal (t , expected .statusEventType .String (), e .StatusEvent .Type .String ())
260
455
case event .PruneType :
261
456
assert .Equal (t , expected .pruneEventType .String (), e .PruneEvent .Type .String ())
457
+ assert .Equal (t , expected .pruneEventOp .String (), e .PruneEvent .Operation .String ())
262
458
case event .DeleteType :
263
459
assert .Equal (t , expected .deleteEventType .String (), e .DeleteEvent .Type .String ())
264
460
default :
@@ -523,7 +719,7 @@ func newFakeRESTClient(t *testing.T, handlers []handler) *fake.RESTClient {
523
719
}
524
720
}
525
721
526
- func toIdentifier (t * testing.T , resourceInfo resourceInfo , namespace string ) object.ObjMetadata {
722
+ func toIdentifier (t * testing.T , resourceInfo resourceInfo ) object.ObjMetadata {
527
723
obj := resourceInfo .factoryFunc ()
528
724
err := runtime .DecodeInto (codec , []byte (resourceInfo .manifest ), obj )
529
725
if err != nil {
@@ -537,7 +733,7 @@ func toIdentifier(t *testing.T, resourceInfo resourceInfo, namespace string) obj
537
733
return object.ObjMetadata {
538
734
GroupKind : obj .GetObjectKind ().GroupVersionKind ().GroupKind (),
539
735
Name : accessor .GetName (),
540
- Namespace : namespace ,
736
+ Namespace : "default" ,
541
737
}
542
738
}
543
739
@@ -768,3 +964,17 @@ func objSetsEqual(setA []*unstructured.Unstructured, setB []*unstructured.Unstru
768
964
}
769
965
return true
770
966
}
967
+
968
+ // fakeDynamicClient returns a fake dynamic client.
969
+ func fakeDynamicClient (obj * unstructured.Unstructured ) * dynamicfake.FakeDynamicClient {
970
+ fakeClient := dynamicfake .NewSimpleDynamicClient (runtime .NewScheme ())
971
+
972
+ fakeClient .PrependReactor ("get" , "deployments" , func (action clienttesting.Action ) (handled bool , ret runtime.Object , err error ) {
973
+ return true , obj , nil
974
+ })
975
+ fakeClient .PrependReactor ("delete" , "deployments" , func (action clienttesting.Action ) (handled bool , ret runtime.Object , err error ) {
976
+ return true , nil , nil
977
+ })
978
+
979
+ return fakeClient
980
+ }
0 commit comments