test(ut/dra): add unit test for pod requesting prepared and new claims

This commit is contained in:
Piotr Rogowski
2026-01-14 11:43:55 +00:00
parent 9d1474f487
commit ea4f784f4b

View File

@@ -65,8 +65,9 @@ const (
)
var (
shareID = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
shareUID = types.UID(shareID)
shareID = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
shareUID = types.UID(shareID)
testPodCounter atomic.Uint32
)
type fakeDRADriverGRPCServer struct {
@@ -300,6 +301,23 @@ func setupFakeDRADriverGRPCServer(ctx context.Context, shouldTimeout bool, plugi
}, nil
}
func genPrepareResourcesResponse(claimUID types.UID) *drapb.NodePrepareResourcesResponse {
return &drapb.NodePrepareResourcesResponse{
Claims: map[string]*drapb.NodePrepareResourceResponse{
string(claimUID): {
Devices: []*drapb.Device{
{
PoolName: poolName,
DeviceName: deviceName,
RequestNames: []string{requestName},
CdiDeviceIds: []string{cdiID},
},
},
},
},
}
}
func TestNewManagerImpl(t *testing.T) {
kubeClient := fake.NewSimpleClientset()
for _, test := range []struct {
@@ -363,6 +381,45 @@ func genTestPod() *v1.Pod {
}
}
func genTestPodWithClaims(claimNames ...string) *v1.Pod {
podCounter := testPodCounter.Add(1)
podName := fmt.Sprintf("test-pod-%d", podCounter)
podUID := types.UID(fmt.Sprintf("test-pod-uid-%d", podCounter))
resourceClaims := make([]v1.PodResourceClaim, 0, len(claimNames))
containerClaims := make([]v1.ResourceClaim, 0, len(claimNames))
for _, claimName := range claimNames {
cn := claimName
resourceClaims = append(resourceClaims, v1.PodResourceClaim{
Name: cn,
ResourceClaimName: &cn,
})
containerClaims = append(containerClaims, v1.ResourceClaim{
Name: cn,
})
}
return &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: podName,
Namespace: namespace,
UID: podUID,
},
Spec: v1.PodSpec{
ResourceClaims: resourceClaims,
Containers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Claims: containerClaims,
},
},
},
},
}
}
// genTestPodWithExtendedResource generates pod object
func genTestPodWithExtendedResource() *v1.Pod {
return &v1.Pod{
@@ -787,18 +844,7 @@ dra_operations_duration_seconds_sum{is_error="false",operation_name="PrepareReso
dra_operations_duration_seconds_count{is_error="false",operation_name="PrepareResources"} 1
`,
expectedClaimInfoState: genClaimInfoState(cdiID),
resp: &drapb.NodePrepareResourcesResponse{Claims: map[string]*drapb.NodePrepareResourceResponse{
string(claimUID): {
Devices: []*drapb.Device{
{
PoolName: poolName,
DeviceName: deviceName,
RequestNames: []string{requestName},
CdiDeviceIds: []string{cdiID},
},
},
},
}},
resp: genPrepareResourcesResponse(claimUID),
},
{
description: "resource already prepared",
@@ -807,18 +853,7 @@ dra_operations_duration_seconds_count{is_error="false",operation_name="PrepareRe
claim: genTestClaim(claimName, driverName, deviceName, podUID),
claimInfo: genTestClaimInfo(claimUID, []string{podUID}, true),
expectedClaimInfoState: genClaimInfoState(cdiID),
resp: &drapb.NodePrepareResourcesResponse{Claims: map[string]*drapb.NodePrepareResourceResponse{
string(claimUID): {
Devices: []*drapb.Device{
{
PoolName: poolName,
DeviceName: deviceName,
RequestNames: []string{requestName},
CdiDeviceIds: []string{cdiID},
},
},
},
}},
resp: genPrepareResourcesResponse(claimUID),
expectedMetric: `# HELP dra_operations_duration_seconds [ALPHA] Latency histogram in seconds for the duration of handling all ResourceClaims referenced by a pod when the pod starts or stops. Identified by the name of the operation (PrepareResources or UnprepareResources) and separated by the success of the operation. The number of failed operations is provided through the histogram's overall count.
# TYPE dra_operations_duration_seconds histogram
dra_operations_duration_seconds_bucket{is_error="false",operation_name="PrepareResources",le="+Inf"} 1
@@ -852,19 +887,8 @@ dra_operations_duration_seconds_count{is_error="true",operation_name="PrepareRes
pod: genTestPod(),
claim: genTestClaim(claimName, driverName, deviceName, podUID),
expectedClaimInfoState: genClaimInfoState(cdiID),
resp: &drapb.NodePrepareResourcesResponse{Claims: map[string]*drapb.NodePrepareResourceResponse{
string(claimUID): {
Devices: []*drapb.Device{
{
PoolName: poolName,
DeviceName: deviceName,
RequestNames: []string{requestName},
CdiDeviceIds: []string{cdiID},
},
},
},
}},
expectedPrepareCalls: 1,
resp: genPrepareResourcesResponse(claimUID),
expectedPrepareCalls: 1,
expectedMetric: `# HELP dra_grpc_operations_duration_seconds [ALPHA] Duration in seconds of the DRA gRPC operations
# TYPE dra_grpc_operations_duration_seconds histogram
dra_grpc_operations_duration_seconds_bucket{driver_name="test-driver",grpc_status_code="OK",method_name="/k8s.io.kubelet.pkg.apis.dra.v1.DRAPlugin/NodePrepareResources",le="+Inf"} 1
@@ -1053,6 +1077,74 @@ dra_operations_duration_seconds_count{is_error="false",operation_name="PrepareRe
}
}
// TestPrepareResourcesWithPreparedAndNewClaim verifies that PrepareResources
// correctly handles a pod that references a mix of ResourceClaims:
// - first claim already prepared by a previous pod
// - second claim is new and needs to be prepared
func TestPrepareResourcesWithPreparedAndNewClaim(t *testing.T) {
logger, tCtx := ktesting.NewTestContext(t)
fakeKubeClient := fake.NewClientset()
manager, err := NewManager(logger, fakeKubeClient, t.TempDir())
require.NoError(t, err)
manager.initDRAPluginManager(tCtx, getFakeNode, time.Second)
secondClaimName := fmt.Sprintf("%s-second", claimName)
// Generate two pods where the second pod reuses an existing claim and adds a new one
firstPod := genTestPodWithClaims(claimName)
secondPod := genTestPodWithClaims(claimName, secondClaimName)
firstClaim := genTestClaim(claimName, driverName, deviceName, string(firstPod.ObjectMeta.UID))
secondClaim := genTestClaim(secondClaimName, driverName, deviceName, string(secondPod.ObjectMeta.UID))
// Make firstClaim reserved for first and second pod
firstClaim.Status.ReservedFor = append(
firstClaim.Status.ReservedFor,
resourceapi.ResourceClaimConsumerReference{UID: secondPod.ObjectMeta.UID},
)
_, err = fakeKubeClient.ResourceV1().ResourceClaims(namespace).Create(tCtx, firstClaim, metav1.CreateOptions{})
require.NoError(t, err)
_, err = fakeKubeClient.ResourceV1().ResourceClaims(namespace).Create(tCtx, secondClaim, metav1.CreateOptions{})
require.NoError(t, err)
respFirst := genPrepareResourcesResponse(firstClaim.UID)
draServerInfo, err := setupFakeDRADriverGRPCServer(tCtx, false, nil, respFirst, nil, nil)
require.NoError(t, err)
defer draServerInfo.teardownFn()
plg := manager.GetWatcherHandler()
require.NoError(t, plg.RegisterPlugin(driverName, draServerInfo.socketName, []string{drapb.DRAPluginService}, nil))
err = manager.PrepareResources(tCtx, firstPod)
require.NoError(t, err)
assert.Equal(t, uint32(1),
draServerInfo.server.prepareResourceCalls.Load(),
"first pod should trigger one prepare call",
)
respSecond := genPrepareResourcesResponse(secondClaim.UID)
draServerInfo.server.prepareResourcesResponse = respSecond
err = manager.PrepareResources(tCtx, secondPod)
require.NoError(t, err)
// second pod triggered exactly one prepare call (new claim only) + previous one call
assert.Equal(t, uint32(2),
draServerInfo.server.prepareResourceCalls.Load(),
"second pod should trigger one prepare call for the new claim",
)
for _, claimName := range []string{firstClaim.Name, secondClaim.Name} {
claimInfo, exists := manager.cache.get(claimName, namespace)
require.True(t, exists, "claim %s should exist in cache", claimName)
assert.True(t, claimInfo.prepared, "claim %s should be marked as prepared", claimName)
}
}
func TestUnprepareResources(t *testing.T) {
fakeKubeClient := fake.NewSimpleClientset()
for _, test := range []struct {