@@ -511,6 +511,50 @@ func TestGetPodGroupMetadata_Segments_5Workers_2PerSegment(t *testing.T) {
511511 assert .Equal (t , "test-job-worker-4" , workerSegment2 .PodsReferences [0 ])
512512}
513513
514+ func TestGetPodGroupMetadata_Segments_ElasticMinReplicas (t * testing.T ) {
515+ // 1 master + 8 workers, minReplicas=5, segment size 2 → 4 segments, 2 mandatory
516+ pytorchJob := getPytorchJobWithSegments (1 , 8 , "2" )
517+ err := unstructured .SetNestedField (pytorchJob .Object , int64 (5 ), "spec" , "elasticPolicy" , "minReplicas" )
518+ assert .Nil (t , err )
519+ grouper := newTestPyTorchGrouper ()
520+
521+ workerPod := & v1.Pod {
522+ ObjectMeta : metav1.ObjectMeta {
523+ Name : "test-job-worker-0" ,
524+ Namespace : "test_namespace" ,
525+ Labels : map [string ]string {
526+ replicaTypeLabel : "worker" ,
527+ "training.kubeflow.org/replica-index" : "0" ,
528+ },
529+ Annotations : map [string ]string {
530+ "kai.scheduler/segment-size" : "2" ,
531+ },
532+ },
533+ }
534+
535+ metadata , err := grouper .GetPodGroupMetadata (pytorchJob , workerPod )
536+ assert .Nil (t , err )
537+ assert .Equal (t , int32 (5 ), metadata .MinAvailable )
538+
539+ workerParent := findSubGroupByName (metadata .SubGroups , strings .ToLower (replicaTypeWorker ))
540+ assert .NotNil (t , workerParent )
541+ assert .Equal (t , ptr .To (int32 (4 )), workerParent .MinSubGroup )
542+
543+ for _ , tc := range []struct {
544+ name string
545+ minAvailable int32
546+ }{
547+ {"worker-0" , 2 },
548+ {"worker-1" , 2 },
549+ {"worker-2" , 0 },
550+ {"worker-3" , 0 },
551+ } {
552+ sg := findSubGroupByName (metadata .SubGroups , tc .name )
553+ assert .NotNil (t , sg , "segment %s not found" , tc .name )
554+ assert .Equal (t , tc .minAvailable , sg .MinAvailable , "segment %s MinAvailable" , tc .name )
555+ }
556+ }
557+
514558func TestGetPodGroupMetadata_Segments_MalformedAnnotation (t * testing.T ) {
515559 pytorchJob := getPytorchJobWithSegments (1 , 4 , "invalid" )
516560 grouper := newTestPyTorchGrouper ()
0 commit comments