diff --git a/pkg/cache/clusterqueue_test.go b/pkg/cache/clusterqueue_test.go index 43fc91f5829..f86168b1505 100644 --- a/pkg/cache/clusterqueue_test.go +++ b/pkg/cache/clusterqueue_test.go @@ -98,206 +98,238 @@ func TestFitInCohort(t *testing.T) { cases := map[string]struct { request resources.FlavorResourceQuantitiesFlat wantFit bool - cq *ClusterQueueSnapshot + usage resources.FlavorResourceQuantitiesFlat + clusterQueue []*kueue.ClusterQueue enableLendingLimit bool }{ "full cohort, empty request": { request: resources.FlavorResourceQuantitiesFlat{}, wantFit: true, - cq: &ClusterQueueSnapshot{ - Name: "CQ", - Cohort: &CohortSnapshot{ - Name: "C", - RequestableResources: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f2", Resource: corev1.ResourceMemory}: 5, - }.Unflatten(), - Usage: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f2", Resource: corev1.ResourceMemory}: 5, - }.Unflatten(), - }, - ResourceGroups: nil, + usage: resources.FlavorResourceQuantitiesFlat{ + {Flavor: "f1", Resource: corev1.ResourceCPU}: 5_000, + {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, + {Flavor: "f2", Resource: corev1.ResourceCPU}: 5_000, + {Flavor: "f2", Resource: corev1.ResourceMemory}: 5, + }, + clusterQueue: []*kueue.ClusterQueue{ + utiltesting. + MakeClusterQueue("CQ"). + ResourceGroup( + *utiltesting.MakeFlavorQuotas("f1"). + Resource(corev1.ResourceCPU, "5"). + Resource(corev1.ResourceMemory, "5"). + Obj(), + *utiltesting.MakeFlavorQuotas("f2"). + Resource(corev1.ResourceCPU, "5"). + Resource(corev1.ResourceMemory, "5"). + Obj(), + ). + Cohort("C"). + Obj(), }, }, "can fit": { request: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f2", Resource: corev1.ResourceCPU}: 1, + {Flavor: "f2", Resource: corev1.ResourceCPU}: 1_000, {Flavor: "f2", Resource: corev1.ResourceMemory}: 1, }, wantFit: true, - cq: &ClusterQueueSnapshot{ - Name: "CQ", - Cohort: &CohortSnapshot{ - Name: "C", - RequestableResources: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f2", Resource: corev1.ResourceMemory}: 5, - }.Unflatten(), - Usage: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 4, - {Flavor: "f2", Resource: corev1.ResourceMemory}: 4, - }.Unflatten(), - }, - ResourceGroups: nil, + usage: resources.FlavorResourceQuantitiesFlat{ + {Flavor: "f1", Resource: corev1.ResourceCPU}: 5_000, + {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, + {Flavor: "f2", Resource: corev1.ResourceCPU}: 4_000, + {Flavor: "f2", Resource: corev1.ResourceMemory}: 4, + }, + clusterQueue: []*kueue.ClusterQueue{ + utiltesting. + MakeClusterQueue("CQ"). + ResourceGroup( + *utiltesting.MakeFlavorQuotas("f1"). + Resource(corev1.ResourceCPU, "5"). + Resource(corev1.ResourceMemory, "5"). + Obj(), + *utiltesting.MakeFlavorQuotas("f2"). + Resource(corev1.ResourceCPU, "5"). + Resource(corev1.ResourceMemory, "5"). + Obj(), + ). + Cohort("C"). + Obj(), }, }, "full cohort, none fit": { request: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 1, + {Flavor: "f1", Resource: corev1.ResourceCPU}: 1_000, {Flavor: "f1", Resource: corev1.ResourceMemory}: 1, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 1, + {Flavor: "f2", Resource: corev1.ResourceCPU}: 1_000, {Flavor: "f2", Resource: corev1.ResourceMemory}: 1, }, wantFit: false, - cq: &ClusterQueueSnapshot{ - Name: "CQ", - Cohort: &CohortSnapshot{ - Name: "C", - RequestableResources: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f2", Resource: corev1.ResourceMemory}: 5, - }.Unflatten(), - Usage: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f2", Resource: corev1.ResourceMemory}: 5, - }.Unflatten(), - }, - ResourceGroups: nil, + usage: resources.FlavorResourceQuantitiesFlat{ + {Flavor: "f1", Resource: corev1.ResourceCPU}: 5_000, + {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, + {Flavor: "f2", Resource: corev1.ResourceCPU}: 5_000, + {Flavor: "f2", Resource: corev1.ResourceMemory}: 5, + }, + clusterQueue: []*kueue.ClusterQueue{ + utiltesting. + MakeClusterQueue("CQ"). + ResourceGroup( + *utiltesting.MakeFlavorQuotas("f1"). + Resource(corev1.ResourceCPU, "5"). + Resource(corev1.ResourceMemory, "5"). + Obj(), + *utiltesting.MakeFlavorQuotas("f2"). + Resource(corev1.ResourceCPU, "5"). + Resource(corev1.ResourceMemory, "5"). + Obj(), + ). + Cohort("C"). + Obj(), }, }, "one cannot fit": { request: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 1, + {Flavor: "f1", Resource: corev1.ResourceCPU}: 1_000, {Flavor: "f1", Resource: corev1.ResourceMemory}: 1, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 2, + {Flavor: "f2", Resource: corev1.ResourceCPU}: 2_000, {Flavor: "f2", Resource: corev1.ResourceMemory}: 1, }, wantFit: false, - cq: &ClusterQueueSnapshot{ - Name: "CQ", - Cohort: &CohortSnapshot{ - Name: "C", - RequestableResources: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f2", Resource: corev1.ResourceMemory}: 5, - }.Unflatten(), - Usage: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 4, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 4, - {Flavor: "f2", Resource: corev1.ResourceCPU}: 4, - {Flavor: "f2", Resource: corev1.ResourceMemory}: 4, - }.Unflatten(), - }, - ResourceGroups: nil, + usage: resources.FlavorResourceQuantitiesFlat{ + {Flavor: "f1", Resource: corev1.ResourceCPU}: 4_000, + {Flavor: "f1", Resource: corev1.ResourceMemory}: 4, + {Flavor: "f2", Resource: corev1.ResourceCPU}: 4_000, + {Flavor: "f2", Resource: corev1.ResourceMemory}: 4, + }, + clusterQueue: []*kueue.ClusterQueue{ + utiltesting. + MakeClusterQueue("CQ"). + ResourceGroup( + *utiltesting.MakeFlavorQuotas("f1"). + Resource(corev1.ResourceCPU, "5"). + Resource(corev1.ResourceMemory, "5"). + Obj(), + *utiltesting.MakeFlavorQuotas("f2"). + Resource(corev1.ResourceCPU, "5"). + Resource(corev1.ResourceMemory, "5"). + Obj(), + ). + Cohort("C"). + Obj(), }, }, "missing flavor": { request: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f2", Resource: corev1.ResourceCPU}: 1, - {Flavor: "f2", Resource: corev1.ResourceMemory}: 1, + {Flavor: "non-existent-flavor", Resource: corev1.ResourceCPU}: 1_000, + {Flavor: "non-existent-flavor", Resource: corev1.ResourceMemory}: 1, }, wantFit: false, - cq: &ClusterQueueSnapshot{ - Name: "CQ", - Cohort: &CohortSnapshot{ - Name: "C", - RequestableResources: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, - }.Unflatten(), - Usage: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, - }.Unflatten(), - }, - ResourceGroups: nil, + usage: resources.FlavorResourceQuantitiesFlat{ + {Flavor: "f1", Resource: corev1.ResourceCPU}: 5_000, + {Flavor: "f1", Resource: corev1.ResourceMemory}: 5, + }, + clusterQueue: []*kueue.ClusterQueue{ + utiltesting. + MakeClusterQueue("CQ"). + ResourceGroup( + *utiltesting.MakeFlavorQuotas("f1"). + Resource(corev1.ResourceCPU, "5"). + Resource(corev1.ResourceMemory, "5"). + Obj(), + ). + Cohort("C"). + Obj(), }, }, "missing resource": { request: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 1, + {Flavor: "f1", Resource: corev1.ResourceCPU}: 1_000, {Flavor: "f1", Resource: corev1.ResourceMemory}: 1, }, wantFit: false, - cq: &ClusterQueueSnapshot{ - Name: "CQ", - Cohort: &CohortSnapshot{ - Name: "C", - RequestableResources: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 5, - }.Unflatten(), - Usage: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 3, - }.Unflatten(), - }, - ResourceGroups: nil, + usage: resources.FlavorResourceQuantitiesFlat{ + {Flavor: "f1", Resource: corev1.ResourceCPU}: 3_000, + }, + clusterQueue: []*kueue.ClusterQueue{ + utiltesting. + MakeClusterQueue("CQ"). + ResourceGroup( + *utiltesting.MakeFlavorQuotas("f1"). + Resource(corev1.ResourceCPU, "5"). + Obj(), + ). + Cohort("C"). + Obj(), }, }, "lendingLimit enabled can't fit": { request: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 3, + {Flavor: "f1", Resource: corev1.ResourceCPU}: 3_000, }, wantFit: false, - cq: &ClusterQueueSnapshot{ - Name: "CQ-A", - Cohort: &CohortSnapshot{ - Name: "C", - RequestableResources: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: - // CQ-A has 2 nominal cpu, CQ-B has 3 nominal cpu and 2 lendingLimit, - // so when lendingLimit enabled, the cohort's RequestableResources is 4 cpu. - corev1.ResourceCPU}: 4, - }.Unflatten(), - Usage: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 2, - }.Unflatten(), - }, - GuaranteedQuota: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 0, - }.Unflatten(), + usage: resources.FlavorResourceQuantitiesFlat{ + {Flavor: "f1", Resource: corev1.ResourceCPU}: 2_000, + }, + clusterQueue: []*kueue.ClusterQueue{ + utiltesting. + MakeClusterQueue("CQ"). + ResourceGroup( + utiltesting.MakeFlavorQuotas("f1"). + ResourceQuotaWrapper(corev1.ResourceCPU). + NominalQuota("2"). + Append(). + FlavorQuotas, + ). + Cohort("C"). + Obj(), + utiltesting. + MakeClusterQueue("CQ-B"). + ResourceGroup( + utiltesting.MakeFlavorQuotas("f1"). + ResourceQuotaWrapper(corev1.ResourceCPU). + NominalQuota("3"). + LendingLimit("2"). + Append(). + FlavorQuotas, + ). + Cohort("C"). + Obj(), }, enableLendingLimit: true, }, "lendingLimit enabled can fit": { request: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 3, + {Flavor: "f1", Resource: corev1.ResourceCPU}: 3_000, }, wantFit: true, - cq: &ClusterQueueSnapshot{ - Name: "CQ-A", - Cohort: &CohortSnapshot{ - Name: "C", - RequestableResources: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: - // CQ-A has 2 nominal cpu, CQ-B has 3 nominal cpu and 2 lendingLimit, - // so when lendingLimit enabled, the cohort's RequestableResources is 4 cpu. - corev1.ResourceCPU}: 4, - }.Unflatten(), - Usage: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: - // CQ-B has admitted a workload with 2 cpus, but with 1 GuaranteedQuota, - // so when lendingLimit enabled, Cohort.Usage should be 2 - 1 = 1. - corev1.ResourceCPU}: 1, - }.Unflatten(), - }, - GuaranteedQuota: resources.FlavorResourceQuantitiesFlat{ - {Flavor: "f1", Resource: corev1.ResourceCPU}: 2, - }.Unflatten(), + usage: resources.FlavorResourceQuantitiesFlat{ + {Flavor: "f1", Resource: corev1.ResourceCPU}: 1_000, + }, + clusterQueue: []*kueue.ClusterQueue{ + utiltesting. + MakeClusterQueue("CQ"). + ResourceGroup( + utiltesting.MakeFlavorQuotas("f1"). + ResourceQuotaWrapper(corev1.ResourceCPU). + NominalQuota("2"). + Append(). + FlavorQuotas, + ). + Cohort("C"). + Obj(), + utiltesting. + MakeClusterQueue("CQ-B"). + ResourceGroup( + utiltesting.MakeFlavorQuotas("f1"). + ResourceQuotaWrapper(corev1.ResourceCPU). + NominalQuota("3"). + LendingLimit("2"). + Append(). + FlavorQuotas, + ). + Cohort("C"). + Obj(), }, enableLendingLimit: true, }, @@ -306,7 +338,20 @@ func TestFitInCohort(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { defer features.SetFeatureGateDuringTest(t, features.LendingLimit, tc.enableLendingLimit)() - got := tc.cq.FitInCohort(tc.request) + cache := New(utiltesting.NewFakeClient()) + + cache.AddOrUpdateResourceFlavor(utiltesting.MakeResourceFlavor("f1").Obj()) + cache.AddOrUpdateResourceFlavor(utiltesting.MakeResourceFlavor("f2").Obj()) + + for _, cq := range tc.clusterQueue { + _ = cache.AddClusterQueue(context.Background(), cq) + } + + snapshot := cache.Snapshot() + cq := snapshot.ClusterQueues["CQ"] + cq.AddUsage(tc.usage) + + got := cq.FitInCohort(tc.request) if got != tc.wantFit { t.Errorf("Unexpected result, %v", got) }