Skip to content

Commit 6c2356d

Browse files
committed
e2e: pcieroot: add resourceslice tests
Bootstrap resource slice tests to check the attribute values. Enable DRAListTypeAttributes, and check we populate `dra.cpu/pcieRoots` correctly and consistently. We can't predict what will show up on CI and how, so the tests are, out of necessity, laxer than they can be. Signed-off-by: Francesco Romani <fromani@redhat.com>
1 parent 2a0d0cf commit 6c2356d

1 file changed

Lines changed: 149 additions & 0 deletions

File tree

test/e2e/resource_slice_test.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
Copyright The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package e2e
18+
19+
import (
20+
"context"
21+
22+
"github.com/kubernetes-sigs/dra-driver-cpu/pkg/driver"
23+
"github.com/kubernetes-sigs/dra-driver-cpu/test/pkg/fixture"
24+
"github.com/onsi/ginkgo/v2"
25+
"github.com/onsi/gomega"
26+
resourcev1 "k8s.io/api/resource/v1"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
)
29+
30+
const (
31+
driverName = "dra.cpu"
32+
)
33+
34+
var _ = ginkgo.Describe("Resource Attributes", ginkgo.Ordered, ginkgo.ContinueOnFailure, func() {
35+
var (
36+
fxt *fixture.Fixture
37+
cpuDeviceMode string
38+
slices []resourcev1.ResourceSlice
39+
)
40+
41+
ginkgo.BeforeAll(func(ctx context.Context) {
42+
var err error
43+
fxt, err = fixture.ForGinkgo()
44+
gomega.Expect(err).ToNot(gomega.HaveOccurred(), "cannot create fixture")
45+
46+
ginkgo.By("reading daemonset configuration")
47+
daemonSet, err := fxt.K8SClientset.AppsV1().DaemonSets(daemonSetNamespace).Get(ctx, "dracpu", metav1.GetOptions{})
48+
gomega.Expect(err).ToNot(gomega.HaveOccurred(), "cannot get dracpu daemonset")
49+
gomega.Expect(daemonSet.Spec.Template.Spec.Containers).ToNot(gomega.BeEmpty())
50+
51+
cnt := &daemonSet.Spec.Template.Spec.Containers[0]
52+
if val, ok := findArgInContainer(cnt, argCPUDeviceMode); ok {
53+
cpuDeviceMode = val
54+
}
55+
fxt.Log.Info("daemonset configuration", "cpuDeviceMode", cpuDeviceMode)
56+
57+
ginkgo.By("listing ResourceSlices for driver " + driverName)
58+
sliceList, err := fxt.K8SClientset.ResourceV1().ResourceSlices().List(ctx, metav1.ListOptions{
59+
FieldSelector: "spec.driver=" + driverName,
60+
})
61+
gomega.Expect(err).ToNot(gomega.HaveOccurred(), "cannot list ResourceSlices")
62+
gomega.Expect(sliceList.Items).ToNot(gomega.BeEmpty(), "no ResourceSlices found for driver %s", driverName)
63+
slices = sliceList.Items
64+
fxt.Log.Info("found ResourceSlices", "count", len(slices))
65+
})
66+
67+
ginkgo.It("should have devices in ResourceSlices", func() {
68+
totalDevices := 0
69+
for _, slice := range slices {
70+
totalDevices += len(slice.Spec.Devices)
71+
}
72+
gomega.Expect(totalDevices).To(gomega.BeNumerically(">", 0), "no devices found across all ResourceSlices")
73+
})
74+
75+
ginkgo.It("should have correct base attributes on every device", func() {
76+
type attrCheck struct {
77+
name resourcev1.QualifiedName
78+
checker func(resourcev1.DeviceAttribute) bool
79+
}
80+
81+
isInt := func(a resourcev1.DeviceAttribute) bool { return a.IntValue != nil }
82+
isBool := func(a resourcev1.DeviceAttribute) bool { return a.BoolValue != nil }
83+
isString := func(a resourcev1.DeviceAttribute) bool { return a.StringValue != nil }
84+
85+
var checks []attrCheck
86+
switch cpuDeviceMode {
87+
case driver.CPU_DEVICE_MODE_INDIVIDUAL:
88+
checks = []attrCheck{
89+
{driver.AttributeNUMANodeID, isInt},
90+
{driver.AttributeSocketID, isInt},
91+
{driver.AttributeSMTEnabled, isBool},
92+
{driver.AttributeCacheL3ID, isInt},
93+
{driver.AttributeCoreType, isString},
94+
{driver.AttributeCoreID, isInt},
95+
{driver.AttributeCPUID, isInt},
96+
}
97+
default:
98+
checks = []attrCheck{
99+
{driver.AttributeSocketID, isInt},
100+
{driver.AttributeSMTEnabled, isBool},
101+
{driver.AttributeNumCPUs, isInt},
102+
}
103+
}
104+
105+
for _, slice := range slices {
106+
for _, dev := range slice.Spec.Devices {
107+
for _, check := range checks {
108+
attr, ok := dev.Attributes[check.name]
109+
gomega.Expect(ok).To(gomega.BeTrue(),
110+
"device %q in slice %q missing attribute %s", dev.Name, slice.Name, check.name)
111+
gomega.Expect(check.checker(attr)).To(gomega.BeTrue(),
112+
"device %q in slice %q attribute %s has wrong type", dev.Name, slice.Name, check.name)
113+
}
114+
}
115+
}
116+
})
117+
118+
ginkgo.It("should have valid PCIe root attributes when present", func() {
119+
devicesWithPCIeRoots := 0
120+
121+
for _, slice := range slices {
122+
for _, dev := range slice.Spec.Devices {
123+
_, hasPCIeRoots := dev.Attributes[driver.AttributePCIeRoots]
124+
if !hasPCIeRoots {
125+
continue
126+
}
127+
devicesWithPCIeRoots++
128+
}
129+
}
130+
131+
if devicesWithPCIeRoots == 0 {
132+
// Skip is more explicit than passing the tests doing nothing.
133+
// It's the strongest signal we get until we find a way to inspect the system before
134+
// the suite runs and set expectations accordingly.
135+
ginkgo.Skip("No PCIe roots reported on this system")
136+
}
137+
138+
for _, slice := range slices {
139+
for _, dev := range slice.Spec.Devices {
140+
pcieRoots, ok := dev.Attributes[driver.AttributePCIeRoots]
141+
if !ok {
142+
continue
143+
}
144+
gomega.Expect(pcieRoots.StringValues).ToNot(gomega.BeEmpty(),
145+
"device %q in slice %q has dra.cpu/pcieRoots but StringValues is empty", dev.Name, slice.Name)
146+
}
147+
}
148+
})
149+
})

0 commit comments

Comments
 (0)