Skip to content

Commit 103e4dc

Browse files
authored
Merge pull request #295 from Liujingfang1/applytest
add test cases for applier
2 parents c89861c + 5aad5ee commit 103e4dc

File tree

1 file changed

+215
-5
lines changed

1 file changed

+215
-5
lines changed

pkg/apply/applier_test.go

Lines changed: 215 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"io/ioutil"
1111
"net/http"
1212
"path"
13+
"reflect"
1314
"regexp"
1415
"testing"
1516
"time"
@@ -23,7 +24,9 @@ import (
2324
"k8s.io/apimachinery/pkg/runtime"
2425
"k8s.io/apimachinery/pkg/runtime/schema"
2526
"k8s.io/cli-runtime/pkg/resource"
27+
dynamicfake "k8s.io/client-go/dynamic/fake"
2628
"k8s.io/client-go/rest/fake"
29+
clienttesting "k8s.io/client-go/testing"
2730
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
2831
"k8s.io/kubectl/pkg/scheme"
2932
"sigs.k8s.io/cli-utils/pkg/apply/event"
@@ -66,6 +69,34 @@ var (
6669
}
6770
)
6871

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+
69100
// resourceStatus contains information about a specific resource, such
70101
// as the manifest yaml and the URL path for this resource in the
71102
// client. It also contains a factory function for creating a new
@@ -83,6 +114,9 @@ type expectedEvent struct {
83114
statusEventType event.StatusEventType
84115
pruneEventType event.PruneEventType
85116
deleteEventType event.DeleteEventType
117+
118+
applyErrorType error
119+
pruneEventOp event.PruneEventOperation
86120
}
87121

88122
func TestApplier(t *testing.T) {
@@ -94,6 +128,7 @@ func TestApplier(t *testing.T) {
94128
prune bool
95129
statusEvents []pollevent.Event
96130
expectedEventTypes []expectedEvent
131+
clusterObj *unstructured.Unstructured
97132
}{
98133
"apply without status or prune": {
99134
namespace: "default",
@@ -158,14 +193,14 @@ func TestApplier(t *testing.T) {
158193
{
159194
EventType: pollevent.ResourceUpdateEvent,
160195
Resource: &pollevent.ResourceStatus{
161-
Identifier: toIdentifier(t, resources["deployment"], "default"),
196+
Identifier: toIdentifier(t, resources["deployment"]),
162197
Status: status.InProgressStatus,
163198
},
164199
},
165200
{
166201
EventType: pollevent.ResourceUpdateEvent,
167202
Resource: &pollevent.ResourceStatus{
168-
Identifier: toIdentifier(t, resources["deployment"], "default"),
203+
Identifier: toIdentifier(t, resources["deployment"]),
169204
Status: status.CurrentStatus,
170205
},
171206
},
@@ -200,6 +235,152 @@ func TestApplier(t *testing.T) {
200235
},
201236
},
202237
},
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+
},
203384
}
204385

205386
for tn, tc := range testCases {
@@ -211,6 +392,9 @@ func TestApplier(t *testing.T) {
211392
defer tf.Cleanup()
212393

213394
tf.UnstructuredClient = newFakeRESTClient(t, tc.handlers)
395+
if tc.clusterObj != nil {
396+
tf.FakeDynamicClient = fakeDynamicClient(tc.clusterObj)
397+
}
214398

215399
cf := provider.NewProvider(tf)
216400
applier := NewApplier(cf)
@@ -222,7 +406,17 @@ func TestApplier(t *testing.T) {
222406
if !assert.NoError(t, err) {
223407
return
224408
}
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+
}
226420

227421
poller := &fakePoller{
228422
events: tc.statusEvents,
@@ -255,10 +449,12 @@ func TestApplier(t *testing.T) {
255449
case event.InitType:
256450
case event.ApplyType:
257451
assert.Equal(t, expected.applyEventType.String(), e.ApplyEvent.Type.String())
452+
assert.Equal(t, reflect.TypeOf(expected.applyErrorType), reflect.TypeOf(e.ApplyEvent.Error))
258453
case event.StatusType:
259454
assert.Equal(t, expected.statusEventType.String(), e.StatusEvent.Type.String())
260455
case event.PruneType:
261456
assert.Equal(t, expected.pruneEventType.String(), e.PruneEvent.Type.String())
457+
assert.Equal(t, expected.pruneEventOp.String(), e.PruneEvent.Operation.String())
262458
case event.DeleteType:
263459
assert.Equal(t, expected.deleteEventType.String(), e.DeleteEvent.Type.String())
264460
default:
@@ -523,7 +719,7 @@ func newFakeRESTClient(t *testing.T, handlers []handler) *fake.RESTClient {
523719
}
524720
}
525721

526-
func toIdentifier(t *testing.T, resourceInfo resourceInfo, namespace string) object.ObjMetadata {
722+
func toIdentifier(t *testing.T, resourceInfo resourceInfo) object.ObjMetadata {
527723
obj := resourceInfo.factoryFunc()
528724
err := runtime.DecodeInto(codec, []byte(resourceInfo.manifest), obj)
529725
if err != nil {
@@ -537,7 +733,7 @@ func toIdentifier(t *testing.T, resourceInfo resourceInfo, namespace string) obj
537733
return object.ObjMetadata{
538734
GroupKind: obj.GetObjectKind().GroupVersionKind().GroupKind(),
539735
Name: accessor.GetName(),
540-
Namespace: namespace,
736+
Namespace: "default",
541737
}
542738
}
543739

@@ -768,3 +964,17 @@ func objSetsEqual(setA []*unstructured.Unstructured, setB []*unstructured.Unstru
768964
}
769965
return true
770966
}
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

Comments
 (0)