@@ -683,6 +683,127 @@ func TestValidateRayClusterSpecAutoscaler(t *testing.T) {
683683 }
684684}
685685
686+ func TestValidateRayClusterSpec_ResourcesAndLabels (t * testing.T ) {
687+ // Util function to create a RayCluster spec.
688+ createSpec := func () rayv1.RayClusterSpec {
689+ return rayv1.RayClusterSpec {
690+ HeadGroupSpec : rayv1.HeadGroupSpec {
691+ Template : podTemplateSpec (nil , nil ),
692+ },
693+ WorkerGroupSpecs : []rayv1.WorkerGroupSpec {
694+ {
695+ GroupName : "worker-group" ,
696+ Template : podTemplateSpec (nil , nil ),
697+ },
698+ },
699+ }
700+ }
701+
702+ tests := []struct {
703+ name string
704+ errorMessage string
705+ spec rayv1.RayClusterSpec
706+ expectError bool
707+ }{
708+ {
709+ name : "Invalid: Head group has resources in both rayStartParams and top-level Resources" ,
710+ spec : func () rayv1.RayClusterSpec {
711+ s := createSpec ()
712+ s .HeadGroupSpec .RayStartParams = map [string ]string {"num-cpus" : "1" }
713+ s .HeadGroupSpec .Resources = map [string ]string {"CPU" : "1" }
714+ return s
715+ }(),
716+ expectError : true ,
717+ errorMessage : "resource fields should not be set in both rayStartParams and Resources for Head group. Please use only one" ,
718+ },
719+ {
720+ name : "Invalid: Worker group has resources in both rayStartParams and .Resources" ,
721+ spec : func () rayv1.RayClusterSpec {
722+ s := createSpec ()
723+ s .WorkerGroupSpecs [0 ].RayStartParams = map [string ]string {"num-gpus" : "1" }
724+ s .WorkerGroupSpecs [0 ].Resources = map [string ]string {"GPU" : "1" }
725+ return s
726+ }(),
727+ expectError : true ,
728+ errorMessage : "resource fields should not be set in both rayStartParams and Resources for worker-group group. Please use only one" ,
729+ },
730+ {
731+ name : "Valid: Only rayStartParams resources are set for head" ,
732+ spec : func () rayv1.RayClusterSpec {
733+ s := createSpec ()
734+ s .HeadGroupSpec .RayStartParams = map [string ]string {
735+ "num-cpus" : "2" ,
736+ "memory" : "4G" ,
737+ "resources" : "{\" TPU\" : \" 8\" }" ,
738+ }
739+ return s
740+ }(),
741+ expectError : false ,
742+ },
743+ {
744+ name : "Valid: Only .Resources field is set for worker" ,
745+ spec : func () rayv1.RayClusterSpec {
746+ s := createSpec ()
747+ s .WorkerGroupSpecs [0 ].Resources = map [string ]string {"CPU" : "2" , "memory" : "4G" , "TPU" : "8" }
748+ return s
749+ }(),
750+ expectError : false ,
751+ },
752+ {
753+ name : "Invalid: Head group has 'labels' in rayStartParams" ,
754+ spec : func () rayv1.RayClusterSpec {
755+ s := createSpec ()
756+ s .HeadGroupSpec .RayStartParams = map [string ]string {"labels" : "ray.io/node-group=worker-group-1" }
757+ return s
758+ }(),
759+ expectError : true ,
760+ errorMessage : "rayStartParams['labels'] is not supported for Head group. Please use the top-level Labels field instead" ,
761+ },
762+ {
763+ name : "Invalid: Worker group has 'labels' in rayStartParams" ,
764+ spec : func () rayv1.RayClusterSpec {
765+ s := createSpec ()
766+ s .WorkerGroupSpecs [0 ].RayStartParams = map [string ]string {"labels" : "ray.io/node-group=worker-group-1" }
767+ return s
768+ }(),
769+ expectError : true ,
770+ errorMessage : "rayStartParams['labels'] is not supported for worker-group group. Please use the top-level Labels field instead" ,
771+ },
772+ {
773+ name : "Valid: Only .Labels field is set" ,
774+ spec : func () rayv1.RayClusterSpec {
775+ s := createSpec ()
776+ s .HeadGroupSpec .Labels = map [string ]string {"ray.io/market-type" : "on-demand" }
777+ s .WorkerGroupSpecs [0 ].Labels = map [string ]string {"ray.io/accelerator-type" : "TPU-V6E" }
778+ return s
779+ }(),
780+ expectError : false ,
781+ },
782+ {
783+ name : "Invalid: .Labels field values contain commas" ,
784+ spec : func () rayv1.RayClusterSpec {
785+ s := createSpec ()
786+ s .HeadGroupSpec .Labels = map [string ]string {"invalid,labels,with,commas" : "value" }
787+ return s
788+ }(),
789+ expectError : true ,
790+ errorMessage : "label key for Head group cannot contain commas, but found: 'invalid,labels,with,commas'" ,
791+ },
792+ }
793+
794+ for _ , tt := range tests {
795+ t .Run (tt .name , func (t * testing.T ) {
796+ err := ValidateRayClusterSpec (& tt .spec , nil )
797+ if tt .expectError {
798+ require .Error (t , err )
799+ assert .EqualError (t , err , tt .errorMessage )
800+ } else {
801+ require .NoError (t , err )
802+ }
803+ })
804+ }
805+ }
806+
686807func TestValidateRayJobStatus (t * testing.T ) {
687808 tests := []struct {
688809 name string
0 commit comments