Skip to content

Commit 14fc2ea

Browse files
author
Arvind Thirumurugan
committed
add UTs for maxConcurrency calculation
Signed-off-by: Arvind Thirumurugan <[email protected]>
1 parent 7a2f582 commit 14fc2ea

File tree

2 files changed

+122
-2
lines changed

2 files changed

+122
-2
lines changed

pkg/controllers/updaterun/execution.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ func (r *Reconciler) execute(
7070

7171
updateRunStatus := updateRun.GetUpdateRunStatus()
7272
if updatingStageIndex < len(updateRunStatus.StagesStatus) {
73-
// Round down the maxConcurrency to the number of clusters in the stage.
74-
maxConcurrency, err := intstr.GetScaledValueFromIntOrPercent(updateRunStatus.UpdateStrategySnapshot.Stages[updatingStageIndex].MaxConcurrency, len(updateRunStatus.StagesStatus[updatingStageIndex].Clusters), false)
73+
maxConcurrency, err := calculateMaxConcurrencyValue(updateRunStatus, updatingStageIndex)
7574
if err != nil {
7675
return false, 0, err
7776
}
@@ -467,6 +466,22 @@ func (r *Reconciler) updateApprovalRequestAccepted(ctx context.Context, appReq p
467466
return nil
468467
}
469468

469+
// calculateMaxConcurrencyValue calculates the actual max concurrency value for a stage.
470+
// It converts the IntOrString maxConcurrency (which can be an integer or percentage) to an integer value
471+
// based on the total number of clusters in the stage. The value is rounded down.
472+
func calculateMaxConcurrencyValue(status *placementv1beta1.UpdateRunStatus, stageIndex int) (int, error) {
473+
specifiedMaxConcurrency := status.UpdateStrategySnapshot.Stages[stageIndex].MaxConcurrency
474+
clusterCount := len(status.StagesStatus[stageIndex].Clusters)
475+
// Round down the maxConcurrency to the number of clusters in the stage.
476+
maxConcurrencyValue, err := intstr.GetScaledValueFromIntOrPercent(specifiedMaxConcurrency, clusterCount, false)
477+
if err != nil {
478+
return 0, err
479+
}
480+
return maxConcurrencyValue, nil
481+
}
482+
483+
// aggregateUpdateRunStatus aggregates the status of the update run based on the cluster update status.
484+
// It marks the update run as stuck if any clusters are stuck, or as progressing if some clusters have finished updating.
470485
func aggregateUpdateRunStatus(updateRun placementv1beta1.UpdateRunObj, stageName string, stuckClusterNames []string, finishedClusterCount int) {
471486
if len(stuckClusterNames) > 0 {
472487
markUpdateRunStuck(updateRun, stageName, strings.Join(stuckClusterNames, ", "))

pkg/controllers/updaterun/execution_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,3 +817,108 @@ func TestExecuteUpdatingStage_Error(t *testing.T) {
817817
})
818818
}
819819
}
820+
821+
func TestCalculateMaxConcurrencyValue(t *testing.T) {
822+
tests := []struct {
823+
name string
824+
maxConcurrency *intstr.IntOrString
825+
clusterCount int
826+
wantValue int
827+
wantErr bool
828+
}{
829+
{
830+
name: "integer value - less than cluster count",
831+
maxConcurrency: &intstr.IntOrString{Type: intstr.Int, IntVal: 3},
832+
clusterCount: 10,
833+
wantValue: 3,
834+
wantErr: false,
835+
},
836+
{
837+
name: "integer value - equal to cluster count",
838+
maxConcurrency: &intstr.IntOrString{Type: intstr.Int, IntVal: 10},
839+
clusterCount: 10,
840+
wantValue: 10,
841+
wantErr: false,
842+
},
843+
{
844+
name: "integer value - greater than cluster count",
845+
maxConcurrency: &intstr.IntOrString{Type: intstr.Int, IntVal: 15},
846+
clusterCount: 10,
847+
wantValue: 15,
848+
wantErr: false,
849+
},
850+
{
851+
name: "percentage value - 50%",
852+
maxConcurrency: &intstr.IntOrString{Type: intstr.String, StrVal: "50%"},
853+
clusterCount: 10,
854+
wantValue: 5,
855+
wantErr: false,
856+
},
857+
{
858+
name: "percentage value - 33% rounds down",
859+
maxConcurrency: &intstr.IntOrString{Type: intstr.String, StrVal: "33%"},
860+
clusterCount: 10,
861+
wantValue: 3,
862+
wantErr: false,
863+
},
864+
{
865+
name: "percentage value - 100%",
866+
maxConcurrency: &intstr.IntOrString{Type: intstr.String, StrVal: "100%"},
867+
clusterCount: 10,
868+
wantValue: 10,
869+
wantErr: false,
870+
},
871+
{
872+
name: "percentage value - 25% with 7 clusters",
873+
maxConcurrency: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"},
874+
clusterCount: 7,
875+
wantValue: 1,
876+
wantErr: false,
877+
},
878+
{
879+
name: "zero clusters",
880+
maxConcurrency: &intstr.IntOrString{Type: intstr.Int, IntVal: 3},
881+
clusterCount: 0,
882+
wantValue: 3,
883+
wantErr: false,
884+
},
885+
{
886+
name: "non-zero percentage with zero clusters",
887+
maxConcurrency: &intstr.IntOrString{Type: intstr.String, StrVal: "50%"},
888+
clusterCount: 0,
889+
wantValue: 0,
890+
wantErr: false,
891+
},
892+
}
893+
894+
for _, tt := range tests {
895+
t.Run(tt.name, func(t *testing.T) {
896+
status := &placementv1beta1.UpdateRunStatus{
897+
StagesStatus: []placementv1beta1.StageUpdatingStatus{
898+
{
899+
StageName: "test-stage",
900+
Clusters: make([]placementv1beta1.ClusterUpdatingStatus, tt.clusterCount),
901+
},
902+
},
903+
UpdateStrategySnapshot: &placementv1beta1.UpdateStrategySpec{
904+
Stages: []placementv1beta1.StageConfig{
905+
{
906+
Name: "test-stage",
907+
MaxConcurrency: tt.maxConcurrency,
908+
},
909+
},
910+
},
911+
}
912+
913+
gotValue, gotErr := calculateMaxConcurrencyValue(status, 0)
914+
915+
if (gotErr != nil) != tt.wantErr {
916+
t.Fatalf("calculateMaxConcurrencyValue() error = %v, wantErr %v", gotErr, tt.wantErr)
917+
}
918+
919+
if gotValue != tt.wantValue {
920+
t.Fatalf("calculateMaxConcurrencyValue() = %v, want %v", gotValue, tt.wantValue)
921+
}
922+
})
923+
}
924+
}

0 commit comments

Comments
 (0)