@@ -931,10 +931,198 @@ func TestDeployParam(t *testing.T) {
931931 assert .Equal (t , "5" , appInstance .Status .AppSpec .Containers ["foo" ].Environment [0 ].Value )
932932}
933933
934+ func TestRequireComputeClass (t * testing.T ) {
935+ ctx := helper .GetCTX (t )
936+
937+ helper .StartController (t )
938+ c , _ := helper .ClientAndProject (t )
939+ kc := helper .MustReturn (kclient .Default )
940+
941+ helper .SetRequireComputeClassWithRestore (ctx , t , kc )
942+
943+ checks := []struct {
944+ name string
945+ noComputeClass bool
946+ testDataDirectory string
947+ computeClass adminv1.ProjectComputeClassInstance
948+ expected map [string ]v1.Scheduling
949+ waitFor func (obj * v1.AppInstance ) bool
950+ fail bool
951+ failMessage string
952+ }{
953+ {
954+ name : "no-computeclass" ,
955+ noComputeClass : true ,
956+ testDataDirectory : "./testdata/simple" ,
957+ fail : true ,
958+ failMessage : "compute class required but none configured" ,
959+ },
960+ {
961+ name : "valid" ,
962+ testDataDirectory : "./testdata/computeclass" ,
963+ computeClass : adminv1.ProjectComputeClassInstance {
964+ ObjectMeta : metav1.ObjectMeta {
965+ Name : "acorn-test-custom" ,
966+ Namespace : c .GetNamespace (),
967+ },
968+ CPUScaler : 0.25 ,
969+ Memory : adminv1.ComputeClassMemory {
970+ Min : "512Mi" ,
971+ Max : "1Gi" ,
972+ },
973+ Resources : & corev1.ResourceRequirements {
974+ Limits : corev1.ResourceList {
975+ "mygpu/nvidia" : resource .MustParse ("1" ),
976+ }, Requests : corev1.ResourceList {
977+ "mygpu/nvidia" : resource .MustParse ("1" ),
978+ }},
979+ SupportedRegions : []string {apiv1 .LocalRegion },
980+ },
981+ expected : map [string ]v1.Scheduling {"simple" : {
982+ Requirements : corev1.ResourceRequirements {
983+ Limits : corev1.ResourceList {
984+ corev1 .ResourceMemory : resource .MustParse ("1Gi" ),
985+ "mygpu/nvidia" : resource .MustParse ("1" ),
986+ },
987+ Requests : corev1.ResourceList {
988+ corev1 .ResourceMemory : resource .MustParse ("1Gi" ),
989+ corev1 .ResourceCPU : resource .MustParse ("250m" ),
990+ "mygpu/nvidia" : resource .MustParse ("1" ),
991+ },
992+ },
993+ Tolerations : []corev1.Toleration {
994+ {
995+ Key : tolerations .WorkloadTolerationKey ,
996+ Operator : corev1 .TolerationOpExists ,
997+ },
998+ }},
999+ },
1000+ waitFor : func (obj * v1.AppInstance ) bool {
1001+ return obj .Status .Condition (v1 .AppInstanceConditionParsed ).Success &&
1002+ obj .Status .Condition (v1 .AppInstanceConditionScheduling ).Success
1003+ },
1004+ },
1005+ {
1006+ name : "default" ,
1007+ testDataDirectory : "./testdata/simple" ,
1008+ computeClass : adminv1.ProjectComputeClassInstance {
1009+ ObjectMeta : metav1.ObjectMeta {
1010+ Name : "acorn-test-custom" ,
1011+ Namespace : c .GetNamespace (),
1012+ },
1013+ Default : true ,
1014+ CPUScaler : 0.25 ,
1015+ Memory : adminv1.ComputeClassMemory {
1016+ Default : "512Mi" ,
1017+ Max : "1Gi" ,
1018+ Min : "512Mi" ,
1019+ },
1020+ SupportedRegions : []string {apiv1 .LocalRegion },
1021+ },
1022+ expected : map [string ]v1.Scheduling {"simple" : {
1023+ Requirements : corev1.ResourceRequirements {
1024+ Limits : corev1.ResourceList {
1025+ corev1 .ResourceMemory : resource .MustParse ("512Mi" )},
1026+ Requests : corev1.ResourceList {
1027+ corev1 .ResourceMemory : resource .MustParse ("512Mi" ),
1028+ corev1 .ResourceCPU : resource .MustParse ("125m" ),
1029+ },
1030+ },
1031+ Tolerations : []corev1.Toleration {
1032+ {
1033+ Key : tolerations .WorkloadTolerationKey ,
1034+ Operator : corev1 .TolerationOpExists ,
1035+ },
1036+ }},
1037+ },
1038+ waitFor : func (obj * v1.AppInstance ) bool {
1039+ return obj .Status .Condition (v1 .AppInstanceConditionParsed ).Success &&
1040+ obj .Status .Condition (v1 .AppInstanceConditionScheduling ).Success
1041+ },
1042+ },
1043+ }
1044+
1045+ for _ , tt := range checks {
1046+ asClusterComputeClass := adminv1 .ClusterComputeClassInstance (tt .computeClass )
1047+ // Perform the same test cases on both Project and Cluster ComputeClasses
1048+ for kind , computeClass := range map [string ]crClient.Object {"projectcomputeclass" : & tt .computeClass , "clustercomputeclass" : & asClusterComputeClass } {
1049+ testcase := fmt .Sprintf ("%v-%v" , kind , tt .name )
1050+ t .Run (testcase , func (t * testing.T ) {
1051+ if ! tt .noComputeClass {
1052+ if err := kc .Create (ctx , computeClass ); err != nil {
1053+ t .Fatal (err )
1054+ }
1055+
1056+ // Clean-up and gurantee the computeclass doesn't exist after this test run
1057+ t .Cleanup (func () {
1058+ if err := kc .Delete (context .Background (), computeClass ); err != nil && ! apierrors .IsNotFound (err ) {
1059+ t .Fatal (err )
1060+ }
1061+ err := helper .EnsureDoesNotExist (ctx , func () (crClient.Object , error ) {
1062+ lookingFor := computeClass
1063+ err := kc .Get (ctx , router .Key (computeClass .GetNamespace (), computeClass .GetName ()), lookingFor )
1064+ return lookingFor , err
1065+ })
1066+ if err != nil {
1067+ t .Fatal (err )
1068+ }
1069+ })
1070+ }
1071+
1072+ image , err := c .AcornImageBuild (ctx , tt .testDataDirectory + "/Acornfile" , & client.AcornImageBuildOptions {
1073+ Cwd : tt .testDataDirectory ,
1074+ })
1075+ if err != nil {
1076+ t .Fatal (err )
1077+ }
1078+
1079+ // Assign a name for the test case so no collisions occur
1080+ app , err := c .AppRun (ctx , image .ID , & client.AppRunOptions {Name : testcase })
1081+ if err == nil && tt .fail {
1082+ t .Fatal ("expected error, got nil" )
1083+ } else if err != nil {
1084+ if ! tt .fail {
1085+ t .Fatal (err )
1086+ }
1087+ assert .Contains (t , err .Error (), tt .failMessage )
1088+ }
1089+
1090+ // Clean-up and gurantee the app doesn't exist after this test run
1091+ if app != nil {
1092+ t .Cleanup (func () {
1093+ if err = kc .Delete (context .Background (), app ); err != nil && ! apierrors .IsNotFound (err ) {
1094+ t .Fatal (err )
1095+ }
1096+ err := helper .EnsureDoesNotExist (ctx , func () (crClient.Object , error ) {
1097+ lookingFor := app
1098+ err := kc .Get (ctx , router .Key (app .GetName (), app .GetNamespace ()), lookingFor )
1099+ return lookingFor , err
1100+ })
1101+ if err != nil {
1102+ t .Fatal (err )
1103+ }
1104+ })
1105+ }
1106+
1107+ if tt .waitFor != nil {
1108+ appInstance := & v1.AppInstance {
1109+ ObjectMeta : metav1.ObjectMeta {
1110+ Name : app .Name ,
1111+ Namespace : app .Namespace ,
1112+ },
1113+ }
1114+ appInstance = helper .WaitForObject (t , kc .Watch , new (v1.AppInstanceList ), appInstance , tt .waitFor )
1115+ assert .EqualValues (t , appInstance .Status .Scheduling , tt .expected , "generated scheduling rules are incorrect" )
1116+ }
1117+ })
1118+ }
1119+ }
1120+ }
1121+
9341122func TestUsingComputeClasses (t * testing.T ) {
9351123 helper .StartController (t )
9361124 c , _ := helper .ClientAndProject (t )
937- kclient := helper .MustReturn (kclient .Default )
1125+ kc := helper .MustReturn (kclient .Default )
9381126
9391127 ctx := helper .GetCTX (t )
9401128
@@ -1149,6 +1337,24 @@ func TestUsingComputeClasses(t *testing.T) {
11491337 },
11501338 fail : true ,
11511339 },
1340+ {
1341+ name : "no-region" ,
1342+ testDataDirectory : "./testdata/computeclass" ,
1343+ computeClass : adminv1.ProjectComputeClassInstance {
1344+ ObjectMeta : metav1.ObjectMeta {
1345+ Name : "acorn-test-custom" ,
1346+ Namespace : c .GetNamespace (),
1347+ },
1348+ Default : true ,
1349+ CPUScaler : 0.25 ,
1350+ Memory : adminv1.ComputeClassMemory {
1351+ Default : "512Mi" ,
1352+ Max : "1Gi" ,
1353+ Min : "512Mi" ,
1354+ },
1355+ },
1356+ fail : true ,
1357+ },
11521358 {
11531359 name : "does-not-exist" ,
11541360 noComputeClass : true ,
@@ -1164,18 +1370,18 @@ func TestUsingComputeClasses(t *testing.T) {
11641370 testcase := fmt .Sprintf ("%v-%v" , kind , tt .name )
11651371 t .Run (testcase , func (t * testing.T ) {
11661372 if ! tt .noComputeClass {
1167- if err := kclient .Create (ctx , computeClass ); err != nil {
1373+ if err := kc .Create (ctx , computeClass ); err != nil {
11681374 t .Fatal (err )
11691375 }
11701376
11711377 // Clean-up and gurantee the computeclass doesn't exist after this test run
11721378 t .Cleanup (func () {
1173- if err := kclient .Delete (context .Background (), computeClass ); err != nil && ! apierrors .IsNotFound (err ) {
1379+ if err := kc .Delete (context .Background (), computeClass ); err != nil && ! apierrors .IsNotFound (err ) {
11741380 t .Fatal (err )
11751381 }
11761382 err := helper .EnsureDoesNotExist (ctx , func () (crClient.Object , error ) {
11771383 lookingFor := computeClass
1178- err := kclient .Get (ctx , router .Key (computeClass .GetNamespace (), computeClass .GetName ()), lookingFor )
1384+ err := kc .Get (ctx , router .Key (computeClass .GetNamespace (), computeClass .GetName ()), lookingFor )
11791385 return lookingFor , err
11801386 })
11811387 if err != nil {
@@ -1204,12 +1410,12 @@ func TestUsingComputeClasses(t *testing.T) {
12041410 // Clean-up and gurantee the app doesn't exist after this test run
12051411 if app != nil {
12061412 t .Cleanup (func () {
1207- if err = kclient .Delete (context .Background (), app ); err != nil && ! apierrors .IsNotFound (err ) {
1413+ if err = kc .Delete (context .Background (), app ); err != nil && ! apierrors .IsNotFound (err ) {
12081414 t .Fatal (err )
12091415 }
12101416 err := helper .EnsureDoesNotExist (ctx , func () (crClient.Object , error ) {
12111417 lookingFor := app
1212- err := kclient .Get (ctx , router .Key (app .GetName (), app .GetNamespace ()), lookingFor )
1418+ err := kc .Get (ctx , router .Key (app .GetName (), app .GetNamespace ()), lookingFor )
12131419 return lookingFor , err
12141420 })
12151421 if err != nil {
@@ -1225,7 +1431,7 @@ func TestUsingComputeClasses(t *testing.T) {
12251431 Namespace : app .Namespace ,
12261432 },
12271433 }
1228- appInstance = helper .WaitForObject (t , kclient .Watch , new (v1.AppInstanceList ), appInstance , tt .waitFor )
1434+ appInstance = helper .WaitForObject (t , kc .Watch , new (v1.AppInstanceList ), appInstance , tt .waitFor )
12291435 assert .EqualValues (t , appInstance .Status .Scheduling , tt .expected , "generated scheduling rules are incorrect" )
12301436 }
12311437 })
@@ -1288,11 +1494,11 @@ func TestAppWithBadDefaultRegion(t *testing.T) {
12881494 helper .StartController (t )
12891495
12901496 ctx := helper .GetCTX (t )
1291- kclient := helper .MustReturn (kclient .Default )
1497+ kc := helper .MustReturn (kclient .Default )
12921498 c , project := helper .ClientAndProject (t )
12931499
12941500 storageClasses := new (storagev1.StorageClassList )
1295- err := kclient .List (ctx , storageClasses )
1501+ err := kc .List (ctx , storageClasses )
12961502 if err != nil || len (storageClasses .Items ) == 0 {
12971503 t .Skip ("No storage classes, so skipping TestAppWithBadDefaultRegion" )
12981504 return
@@ -1307,11 +1513,11 @@ func TestAppWithBadDefaultRegion(t *testing.T) {
13071513 Default : true ,
13081514 SupportedRegions : []string {"custom" },
13091515 }
1310- if err = kclient .Create (ctx , & volumeClass ); err != nil {
1516+ if err = kc .Create (ctx , & volumeClass ); err != nil {
13111517 t .Fatal (err )
13121518 }
13131519 defer func () {
1314- if err = kclient .Delete (context .Background (), & volumeClass ); err != nil && ! apierrors .IsNotFound (err ) {
1520+ if err = kc .Delete (context .Background (), & volumeClass ); err != nil && ! apierrors .IsNotFound (err ) {
13151521 t .Fatal (err )
13161522 }
13171523 }()
@@ -1629,8 +1835,8 @@ func TestEnforcedQuota(t *testing.T) {
16291835 t .Fatal ("error while getting rest config:" , err )
16301836 }
16311837 // Create a project.
1632- kclient := helper .MustReturn (kclient .Default )
1633- project := helper .TempProject (t , kclient )
1838+ kc := helper .MustReturn (kclient .Default )
1839+ project := helper .TempProject (t , kc )
16341840
16351841 // Create a client for the project.
16361842 c , err := client .New (restConfig , project .Name , project .Name )
@@ -1644,7 +1850,7 @@ func TestEnforcedQuota(t *testing.T) {
16441850 obj .Annotations = make (map [string ]string )
16451851 }
16461852 obj .Annotations [labels .ProjectEnforcedQuotaAnnotation ] = "true"
1647- return kclient .Update (ctx , obj ) == nil
1853+ return kc .Update (ctx , obj ) == nil
16481854 })
16491855
16501856 // Run a scaled app.
@@ -1673,7 +1879,7 @@ func TestEnforcedQuota(t *testing.T) {
16731879
16741880 // Grab the app's QuotaRequest and check that it has the appropriate values set.
16751881 quotaRequest := & adminv1.QuotaRequestInstance {}
1676- err = kclient .Get (ctx , router .Key (app .Namespace , app .Name ), quotaRequest )
1882+ err = kc .Get (ctx , router .Key (app .Namespace , app .Name ), quotaRequest )
16771883 if err != nil {
16781884 t .Fatal (err )
16791885 }
@@ -1690,7 +1896,7 @@ func TestEnforcedQuota(t *testing.T) {
16901896 }},
16911897 AllocatedResources : quotaRequest .Spec .Resources ,
16921898 }
1693- err = kclient .Status ().Update (ctx , quotaRequest )
1899+ err = kc .Status ().Update (ctx , quotaRequest )
16941900 if err != nil {
16951901 t .Fatal (err )
16961902 }
@@ -1709,8 +1915,8 @@ func TestAutoUpgradeImageValidation(t *testing.T) {
17091915 if err != nil {
17101916 t .Fatal ("error while getting rest config:" , err )
17111917 }
1712- kclient := helper .MustReturn (kclient .Default )
1713- project := helper .TempProject (t , kclient )
1918+ kc := helper .MustReturn (kclient .Default )
1919+ project := helper .TempProject (t , kc )
17141920
17151921 c , err := client .New (restConfig , project .Name , project .Name )
17161922 if err != nil {
0 commit comments