@@ -25,6 +25,7 @@ import (
2525
2626 "github.com/eapache/go-resiliency/retrier"
2727 "github.com/project-codeflare/multi-cluster-app-dispatcher/pkg/quotaplugins/quota-forest/quota-manager/quota"
28+ "github.com/project-codeflare/multi-cluster-app-dispatcher/pkg/quotaplugins/quota-forest/quota-manager/quota/core"
2829 "github.com/project-codeflare/multi-cluster-app-dispatcher/pkg/quotaplugins/quota-forest/quota-manager/quota/utils"
2930 "github.com/stretchr/testify/assert"
3031 "k8s.io/utils/strings/slices"
@@ -662,6 +663,158 @@ func TestAddRemoveConsumers(t *testing.T) {
662663 assert .Error (t , err , "Expecting error when removing a non-existing consumer" )
663664}
664665
666+ // TestPreemptSamePriorityAtRoot : test preemption of same priority borrowing consumer at root
667+ func TestPreemptSamePriorityAtRoot (t * testing.T ) {
668+
669+ var treeString string = `{
670+ "kind": "QuotaTree",
671+ "metadata": {
672+ "name": "tree"
673+ },
674+ "spec": {
675+ "resourceNames": [
676+ "gpu"
677+ ],
678+ "nodes": {
679+ "T": {
680+ "parent": "nil",
681+ "hard": "true",
682+ "quota": {
683+ "gpu": "32"
684+ }
685+ },
686+ "M": {
687+ "parent": "T",
688+ "quota": {
689+ "gpu": "16"
690+ }
691+ },
692+ "N": {
693+ "parent": "T",
694+ "quota": {
695+ "gpu": "16"
696+ }
697+ },
698+ "A": {
699+ "parent": "M",
700+ "quota": {
701+ "gpu": "8"
702+ }
703+ },
704+ "B": {
705+ "parent": "M",
706+ "quota": {
707+ "gpu": "8"
708+ }
709+ },
710+ "C": {
711+ "parent": "N",
712+ "quota": {
713+ "gpu": "8"
714+ }
715+ },
716+ "D": {
717+ "parent": "N",
718+ "quota": {
719+ "gpu": "8"
720+ }
721+ }
722+ }
723+ }
724+ }`
725+
726+ var job1String string = `{
727+ "kind": "Consumer",
728+ "metadata": {
729+ "name": "job-1"
730+ },
731+ "spec": {
732+ "id": "job-1",
733+ "trees": [
734+ {
735+ "treeName": "tree",
736+ "groupID": "A",
737+ "request": {
738+ "gpu": 24
739+ }
740+ }
741+ ]
742+ }
743+ }`
744+
745+ var job2String string = `{
746+ "kind": "Consumer",
747+ "metadata": {
748+ "name": "job-2"
749+ },
750+ "spec": {
751+ "id": "job-2",
752+ "trees": [
753+ {
754+ "treeName": "tree",
755+ "groupID": "C",
756+ "request": {
757+ "gpu": 8
758+ }
759+ }
760+ ]
761+ }
762+ }`
763+
764+ var job3String string = `{
765+ "kind": "Consumer",
766+ "metadata": {
767+ "name": "job-3"
768+ },
769+ "spec": {
770+ "id": "job-3",
771+ "trees": [
772+ {
773+ "treeName": "tree",
774+ "groupID": "B",
775+ "request": {
776+ "gpu": 1
777+ }
778+ }
779+ ]
780+ }
781+ }`
782+
783+ // create a test quota manager
784+ qmTest := quota .NewManager ()
785+ assert .NotNil (t , qmTest , "Expecting no error creating a quota manager" )
786+ modeSet := qmTest .SetMode (quota .Normal )
787+ assert .True (t , modeSet , "Expecting no error setting mode to normal" )
788+
789+ // add quota tree
790+ treeName , err := qmTest .AddTreeFromString (treeString )
791+ assert .NoError (t , err , "No error expected when adding a tree" )
792+
793+ // create and add consumers
794+ consumerStrings := []string {job1String , job2String , job3String }
795+ numConsumers := len (consumerStrings )
796+ consumerID := make ([]string , numConsumers )
797+ var response * core.AllocationResponse
798+ for i , consumerString := range consumerStrings {
799+ consumerInfo , err := quota .NewConsumerInfoFromString (consumerString )
800+ assert .NoError (t , err , "No error expected when creating a consumer info" )
801+ consumerID [i ] = consumerInfo .GetID ()
802+ added , err := qmTest .AddConsumer (consumerInfo )
803+ assert .True (t , added && err == nil , "Expecting consumer to be added to quota manager" )
804+ response , err = qmTest .Allocate (treeName , consumerID [i ])
805+ assert .NoError (t , err , "No Error expected when allocating consumer %s to tree, err %v, got %v" ,
806+ consumerID [i ], err , qmTest .GetTreeController (treeName ))
807+ }
808+
809+ // check expected results after last allocation
810+ assert .NotNil (t , response , "A non nill response is expected" )
811+ assert .True (t , response .IsAllocated (), "Allocating consumer %s should succeed" , consumerID [numConsumers - 1 ])
812+ assert .Contains (t , response .GetPreemptedIds (), consumerID [0 ],
813+ "Expecting consumer %s to be preempted" , consumerID [0 ])
814+ assert .Contains (t , qmTest .GetTreeController (treeName ).GetConsumerIDs (), consumerID [1 ],
815+ "Expecting consumer %s to remain allocated" , consumerID [1 ])
816+ }
817+
665818type AllocationClassifier struct {
666819}
667820
0 commit comments