DRA tests: stop using deprecated ktesting functions

Some of them were already converted previously, but didn't take full advantage
of the more flexible methods: errors can be checked again by Gomega.
This commit is contained in:
Patrick Ohly 2026-01-14 20:52:25 +01:00
parent 8de4a11252
commit fda3bdbd5e
9 changed files with 49 additions and 78 deletions

View file

@ -522,10 +522,8 @@ func (b *Builder) tearDown(tCtx ktesting.TContext) {
tCtx.ExpectNoError(err, "delete pod")
}
}
ktesting.Eventually(tCtx, func(tCtx ktesting.TContext) []v1.Pod {
pods, err := b.listTestPods(tCtx)
tCtx.ExpectNoError(err)
return pods
tCtx.Eventually(func(tCtx ktesting.TContext) ([]v1.Pod, error) {
return b.listTestPods(tCtx)
}).WithTimeout(time.Minute).Should(gomega.BeEmpty(), "remaining pods despite deletion")
claims, err := b.ClientV1(tCtx).ResourceClaims(b.namespace).List(tCtx, metav1.ListOptions{})
@ -543,15 +541,13 @@ func (b *Builder) tearDown(tCtx ktesting.TContext) {
for host, plugin := range b.driver.Nodes {
tCtx.Logf("Waiting for resources on %s to be unprepared", host)
ktesting.Eventually(tCtx, func(ktesting.TContext) []app.ClaimID { return plugin.GetPreparedResources() }).WithTimeout(time.Minute).Should(gomega.BeEmpty(), "prepared claims on host %s", host)
tCtx.Eventually(func(ktesting.TContext) []app.ClaimID { return plugin.GetPreparedResources() }).WithTimeout(time.Minute).Should(gomega.BeEmpty(), "prepared claims on host %s", host)
}
tCtx.Log("waiting for claims to be deallocated and deleted")
ktesting.Eventually(tCtx, func(tCtx ktesting.TContext) []resourceapi.ResourceClaim {
claims, err := client.ResourceClaims(tCtx.Namespace()).List(tCtx, metav1.ListOptions{})
tCtx.ExpectNoError(err)
return claims.Items
}).WithTimeout(time.Minute).Should(gomega.BeEmpty(), "claims in the namespaces")
tCtx.Eventually(func(tCtx ktesting.TContext) (*resourceapi.ResourceClaimList, error) {
return client.ResourceClaims(tCtx.Namespace()).List(tCtx, metav1.ListOptions{})
}).WithTimeout(time.Minute).Should(gomega.HaveField("Items", gomega.BeEmpty()), "claims in the namespaces")
}
func (b *Builder) listTestPods(tCtx ktesting.TContext) ([]v1.Pod, error) {

View file

@ -664,7 +664,7 @@ func (d *Driver) SetUp(tCtx ktesting.TContext, kubeletRootDir string, nodes *Nod
// Wait for registration.
tCtx.Log("wait for plugin registration")
ktesting.Eventually(tCtx, func(tCtx ktesting.TContext) map[string][]app.GRPCCall {
tCtx.Eventually(func(tCtx ktesting.TContext) map[string][]app.GRPCCall {
notRegistered := make(map[string][]app.GRPCCall)
for nodename, plugin := range d.Nodes {
calls := plugin.GetGRPCCalls()
@ -995,7 +995,7 @@ func (d *Driver) TearDown(tCtx ktesting.TContext) {
// Only use this in tests where kubelet support for DRA is guaranteed.
func (d *Driver) IsGone(tCtx ktesting.TContext) {
tCtx.Logf("Waiting for ResourceSlices of driver %s to be removed...", d.Name)
ktesting.Eventually(tCtx, d.NewGetSlices()).WithTimeout(2 * time.Minute).Should(gomega.HaveField("Items", gomega.BeEmpty()))
tCtx.Eventually(d.NewGetSlices()).WithTimeout(2 * time.Minute).Should(gomega.HaveField("Items", gomega.BeEmpty()))
}
func (d *Driver) interceptor(nodename string, ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {

View file

@ -56,13 +56,13 @@ func coreDRA(tCtx ktesting.TContext, b *drautils.Builder) upgradedTestFunc {
// to the restarted apiserver. Sometimes, attempts fail with "EOF" as error
// or (even weirder) with
// getting *v1.Pod: pods "tester-2" is forbidden: User "kubernetes-admin" cannot get resource "pods" in API group "" in the namespace "dra-9021"
ktesting.Eventually(tCtx, func(tCtx ktesting.TContext) error {
tCtx.Eventually(func(tCtx ktesting.TContext) error {
return tCtx.Client().ResourceV1beta1().ResourceClaims(namespace).Delete(tCtx, claim.Name, metav1.DeleteOptions{})
}).Should(gomega.Succeed(), "delete claim after downgrade")
ktesting.Eventually(tCtx, func(tCtx ktesting.TContext) error {
tCtx.Eventually(func(tCtx ktesting.TContext) error {
return tCtx.Client().CoreV1().Pods(namespace).Delete(tCtx, pod.Name, metav1.DeleteOptions{})
}).Should(gomega.Succeed(), "delete pod after downgrade")
ktesting.Eventually(tCtx, func(tCtx ktesting.TContext) *v1.Pod {
tCtx.Eventually(func(tCtx ktesting.TContext) *v1.Pod {
pod, err := tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
return nil

View file

@ -255,7 +255,7 @@ func testUpgradeDowngrade(tCtx ktesting.TContext) {
// The kubelet wipes all ResourceSlices on a restart because it doesn't know which drivers were running.
// Wait for the ResourceSlice controller in the driver to notice and recreate the ResourceSlices.
ktesting.Eventually(tCtx.WithStep("wait for ResourceSlices"), driver.NewGetSlices()).WithTimeout(5 * time.Minute).Should(gomega.HaveField("Items", gomega.HaveLen(len(nodes.NodeNames))))
tCtx.WithStep("wait for ResourceSlices").Eventually(driver.NewGetSlices()).WithTimeout(5 * time.Minute).Should(gomega.HaveField("Items", gomega.HaveLen(len(nodes.NodeNames))))
downgradedTestFuncs := make(map[string]downgradedTestFunc, len(subTests))
tCtx.Run("after-cluster-upgrade", func(tCtx ktesting.TContext) {

View file

@ -444,10 +444,8 @@ profiles:
// The scheduler should hit the binding timeout and surface that on the pod.
// We poll the pod's conditions until we see a message containing "binding timeout".
tCtx.Eventually(func(tCtx ktesting.TContext) *v1.Pod {
p, err := tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err, "get pod")
return p
tCtx.Eventually(func(tCtx ktesting.TContext) (*v1.Pod, error) {
return tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
}).WithTimeout(maxTO).WithPolling(300*time.Millisecond).Should(
gomega.HaveField("Status.Conditions",
gomega.ContainElement(
@ -465,10 +463,8 @@ profiles:
"bindingTimeout should trigger roughly near %s (observed %v)", wantTO, elapsed,
)
// Verify that the pod remains unscheduled after the binding timeout.
tCtx.Eventually(func(tCtx ktesting.TContext) *v1.Pod {
pod, err := tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err, "get pod")
return pod
tCtx.Eventually(func(tCtx ktesting.TContext) (*v1.Pod, error) {
return tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
}).WithTimeout(wantTO).WithPolling(200 * time.Millisecond).Should(gomega.SatisfyAll(
gomega.HaveField("Spec.NodeName", gomega.BeEmpty()),
@ -570,10 +566,8 @@ profiles:
gomega.Succeed(), "slice must be created before binding timeout")
// Wait until the binding timeout occurs.
tCtx.Eventually(func(tCtx ktesting.TContext) *v1.Pod {
p, err := tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err, "get pod")
return p
tCtx.Eventually(func(tCtx ktesting.TContext) (*v1.Pod, error) {
return tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
}).WithTimeout(20*time.Second).WithPolling(300*time.Millisecond).Should(
gomega.HaveField("Status.Conditions",
gomega.ContainElement(
@ -586,10 +580,8 @@ profiles:
)
// Verify recovery to the newly added device without BindingConditions through rescheduling triggered by binding timeout.
tCtx.Eventually(func(tCtx ktesting.TContext) *resourceapi.ResourceClaim {
c, err := tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claim1.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err)
return c
tCtx.Eventually(func(tCtx ktesting.TContext) (*resourceapi.ResourceClaim, error) {
return tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claim1.Name, metav1.GetOptions{})
}).WithTimeout(10*time.Second).WithPolling(1*time.Second).Should(gomega.HaveField(
"Status.Allocation",
gstruct.PointTo(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{

View file

@ -618,10 +618,8 @@ func testPrioritizedList(tCtx ktesting.TContext, enabled bool) {
"Message": gomega.Equal("0/8 nodes are available: 8 cannot allocate all claims. still not schedulable, preemption: 0/8 nodes are available: 8 Preemption is not helpful for scheduling."),
}),
))
tCtx.Eventually(func(tCtx ktesting.TContext) *v1.Pod {
pod, err := tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err, "get pod")
return pod
tCtx.Eventually(func(tCtx ktesting.TContext) (*v1.Pod, error) {
return tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
}).WithTimeout(10 * time.Second).WithPolling(time.Second).Should(schedulingAttempted)
}
@ -689,10 +687,8 @@ func testPrioritizedListScoring(tCtx ktesting.TContext) {
_ = createPod(tCtx, namespace, "-pl-single-claim", podWithClaimName, claim)
expectedSelectedRequest := fmt.Sprintf("%s/%s", claim.Spec.Devices.Requests[0].Name, claim.Spec.Devices.Requests[0].FirstAvailable[0].Name)
tCtx.Eventually(func(tCtx ktesting.TContext) *resourceapi.ResourceClaim {
c, err := tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claim.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err)
return c
tCtx.Eventually(func(tCtx ktesting.TContext) (*resourceapi.ResourceClaim, error) {
return tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claim.Name, metav1.GetOptions{})
}).WithTimeout(10 * time.Second).WithPolling(time.Second).Should(expectedAllocatedClaim(expectedSelectedRequest, nodeInfos[0]))
})
@ -751,18 +747,14 @@ func testPrioritizedListScoring(tCtx ktesting.TContext) {
// The second subrequest in claim1 is for nodeInfos[2], so it should be chosen.
expectedSelectedRequest := fmt.Sprintf("%s/%s", claim1.Spec.Devices.Requests[0].Name, claim1.Spec.Devices.Requests[0].FirstAvailable[1].Name)
tCtx.Eventually(func(tCtx ktesting.TContext) *resourceapi.ResourceClaim {
c, err := tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claimPrioritizedList1.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err)
return c
tCtx.Eventually(func(tCtx ktesting.TContext) (*resourceapi.ResourceClaim, error) {
return tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claimPrioritizedList1.Name, metav1.GetOptions{})
}).WithTimeout(10 * time.Second).WithPolling(time.Second).Should(expectedAllocatedClaim(expectedSelectedRequest, nodeInfos[2]))
// The first subrequest in claim2 is for nodeInfos[2], so it should be chosen.
expectedSelectedRequest = fmt.Sprintf("%s/%s", claim2.Spec.Devices.Requests[0].Name, claim2.Spec.Devices.Requests[0].FirstAvailable[0].Name)
tCtx.Eventually(func(tCtx ktesting.TContext) *resourceapi.ResourceClaim {
c, err := tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claimPrioritizedList2.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err)
return c
tCtx.Eventually(func(tCtx ktesting.TContext) (*resourceapi.ResourceClaim, error) {
return tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claimPrioritizedList2.Name, metav1.GetOptions{})
}).WithTimeout(10 * time.Second).WithPolling(time.Second).Should(expectedAllocatedClaim(expectedSelectedRequest, nodeInfos[2]))
})
}
@ -833,10 +825,8 @@ func testExtendedResource(tCtx ktesting.TContext, enabled bool) {
}),
))
}
tCtx.Eventually(func(tCtx ktesting.TContext) *v1.Pod {
pod, err := tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err, "get pod")
return pod
tCtx.Eventually(func(tCtx ktesting.TContext) (*v1.Pod, error) {
return tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
}).WithTimeout(time.Minute).WithPolling(time.Second).Should(schedulingAttempted)
})
}
@ -1716,18 +1706,14 @@ func testInvalidResourceSlices(tCtx ktesting.TContext) {
schedulingAttempted := gomega.HaveField("Status.Conditions", gomega.ContainElement(
gstruct.MatchFields(gstruct.IgnoreExtras, tc.expectedPodScheduledCondition),
))
tCtx.Eventually(func(tCtx ktesting.TContext) *v1.Pod {
pod, err := tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err, "get pod")
return pod
tCtx.Eventually(func(tCtx ktesting.TContext) (*v1.Pod, error) {
return tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, pod.Name, metav1.GetOptions{})
}).WithTimeout(10 * time.Second).WithPolling(time.Second).Should(schedulingAttempted)
// Only check the ResourceClaim if we expected the Pod to schedule.
if tc.expectPodToSchedule {
tCtx.Eventually(func(tCtx ktesting.TContext) *resourceapi.ResourceClaim {
c, err := tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claim.Name, metav1.GetOptions{})
tCtx.ExpectNoError(err)
return c
tCtx.Eventually(func(tCtx ktesting.TContext) (*resourceapi.ResourceClaim, error) {
return tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claim.Name, metav1.GetOptions{})
}).WithTimeout(10 * time.Second).WithPolling(time.Second).Should(gomega.HaveField("Status.Allocation", gstruct.PointTo(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
"Devices": gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
"Results": gomega.HaveExactElements(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{

View file

@ -165,8 +165,8 @@ func createPod(tCtx ktesting.TContext, namespace string, suffix string, pod *v1.
func waitForPodScheduled(tCtx ktesting.TContext, namespace, podName string) {
tCtx.Helper()
tCtx.Eventually(func(tCtx ktesting.TContext) *v1.Pod {
return must(tCtx, tCtx.Client().CoreV1().Pods(namespace).Get, podName, metav1.GetOptions{})
tCtx.Eventually(func(tCtx ktesting.TContext) (*v1.Pod, error) {
return tCtx.Client().CoreV1().Pods(namespace).Get(tCtx, podName, metav1.GetOptions{})
}).WithTimeout(60*time.Second).Should(
gomega.HaveField("Status.Conditions", gomega.ContainElement(
gomega.And(
@ -207,11 +207,10 @@ func waitForNotFound[T any](tCtx ktesting.TContext, get func(context.Context, st
func waitForClaim(tCtx ktesting.TContext, namespace, claimName string, timeout time.Duration, match gtypes.GomegaMatcher, description ...any) *resourceapi.ResourceClaim {
tCtx.Helper()
var latestClaim *resourceapi.ResourceClaim
tCtx.Eventually(func(tCtx ktesting.TContext) *resourceapi.ResourceClaim {
tCtx.Eventually(func(tCtx ktesting.TContext) (*resourceapi.ResourceClaim, error) {
c, err := tCtx.Client().ResourceV1().ResourceClaims(namespace).Get(tCtx, claimName, metav1.GetOptions{})
tCtx.ExpectNoError(err, "get claim")
latestClaim = c
return latestClaim
return c, err
}).WithTimeout(timeout).WithPolling(time.Second).Should(match, description...)
return latestClaim
}

View file

@ -87,7 +87,7 @@ func TestCreateResourceSlices(tCtx ktesting.TContext, numSlices int) {
tCtx.ExpectNoError(err, "start controller")
tCtx.CleanupCtx(func(tCtx ktesting.TContext) {
controller.Stop()
ktesting.Eventually(tCtx, func(tCtx ktesting.TContext) *resourceapi.ResourceSliceList {
tCtx.Eventually(func(tCtx ktesting.TContext) *resourceapi.ResourceSliceList {
err := tCtx.Client().ResourceV1().ResourceSlices().DeleteCollection(tCtx, metav1.DeleteOptions{}, metav1.ListOptions{
FieldSelector: resourceapi.ResourceSliceSelectorDriver + "=" + driverName,
})
@ -97,7 +97,7 @@ func TestCreateResourceSlices(tCtx ktesting.TContext, numSlices int) {
})
// Eventually we should have all desired slices.
ktesting.Eventually(tCtx, listSlices).WithTimeout(3 * time.Minute).Should(gomega.HaveField("Items", gomega.HaveLen(numSlices)))
tCtx.Eventually(listSlices).WithTimeout(3 * time.Minute).Should(gomega.HaveField("Items", gomega.HaveLen(numSlices)))
// Verify state.
expectSlices := listSlices(tCtx)
@ -110,7 +110,7 @@ func TestCreateResourceSlices(tCtx ktesting.TContext, numSlices int) {
// No further changes expected now, after checking again.
getStats := func(tCtx ktesting.TContext) resourceslice.Stats { return controller.GetStats() }
ktesting.Consistently(tCtx, getStats).WithTimeout(2 * mutationCacheTTL).Should(gomega.Equal(expectStats))
tCtx.Consistently(getStats).WithTimeout(2 * mutationCacheTTL).Should(gomega.Equal(expectStats))
// Ask the controller to delete all slices except for one empty slice.
tCtx.Log("Deleting slices")
@ -120,7 +120,7 @@ func TestCreateResourceSlices(tCtx ktesting.TContext, numSlices int) {
// One empty slice should remain, after removing the full ones and adding the empty one.
emptySlice := gomega.HaveField("Spec.Devices", gomega.BeEmpty())
ktesting.Eventually(tCtx, listSlices).WithTimeout(2 * time.Minute).Should(gomega.HaveField("Items", gomega.HaveExactElements(emptySlice)))
tCtx.Eventually(listSlices).WithTimeout(2 * time.Minute).Should(gomega.HaveField("Items", gomega.HaveExactElements(emptySlice)))
expectStats = resourceslice.Stats{NumCreates: int64(numSlices) + 1, NumDeletes: int64(numSlices)}
// There is a window of time where the ResourceSlice exists and is
@ -128,7 +128,7 @@ func TestCreateResourceSlices(tCtx ktesting.TContext, numSlices int) {
// in the controller's stats, consisting mostly of network latency
// between this test process and the API server. Wait for the stats
// to converge before asserting there are no further changes.
ktesting.Eventually(tCtx, getStats).WithTimeout(30 * time.Second).Should(gomega.Equal(expectStats))
tCtx.Eventually(getStats).WithTimeout(30 * time.Second).Should(gomega.Equal(expectStats))
ktesting.Consistently(tCtx, getStats).WithTimeout(2 * mutationCacheTTL).Should(gomega.Equal(expectStats))
tCtx.Consistently(getStats).WithTimeout(2 * mutationCacheTTL).Should(gomega.Equal(expectStats))
}

View file

@ -472,20 +472,18 @@ func (c *Cluster) checkReadiness(tCtx ktesting.TContext, cmd *Cmd) {
c.checkHealthz(tCtx, cmd, "https", c.settings["KUBELET_HOST"], c.settings["KUBELET_PORT"])
// Also wait for the node to be ready.
ktesting.Eventually(tCtx.WithStep("wait for node ready"), func(tCtx ktesting.TContext) []corev1.Node {
nodes, err := tCtx.Client().CoreV1().Nodes().List(tCtx, metav1.ListOptions{})
tCtx.ExpectNoError(err, "list nodes")
return nodes.Items
}).Should(gomega.ConsistOf(gomega.HaveField("Status.Conditions", gomega.ContainElement(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
tCtx.WithStep("wait for node ready").Eventually(func(tCtx ktesting.TContext) (*corev1.NodeList, error) {
return tCtx.Client().CoreV1().Nodes().List(tCtx, metav1.ListOptions{})
}).Should(gomega.HaveField("Items", gomega.ConsistOf(gomega.HaveField("Status.Conditions", gomega.ContainElement(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
"Type": gomega.Equal(corev1.NodeReady),
"Status": gomega.Equal(corev1.ConditionTrue),
})))))
}))))))
}
}
func (c *Cluster) checkHealthz(tCtx ktesting.TContext, cmd *Cmd, method, hostIP, port string) {
url := fmt.Sprintf("%s://%s:%s/healthz", method, hostIP, port)
ktesting.Eventually(tCtx, func(tCtx ktesting.TContext) error {
tCtx.WithStep(fmt.Sprintf("check health %s", url)).Eventually(func(tCtx ktesting.TContext) error {
if !cmd.Running() {
return gomega.StopTrying(fmt.Sprintf("%s stopped unexpectedly", cmd.Name))
}