Skip to content

Commit 003554e

Browse files
committed
add tests for WorkStatusController onAdd/onUpdate/onDelete
Signed-off-by: zach593 <[email protected]>
1 parent deeadfe commit 003554e

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

pkg/controllers/status/work_status_controller_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"k8s.io/apimachinery/pkg/util/uuid"
3737
dynamicfake "k8s.io/client-go/dynamic/fake"
3838
"k8s.io/client-go/kubernetes/scheme"
39+
"k8s.io/client-go/tools/cache"
3940
"k8s.io/client-go/tools/record"
4041
"k8s.io/utils/ptr"
4142
controllerruntime "sigs.k8s.io/controller-runtime"
@@ -1096,3 +1097,113 @@ func TestWorkStatusController_interpretHealth(t *testing.T) {
10961097
})
10971098
}
10981099
}
1100+
1101+
type TestObject struct {
1102+
metav1.TypeMeta
1103+
metav1.ObjectMeta
1104+
Spec string
1105+
}
1106+
1107+
func (in *TestObject) DeepCopyObject() runtime.Object {
1108+
return &TestObject{
1109+
TypeMeta: in.TypeMeta,
1110+
ObjectMeta: in.ObjectMeta,
1111+
Spec: in.Spec,
1112+
}
1113+
}
1114+
1115+
// mockAsyncWorker implements util.AsyncPriorityWorker for testing onAdd/onUpdate/onDelete behavior.
1116+
type mockAsyncWorker struct {
1117+
receivedObjs []any // objects passed via EnqueueWithOpts (onAdd)
1118+
receivedPriorities []*int // priorities captured from EnqueueWithOpts
1119+
enqueuedObjs []any // objects passed via Enqueue (onUpdate/onDelete)
1120+
}
1121+
1122+
func (m *mockAsyncWorker) EnqueueWithOpts(opts util.AddOpts, obj any) { // capture inputs for onAdd
1123+
m.receivedObjs = append(m.receivedObjs, obj)
1124+
m.receivedPriorities = append(m.receivedPriorities, opts.Priority)
1125+
}
1126+
func (m *mockAsyncWorker) AddWithOpts(_ util.AddOpts, _ ...any) {}
1127+
func (m *mockAsyncWorker) Add(_ interface{}) {}
1128+
func (m *mockAsyncWorker) AddAfter(_ interface{}, _ time.Duration) {}
1129+
func (m *mockAsyncWorker) Enqueue(obj interface{}) { // capture inputs for onUpdate/onDelete
1130+
m.enqueuedObjs = append(m.enqueuedObjs, obj)
1131+
}
1132+
func (m *mockAsyncWorker) Run(_ context.Context, _ int) {}
1133+
1134+
func TestWorkStatusController_onAdd(t *testing.T) {
1135+
cluster := newCluster("cluster", clusterv1alpha1.ClusterConditionReady, metav1.ConditionTrue)
1136+
c := newWorkStatusController(cluster)
1137+
mockWorker := &mockAsyncWorker{}
1138+
c.worker = mockWorker
1139+
1140+
obj := &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj"}}
1141+
1142+
t.Run("in initial list -> low priority", func(t *testing.T) {
1143+
c.onAdd(obj, true)
1144+
assert.Equal(t, 1, len(mockWorker.receivedObjs))
1145+
assert.Equal(t, obj, mockWorker.receivedObjs[0])
1146+
if assert.NotNil(t, mockWorker.receivedPriorities[0]) {
1147+
assert.Equal(t, util.LowPriority, *mockWorker.receivedPriorities[0])
1148+
}
1149+
})
1150+
1151+
t.Run("not in initial list -> nil priority", func(t *testing.T) {
1152+
c.onAdd(obj, false)
1153+
assert.Equal(t, 2, len(mockWorker.receivedObjs))
1154+
assert.Equal(t, obj, mockWorker.receivedObjs[1])
1155+
assert.Nil(t, mockWorker.receivedPriorities[1])
1156+
})
1157+
}
1158+
1159+
func TestWorkStatusController_onUpdate(t *testing.T) {
1160+
cluster := newCluster("cluster", clusterv1alpha1.ClusterConditionReady, metav1.ConditionTrue)
1161+
c := newWorkStatusController(cluster)
1162+
mockWorker := &mockAsyncWorker{}
1163+
c.worker = mockWorker
1164+
1165+
oldObj := &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj"}, Spec: "same"}
1166+
// Deep copy same content
1167+
curSame := oldObj.DeepCopyObject().(*TestObject)
1168+
// Different spec
1169+
curDiff := &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "test-obj"}, Spec: "different"}
1170+
1171+
t.Run("objects equal -> no enqueue", func(t *testing.T) {
1172+
c.onUpdate(oldObj, curSame)
1173+
assert.Equal(t, 0, len(mockWorker.enqueuedObjs))
1174+
})
1175+
1176+
t.Run("objects differ -> enqueue", func(t *testing.T) {
1177+
c.onUpdate(oldObj, curDiff)
1178+
assert.Equal(t, 1, len(mockWorker.enqueuedObjs))
1179+
assert.Equal(t, curDiff, mockWorker.enqueuedObjs[0])
1180+
})
1181+
}
1182+
1183+
func TestWorkStatusController_onDelete(t *testing.T) {
1184+
cluster := newCluster("cluster", clusterv1alpha1.ClusterConditionReady, metav1.ConditionTrue)
1185+
c := newWorkStatusController(cluster)
1186+
mockWorker := &mockAsyncWorker{}
1187+
c.worker = mockWorker
1188+
1189+
obj := &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "to-delete"}}
1190+
1191+
t.Run("direct object -> enqueue", func(t *testing.T) {
1192+
c.onDelete(obj)
1193+
assert.Equal(t, 1, len(mockWorker.enqueuedObjs))
1194+
assert.Equal(t, obj, mockWorker.enqueuedObjs[0])
1195+
})
1196+
1197+
t.Run("DeletedFinalStateUnknown wrapper -> enqueue", func(t *testing.T) {
1198+
wrapped := cache.DeletedFinalStateUnknown{Obj: &TestObject{ObjectMeta: metav1.ObjectMeta{Name: "wrapped"}}}
1199+
c.onDelete(wrapped)
1200+
assert.Equal(t, 2, len(mockWorker.enqueuedObjs))
1201+
assert.Equal(t, "wrapped", mockWorker.enqueuedObjs[1].(*TestObject).Name)
1202+
})
1203+
1204+
t.Run("DeletedFinalStateUnknown with nil Obj -> no additional enqueue", func(t *testing.T) {
1205+
wrappedNil := cache.DeletedFinalStateUnknown{Obj: nil}
1206+
c.onDelete(wrappedNil)
1207+
assert.Equal(t, 2, len(mockWorker.enqueuedObjs)) // unchanged
1208+
})
1209+
}

0 commit comments

Comments
 (0)