Skip to content

Commit 1681e8a

Browse files
committed
test
1 parent d83c930 commit 1681e8a

File tree

14 files changed

+888
-284
lines changed

14 files changed

+888
-284
lines changed

.github/.copilot/breadcrumbs/2025-06-24-0900-rollout-controller-binding-interface-refactor.md

Lines changed: 511 additions & 0 deletions
Large diffs are not rendered by default.

apis/placement/v1beta1/binding_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"k8s.io/apimachinery/pkg/api/meta"
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
"sigs.k8s.io/controller-runtime/pkg/client"
23+
24+
"github.com/kubefleet-dev/kubefleet/apis"
2325
)
2426

2527
const (
@@ -52,7 +54,7 @@ type BindingStatusGetterSetter interface {
5254
// A BindingObj offers an abstract way to work with fleet binding objects.
5355
// +kubebuilder:object:generate=false
5456
type BindingObj interface {
55-
client.Object
57+
apis.ConditionedObj
5658
BindingSpecGetterSetter
5759
BindingStatusGetterSetter
5860
}

apis/placement/v1beta1/clusterresourceplacement_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2323
"k8s.io/apimachinery/pkg/util/intstr"
2424
"sigs.k8s.io/controller-runtime/pkg/client"
25+
26+
"github.com/kubefleet-dev/kubefleet/apis"
2527
)
2628

2729
const (
@@ -58,7 +60,7 @@ type PlacementStatusGetterSetter interface {
5860
// PlacementObj offers the functionality to work with fleet placement object.
5961
// +kubebuilder:object:generate=false
6062
type PlacementObj interface {
61-
client.Object
63+
apis.ConditionedObj
6264
PlacementSpecGetterSetter
6365
PlacementStatusGetterSetter
6466
}

apis/placement/v1beta1/policysnapshot_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"k8s.io/apimachinery/pkg/api/meta"
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
"sigs.k8s.io/controller-runtime/pkg/client"
23+
24+
"github.com/kubefleet-dev/kubefleet/apis"
2325
)
2426

2527
const (
@@ -57,7 +59,7 @@ type PolicySnapshotStatusGetterSetter interface {
5759
// A PolicySnapshotObj offers an abstract way to work with a fleet policy snapshot object.
5860
// +kubebuilder:object:generate=false
5961
type PolicySnapshotObj interface {
60-
client.Object
62+
apis.ConditionedObj
6163
PolicySnapshotSpecGetterSetter
6264
PolicySnapshotStatusGetterSetter
6365
}

apis/placement/v1beta1/resourcesnapshot_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
"k8s.io/apimachinery/pkg/runtime"
2323
"sigs.k8s.io/controller-runtime/pkg/client"
24+
25+
"github.com/kubefleet-dev/kubefleet/apis"
2426
)
2527

2628
const (
@@ -71,7 +73,7 @@ type ResourceSnapshotStatusGetterSetter interface {
7173
// A ResourceSnapshotObj offers an abstract way to work with a resource snapshot object.
7274
// +kubebuilder:object:generate=false
7375
type ResourceSnapshotObj interface {
74-
client.Object
76+
apis.ConditionedObj
7577
ResourceSnapshotSpecGetterSetter
7678
ResourceSnapshotStatusGetterSetter
7779
}

pkg/controllers/clusterresourceplacementeviction/controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ func (r *Reconciler) validateEviction(ctx context.Context, eviction *placementv1
118118
}
119119

120120
// set default values for CRP.
121-
defaulter.SetDefaultsClusterResourcePlacement(&crp)
121+
defaulter.SetPlacementDefaults(&crp)
122122

123123
if crp.DeletionTimestamp != nil {
124124
klog.V(2).InfoS(condition.EvictionInvalidDeletingCRPMessage, "clusterResourcePlacementEviction", eviction.Name, "clusterResourcePlacement", eviction.Spec.PlacementName)

pkg/controllers/clusterresourceplacementeviction/controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ func TestValidateEviction(t *testing.T) {
258258
// Since default values are applied to the affected CRP in the eviction controller; the
259259
// the same must be done on the expected result as well.
260260
if tc.wantValidationResult.crp != nil {
261-
defaulter.SetDefaultsClusterResourcePlacement(tc.wantValidationResult.crp)
261+
defaulter.SetPlacementDefaults(tc.wantValidationResult.crp)
262262
}
263263

264264
if diff := cmp.Diff(tc.wantValidationResult, gotValidationResult, validationResultCmpOptions...); diff != "" {

pkg/controllers/rollout/controller.go

Lines changed: 291 additions & 200 deletions
Large diffs are not rendered by default.

pkg/controllers/rollout/controller_test.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ func TestWaitForResourcesToCleanUp(t *testing.T) {
264264
for name, tt := range tests {
265265
crp := &fleetv1beta1.ClusterResourcePlacement{}
266266
t.Run(name, func(t *testing.T) {
267-
gotWait, err := waitForResourcesToCleanUp(tt.allBindings, crp)
267+
gotWait, err := waitForResourcesToCleanUp(controller.ConvertCRBArrayToBindingObjs(tt.allBindings), crp)
268268
if (err != nil) != tt.wantErr {
269269
t.Errorf("waitForResourcesToCleanUp test `%s` error = %v, wantErr %v", name, err, tt.wantErr)
270270
return
@@ -618,7 +618,7 @@ func TestUpdateBindings(t *testing.T) {
618618
}
619619
if tt.desiredBindingsSpec != nil {
620620
inputs[i].desiredBinding = tt.bindings[i].DeepCopy()
621-
inputs[i].desiredBinding.Spec = tt.desiredBindingsSpec[i]
621+
inputs[i].desiredBinding.SetBindingSpec(tt.desiredBindingsSpec[i])
622622
}
623623
}
624624
err := r.updateBindings(ctx, inputs)
@@ -2172,7 +2172,7 @@ func TestPickBindingsToRoll(t *testing.T) {
21722172
Name: tt.latestResourceSnapshotName,
21732173
},
21742174
}
2175-
gotUpdatedBindings, gotStaleUnselectedBindings, gotUpToDateBoundBindings, gotNeedRoll, gotWaitTime, err := r.pickBindingsToRoll(context.Background(), tt.allBindings, resourceSnapshot, tt.crp, tt.matchedCROs, tt.matchedROs)
2175+
gotUpdatedBindings, gotStaleUnselectedBindings, gotUpToDateBoundBindings, gotNeedRoll, gotWaitTime, err := r.pickBindingsToRoll(context.Background(), controller.ConvertCRBArrayToBindingObjs(tt.allBindings), resourceSnapshot, tt.crp, tt.matchedCROs, tt.matchedROs)
21762176
if (err != nil) != (tt.wantErr != nil) || err != nil && !errors.Is(err, tt.wantErr) {
21772177
t.Fatalf("pickBindingsToRoll() error = %v, wantErr %v", err, tt.wantErr)
21782178
}
@@ -2183,21 +2183,23 @@ func TestPickBindingsToRoll(t *testing.T) {
21832183
wantTobeUpdatedBindings := make([]toBeUpdatedBinding, len(tt.wantTobeUpdatedBindings))
21842184
for i, index := range tt.wantTobeUpdatedBindings {
21852185
// Unscheduled bindings are only removed in a single rollout cycle.
2186-
if tt.allBindings[index].Spec.State != fleetv1beta1.BindingStateUnscheduled {
2186+
bindingSpec := tt.allBindings[index].GetBindingSpec()
2187+
if bindingSpec.State != fleetv1beta1.BindingStateUnscheduled {
21872188
wantTobeUpdatedBindings[i].currentBinding = tt.allBindings[index]
21882189
wantTobeUpdatedBindings[i].desiredBinding = tt.allBindings[index].DeepCopy()
2189-
wantTobeUpdatedBindings[i].desiredBinding.Spec = tt.wantDesiredBindingsSpec[index]
2190+
wantTobeUpdatedBindings[i].desiredBinding.SetBindingSpec(tt.wantDesiredBindingsSpec[index])
21902191
} else {
21912192
wantTobeUpdatedBindings[i].currentBinding = tt.allBindings[index]
21922193
}
21932194
}
21942195
wantStaleUnselectedBindings := make([]toBeUpdatedBinding, len(tt.wantStaleUnselectedBindings))
21952196
for i, index := range tt.wantStaleUnselectedBindings {
21962197
// Unscheduled bindings are only removed in a single rollout cycle.
2197-
if tt.allBindings[index].Spec.State != fleetv1beta1.BindingStateUnscheduled {
2198+
bindingSpec := tt.allBindings[index].GetBindingSpec()
2199+
if bindingSpec.State != fleetv1beta1.BindingStateUnscheduled {
21982200
wantStaleUnselectedBindings[i].currentBinding = tt.allBindings[index]
21992201
wantStaleUnselectedBindings[i].desiredBinding = tt.allBindings[index].DeepCopy()
2200-
wantStaleUnselectedBindings[i].desiredBinding.Spec = tt.wantDesiredBindingsSpec[index]
2202+
wantStaleUnselectedBindings[i].desiredBinding.SetBindingSpec(tt.wantDesiredBindingsSpec[index])
22012203
} else {
22022204
wantStaleUnselectedBindings[i].currentBinding = tt.allBindings[index]
22032205
}
@@ -2892,7 +2894,7 @@ func TestCheckAndUpdateStaleBindingsStatus(t *testing.T) {
28922894
Client: fakeClient,
28932895
}
28942896
ctx := context.Background()
2895-
if err := r.checkAndUpdateStaleBindingsStatus(ctx, tt.bindings); err != nil {
2897+
if err := r.checkAndUpdateStaleBindingsStatus(ctx, controller.ConvertCRBArrayToBindingObjs(tt.bindings)); err != nil {
28962898
t.Fatalf("checkAndUpdateStaleBindingsStatus() got error %v, want no err", err)
28972899
}
28982900
bindingList := &fleetv1beta1.ClusterResourceBindingList{}
@@ -3168,7 +3170,7 @@ func TestProcessApplyStrategyUpdates(t *testing.T) {
31683170
Client: fakeClient,
31693171
}
31703172

3171-
applyStrategyUpdated, err := r.processApplyStrategyUpdates(ctx, tc.crp, tc.allBindings)
3173+
applyStrategyUpdated, err := r.processApplyStrategyUpdates(ctx, tc.crp, controller.ConvertCRBArrayToBindingObjs(tc.allBindings))
31723174
if err != nil {
31733175
t.Errorf("processApplyStrategyUpdates() error = %v, want no error", err)
31743176
}

pkg/scheduler/framework/frameworkutils_test.go

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -126,28 +126,6 @@ func TestGenerateBinding(t *testing.T) {
126126
t.Errorf("expected empty namespace for ClusterResourceBinding, got %s", crb.Namespace)
127127
}
128128

129-
// Verify name pattern: placement-cluster-uuid (8 chars)
130-
nameParts := strings.Split(crb.Name, "-")
131-
if len(nameParts) < 3 {
132-
t.Errorf("expected binding name to have at least 3 parts separated by '-', got %s", crb.Name)
133-
} else {
134-
// Last part should be 8-character UUID
135-
uuidPart := nameParts[len(nameParts)-1]
136-
if len(uuidPart) != 8 {
137-
t.Errorf("expected UUID part to be 8 characters, got %d characters: %s", len(uuidPart), uuidPart)
138-
}
139-
}
140-
141-
// Verify labels
142-
if crb.Labels[placementv1beta1.CRPTrackingLabel] != tt.expectedLabel {
143-
t.Errorf("expected CRPTrackingLabel %s, got %s", tt.expectedLabel, crb.Labels[placementv1beta1.CRPTrackingLabel])
144-
}
145-
146-
// Verify finalizers
147-
if len(crb.Finalizers) != 1 || crb.Finalizers[0] != placementv1beta1.SchedulerCRBCleanupFinalizer {
148-
t.Errorf("expected finalizer %s, got %v", placementv1beta1.SchedulerCRBCleanupFinalizer, crb.Finalizers)
149-
}
150-
151129
case "ResourceBinding":
152130
rb, ok := binding.(*placementv1beta1.ResourceBinding)
153131
if !ok {
@@ -158,30 +136,31 @@ func TestGenerateBinding(t *testing.T) {
158136
t.Errorf("expected namespace %s, got %s", tt.expectedNamespace, rb.Namespace)
159137
}
160138

161-
// Verify name pattern: placement-cluster-uuid (8 chars)
162-
nameParts := strings.Split(rb.Name, "-")
163-
if len(nameParts) < 3 {
164-
t.Errorf("expected binding name to have at least 3 parts separated by '-', got %s", rb.Name)
165-
} else {
166-
// Last part should be 8-character UUID
167-
uuidPart := nameParts[len(nameParts)-1]
168-
if len(uuidPart) != 8 {
169-
t.Errorf("expected UUID part to be 8 characters, got %d characters: %s", len(uuidPart), uuidPart)
170-
}
171-
}
139+
default:
140+
t.Errorf("unexpected expected type: %s", tt.expectedType)
141+
}
172142

173-
// Verify labels
174-
if rb.Labels[placementv1beta1.CRPTrackingLabel] != tt.expectedLabel {
175-
t.Errorf("expected CRPTrackingLabel %s, got %s", tt.expectedLabel, rb.Labels[placementv1beta1.CRPTrackingLabel])
143+
// Verify name pattern: placement-cluster-uuid (8 chars), the placement and cluster name part are already validated
144+
// in NewBindingName UT.
145+
nameParts := strings.Split(binding.GetName(), "-")
146+
if len(nameParts) < 3 {
147+
t.Errorf("expected binding name to have at least 3 parts separated by '-', got %s", binding.GetName())
148+
} else {
149+
// Last part should be 8-character UUID
150+
uuidPart := nameParts[len(nameParts)-1]
151+
if len(uuidPart) != 8 {
152+
t.Errorf("expected UUID part to be 8 characters, got %d characters: %s", len(uuidPart), uuidPart)
176153
}
154+
}
177155

178-
// Verify finalizers
179-
if len(rb.Finalizers) != 1 || rb.Finalizers[0] != placementv1beta1.SchedulerCRBCleanupFinalizer {
180-
t.Errorf("expected finalizer %s, got %v", placementv1beta1.SchedulerCRBCleanupFinalizer, rb.Finalizers)
181-
}
156+
// Verify labels
157+
if binding.GetLabels()[placementv1beta1.CRPTrackingLabel] != tt.expectedLabel {
158+
t.Errorf("expected CRPTrackingLabel %s, got %s", tt.expectedLabel, binding.GetLabels()[placementv1beta1.CRPTrackingLabel])
159+
}
182160

183-
default:
184-
t.Errorf("unexpected expected type: %s", tt.expectedType)
161+
// Verify finalizers
162+
if len(binding.GetFinalizers()) != 1 || binding.GetFinalizers()[0] != placementv1beta1.SchedulerCRBCleanupFinalizer {
163+
t.Errorf("expected finalizer %s, got %v", placementv1beta1.SchedulerCRBCleanupFinalizer, binding.GetFinalizers())
185164
}
186165
})
187166
}

0 commit comments

Comments
 (0)