diff --git a/duck/client.go b/duck/client.go index c0faada..e22cd40 100644 --- a/duck/client.go +++ b/duck/client.go @@ -312,6 +312,10 @@ func (w *duckAwareSubResourceWriterWrapper) Patch(ctx context.Context, obj clien return Convert(u, obj) } +func (w *duckAwareSubResourceWriterWrapper) Apply(ctx context.Context, obj runtime.ApplyConfiguration, opts ...client.SubResourceApplyOption) error { + return w.subResourceWriter.Apply(ctx, obj, opts...) +} + type duckAwareSubResourceClientWrapper struct { subResourceClient client.SubResourceClient scheme SchemeAccessor @@ -362,3 +366,7 @@ func (c *duckAwareSubResourceClientWrapper) Patch(ctx context.Context, obj clien } return Convert(u, obj) } + +func (w *duckAwareSubResourceClientWrapper) Apply(ctx context.Context, obj runtime.ApplyConfiguration, opts ...client.SubResourceApplyOption) error { + return w.subResourceClient.Apply(ctx, obj, opts...) +} diff --git a/go.mod b/go.mod index 644f708..f96e76c 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/fatih/color v1.18.0 github.com/go-logr/logr v1.4.3 github.com/google/go-cmp v0.7.0 - golang.org/x/net v0.48.0 + golang.org/x/net v0.49.0 gomodules.xyz/jsonpatch/v2 v2.5.0 gomodules.xyz/jsonpatch/v3 v3.0.1 k8s.io/api v0.35.0 @@ -15,7 +15,7 @@ require ( k8s.io/client-go v0.35.0 k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 reconciler.io/dies v0.18.0 - sigs.k8s.io/controller-runtime v0.22.4 + sigs.k8s.io/controller-runtime v0.23.1 sigs.k8s.io/yaml v1.6.0 ) @@ -52,9 +52,9 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/term v0.38.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/term v0.39.0 // indirect + golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.9.0 // indirect gomodules.xyz/orderedmap v0.1.0 // indirect google.golang.org/protobuf v1.36.8 // indirect @@ -66,5 +66,5 @@ require ( k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect ) diff --git a/go.sum b/go.sum index d5c1c06..9efa78a 100644 --- a/go.sum +++ b/go.sum @@ -112,26 +112,26 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gomodules.xyz/jsonpatch/v3 v3.0.1 h1:Te7hKxV52TKCbNYq3t84tzKav3xhThdvSsSp/W89IyI= @@ -166,13 +166,13 @@ k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzk k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= reconciler.io/dies v0.18.0 h1:XY0knxZSjfbgXMOcCL39lqaOSj2tBg3jPwP/FeIoxpg= reconciler.io/dies v0.18.0/go.mod h1:nH3PU3+dJEJ7GBFzslUFKOVbq/Gc0SIGL0Ltlp22/Ks= -sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A= -sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= +sigs.k8s.io/controller-runtime v0.23.1 h1:TjJSM80Nf43Mg21+RCy3J70aj/W6KyvDtOlpKf+PupE= +sigs.k8s.io/controller-runtime v0.23.1/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 h1:2WOzJpHUBVrrkDjU4KBT8n5LDcj824eX0I5UKcgeRUs= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/reconcilers/resource.go b/reconcilers/resource.go index 9d8bf09..8a8e9bc 100644 --- a/reconcilers/resource.go +++ b/reconcilers/resource.go @@ -304,6 +304,9 @@ func (r *ResourceReconciler[T]) Reconcile(ctx context.Context, req Request) (Res result, err := r.AfterReconcile(ctx, req, AggregateResults(beforeResult, reconcileResult), err) if errors.Is(err, ErrQuiet) { // suppress error, while forcing a requeue + if result.RequeueAfter > 0 { // honor requeue after returned by reconciler + return result, nil + } return Result{Requeue: true}, nil } return result, err diff --git a/testing/actions.go b/testing/actions.go index 8afb5c0..8af3b1c 100644 --- a/testing/actions.go +++ b/testing/actions.go @@ -79,3 +79,11 @@ func NewApplyAction(ac runtime.ApplyConfiguration) ApplyAction { return action } + +func NewApplySubresourceAction(ac runtime.ApplyConfiguration, subresource string) ApplyAction { + action := NewApplyAction(ac).(ApplyActionImpl) + + action.Subresource = subresource + + return action +} diff --git a/testing/client.go b/testing/client.go index bdceb63..835bea0 100644 --- a/testing/client.go +++ b/testing/client.go @@ -51,6 +51,7 @@ type clientWrapper struct { DeleteCollectionActions []DeleteCollectionAction StatusUpdateActions []objectAction StatusPatchActions []PatchAction + StatusApplyActions []ApplyAction genCount int reactionChain []Reactor } @@ -69,6 +70,7 @@ func NewFakeClientWrapper(client client.Client, tracker clientgotesting.ObjectTr DeleteCollectionActions: []DeleteCollectionAction{}, StatusUpdateActions: []objectAction{}, StatusPatchActions: []PatchAction{}, + StatusApplyActions: []ApplyAction{}, genCount: 0, reactionChain: []Reactor{}, } @@ -401,6 +403,18 @@ func (w *statusWriterWrapper) Patch(ctx context.Context, obj client.Object, patc return w.statusWriter.Patch(ctx, obj, patch, opts...) } +func (w *statusWriterWrapper) Apply(ctx context.Context, obj runtime.ApplyConfiguration, opts ...client.SubResourceApplyOption) error { + // capture action + w.clientWrapper.StatusApplyActions = append(w.clientWrapper.StatusApplyActions, NewApplySubresourceAction(obj, "status")) + + // call reactor chain + if err := w.clientWrapper.react(NewApplySubresourceAction(obj, "status")); err != nil { + return err + } + + return w.statusWriter.Apply(ctx, obj, opts...) +} + type subResourceClientWrapper struct { subResource string clientWrapper *clientWrapper @@ -464,6 +478,15 @@ func (w *subResourceClientWrapper) Patch(ctx context.Context, obj client.Object, return w.clientWrapper.react(clientgotesting.NewPatchSubresourceAction(gvr, obj.GetNamespace(), obj.GetName(), patch.Type(), b, w.subResource)) } +func (w *subResourceClientWrapper) Apply(ctx context.Context, obj runtime.ApplyConfiguration, opts ...client.SubResourceApplyOption) error { + if w.subResource == "status" { + return w.clientWrapper.Status().Apply(ctx, obj, opts...) + } + + // call reactor chain + return w.clientWrapper.react(NewApplySubresourceAction(obj, w.subResource)) +} + // InduceFailure is used in conjunction with reconciler test's WithReactors field. // Tests that want to induce a failure in a testcase of a reconciler test would add: // diff --git a/testing/config.go b/testing/config.go index e7e8146..f0e4d62 100644 --- a/testing/config.go +++ b/testing/config.go @@ -105,6 +105,8 @@ type ExpectConfig struct { ExpectStatusUpdates []client.Object // ExpectStatusPatches builds the ordered list of objects whose status is patched during reconciliation ExpectStatusPatches []PatchRef + // ExpectStatusApplies builds the ordered list of objects whose status is applied during reconciliation + ExpectStatusApplies []ApplyRef once sync.Once client *clientWrapper @@ -254,6 +256,7 @@ func (c *ExpectConfig) AssertClientExpectations(t *testing.T) { c.AssertClientDeleteCollectionExpectations(t) c.AssertClientStatusUpdateExpectations(t) c.AssertClientStatusPatchExpectations(t) + c.AssertClientStatusApplyExpectations(t) } // AssertClientApplyExpectations asserts observed reconciler client create behavior matches the expected client create behavior @@ -411,6 +414,31 @@ func (c *ExpectConfig) AssertClientStatusPatchExpectations(t *testing.T) { } } +// AssertClientStatusApplyExpectations asserts observed reconciler client status apply behavior matches the expected client status apply behavior +func (c *ExpectConfig) AssertClientStatusApplyExpectations(t *testing.T) { + if t != nil { + t.Helper() + } + c.init() + + for i, exp := range c.ExpectStatusApplies { + if i >= len(c.client.StatusApplyActions) { + c.errorf(t, "ExpectStatusApplies[%d] not observed%s: %#v", i, c.configNameMsg(), exp) + continue + } + actual := NewApplyRef(c.client.StatusApplyActions[i]) + + if diff := c.Differ.ApplyRef(exp, actual); diff != "" { + c.errorf(t, "ExpectStatusApplies[%d] differs%s (%s, %s):\n%s", i, c.configNameMsg(), DiffRemovedColor.Sprint("-expected"), DiffAddedColor.Sprint("+actual"), ColorizeDiff(diff)) + } + } + if actual, expected := len(c.client.StatusApplyActions), len(c.ExpectStatusApplies); actual > expected { + for _, extra := range c.client.StatusApplyActions[expected:] { + c.errorf(t, "Unexpected StatusApply observed%s: %#v", c.configNameMsg(), extra) + } + } +} + // AssertRecorderExpectations asserts observed event recorder behavior matches the expected event recorder behavior func (c *ExpectConfig) AssertRecorderExpectations(t *testing.T) { if t != nil { diff --git a/testing/config_test.go b/testing/config_test.go index d9322ea..258f51d 100644 --- a/testing/config_test.go +++ b/testing/config_test.go @@ -70,6 +70,12 @@ func TestExpectConfig(t *testing.T) { WithSpec(applyconfigurationsappsv1.DeploymentSpec().WithReplicas(1)) ac2 := applyconfigurationsappsv1.Deployment("resource", ns). WithSpec(applyconfigurationsappsv1.DeploymentSpec().WithReplicas(2)) + acs1 := applyconfigurationsappsv1.Deployment("resource", ns). + WithSpec(applyconfigurationsappsv1.DeploymentSpec().WithReplicas(1)). + WithStatus(applyconfigurationsappsv1.DeploymentStatus().WithReplicas(1)) + acs2 := applyconfigurationsappsv1.Deployment("resource", ns). + WithSpec(applyconfigurationsappsv1.DeploymentSpec().WithReplicas(2)). + WithStatus(applyconfigurationsappsv1.DeploymentStatus().WithReplicas(2)) scheme := runtime.NewScheme() _ = resources.AddToScheme(scheme) @@ -798,6 +804,71 @@ func TestExpectConfig(t *testing.T) { }, }, + "expected status apply": { + config: ExpectConfig{ + ExpectStatusApplies: []ApplyRef{ + { + Group: "apps", + Kind: "Deployment", + Namespace: ns, + Name: "resource", + ApplyConfiguration: acs1, + }, + }, + }, + operation: func(t *testing.T, ctx context.Context, c reconcilers.Config) { + c.Status().Apply(ctx, acs1) + }, + failedAssertions: []string{}, + }, + "unexpected status apply": { + config: ExpectConfig{ + ExpectStatusApplies: []ApplyRef{ + { + Group: "apps", + Kind: "Deployment", + Namespace: ns, + Name: "resource", + ApplyConfiguration: acs2, + }, + }, + }, + operation: func(t *testing.T, ctx context.Context, c reconcilers.Config) { + c.Status().Apply(ctx, acs1) + }, + failedAssertions: []string{ + `ExpectStatusApplies[0] differs for config "test" (-expected, +actual):`, + }, + }, + "extra status apply": { + config: ExpectConfig{ + ExpectStatusApplies: []ApplyRef{}, + }, + operation: func(t *testing.T, ctx context.Context, c reconcilers.Config) { + c.Status().Apply(ctx, acs1) + }, + failedAssertions: []string{ + `Unexpected StatusApply observed for config "test": `, + }, + }, + "missing status apply": { + config: ExpectConfig{ + ExpectStatusApplies: []ApplyRef{ + { + Group: "apps", + Kind: "Deployment", + Namespace: ns, + Name: "resource", + ApplyConfiguration: acs1, + }, + }, + }, + operation: func(t *testing.T, ctx context.Context, c reconcilers.Config) {}, + failedAssertions: []string{ + `ExpectStatusApplies[0] not observed for config "test": `, + }, + }, + "custom diff - always different": { config: ExpectConfig{ Differ: &staticDiffer{ @@ -830,6 +901,9 @@ func TestExpectConfig(t *testing.T) { ExpectStatusPatches: []PatchRef{ {Group: "testing.reconciler.runtime", Kind: "TestResource", Namespace: ns, Name: "resource-1", SubResource: "status", PatchType: types.MergePatchType, Patch: []byte(`{"status":{"fields":{"foo":"bar"}}}`)}, }, + ExpectStatusApplies: []ApplyRef{ + {Group: "apps", Kind: "Deployment", Namespace: ns, Name: "resource", ApplyConfiguration: acs1}, + }, }, operation: func(t *testing.T, ctx context.Context, c reconcilers.Config) { c.Tracker.TrackObject(r2, r1) @@ -841,6 +915,7 @@ func TestExpectConfig(t *testing.T) { c.DeleteAllOf(ctx, &resources.TestResourceNoStatus{}) c.Status().Update(ctx, r1.DeepCopy()) c.Status().Patch(ctx, r1patch.DeepCopy(), client.MergeFrom(r1)) + c.Status().Apply(ctx, acs1) }, failedAssertions: []string{ "ExpectCreates[0] differs for config \"test\" (-expected, +actual):\nalways different\n", @@ -850,6 +925,7 @@ func TestExpectConfig(t *testing.T) { "ExpectDeleteCollections[0] differs for config \"test\" (-expected, +actual):\nalways different\n", "ExpectStatusUpdates[0] differs for config \"test\" (-expected, +actual):\nalways different\n", "ExpectStatusPatches[0] differs for config \"test\" (-expected, +actual):\nalways different\n", + "ExpectStatusApplies[0] differs for config \"test\" (-expected, +actual):\nalways different\n", "ExpectEvents[0] differs for config \"test\" (-expected, +actual):\nalways different\n", "ExpectTracks[0] differs for config \"test\" (-expected, +actual):\nalways different\n", }, @@ -886,6 +962,9 @@ func TestExpectConfig(t *testing.T) { ExpectStatusPatches: []PatchRef{ {Group: "testing.reconciler.runtime", Kind: "TestResource", Namespace: ns, Name: "resource-1", SubResource: "status", PatchType: types.MergePatchType, Patch: []byte(`{"status":{"fields":{"foo":"bar"}}}`)}, }, + ExpectStatusApplies: []ApplyRef{ + {Group: "apps", Kind: "Deployment", Namespace: ns, Name: "resource", ApplyConfiguration: acs1}, + }, }, operation: func(t *testing.T, ctx context.Context, c reconcilers.Config) { c.Tracker.TrackObject(r2, r1) @@ -897,6 +976,7 @@ func TestExpectConfig(t *testing.T) { c.DeleteAllOf(ctx, &resources.TestResourceNoStatus{}) c.Status().Update(ctx, r1.DeepCopy()) c.Status().Patch(ctx, r1patch.DeepCopy(), client.MergeFrom(r1)) + c.Status().Apply(ctx, acs1) }, failedAssertions: []string{}, }, diff --git a/testing/reconciler.go b/testing/reconciler.go index 200edcb..44562d8 100644 --- a/testing/reconciler.go +++ b/testing/reconciler.go @@ -95,6 +95,8 @@ type ReconcilerTestCase struct { ExpectStatusUpdates []client.Object // ExpectStatusPatches builds the ordered list of objects whose status is patched during reconciliation ExpectStatusPatches []PatchRef + // ExpectStatusApplies builds the ordered list of objects whose status is applied during reconciliation + ExpectStatusApplies []ApplyRef // AdditionalConfigs holds ExceptConfigs that are available to the test case and will have // their expectations checked again the observed config interactions. The key in this map is @@ -212,6 +214,7 @@ func (tc *ReconcilerTestCase) Run(t *testing.T, scheme *runtime.Scheme, factory ExpectDeleteCollections: tc.ExpectDeleteCollections, ExpectStatusUpdates: tc.ExpectStatusUpdates, ExpectStatusPatches: tc.ExpectStatusPatches, + ExpectStatusApplies: tc.ExpectStatusApplies, } configs := make(map[string]reconcilers.Config, len(tc.AdditionalConfigs)) diff --git a/testing/webhook.go b/testing/webhook.go index b0e6065..7bdeb1a 100644 --- a/testing/webhook.go +++ b/testing/webhook.go @@ -99,6 +99,8 @@ type AdmissionWebhookTestCase struct { ExpectStatusUpdates []client.Object // ExpectStatusPatches builds the ordered list of objects whose status is patched during reconciliation ExpectStatusPatches []PatchRef + // ExpectStatusApplies builds the ordered list of objects whose status is applied during reconciliation + ExpectStatusApplies []ApplyRef // outputs @@ -225,6 +227,7 @@ func (tc *AdmissionWebhookTestCase) RunWithContext(t *testing.T, scheme *runtime ExpectDeleteCollections: tc.ExpectDeleteCollections, ExpectStatusUpdates: tc.ExpectStatusUpdates, ExpectStatusPatches: tc.ExpectStatusPatches, + ExpectStatusApplies: tc.ExpectStatusApplies, } c := expectConfig.Config()