Skip to content

Commit 0a84239

Browse files
committed
test: unit test Adopt-or-Create
1 parent e9c2402 commit 0a84239

File tree

3 files changed

+211
-10
lines changed

3 files changed

+211
-10
lines changed

pkg/runtime/reconciler.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ func (r *resourceReconciler) handlePopulation(
314314
rlog.Info("Adopting Resource")
315315
adoptionFields, err := ExtractAdoptionFields(desired)
316316
if err != nil {
317-
if adoptionPolicy == Magic {
317+
if adoptionPolicy == AdoptOrCreatePolicy {
318318
return desired, nil
319319
}
320320
return desired, ackerr.NewTerminalError(err)
@@ -325,7 +325,7 @@ func (r *resourceReconciler) handlePopulation(
325325
// maybe don't return errors when it's adopt-or-create?
326326
// TODO (michaelhtm) change PopulateResourceFromAnnotation to understand
327327
// adopt-or-create, and validate Spec fields are not nil...
328-
if err != nil && adoptionPolicy != Magic {
328+
if err != nil && adoptionPolicy != AdoptOrCreatePolicy {
329329
return nil, err
330330
}
331331

@@ -430,7 +430,8 @@ func (r *resourceReconciler) Sync(
430430
if err != nil {
431431
return nil, err
432432
}
433-
if adoptionPolicy == Magic {
433+
if adoptionPolicy == AdoptOrCreatePolicy {
434+
// here we assume the spec fields are provided in the spec.
434435
resolved.SetStatus(populated)
435436
} else {
436437
resolved = populated
@@ -453,7 +454,7 @@ func (r *resourceReconciler) Sync(
453454
if err != ackerr.NotFound {
454455
return latest, err
455456
}
456-
if adoptionPolicy == PolicyAdopt || isAdopted {
457+
if adoptionPolicy == AdoptPolicy || isAdopted {
457458
return nil, ackerr.AdoptedResourceNotFound
458459
}
459460
if isReadOnly {
@@ -462,7 +463,7 @@ func (r *resourceReconciler) Sync(
462463
if latest, err = r.createResource(ctx, rm, resolved); err != nil {
463464
return latest, err
464465
}
465-
} else if adoptionPolicy == PolicyAdopt {
466+
} else if adoptionPolicy == AdoptPolicy {
466467
rm.FilterSystemTags(latest)
467468
if err = r.setResourceManaged(ctx, rm, latest); err != nil {
468469
return latest, err
@@ -472,7 +473,7 @@ func (r *resourceReconciler) Sync(
472473
return latest, err
473474
}
474475
} else if !isReadOnly {
475-
if adoptionPolicy == Magic {
476+
if adoptionPolicy == AdoptOrCreatePolicy {
476477
if err = r.setResourceManaged(ctx, rm, latest); err != nil {
477478
return latest, err
478479
}

pkg/runtime/reconciler_test.go

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,205 @@ func TestReconcilerReadOnlyResource(t *testing.T) {
262262
rm.AssertNotCalled(t, "Delta", 0)
263263
}
264264

265+
func TestReconcilerAdoptResource(t *testing.T) {
266+
require := require.New(t)
267+
268+
ctx := context.TODO()
269+
270+
desired, _, metaObj := resourceMocks()
271+
desired.On("ReplaceConditions", []*ackv1alpha1.Condition{}).Return()
272+
metaObj.SetAnnotations(map[string]string{
273+
ackv1alpha1.AnnotationAdoptionPolicy: "adopt",
274+
ackv1alpha1.AnnotationAdoptionFields: "{\"arn\": \"my-adopt-book-arn\"}",
275+
})
276+
277+
latest, latestRTObj, _ := resourceMocks()
278+
latest.On("Conditions").Return([]*ackv1alpha1.Condition{})
279+
latest.On("MetaObject").Return(metav1.ObjectMeta{
280+
Annotations: map[string]string{
281+
ackv1alpha1.AnnotationAdoptionPolicy: "adopt",
282+
ackv1alpha1.AnnotationAdoptionFields: "{\"arn\": \"my-adopt-book-arn\"}",
283+
},
284+
})
285+
latest.On("Conditions").Return([]*ackv1alpha1.Condition{})
286+
latest.On(
287+
"ReplaceConditions",
288+
mock.AnythingOfType("[]*v1alpha1.Condition"),
289+
).Return()
290+
291+
rm := &ackmocks.AWSResourceManager{}
292+
rm.On("ResolveReferences", ctx, nil, desired).Return(
293+
desired, false, nil,
294+
).Times(2)
295+
rm.On("ClearResolvedReferences", desired).Return(desired)
296+
rm.On("ClearResolvedReferences", latest).Return(latest)
297+
rm.On("ReadOne", ctx, desired).Return(
298+
latest, nil,
299+
).Once()
300+
rm.On("IsSynced", ctx, latest).Return(true, nil)
301+
rmf, rd := managedResourceManagerFactoryMocks(desired, latest)
302+
303+
rm.On("LateInitialize", ctx, latest).Return(latest, nil)
304+
rd.On("IsManaged", desired).Return(false)
305+
rd.On("Delta", desired, latest).Return(ackcompare.NewDelta())
306+
rd.On("Delta", latest, latest).Return(ackcompare.NewDelta())
307+
308+
r, kc, scmd := reconcilerMocks(rmf)
309+
rm.On("EnsureTags", ctx, desired, scmd).Return(nil)
310+
statusWriter := &ctrlrtclientmock.SubResourceWriter{}
311+
kc.On("Patch", ctx, latestRTObj, mock.AnythingOfType("*client.mergeFromPatch")).Return(nil)
312+
kc.On("Status").Return(statusWriter)
313+
statusWriter.On("Patch", ctx, latestRTObj, mock.AnythingOfType("*client.mergeFromPatch")).Return(nil)
314+
_, err := r.Sync(ctx, rm, desired)
315+
require.Nil(err)
316+
rm.AssertNumberOfCalls(t, "ReadOne", 1)
317+
// Assert that the resource is not created or updated
318+
rm.AssertNotCalled(t, "Create", 0)
319+
rm.AssertNotCalled(t, "Update", 0)
320+
rm.AssertNotCalled(t, "Delta", 0)
321+
}
322+
323+
func TestReconcilerAdoptOrCreateResource_Create(t *testing.T) {
324+
require := require.New(t)
325+
326+
ctx := context.TODO()
327+
// arn := ackv1alpha1.AWSResourceName("my-adopt-book-arn")
328+
329+
desired, _, metaObj := resourceMocks()
330+
desired.On("ReplaceConditions", []*ackv1alpha1.Condition{}).Return()
331+
metaObj.SetAnnotations(map[string]string{
332+
ackv1alpha1.AnnotationAdoptionPolicy: "adopt-or-create",
333+
ackv1alpha1.AnnotationAdoptionFields: "{\"arn\": \"my-adopt-book-arn\"}",
334+
})
335+
336+
ids := &ackmocks.AWSResourceIdentifiers{}
337+
// ids.On("ARN").Return(&arn)
338+
339+
latest, latestRTObj, _ := resourceMocks()
340+
latest.On("Identifiers").Return(ids)
341+
latest.On("Conditions").Return([]*ackv1alpha1.Condition{})
342+
latest.On("MetaObject").Return(metav1.ObjectMeta{
343+
Annotations: map[string]string{
344+
ackv1alpha1.AnnotationAdoptionPolicy: "adopt",
345+
ackv1alpha1.AnnotationAdoptionFields: "{\"arn\": \"my-adopt-book-arn\"}",
346+
},
347+
})
348+
latest.On("Conditions").Return([]*ackv1alpha1.Condition{})
349+
latest.On(
350+
"ReplaceConditions",
351+
mock.AnythingOfType("[]*v1alpha1.Condition"),
352+
).Return()
353+
354+
rm := &ackmocks.AWSResourceManager{}
355+
rm.On("ResolveReferences", ctx, nil, desired).Return(
356+
desired, false, nil,
357+
).Times(2)
358+
rm.On("ClearResolvedReferences", desired).Return(desired)
359+
rm.On("ClearResolvedReferences", latest).Return(latest)
360+
rm.On("ReadOne", ctx, desired).Return(
361+
nil, ackerr.NotFound,
362+
).Once()
363+
rm.On("ReadOne", ctx, latest).Return(
364+
latest, nil,
365+
)
366+
rm.On("Create", ctx, desired).Return(
367+
latest, nil,
368+
).Once()
369+
rm.On("IsSynced", ctx, latest).Return(true, nil)
370+
rmf, rd := managedResourceManagerFactoryMocks(desired, latest)
371+
372+
rm.On("LateInitialize", ctx, latest).Return(latest, nil)
373+
rd.On("IsManaged", desired).Return(false).Once()
374+
rd.On("IsManaged", desired).Return(true)
375+
rd.On("Delta", desired, latest).Return(ackcompare.NewDelta())
376+
rd.On("Delta", latest, latest).Return(ackcompare.NewDelta())
377+
378+
r, kc, scmd := reconcilerMocks(rmf)
379+
rm.On("EnsureTags", ctx, desired, scmd).Return(nil)
380+
statusWriter := &ctrlrtclientmock.SubResourceWriter{}
381+
kc.On("Status").Return(statusWriter)
382+
kc.On("Patch", ctx, latestRTObj, mock.AnythingOfType("*client.mergeFromPatch")).Return(nil)
383+
statusWriter.On("Patch", ctx, latestRTObj, mock.AnythingOfType("*client.mergeFromPatch")).Return(nil)
384+
_, err := r.Sync(ctx, rm, desired)
385+
require.Nil(err)
386+
rm.AssertNumberOfCalls(t, "ReadOne", 2)
387+
rm.AssertNumberOfCalls(t, "Create", 1)
388+
// Assert that the resource is not created or updated
389+
rm.AssertNotCalled(t, "Update", 0)
390+
rm.AssertNotCalled(t, "Delta", 0)
391+
}
392+
393+
func TestReconcilerAdoptOrCreateResource_Adopt(t *testing.T) {
394+
require := require.New(t)
395+
396+
ctx := context.TODO()
397+
// arn := ackv1alpha1.AWSResourceName("my-adopt-book-arn")
398+
399+
desired, _, metaObj := resourceMocks()
400+
desired.On("ReplaceConditions", []*ackv1alpha1.Condition{}).Return()
401+
metaObj.SetAnnotations(map[string]string{
402+
ackv1alpha1.AnnotationAdoptionPolicy: "adopt-or-create",
403+
ackv1alpha1.AnnotationAdoptionFields: "{\"arn\": \"my-adopt-book-arn\"}",
404+
})
405+
406+
ids := &ackmocks.AWSResourceIdentifiers{}
407+
// ids.On("ARN").Return(&arn)
408+
delta := ackcompare.NewDelta()
409+
delta.Add("Spec.A", "val1", "val2")
410+
411+
latest, latestRTObj, _ := resourceMocks()
412+
latest.On("Identifiers").Return(ids)
413+
latest.On("Conditions").Return([]*ackv1alpha1.Condition{})
414+
latest.On("MetaObject").Return(metav1.ObjectMeta{
415+
Annotations: map[string]string{
416+
ackv1alpha1.AnnotationAdoptionPolicy: "adopt",
417+
ackv1alpha1.AnnotationAdoptionFields: "{\"arn\": \"my-adopt-book-arn\"}",
418+
},
419+
})
420+
latest.On("Conditions").Return([]*ackv1alpha1.Condition{})
421+
latest.On(
422+
"ReplaceConditions",
423+
mock.AnythingOfType("[]*v1alpha1.Condition"),
424+
).Return()
425+
426+
rm := &ackmocks.AWSResourceManager{}
427+
rm.On("ResolveReferences", ctx, nil, desired).Return(
428+
desired, false, nil,
429+
).Times(2)
430+
rm.On("ClearResolvedReferences", desired).Return(desired)
431+
rm.On("ClearResolvedReferences", latest).Return(latest)
432+
rm.On("ReadOne", ctx, desired).Return(
433+
latest, nil,
434+
).Once()
435+
rm.On("Update", ctx, desired, latest, delta).Return(
436+
latest, nil,
437+
).Once()
438+
rm.On("IsSynced", ctx, latest).Return(true, nil)
439+
rmf, rd := managedResourceManagerFactoryMocks(desired, latest)
440+
441+
rm.On("LateInitialize", ctx, latest).Return(latest, nil)
442+
rd.On("IsManaged", desired).Return(true)
443+
rd.On("Delta", desired, latest).Return(
444+
delta,
445+
).Once()
446+
rd.On("Delta", desired, latest).Return(ackcompare.NewDelta())
447+
rd.On("Delta", latest, latest).Return(ackcompare.NewDelta())
448+
449+
r, kc, scmd := reconcilerMocks(rmf)
450+
rm.On("EnsureTags", ctx, desired, scmd).Return(nil)
451+
statusWriter := &ctrlrtclientmock.SubResourceWriter{}
452+
kc.On("Status").Return(statusWriter)
453+
kc.On("Patch", ctx, latestRTObj, mock.AnythingOfType("*client.mergeFromPatch")).Return(nil)
454+
statusWriter.On("Patch", ctx, latestRTObj, mock.AnythingOfType("*client.mergeFromPatch")).Return(nil)
455+
_, err := r.Sync(ctx, rm, desired)
456+
require.Nil(err)
457+
rm.AssertNumberOfCalls(t, "ReadOne", 1)
458+
rm.AssertCalled(t, "Update", ctx, desired, latest, delta)
459+
rd.AssertCalled(t, "Delta", desired, latest)
460+
// Assert that the resource is not created or updated
461+
rm.AssertNumberOfCalls(t, "Create", 0)
462+
}
463+
265464
func TestReconcilerCreate_UnManagedResource_CheckReferencesResolveOnce(t *testing.T) {
266465
require := require.New(t)
267466

pkg/runtime/util.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ import (
3232
// TODO(michaelhtm) Maybe we need a different place for this...
3333
// next refactor maybe? 🤷‍♂️
3434
type AdoptionPolicy string
35+
3536
const (
36-
PolicyAdopt AdoptionPolicy = "adopt"
37-
// calling this policy constant `Magic`
37+
AdoptPolicy AdoptionPolicy = "adopt"
38+
// calling this policy constant `AdoptOrCreatePolicy`
3839
// and see if we need to rename it!!!
39-
Magic AdoptionPolicy = "adopt-or-create"
40+
AdoptOrCreatePolicy AdoptionPolicy = "adopt-or-create"
4041
)
4142

4243
// IsAdopted returns true if the supplied AWSResource was created with a
@@ -99,7 +100,7 @@ func GetAdoptionPolicy(res acktypes.AWSResource) (AdoptionPolicy, error) {
99100
return "", nil
100101
}
101102

102-
if policy != string(PolicyAdopt) && policy != string(Magic) {
103+
if policy != string(AdoptPolicy) && policy != string(AdoptOrCreatePolicy) {
103104
return "", fmt.Errorf("unrecognized adoption policy")
104105
}
105106

0 commit comments

Comments
 (0)