@@ -19,30 +19,17 @@ import (
1919
2020// NewFakeClient creates a fake K8s client with ability to override specific Get/List/Create/Update/StatusUpdate/Delete functions
2121func NewFakeClient (t T , initObjs ... client.Object ) * FakeClient {
22- return newFakeClient (t , false , initObjs ... )
23- }
24-
25- // NewFakeClientWithManagedFields is like NewFakeClient but configures the fake client to return managed fields.
26- // This is needed for tests that verify SSA managed fields behavior.
27- func NewFakeClientWithManagedFields (t T , initObjs ... client.Object ) * FakeClient {
28- return newFakeClient (t , true , initObjs ... )
29- }
30-
31- func newFakeClient (t T , returnManagedFields bool , initObjs ... client.Object ) * FakeClient {
3222 s := scheme .Scheme
3323 err := toolchainv1alpha1 .AddToScheme (s )
3424 require .NoError (t , err )
3525
3626 toolchainObjs := getAllToolchainResources (s )
3727
38- builder := fake .NewClientBuilder ().
28+ cl := fake .NewClientBuilder ().
3929 WithScheme (s ).
4030 WithObjects (initObjs ... ).
41- WithStatusSubresource (toolchainObjs ... )
42- if returnManagedFields {
43- builder = builder .WithReturnManagedFields ()
44- }
45- cl := builder .Build ()
31+ WithStatusSubresource (toolchainObjs ... ).
32+ Build ()
4633 return & FakeClient {Client : cl , T : t }
4734}
4835
@@ -150,35 +137,7 @@ func Update(ctx context.Context, cl *FakeClient, obj client.Object, opts ...clie
150137 obj .SetGeneration (current .GetGeneration ())
151138 }
152139
153- // Work around a controller-runtime fake client bug where Update unconditionally
154- // replaces managed fields with the stored version, discarding caller-set values.
155- // A real API server preserves managed fields set by the caller, which is needed
156- // for csaupgrade.UpgradeManagedFields to work correctly.
157- managedFields := obj .GetManagedFields ()
158-
159- if err := cl .Client .Update (ctx , obj , opts ... ); err != nil {
160- return err
161- }
162-
163- if managedFields != nil {
164- // Fix the stored managed fields in the tracker using a MergePatch.
165- // The fake client's Update unconditionally replaces managed fields with
166- // the stored version, so we use Patch to correct them.
167- mfJSON , err := json .Marshal (map [string ]any {
168- "metadata" : map [string ]any {
169- "managedFields" : managedFields ,
170- },
171- })
172- if err != nil {
173- return err
174- }
175- if err := cl .Client .Patch (ctx , obj , client .RawPatch (types .MergePatchType , mfJSON )); err != nil {
176- return err
177- }
178- obj .SetManagedFields (managedFields )
179- }
180-
181- return nil
140+ return cl .Client .Update (ctx , obj , opts ... )
182141}
183142
184143func isGenerationChangeNeeded (currentObj , updatedObj client.Object ) (bool , error ) {
@@ -283,9 +242,19 @@ func (c *FakeClient) Patch(ctx context.Context, obj client.Object, patch client.
283242
284243func Patch (ctx context.Context , fakeClient * FakeClient , obj client.Object , patch client.Patch , opts ... client.PatchOption ) error {
285244 // Our tests assume that an update to the spec increases the Generation - this is what we do by default in the Create and Update
286- // methods, too. We need to replicate this behavior in Patch, too.
287-
288- // SSA patches are fully supported by the fake client now, so we just need to handle the generation bump.
245+ // methods, too. We need replicate this behavior in Patch, too.
246+
247+ // Fake client doesn't support SSA yet, so we have to be creative here and try to mock it out. Hopefully, SSA will be merged soon and we will
248+ // be able to remove this. See https://github.com/kubernetes-sigs/controller-runtime/issues/2341 and
249+ // https://github.com/kubernetes-sigs/controller-runtime/pull/2981.
250+ //
251+ // The above PR is merged but the SSA implementation in the fake client is still problematic. There is an issue and PR
252+ // that we created to fix the problem we have with controller-runtime 0.22 and 0.23:
253+ //
254+ // https://github.com/kubernetes-sigs/controller-runtime/issues/3484
255+ // https://github.com/kubernetes-sigs/controller-runtime/pull/3485
256+ //
257+ // NOTE: this doesn't really implement SSA in any sense. It is just here so that the existing tests pass.
289258
290259 found := true
291260 orig := obj .DeepCopyObject ().(client.Object )
@@ -296,6 +265,18 @@ func Patch(ctx context.Context, fakeClient *FakeClient, obj client.Object, patch
296265 found = false
297266 }
298267
268+ // A non-SSA patch assumes the object must already exist and should break if it doesn't. The SSA patch, on the other hand, creates the object
269+ // if it doesn't exist.
270+ if patch == client .Apply {
271+ if ! found {
272+ if err := Create (ctx , fakeClient , obj ); err != nil {
273+ return err
274+ }
275+ }
276+ // the fake client actively complains if it sees an SSA patch...
277+ patch = client .Merge
278+ }
279+
299280 if found {
300281 // we need to figure out whether we should update the generation or not.
301282 // We do that by applying the patch in a dry-run and comparing the changes it made
@@ -321,10 +302,6 @@ func Patch(ctx context.Context, fakeClient *FakeClient, obj client.Object, patch
321302 if shouldUpdateGeneration {
322303 obj .SetGeneration (orig .GetGeneration () + 1 )
323304 }
324- } else if patch == client .Apply {
325- // SSA Apply creates the object if it doesn't exist. Set Generation to 1
326- // since the fake client doesn't do this automatically.
327- obj .SetGeneration (1 )
328305 }
329306
330307 return fakeClient .Client .Patch (ctx , obj , patch , opts ... )
0 commit comments