@@ -2,13 +2,18 @@ package devicestate
22
33import (
44 "context"
5+ "fmt"
56
67 . "github.com/onsi/ginkgo/v2"
78 . "github.com/onsi/gomega"
9+ "go.uber.org/mock/gomock"
10+ "k8s.io/utils/ptr"
811
912 resourceapi "k8s.io/api/resource/v1"
1013
1114 "github.com/k8snetworkplumbingwg/dra-driver-sriov/pkg/consts"
15+ "github.com/k8snetworkplumbingwg/dra-driver-sriov/pkg/host"
16+ mock_host "github.com/k8snetworkplumbingwg/dra-driver-sriov/pkg/host/mock"
1217)
1318
1419var _ = Describe ("Manager" , func () {
@@ -45,4 +50,212 @@ var _ = Describe("Manager", func() {
4550 Expect (exists ).To (BeFalse ())
4651 })
4752 })
53+
54+ Context ("RDMA Device Preparation" , func () {
55+ It ("should skip RDMA preparation when device is not RDMA capable" , func () {
56+ // Create device without RDMA capability
57+ nonRdmaDevice := & resourceapi.Device {
58+ Name : "0000-08-00-1" ,
59+ Attributes : map [resourceapi.QualifiedName ]resourceapi.DeviceAttribute {
60+ consts .AttributePciAddress : {
61+ StringValue : ptr .To ("0000:08:00.1" ),
62+ },
63+ consts .AttributeRDMACapable : {
64+ BoolValue : ptr .To (false ),
65+ },
66+ },
67+ }
68+
69+ // Verify device is not RDMA capable
70+ rdmaCapable , exists := nonRdmaDevice .Attributes [consts .AttributeRDMACapable ]
71+ Expect (exists ).To (BeTrue ())
72+ Expect (rdmaCapable .BoolValue ).ToNot (BeNil ())
73+ Expect (* rdmaCapable .BoolValue ).To (BeFalse ())
74+
75+ // Test the conditional logic that determines if RDMA preparation should occur
76+ // This replicates the production code condition:
77+ // if rdmaCapableAttr, ok := deviceInfo.Attributes[consts.AttributeRDMACapable]; ok && rdmaCapableAttr.BoolValue != nil && *rdmaCapableAttr.BoolValue
78+ shouldPrepareRDMA := exists && rdmaCapable .BoolValue != nil && * rdmaCapable .BoolValue
79+ Expect (shouldPrepareRDMA ).To (BeFalse (), "RDMA preparation should be skipped for non-RDMA capable devices" )
80+
81+ // When this condition is false, the production code never calls:
82+ // - GetRDMADeviceForPCI
83+ // - GetRDMACharDevices
84+ // This test verifies the condition evaluates correctly for non-RDMA devices
85+ })
86+ })
87+
88+ Context ("handleRDMADevice" , func () {
89+ var (
90+ mockCtrl * gomock.Controller
91+ mockHost * mock_host.MockInterface
92+ origHelpers host.Interface
93+ manager * Manager
94+ )
95+
96+ BeforeEach (func () {
97+ mockCtrl = gomock .NewController (GinkgoT ())
98+ mockHost = mock_host .NewMockInterface (mockCtrl )
99+ // Save original helpers and replace with mock
100+ _ = host .GetHelpers ()
101+ origHelpers = host .Helpers
102+ host .Helpers = mockHost
103+
104+ manager = & Manager {}
105+ })
106+
107+ AfterEach (func () {
108+ // Restore original helpers
109+ host .Helpers = origHelpers
110+ mockCtrl .Finish ()
111+ })
112+
113+ It ("should return device nodes and environment variables for RDMA device" , func () {
114+ pciAddress := "0000:08:00.1"
115+ deviceName := "device-1"
116+ rdmaDeviceName := "mlx5_0"
117+
118+ // Mock GetRDMADeviceForPCI to return one RDMA device
119+ mockHost .EXPECT ().GetRDMADeviceForPCI (pciAddress ).Return ([]string {rdmaDeviceName }, nil )
120+
121+ // Mock GetRDMACharDevices to return various character devices
122+ mockHost .EXPECT ().GetRDMACharDevices (rdmaDeviceName ).Return ([]string {
123+ "/dev/infiniband/uverbs0" ,
124+ "/dev/infiniband/umad0" ,
125+ "/dev/infiniband/issm0" ,
126+ "/dev/infiniband/rdma_cm" ,
127+ }, nil )
128+
129+ // Call the function
130+ deviceNodes , envs , err := manager .handleRDMADevice (context .Background (), pciAddress , deviceName )
131+
132+ // Verify no error
133+ Expect (err ).ToNot (HaveOccurred ())
134+
135+ // Verify device nodes
136+ Expect (deviceNodes ).To (HaveLen (4 ))
137+ Expect (deviceNodes [0 ].Path ).To (Equal ("/dev/infiniband/uverbs0" ))
138+ Expect (deviceNodes [0 ].HostPath ).To (Equal ("/dev/infiniband/uverbs0" ))
139+ Expect (deviceNodes [0 ].Type ).To (Equal ("c" ))
140+ Expect (deviceNodes [1 ].Path ).To (Equal ("/dev/infiniband/umad0" ))
141+ Expect (deviceNodes [2 ].Path ).To (Equal ("/dev/infiniband/issm0" ))
142+ Expect (deviceNodes [3 ].Path ).To (Equal ("/dev/infiniband/rdma_cm" ))
143+
144+ // Verify environment variables
145+ Expect (envs ).To (HaveLen (5 ))
146+ Expect (envs ).To (ContainElement ("SRIOVNETWORK_device_1_mlx50_RDMA_UVERBS=/dev/infiniband/uverbs0" ))
147+ Expect (envs ).To (ContainElement ("SRIOVNETWORK_device_1_mlx50_RDMA_UMAD=/dev/infiniband/umad0" ))
148+ Expect (envs ).To (ContainElement ("SRIOVNETWORK_device_1_mlx50_RDMA_ISSM=/dev/infiniband/issm0" ))
149+ Expect (envs ).To (ContainElement ("SRIOVNETWORK_device_1_mlx50_RDMA_CM=/dev/infiniband/rdma_cm" ))
150+ Expect (envs ).To (ContainElement ("SRIOVNETWORK_device_1_mlx50_RDMA_DEVICE=mlx5_0" ))
151+ })
152+
153+ It ("should handle multiple RDMA devices" , func () {
154+ pciAddress := "0000:08:00.1"
155+ deviceName := "device-1"
156+
157+ // Mock GetRDMADeviceForPCI to return two RDMA devices
158+ mockHost .EXPECT ().GetRDMADeviceForPCI (pciAddress ).Return ([]string {"mlx5_0" , "mlx5_1" }, nil )
159+
160+ // Mock GetRDMACharDevices for first device
161+ mockHost .EXPECT ().GetRDMACharDevices ("mlx5_0" ).Return ([]string {"/dev/infiniband/uverbs0" }, nil )
162+
163+ // Mock GetRDMACharDevices for second device
164+ mockHost .EXPECT ().GetRDMACharDevices ("mlx5_1" ).Return ([]string {"/dev/infiniband/uverbs1" }, nil )
165+
166+ // Call the function
167+ deviceNodes , envs , err := manager .handleRDMADevice (context .Background (), pciAddress , deviceName )
168+
169+ // Verify no error
170+ Expect (err ).ToNot (HaveOccurred ())
171+
172+ // Verify device nodes for both RDMA devices
173+ Expect (deviceNodes ).To (HaveLen (2 ))
174+ Expect (deviceNodes [0 ].Path ).To (Equal ("/dev/infiniband/uverbs0" ))
175+ Expect (deviceNodes [1 ].Path ).To (Equal ("/dev/infiniband/uverbs1" ))
176+
177+ // Verify environment variables for both RDMA devices
178+ Expect (envs ).To (HaveLen (4 ))
179+ Expect (envs ).To (ContainElement ("SRIOVNETWORK_device_1_mlx50_RDMA_UVERBS=/dev/infiniband/uverbs0" ))
180+ Expect (envs ).To (ContainElement ("SRIOVNETWORK_device_1_mlx50_RDMA_DEVICE=mlx5_0" ))
181+ Expect (envs ).To (ContainElement ("SRIOVNETWORK_device_1_mlx51_RDMA_UVERBS=/dev/infiniband/uverbs1" ))
182+ Expect (envs ).To (ContainElement ("SRIOVNETWORK_device_1_mlx51_RDMA_DEVICE=mlx5_1" ))
183+ })
184+
185+ It ("should return error when GetRDMADeviceForPCI fails" , func () {
186+ pciAddress := "0000:08:00.1"
187+ deviceName := "device-1"
188+
189+ // Mock GetRDMADeviceForPCI to return an error
190+ mockHost .EXPECT ().GetRDMADeviceForPCI (pciAddress ).Return (nil , fmt .Errorf ("failed to get RDMA devices" ))
191+
192+ // Call the function
193+ deviceNodes , envs , err := manager .handleRDMADevice (context .Background (), pciAddress , deviceName )
194+
195+ // Verify error is returned
196+ Expect (err ).To (HaveOccurred ())
197+ Expect (err .Error ()).To (ContainSubstring ("failed to get RDMA devices" ))
198+ Expect (deviceNodes ).To (BeNil ())
199+ Expect (envs ).To (BeNil ())
200+ })
201+
202+ It ("should return error when no RDMA devices found" , func () {
203+ pciAddress := "0000:08:00.1"
204+ deviceName := "device-1"
205+
206+ // Mock GetRDMADeviceForPCI to return empty list
207+ mockHost .EXPECT ().GetRDMADeviceForPCI (pciAddress ).Return ([]string {}, nil )
208+
209+ // Call the function
210+ deviceNodes , envs , err := manager .handleRDMADevice (context .Background (), pciAddress , deviceName )
211+
212+ // Verify error is returned
213+ Expect (err ).To (HaveOccurred ())
214+ Expect (err .Error ()).To (ContainSubstring ("no RDMA devices found" ))
215+ Expect (deviceNodes ).To (BeNil ())
216+ Expect (envs ).To (BeNil ())
217+ })
218+
219+ It ("should return error when GetRDMACharDevices fails" , func () {
220+ pciAddress := "0000:08:00.1"
221+ deviceName := "device-1"
222+ rdmaDeviceName := "mlx5_0"
223+
224+ // Mock GetRDMADeviceForPCI to return one RDMA device
225+ mockHost .EXPECT ().GetRDMADeviceForPCI (pciAddress ).Return ([]string {rdmaDeviceName }, nil )
226+
227+ // Mock GetRDMACharDevices to return an error
228+ mockHost .EXPECT ().GetRDMACharDevices (rdmaDeviceName ).Return (nil , fmt .Errorf ("failed to get char devices" ))
229+
230+ // Call the function
231+ deviceNodes , envs , err := manager .handleRDMADevice (context .Background (), pciAddress , deviceName )
232+
233+ // Verify error is returned
234+ Expect (err ).To (HaveOccurred ())
235+ Expect (err .Error ()).To (ContainSubstring ("failed to get char devices" ))
236+ Expect (deviceNodes ).To (BeNil ())
237+ Expect (envs ).To (BeNil ())
238+ })
239+
240+ It ("should return error when no character devices found" , func () {
241+ pciAddress := "0000:08:00.1"
242+ deviceName := "device-1"
243+ rdmaDeviceName := "mlx5_0"
244+
245+ // Mock GetRDMADeviceForPCI to return one RDMA device
246+ mockHost .EXPECT ().GetRDMADeviceForPCI (pciAddress ).Return ([]string {rdmaDeviceName }, nil )
247+
248+ // Mock GetRDMACharDevices to return empty list
249+ mockHost .EXPECT ().GetRDMACharDevices (rdmaDeviceName ).Return ([]string {}, nil )
250+
251+ // Call the function
252+ deviceNodes , envs , err := manager .handleRDMADevice (context .Background (), pciAddress , deviceName )
253+
254+ // Verify error is returned
255+ Expect (err ).To (HaveOccurred ())
256+ Expect (err .Error ()).To (ContainSubstring ("no RDMA character devices found" ))
257+ Expect (deviceNodes ).To (BeNil ())
258+ Expect (envs ).To (BeNil ())
259+ })
260+ })
48261})
0 commit comments