Files
capsule/pkg/api/meta/conditions_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

214 lines
5.6 KiB
Go

// Copyright 2020-2025 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0
package meta_test
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/projectcapsule/capsule/pkg/api/meta"
)
// helper
func makeCond(tpe, status, reason, msg string, gen int64) meta.Condition {
return meta.Condition{
Type: tpe,
Status: metav1.ConditionStatus(status),
Reason: reason,
Message: msg,
ObservedGeneration: gen,
LastTransitionTime: metav1.NewTime(time.Unix(0, 0)),
}
}
func TestConditionList_GetConditionByType(t *testing.T) {
t.Run("returns matching condition", func(t *testing.T) {
list := meta.ConditionList{
makeCond("Ready", "False", "Init", "starting", 1),
makeCond("Synced", "True", "Ok", "done", 2),
}
got := list.GetConditionByType("Synced")
assert.NotNil(t, got)
assert.Equal(t, "Synced", got.Type)
assert.Equal(t, metav1.ConditionTrue, got.Status)
assert.Equal(t, "Ok", got.Reason)
assert.Equal(t, "done", got.Message)
})
t.Run("returns nil when not found", func(t *testing.T) {
list := meta.ConditionList{
makeCond("Ready", "False", "Init", "starting", 1),
}
assert.Nil(t, list.GetConditionByType("Missing"))
})
t.Run("returned pointer refers to slice element (not copy)", func(t *testing.T) {
list := meta.ConditionList{
makeCond("Ready", "False", "Init", "starting", 1),
makeCond("Synced", "True", "Ok", "done", 2),
}
ptr := list.GetConditionByType("Ready")
assert.NotNil(t, ptr)
ptr.Message = "mutated"
// This asserts GetConditionByType returns &list[i] (via index),
// not &cond where cond is the range variable copy.
assert.Equal(t, "mutated", list[0].Message)
})
}
func TestConditionList_UpdateConditionByType(t *testing.T) {
now := metav1.Now()
t.Run("updates existing condition in place", func(t *testing.T) {
list := meta.ConditionList{
makeCond("Ready", "False", "Init", "starting", 1),
makeCond("Synced", "True", "Ok", "done", 2),
}
beforeLen := len(list)
list.UpdateConditionByType(meta.Condition{
Type: "Ready",
Status: metav1.ConditionTrue,
Reason: "Reconciled",
Message: "ready now",
ObservedGeneration: 3,
LastTransitionTime: now,
})
assert.Equal(t, beforeLen, len(list))
got := list.GetConditionByType("Ready")
assert.NotNil(t, got)
assert.Equal(t, metav1.ConditionTrue, got.Status)
assert.Equal(t, "Reconciled", got.Reason)
assert.Equal(t, "ready now", got.Message)
assert.Equal(t, int64(3), got.ObservedGeneration)
})
t.Run("appends when condition type not present", func(t *testing.T) {
list := meta.ConditionList{
makeCond("Ready", "True", "Ok", "ready", 1),
}
beforeLen := len(list)
list.UpdateConditionByType(meta.Condition{
Type: "Synced",
Status: metav1.ConditionTrue,
Reason: "Done",
Message: "synced",
ObservedGeneration: 2,
LastTransitionTime: now,
})
assert.Equal(t, beforeLen+1, len(list))
got := list.GetConditionByType("Synced")
assert.NotNil(t, got)
assert.Equal(t, metav1.ConditionTrue, got.Status)
assert.Equal(t, "Done", got.Reason)
assert.Equal(t, "synced", got.Message)
assert.Equal(t, int64(2), got.ObservedGeneration)
})
}
func TestConditionList_RemoveConditionByType(t *testing.T) {
t.Run("removes all conditions with matching type", func(t *testing.T) {
list := meta.ConditionList{
makeCond("A", "True", "x", "m1", 1),
makeCond("B", "True", "y", "m2", 1),
makeCond("A", "False", "z", "m3", 2),
}
list.RemoveConditionByType("A")
assert.Len(t, list, 1)
assert.Equal(t, "B", list[0].Type)
})
t.Run("no-op when type not present", func(t *testing.T) {
orig := meta.ConditionList{
makeCond("A", "True", "x", "m1", 1),
}
list := append(meta.ConditionList{}, orig...) // copy
list.RemoveConditionByType("Missing")
assert.Equal(t, orig, list)
})
t.Run("nil receiver is safe", func(t *testing.T) {
var list *meta.ConditionList // nil receiver
assert.NotPanics(t, func() {
list.RemoveConditionByType("X")
})
})
}
func TestUpdateCondition(t *testing.T) {
now := metav1.Now()
t.Run("no update when all relevant fields match", func(t *testing.T) {
c := &meta.Condition{
Type: "Ready",
Status: "True",
Reason: "Success",
Message: "All good",
}
updated := c.UpdateCondition(meta.Condition{
Type: "Ready",
Status: "True",
Reason: "Success",
Message: "All good",
LastTransitionTime: now,
})
assert.False(t, updated)
})
t.Run("update occurs on message change", func(t *testing.T) {
c := &meta.Condition{
Type: "Ready",
Status: "True",
Reason: "Success",
Message: "Old message",
}
updated := c.UpdateCondition(meta.Condition{
Type: "Ready",
Status: "True",
Reason: "Success",
Message: "New message",
LastTransitionTime: now,
})
assert.True(t, updated)
assert.Equal(t, "New message", c.Message)
})
t.Run("update occurs on status change", func(t *testing.T) {
c := &meta.Condition{
Type: "Ready",
Status: "False",
Reason: "Pending",
Message: "Not ready yet",
}
updated := c.UpdateCondition(meta.Condition{
Type: "Ready",
Status: "True",
Reason: "Success",
Message: "Ready",
LastTransitionTime: now,
})
assert.True(t, updated)
assert.Equal(t, "True", string(c.Status))
assert.Equal(t, "Success", c.Reason)
assert.Equal(t, "Ready", c.Message)
})
}