@@ -958,3 +958,53 @@ func Test_updateQueueAttrShare(t *testing.T) {
958958 })
959959 }
960960}
961+
962+ func TestPreemptiveFn_RespectsCapability (t * testing.T ) {
963+ // Queue has deserved and capability both {cpu: 8, mem: 100Gi}, allocated {cpu: 7, mem: 90Gi}.
964+ // A task requesting {cpu: 2, mem: 5Gi} would keep memory below deserved but push CPU above capability.
965+ // preemptiveFn should reject preemption in this case.
966+
967+ deserved := api .NewResource (api .BuildResourceList ("8" , "100Gi" ))
968+ allocated := api .NewResource (api .BuildResourceList ("7" , "90Gi" ))
969+ capability := api .NewResource (api .BuildResourceList ("8" , "100Gi" ))
970+
971+ attr := & queueAttr {
972+ queueID : "q-test" ,
973+ name : "q-test" ,
974+ deserved : deserved ,
975+ allocated : allocated ,
976+ capability : capability ,
977+ realCapability : capability .Clone (),
978+ }
979+
980+ taskRes := api .NewResource (api .BuildResourceList ("2" , "5Gi" ))
981+ task := & api.TaskInfo {
982+ Resreq : taskRes ,
983+ InitResreq : taskRes ,
984+ }
985+
986+ queue := & api.QueueInfo {
987+ UID : "q-test" ,
988+ Name : "q-test" ,
989+ }
990+
991+ futureUsed := attr .allocated .Clone ().Add (task .Resreq )
992+ if allocatable , _ := futureUsed .LessEqualWithDimensionAndResourcesName (attr .realCapability , task .Resreq ); allocatable {
993+ t .Fatalf ("precondition error: futureUsed %v should exceed capability %v" , futureUsed , attr .realCapability )
994+ }
995+
996+ // Simulate the logic in preemptiveFn after our fix: first capability, then deserved.
997+ allocatable , _ := futureUsed .LessEqualWithDimensionAndResourcesName (attr .realCapability , task .Resreq )
998+ if allocatable {
999+ t .Fatalf ("expected allocatable=false when futureUsed exceeds capability, got true" )
1000+ }
1001+
1002+ // For completeness, check that even though memory is below deserved, we still don't allow reclaim
1003+ // because capability check fails.
1004+ isPreemptive , _ := futureUsed .LessEqualPartlyWithDimensionZeroFiltered (attr .deserved , task .Resreq )
1005+ if isPreemptive {
1006+ t .Logf ("deserved check alone would allow reclaim, but capability check must block it" )
1007+ }
1008+
1009+ _ = queue // queue is only needed to mirror function signature; logic above is independent of it.
1010+ }
0 commit comments