Skip to content

Commit 67b27f2

Browse files
authored
Merge pull request #2725 from alexandremahdhaoui/fix_fakeclient-patch-with-no-rv-should-succeed
🐛 allow fakeclient to patch CR with no RV
2 parents 7ff5801 + 3a19b11 commit 67b27f2

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

pkg/client/fake/client.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,9 +423,18 @@ func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Ob
423423

424424
// If the new object does not have the resource version set and it allows unconditional update,
425425
// default it to the resource version of the existing resource
426-
if accessor.GetResourceVersion() == "" && allowsUnconditionalUpdate(gvk) {
427-
accessor.SetResourceVersion(oldAccessor.GetResourceVersion())
426+
if accessor.GetResourceVersion() == "" {
427+
switch {
428+
case allowsUnconditionalUpdate(gvk):
429+
accessor.SetResourceVersion(oldAccessor.GetResourceVersion())
430+
case bytes.
431+
Contains(debug.Stack(), []byte("sigs.k8s.io/controller-runtime/pkg/client/fake.(*fakeClient).Patch")):
432+
// We apply patches using a client-go reaction that ends up calling the trackers Update. As we can't change
433+
// that reaction, we use the callstack to figure out if this originated from the "fakeClient.Patch" func.
434+
accessor.SetResourceVersion(oldAccessor.GetResourceVersion())
435+
}
428436
}
437+
429438
if accessor.GetResourceVersion() != oldAccessor.GetResourceVersion() {
430439
return apierrors.NewConflict(gvr.GroupResource(), accessor.GetName(), errors.New("object was modified"))
431440
}

pkg/client/fake/client_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,38 @@ var _ = Describe("Fake client", func() {
550550
Expect(obj.ObjectMeta.ResourceVersion).To(Equal("1000"))
551551
})
552552

553+
It("should allow patch with non-set ResourceVersion for a resource that doesn't allow unconditional updates", func() {
554+
schemeBuilder := &scheme.Builder{GroupVersion: schema.GroupVersion{Group: "test", Version: "v1"}}
555+
schemeBuilder.Register(&WithPointerMeta{}, &WithPointerMetaList{})
556+
557+
scheme := runtime.NewScheme()
558+
Expect(schemeBuilder.AddToScheme(scheme)).NotTo(HaveOccurred())
559+
560+
cl := NewClientBuilder().WithScheme(scheme).Build()
561+
original := &WithPointerMeta{
562+
ObjectMeta: &metav1.ObjectMeta{
563+
Name: "obj",
564+
Namespace: "ns2",
565+
}}
566+
567+
err := cl.Create(context.Background(), original)
568+
Expect(err).ToNot(HaveOccurred())
569+
570+
newObj := &WithPointerMeta{
571+
ObjectMeta: &metav1.ObjectMeta{
572+
Name: original.Name,
573+
Namespace: original.Namespace,
574+
Annotations: map[string]string{
575+
"foo": "bar",
576+
},
577+
}}
578+
Expect(cl.Patch(context.Background(), newObj, client.MergeFrom(original))).To(Succeed())
579+
580+
patched := &WithPointerMeta{}
581+
Expect(cl.Get(context.Background(), client.ObjectKeyFromObject(original), patched)).To(Succeed())
582+
Expect(patched.Annotations).To(Equal(map[string]string{"foo": "bar"}))
583+
})
584+
553585
It("should reject updates with non-set ResourceVersion for a resource that doesn't allow unconditional updates", func() {
554586
By("Creating a new binding")
555587
binding := &corev1.Binding{

0 commit comments

Comments
 (0)