From e6d9cbf729edc4eae5f177366be7d591cd0519b1 Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Wed, 14 Jan 2026 15:18:54 +0100 Subject: [PATCH] DRA scheduler plugin: increase test coverage Line coverage isn't much better (81.3% -> 81.8%) but it's not clear whether "in flight claims" were considered by any test case. --- .../dynamicresources/dynamicresources_test.go | 78 ++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/pkg/scheduler/framework/plugins/dynamicresources/dynamicresources_test.go b/pkg/scheduler/framework/plugins/dynamicresources/dynamicresources_test.go index 6eaf6ae86ea..95257297d2d 100644 --- a/pkg/scheduler/framework/plugins/dynamicresources/dynamicresources_test.go +++ b/pkg/scheduler/framework/plugins/dynamicresources/dynamicresources_test.go @@ -587,6 +587,11 @@ var ( otherAllocatedClaim = st.FromResourceClaim(otherClaim). Allocation(allocationResult). Obj() + otherAllocatedClaimOtherDevice = func() *resourceapi.ResourceClaim { + claim := otherAllocatedClaim.DeepCopy() + claim.Status.Allocation.Devices.Results[0].Device += "-other" + return claim + }() extendedResourceClaim = st.MakeResourceClaim(). Name("my-pod-extended-resources-0"). GenerateName("my-pod-extended-resources-"). @@ -1032,6 +1037,8 @@ type testPluginCase struct { claims []*resourceapi.ResourceClaim classes []*resourceapi.DeviceClass + inFlightClaims []*resourceapi.ResourceClaim + // objs get stored directly in the fake client, without passing // through reactors, in contrast to the types above. objs []apiruntime.Object @@ -1326,7 +1333,7 @@ func testPlugin(tCtx ktesting.TContext) { unreserveBeforePreBind: &result{}, }, }, - "exhausted-resources": { + "exhausted-resources-in-informer-cache": { pod: podWithClaimName, claims: []*resourceapi.ResourceClaim{pendingClaim, otherAllocatedClaim}, classes: []*resourceapi.DeviceClass{deviceClass}, @@ -1342,6 +1349,71 @@ func testPlugin(tCtx ktesting.TContext) { }, }, }, + "exhausted-resources-in-flight-claim": { + pod: podWithClaimName, + claims: []*resourceapi.ResourceClaim{pendingClaim, otherClaim}, + inFlightClaims: []*resourceapi.ResourceClaim{otherAllocatedClaim}, + classes: []*resourceapi.DeviceClass{deviceClass}, + objs: []apiruntime.Object{workerNodeSlice}, + want: want{ + preenqueue: result{ + inFlightClaims: []metav1.Object{otherAllocatedClaim}, + }, + prefilter: result{ + inFlightClaims: []metav1.Object{otherAllocatedClaim}, + }, + filter: perNodeResult{ + workerNode.Name: { + inFlightClaims: []metav1.Object{otherAllocatedClaim}, + status: fwk.NewStatus(fwk.UnschedulableAndUnresolvable, `cannot allocate all claims`), + }, + }, + postfilter: result{ + inFlightClaims: []metav1.Object{otherAllocatedClaim}, + status: fwk.NewStatus(fwk.Unschedulable, `still not schedulable`), + }, + }, + }, + "other-resources-in-flight-claim": { + pod: podWithClaimName, + claims: []*resourceapi.ResourceClaim{pendingClaim, otherClaim}, + inFlightClaims: []*resourceapi.ResourceClaim{otherAllocatedClaimOtherDevice}, + classes: []*resourceapi.DeviceClass{deviceClass}, + objs: []apiruntime.Object{workerNodeSlice}, + want: want{ + preenqueue: result{ + inFlightClaims: []metav1.Object{otherAllocatedClaimOtherDevice}, + }, + prefilter: result{ + inFlightClaims: []metav1.Object{otherAllocatedClaimOtherDevice}, + }, + filter: perNodeResult{ + workerNode.Name: { + inFlightClaims: []metav1.Object{otherAllocatedClaimOtherDevice}, + }, + }, + reserve: result{ + inFlightClaims: []metav1.Object{allocatedClaim, otherAllocatedClaimOtherDevice}, + }, + prebind: result{ + inFlightClaims: []metav1.Object{otherAllocatedClaimOtherDevice}, + assumedClaim: reserve(allocatedClaim, podWithClaimName), + changes: change{ + claim: func(claim *resourceapi.ResourceClaim) *resourceapi.ResourceClaim { + if claim.Name == claimName { + claim = claim.DeepCopy() + claim.Status = inUseClaim.Status + } + return claim + }, + }, + }, + postbind: result{ + inFlightClaims: []metav1.Object{allocatedClaim, otherAllocatedClaimOtherDevice}, + assumedClaim: reserve(allocatedClaim, podWithClaimName), + }, + }, + }, // The two test cases for device tainting only need to cover // whether the feature gate is passed through to the allocator @@ -2547,6 +2619,10 @@ func testPlugin(tCtx ktesting.TContext) { featuregatetesting.SetFeatureGateDuringTest(tCtx, utilfeature.DefaultFeatureGate, features.DRAExtendedResource, tc.enableDRAExtendedResource) testCtx := setup(tCtx, tc.args, nodes, tc.claims, tc.classes, tc.objs, feats, tc.failPatch, tc.reactors) + for _, claim := range tc.inFlightClaims { + tCtx.ExpectNoError(testCtx.draManager.ResourceClaims().SignalClaimPendingAllocation(claim.UID, claim)) + } + initialObjects := testCtx.listAll(tCtx) var registry compbasemetrics.KubeRegistry if tc.metrics != nil {