@@ -23,9 +23,11 @@ import (
2323 "log"
2424 "os"
2525 "strings"
26+ "sync/atomic"
2627 "testing"
2728 "time"
2829
30+ crossplanetest "github.com/crossplane/crossplane-runtime/v2/pkg/test"
2931 "github.com/google/go-cmp/cmp"
3032 "github.com/google/go-cmp/cmp/cmpopts"
3133 k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -2734,15 +2736,15 @@ func TestUpdatePolicySnapshotStatusFromBindings(t *testing.T) {
27342736 {
27352737 cluster : & clusterv1beta1.MemberCluster {
27362738 ObjectMeta : metav1.ObjectMeta {
2737- Name : altClusterName ,
2739+ Name : anotherClusterName ,
27382740 },
27392741 },
27402742 status : filteredStatus ,
27412743 },
27422744 {
27432745 cluster : & clusterv1beta1.MemberCluster {
27442746 ObjectMeta : metav1.ObjectMeta {
2745- Name : anotherClusterName ,
2747+ Name : altClusterName ,
27462748 },
27472749 },
27482750 status : filteredStatus ,
@@ -2760,7 +2762,7 @@ func TestUpdatePolicySnapshotStatusFromBindings(t *testing.T) {
27602762 Reason : fmt .Sprintf (resourceScheduleSucceededWithScoreMessageFormat , clusterName , affinityScore1 , topologySpreadScore1 ),
27612763 },
27622764 {
2763- ClusterName : altClusterName ,
2765+ ClusterName : anotherClusterName ,
27642766 Selected : false ,
27652767 Reason : filteredStatus .String (),
27662768 },
@@ -6536,3 +6538,175 @@ func TestUpdatePolicySnapshotStatusForPickFixedPlacementType(t *testing.T) {
65366538 })
65376539 }
65386540}
6541+
6542+ // TestRunSchedulingCycleForPickAllPlacementType_StableStatusOutputInLargeFleet tests the
6543+ // runSchedulingCycleForPickAllPlacementType method, specifically to ensure that the status output
6544+ // remains consistent when running the scheduling cycle in a large fleet (i.e., the scheduler
6545+ // will not constantly refresh the status across scheduling cycles).
6546+ func TestRunSchedulingCycleForPickAllPlacementType_StableStatusOutputInLargeFleet (t * testing.T ) {
6547+ ctx := context .Background ()
6548+
6549+ // Set up the scheduler profile with a label-based dummy filter plugin.
6550+ profile := NewProfile ("TestOnly" )
6551+
6552+ dummyLabelBasedFilterPluginName := fmt .Sprintf (dummyAllPurposePluginNameFormat , 0 )
6553+ wantLabelKey := "pre-selected"
6554+ wantLabelValue := "true"
6555+ wantLabels := map [string ]string {
6556+ wantLabelKey : wantLabelValue ,
6557+ }
6558+ dummyLabelBasedFilterPlugin := & DummyAllPurposePlugin {
6559+ name : dummyLabelBasedFilterPluginName ,
6560+ filterRunner : func (ctx context.Context , state CycleStatePluginReadWriter , policy placementv1beta1.PolicySnapshotObj , cluster * clusterv1beta1.MemberCluster ) (status * Status ) {
6561+ memberClusterLabels := cluster .GetLabels ()
6562+ for wk , wv := range wantLabels {
6563+ if v , ok := memberClusterLabels [wk ]; ! ok || v != wv {
6564+ return NewNonErrorStatus (ClusterUnschedulable , dummyLabelBasedFilterPluginName )
6565+ }
6566+ }
6567+ return nil
6568+ },
6569+ }
6570+ profile .WithFilterPlugin (dummyLabelBasedFilterPlugin )
6571+
6572+ mockClientStatusUpdateCount := atomic.Int32 {}
6573+ mockClient := crossplanetest.MockClient {
6574+ MockCreate : func (ctx context.Context , obj client.Object , opts ... client.CreateOption ) error {
6575+ return nil
6576+ },
6577+ MockStatusUpdate : func (ctx context.Context , obj client.Object , opts ... client.SubResourceUpdateOption ) error {
6578+ _ = mockClientStatusUpdateCount .Add (1 )
6579+ return nil
6580+ },
6581+ }
6582+
6583+ f := & framework {
6584+ profile : profile ,
6585+ client : & mockClient ,
6586+ uncachedReader : & mockClient ,
6587+ manager : nil ,
6588+ eventRecorder : nil ,
6589+ parallelizer : parallelizer .NewParallelizer (parallelizer .DefaultNumOfWorkers ),
6590+ maxUnselectedClusterDecisionCount : 3 ,
6591+ // The cluster eligibility checker is not invoked in this test spec.
6592+ clusterEligibilityChecker : clustereligibilitychecker .New (),
6593+ }
6594+ // No need to set up plugins with the framework.
6595+
6596+ clusters := []clusterv1beta1.MemberCluster {
6597+ {
6598+ ObjectMeta : metav1.ObjectMeta {
6599+ Name : fmt .Sprintf (clusterNameTemplate , 1 ),
6600+ },
6601+ },
6602+ {
6603+ ObjectMeta : metav1.ObjectMeta {
6604+ Name : fmt .Sprintf (clusterNameTemplate , 2 ),
6605+ },
6606+ },
6607+ {
6608+ ObjectMeta : metav1.ObjectMeta {
6609+ Name : fmt .Sprintf (clusterNameTemplate , 3 ),
6610+ },
6611+ },
6612+ {
6613+ ObjectMeta : metav1.ObjectMeta {
6614+ Name : fmt .Sprintf (clusterNameTemplate , 4 ),
6615+ },
6616+ },
6617+ {
6618+ ObjectMeta : metav1.ObjectMeta {
6619+ Name : fmt .Sprintf (clusterNameTemplate , 5 ),
6620+ },
6621+ },
6622+ {
6623+ ObjectMeta : metav1.ObjectMeta {
6624+ Name : fmt .Sprintf (clusterNameTemplate , 6 ),
6625+ },
6626+ },
6627+ {
6628+ ObjectMeta : metav1.ObjectMeta {
6629+ Name : fmt .Sprintf (clusterNameTemplate , 7 ),
6630+ },
6631+ },
6632+ {
6633+ ObjectMeta : metav1.ObjectMeta {
6634+ Name : fmt .Sprintf (clusterNameTemplate , 8 ),
6635+ },
6636+ },
6637+ {
6638+ ObjectMeta : metav1.ObjectMeta {
6639+ Name : fmt .Sprintf (clusterNameTemplate , 9 ),
6640+ },
6641+ },
6642+ }
6643+ state := NewCycleState (clusters , nil , nil )
6644+ placementKey := queue .PlacementKey (crpName )
6645+ wantClusterUnschedulableReason := "ClusterUnschedulable"
6646+ policy := & placementv1beta1.ClusterSchedulingPolicySnapshot {
6647+ ObjectMeta : metav1.ObjectMeta {
6648+ Name : policyName ,
6649+ Annotations : map [string ]string {
6650+ placementv1beta1 .CRPGenerationAnnotation : "0" ,
6651+ },
6652+ },
6653+ Spec : placementv1beta1.SchedulingPolicySnapshotSpec {
6654+ Policy : & placementv1beta1.PlacementPolicy {
6655+ PlacementType : placementv1beta1 .PickAllPlacementType ,
6656+ Affinity : & placementv1beta1.Affinity {
6657+ ClusterAffinity : & placementv1beta1.ClusterAffinity {
6658+ RequiredDuringSchedulingIgnoredDuringExecution : & placementv1beta1.ClusterSelector {
6659+ ClusterSelectorTerms : []placementv1beta1.ClusterSelectorTerm {
6660+ {
6661+ LabelSelector : & metav1.LabelSelector {
6662+ MatchLabels : map [string ]string {
6663+ wantLabelKey : wantLabelValue ,
6664+ },
6665+ },
6666+ },
6667+ },
6668+ },
6669+ },
6670+ },
6671+ },
6672+ },
6673+ Status : placementv1beta1.SchedulingPolicySnapshotStatus {
6674+ Conditions : []metav1.Condition {
6675+ {
6676+ Type : string (placementv1beta1 .PolicySnapshotScheduled ),
6677+ Status : metav1 .ConditionTrue ,
6678+ Reason : FullyScheduledReason ,
6679+ Message : fmt .Sprintf (fullyScheduledMessage , 1 ),
6680+ },
6681+ },
6682+ ObservedCRPGeneration : 0 ,
6683+ ClusterDecisions : []placementv1beta1.ClusterDecision {
6684+ {
6685+ ClusterName : fmt .Sprintf (clusterNameTemplate , 1 ),
6686+ Reason : wantClusterUnschedulableReason ,
6687+ },
6688+ {
6689+ ClusterName : fmt .Sprintf (clusterNameTemplate , 2 ),
6690+ Reason : wantClusterUnschedulableReason ,
6691+ },
6692+ {
6693+ ClusterName : fmt .Sprintf (clusterNameTemplate , 3 ),
6694+ Reason : wantClusterUnschedulableReason ,
6695+ },
6696+ },
6697+ },
6698+ }
6699+
6700+ // Simulate 100 consecutive scheduling cycles.
6701+ for i := 0 ; i < 100 ; i ++ {
6702+ _ , err := f .runSchedulingCycleForPickAllPlacementType (ctx , state , placementKey , policy , clusters , nil , nil , nil , nil )
6703+ if err != nil {
6704+ t .Fatalf ("runSchedulingCycleForPickAllPlacementType() = %v, want no error" , err )
6705+ }
6706+ }
6707+
6708+ // Check if any status update was attempted; all should be skipped as there is no status change.
6709+ if mockClientStatusUpdateCount .Load () != 0 {
6710+ t .Errorf ("runSchedulingCycleForPickAllPlacementType() status update attempt count = %d, want 0" , mockClientStatusUpdateCount .Load ())
6711+ }
6712+ }
0 commit comments