Files
capsule/pkg/api/meta/ownerreference_test.go
Oliver Bähler 0abc77b56a feat: diverse performance improvements (#1861)
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
2026-02-03 22:05:00 +01:00

380 lines
11 KiB
Go

package meta_test
import (
"testing"
"github.com/projectcapsule/capsule/pkg/api/meta"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
)
func TestSetLooseOwnerReference(t *testing.T) {
t.Run("nil object => no error", func(t *testing.T) {
err := meta.SetLooseOwnerReference(nil, metav1.OwnerReference{UID: types.UID("u1")})
if err != nil {
t.Fatalf("expected nil err, got %v", err)
}
})
t.Run("append when not present", func(t *testing.T) {
obj := &corev1.ConfigMap{}
obj.SetName("cm")
obj.SetUID(types.UID("obj"))
owner := metav1.OwnerReference{
APIVersion: "v1",
Kind: "ConfigMap",
Name: "owner",
UID: types.UID("u1"),
}
if err := meta.SetLooseOwnerReference(obj, owner); err != nil {
t.Fatalf("unexpected err: %v", err)
}
refs := obj.GetOwnerReferences()
if len(refs) != 1 {
t.Fatalf("expected 1 ownerref, got %d", len(refs))
}
if !meta.LooseOwnerReferenceEqual(refs[0], owner) {
t.Fatalf("ownerref mismatch: got=%v want=%v", refs[0], owner)
}
})
t.Run("overwrite when same UID exists", func(t *testing.T) {
obj := &corev1.ConfigMap{}
obj.SetName("cm")
orig := metav1.OwnerReference{
APIVersion: "v1",
Kind: "ConfigMap",
Name: "old",
UID: types.UID("u1"),
}
obj.SetOwnerReferences([]metav1.OwnerReference{orig})
repl := metav1.OwnerReference{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "new",
UID: types.UID("u1"),
}
if err := meta.SetLooseOwnerReference(obj, repl); err != nil {
t.Fatalf("unexpected err: %v", err)
}
refs := obj.GetOwnerReferences()
if len(refs) != 1 {
t.Fatalf("expected 1 ownerref, got %d", len(refs))
}
if !meta.LooseOwnerReferenceEqual(refs[0], repl) {
t.Fatalf("expected overwritten ref %v, got %v", repl, refs[0])
}
})
t.Run("multiple existing refs keep others", func(t *testing.T) {
obj := &corev1.ConfigMap{}
obj.SetName("cm")
a := metav1.OwnerReference{APIVersion: "v1", Kind: "A", Name: "a", UID: types.UID("uA")}
b := metav1.OwnerReference{APIVersion: "v1", Kind: "B", Name: "b", UID: types.UID("uB")}
obj.SetOwnerReferences([]metav1.OwnerReference{a, b})
replB := metav1.OwnerReference{APIVersion: "v2", Kind: "B2", Name: "b2", UID: types.UID("uB")}
if err := meta.SetLooseOwnerReference(obj, replB); err != nil {
t.Fatalf("unexpected err: %v", err)
}
refs := obj.GetOwnerReferences()
if len(refs) != 2 {
t.Fatalf("expected 2 ownerrefs, got %d", len(refs))
}
// order preserved; only b overwritten
if !meta.LooseOwnerReferenceEqual(refs[0], a) {
t.Fatalf("expected first ref unchanged %v, got %v", a, refs[0])
}
if !meta.LooseOwnerReferenceEqual(refs[1], replB) {
t.Fatalf("expected second ref overwritten %v, got %v", replB, refs[1])
}
})
}
func TestRemoveLooseOwnerReference(t *testing.T) {
t.Run("removes by UID", func(t *testing.T) {
obj := &corev1.ConfigMap{}
a := metav1.OwnerReference{APIVersion: "v1", Kind: "A", Name: "a", UID: types.UID("uA")}
b := metav1.OwnerReference{APIVersion: "v1", Kind: "B", Name: "b", UID: types.UID("uB")}
obj.SetOwnerReferences([]metav1.OwnerReference{a, b})
meta.RemoveLooseOwnerReference(obj, metav1.OwnerReference{UID: types.UID("uA")})
refs := obj.GetOwnerReferences()
if len(refs) != 1 {
t.Fatalf("expected 1 ownerref remaining, got %d", len(refs))
}
if !meta.LooseOwnerReferenceEqual(refs[0], b) {
t.Fatalf("expected remaining ref %v, got %v", b, refs[0])
}
})
t.Run("no-op when UID not found", func(t *testing.T) {
obj := &corev1.ConfigMap{}
a := metav1.OwnerReference{APIVersion: "v1", Kind: "A", Name: "a", UID: types.UID("uA")}
obj.SetOwnerReferences([]metav1.OwnerReference{a})
meta.RemoveLooseOwnerReference(obj, metav1.OwnerReference{UID: types.UID("uX")})
refs := obj.GetOwnerReferences()
if len(refs) != 1 {
t.Fatalf("expected 1 ownerref, got %d", len(refs))
}
if !meta.LooseOwnerReferenceEqual(refs[0], a) {
t.Fatalf("expected unchanged ref %v, got %v", a, refs[0])
}
})
t.Run("removes duplicates with same UID", func(t *testing.T) {
obj := &corev1.ConfigMap{}
a1 := metav1.OwnerReference{APIVersion: "v1", Kind: "A", Name: "a1", UID: types.UID("uA")}
a2 := metav1.OwnerReference{APIVersion: "v1", Kind: "A", Name: "a2", UID: types.UID("uA")}
b := metav1.OwnerReference{APIVersion: "v1", Kind: "B", Name: "b", UID: types.UID("uB")}
obj.SetOwnerReferences([]metav1.OwnerReference{a1, b, a2})
meta.RemoveLooseOwnerReference(obj, metav1.OwnerReference{UID: types.UID("uA")})
refs := obj.GetOwnerReferences()
if len(refs) != 1 {
t.Fatalf("expected 1 ownerref remaining, got %d", len(refs))
}
if !meta.LooseOwnerReferenceEqual(refs[0], b) {
t.Fatalf("expected remaining ref %v, got %v", b, refs[0])
}
})
}
func TestHasLooseOwnerReference(t *testing.T) {
t.Run("true when UID present", func(t *testing.T) {
obj := &corev1.ConfigMap{}
obj.SetOwnerReferences([]metav1.OwnerReference{{UID: types.UID("u1")}})
if !meta.HasLooseOwnerReference(obj, metav1.OwnerReference{UID: types.UID("u1")}) {
t.Fatalf("expected true")
}
})
t.Run("false when UID absent", func(t *testing.T) {
obj := &corev1.ConfigMap{}
obj.SetOwnerReferences([]metav1.OwnerReference{{UID: types.UID("u1")}})
if meta.HasLooseOwnerReference(obj, metav1.OwnerReference{UID: types.UID("u2")}) {
t.Fatalf("expected false")
}
})
t.Run("false when no ownerrefs", func(t *testing.T) {
obj := &corev1.ConfigMap{}
if meta.HasLooseOwnerReference(obj, metav1.OwnerReference{UID: types.UID("u1")}) {
t.Fatalf("expected false")
}
})
}
func TestGetLooseOwnerReference(t *testing.T) {
obj := &corev1.ConfigMap{}
obj.SetName("cm-1")
obj.SetUID(types.UID("uid-1"))
// Ensure GVK is set (GetObjectKind().GroupVersionKind() reads this)
obj.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "ConfigMap",
})
ref := meta.GetLooseOwnerReference(obj)
// BUG FIXED: APIVersion must be group/version string, not Kind.
if ref.APIVersion != "v1" {
t.Fatalf("expected APIVersion==v1, got %q", ref.APIVersion)
}
if ref.Kind != "ConfigMap" {
t.Fatalf("expected Kind==ConfigMap, got %q", ref.Kind)
}
if ref.Name != "cm-1" {
t.Fatalf("expected Name==cm-1, got %q", ref.Name)
}
if ref.UID != types.UID("uid-1") {
t.Fatalf("expected UID==uid-1, got %q", ref.UID)
}
}
func TestLooseOwnerReferenceEqual(t *testing.T) {
t.Run("equal when all fields match", func(t *testing.T) {
a := metav1.OwnerReference{APIVersion: "v1", Kind: "K", Name: "n", UID: types.UID("u")}
b := metav1.OwnerReference{APIVersion: "v1", Kind: "K", Name: "n", UID: types.UID("u")}
if !meta.LooseOwnerReferenceEqual(a, b) {
t.Fatalf("expected equal")
}
})
t.Run("not equal when APIVersion differs", func(t *testing.T) {
a := metav1.OwnerReference{APIVersion: "v1", Kind: "K", Name: "n", UID: types.UID("u")}
b := metav1.OwnerReference{APIVersion: "v2", Kind: "K", Name: "n", UID: types.UID("u")}
if meta.LooseOwnerReferenceEqual(a, b) {
t.Fatalf("expected not equal")
}
})
t.Run("not equal when Kind differs", func(t *testing.T) {
a := metav1.OwnerReference{APIVersion: "v1", Kind: "K1", Name: "n", UID: types.UID("u")}
b := metav1.OwnerReference{APIVersion: "v1", Kind: "K2", Name: "n", UID: types.UID("u")}
if meta.LooseOwnerReferenceEqual(a, b) {
t.Fatalf("expected not equal")
}
})
t.Run("not equal when Name differs", func(t *testing.T) {
a := metav1.OwnerReference{APIVersion: "v1", Kind: "K", Name: "n1", UID: types.UID("u")}
b := metav1.OwnerReference{APIVersion: "v1", Kind: "K", Name: "n2", UID: types.UID("u")}
if meta.LooseOwnerReferenceEqual(a, b) {
t.Fatalf("expected not equal")
}
})
t.Run("not equal when UID differs", func(t *testing.T) {
a := metav1.OwnerReference{APIVersion: "v1", Kind: "K", Name: "n", UID: types.UID("u1")}
b := metav1.OwnerReference{APIVersion: "v1", Kind: "K", Name: "n", UID: types.UID("u2")}
if meta.LooseOwnerReferenceEqual(a, b) {
t.Fatalf("expected not equal")
}
})
}
func TestRemoveLooseOwnerReferenceForKindExceptGiven(t *testing.T) {
type testCase struct {
name string
initial []metav1.OwnerReference
keep metav1.OwnerReference
expected []metav1.OwnerReference
}
given := metav1.OwnerReference{
APIVersion: "capsule.clastix.io/v1beta2",
Kind: "ResourcePool",
Name: "pool-a",
UID: types.UID("uid-given"),
}
sameKindOtherUID := metav1.OwnerReference{
APIVersion: "capsule.clastix.io/v1beta2",
Kind: "ResourcePool",
Name: "pool-b",
UID: types.UID("uid-other"),
}
sameKindSameUIDDifferentName := metav1.OwnerReference{
APIVersion: "capsule.clastix.io/v1beta2",
Kind: "ResourcePool",
Name: "pool-a-renamed",
UID: types.UID("uid-given"),
}
differentKind := metav1.OwnerReference{
APIVersion: "capsule.clastix.io/v1beta2",
Kind: "Tenant",
Name: "t-1",
UID: types.UID("uid-tenant"),
}
differentAPIVersion := metav1.OwnerReference{
APIVersion: "capsule.clastix.io/v1alpha1",
Kind: "ResourcePool",
Name: "pool-old",
UID: types.UID("uid-old"),
}
tests := []testCase{
{
name: "keeps given ref and removes other refs with same kind/apiversion",
initial: []metav1.OwnerReference{
differentKind,
sameKindOtherUID,
given,
differentAPIVersion,
},
keep: given,
expected: []metav1.OwnerReference{
differentKind,
given,
differentAPIVersion,
},
},
{
name: "preserves refs of different kind/apiversion even if given is absent; removes matching kind/apiversion",
initial: []metav1.OwnerReference{
differentKind,
sameKindOtherUID,
differentAPIVersion,
},
keep: given, // given not present in initial
expected: []metav1.OwnerReference{
differentKind,
differentAPIVersion,
},
},
{
name: "keeps the ref with matching UID even if other fields differ (UID is identity)",
initial: []metav1.OwnerReference{
sameKindOtherUID,
sameKindSameUIDDifferentName, // same UID as given, but different Name
differentKind,
},
keep: given,
expected: []metav1.OwnerReference{
sameKindSameUIDDifferentName,
differentKind,
},
},
{
name: "no ownerReferences results in no ownerReferences",
initial: []metav1.OwnerReference{},
keep: given,
expected: []metav1.OwnerReference{
// empty
},
},
{
name: "only matching kind/apiversion present; leaves only given if present",
initial: []metav1.OwnerReference{
sameKindOtherUID,
given,
},
keep: given,
expected: []metav1.OwnerReference{
given,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
obj := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm",
Namespace: "ns",
OwnerReferences: append([]metav1.OwnerReference(nil), tt.initial...),
},
}
meta.RemoveLooseOwnerReferenceForKindExceptGiven(obj, tt.keep)
assert.Equal(t, tt.expected, obj.GetOwnerReferences())
})
}
}