@@ -5,8 +5,11 @@ import (
55
66 . "github.com/onsi/ginkgo/v2"
77 . "github.com/onsi/gomega"
8+ "go.uber.org/mock/gomock"
9+ "k8s.io/utils/ptr"
810
911 "github.com/k8snetworkplumbingwg/dra-driver-sriov/pkg/consts"
12+ mock_host "github.com/k8snetworkplumbingwg/dra-driver-sriov/pkg/host/mock"
1013 resourceapi "k8s.io/api/resource/v1"
1114)
1215
@@ -44,4 +47,207 @@ var _ = Describe("Manager", func() {
4447 Expect (exists ).To (BeFalse ())
4548 })
4649 })
50+
51+ Context ("RDMA Device Preparation" , func () {
52+ var (
53+ mockCtrl * gomock.Controller
54+ mockHost * mock_host.MockInterface
55+ deviceInfo * resourceapi.Device
56+ pciAddress string
57+ charDevices []string
58+ )
59+
60+ BeforeEach (func () {
61+ mockCtrl = gomock .NewController (GinkgoT ())
62+ mockHost = mock_host .NewMockInterface (mockCtrl )
63+
64+ pciAddress = "0000:08:00.5"
65+ charDevices = []string {
66+ "/dev/infiniband/issm5" ,
67+ "/dev/infiniband/umad5" ,
68+ "/dev/infiniband/uverbs5" ,
69+ "/dev/infiniband/rdma_cm" ,
70+ }
71+
72+ // Create a device with RDMA attributes
73+ deviceInfo = & resourceapi.Device {
74+ Name : "0000-08-00-5" ,
75+ Attributes : map [resourceapi.QualifiedName ]resourceapi.DeviceAttribute {
76+ consts .AttributePciAddress : {
77+ StringValue : ptr .To (pciAddress ),
78+ },
79+ consts .AttributeRDMACapable : {
80+ BoolValue : ptr .To (true ),
81+ },
82+ },
83+ }
84+ })
85+
86+ AfterEach (func () {
87+ mockCtrl .Finish ()
88+ })
89+
90+ It ("should add RDMA character devices to CDI spec" , func () {
91+ // Verify device has RDMA attributes
92+ Expect (deviceInfo .Attributes [consts .AttributeRDMACapable ].BoolValue ).ToNot (BeNil ())
93+ Expect (* deviceInfo .Attributes [consts .AttributeRDMACapable ].BoolValue ).To (BeTrue ())
94+
95+ // Mock GetRDMADeviceForPCI to return RDMA device name
96+ mockHost .EXPECT ().
97+ GetRDMADeviceForPCI (pciAddress ).
98+ Return ([]string {"mlx5_5" }, nil ).
99+ Times (1 )
100+
101+ // Mock GetRDMACharDevices to return character devices
102+ mockHost .EXPECT ().
103+ GetRDMACharDevices ("mlx5_5" ).
104+ Return (charDevices , nil ).
105+ Times (1 )
106+
107+ // Verify RDMA device can be retrieved
108+ rdmaDevices , err := mockHost .GetRDMADeviceForPCI (pciAddress )
109+ Expect (err ).ToNot (HaveOccurred ())
110+ Expect (rdmaDevices ).To (HaveLen (1 ))
111+ Expect (rdmaDevices [0 ]).To (Equal ("mlx5_5" ))
112+
113+ // Verify character devices would be returned
114+ devices , err := mockHost .GetRDMACharDevices ("mlx5_5" )
115+ Expect (err ).ToNot (HaveOccurred ())
116+ Expect (devices ).To (HaveLen (4 ))
117+ Expect (devices ).To (ContainElement ("/dev/infiniband/uverbs5" ))
118+ })
119+
120+ It ("should add RDMA environment variables for each character device type" , func () {
121+ // Verify environment variable naming patterns with RDMA device name included
122+ devicePrefix := "0000_08_00_5"
123+ rdmaDeviceSanitized := "mlx55" // mlx5_5 with underscores removed
124+
125+ expectedEnvVars := map [string ]string {
126+ "SRIOVNETWORK_" + devicePrefix + "_" + rdmaDeviceSanitized + "_RDMA_ISSM" : "/dev/infiniband/issm5" ,
127+ "SRIOVNETWORK_" + devicePrefix + "_" + rdmaDeviceSanitized + "_RDMA_UMAD" : "/dev/infiniband/umad5" ,
128+ "SRIOVNETWORK_" + devicePrefix + "_" + rdmaDeviceSanitized + "_RDMA_UVERBS" : "/dev/infiniband/uverbs5" ,
129+ "SRIOVNETWORK_" + devicePrefix + "_" + rdmaDeviceSanitized + "_RDMA_CM" : "/dev/infiniband/rdma_cm" ,
130+ "SRIOVNETWORK_" + devicePrefix + "_" + rdmaDeviceSanitized + "_RDMA_DEVICE" : "mlx5_5" ,
131+ }
132+
133+ // This verifies the expected environment variable format
134+ Expect (expectedEnvVars ).To (HaveLen (5 ))
135+ Expect (expectedEnvVars ).To (HaveKeyWithValue ("SRIOVNETWORK_0000_08_00_5_mlx55_RDMA_DEVICE" , "mlx5_5" ))
136+ })
137+
138+ It ("should handle multiple RDMA devices" , func () {
139+ // Mock GetRDMADeviceForPCI to return multiple RDMA devices
140+ mockHost .EXPECT ().
141+ GetRDMADeviceForPCI (pciAddress ).
142+ Return ([]string {"mlx5_5" , "mlx5_6" }, nil ).
143+ Times (1 )
144+
145+ // Mock calls for both devices
146+ mockHost .EXPECT ().
147+ GetRDMACharDevices ("mlx5_5" ).
148+ Return ([]string {"/dev/infiniband/uverbs5" , "/dev/infiniband/rdma_cm" }, nil ).
149+ Times (1 )
150+
151+ mockHost .EXPECT ().
152+ GetRDMACharDevices ("mlx5_6" ).
153+ Return ([]string {"/dev/infiniband/uverbs6" , "/dev/infiniband/rdma_cm" }, nil ).
154+ Times (1 )
155+
156+ // Verify GetRDMADeviceForPCI returns multiple devices
157+ rdmaDevicesList , err := mockHost .GetRDMADeviceForPCI (pciAddress )
158+ Expect (err ).ToNot (HaveOccurred ())
159+ Expect (rdmaDevicesList ).To (HaveLen (2 ))
160+
161+ // Call the mocked methods to satisfy expectations
162+ devices1 , err1 := mockHost .GetRDMACharDevices ("mlx5_5" )
163+ Expect (err1 ).ToNot (HaveOccurred ())
164+ Expect (devices1 ).To (HaveLen (2 ))
165+
166+ devices2 , err2 := mockHost .GetRDMACharDevices ("mlx5_6" )
167+ Expect (err2 ).ToNot (HaveOccurred ())
168+ Expect (devices2 ).To (HaveLen (2 ))
169+ })
170+
171+ It ("should skip RDMA preparation when device is not RDMA capable" , func () {
172+ // Create device without RDMA capability
173+ nonRdmaDevice := & resourceapi.Device {
174+ Name : "0000-08-00-1" ,
175+ Attributes : map [resourceapi.QualifiedName ]resourceapi.DeviceAttribute {
176+ consts .AttributePciAddress : {
177+ StringValue : ptr .To ("0000:08:00.1" ),
178+ },
179+ consts .AttributeRDMACapable : {
180+ BoolValue : ptr .To (false ),
181+ },
182+ },
183+ }
184+
185+ // Verify device is not RDMA capable
186+ rdmaCapable , exists := nonRdmaDevice .Attributes [consts .AttributeRDMACapable ]
187+ Expect (exists ).To (BeTrue ())
188+ Expect (rdmaCapable .BoolValue ).ToNot (BeNil ())
189+ Expect (* rdmaCapable .BoolValue ).To (BeFalse ())
190+
191+ // Test the conditional logic that determines if RDMA preparation should occur
192+ // This replicates the production code condition:
193+ // if rdmaCapableAttr, ok := deviceInfo.Attributes[consts.AttributeRDMACapable]; ok && rdmaCapableAttr.BoolValue != nil && *rdmaCapableAttr.BoolValue
194+ shouldPrepareRDMA := exists && rdmaCapable .BoolValue != nil && * rdmaCapable .BoolValue
195+ Expect (shouldPrepareRDMA ).To (BeFalse (), "RDMA preparation should be skipped for non-RDMA capable devices" )
196+
197+ // When this condition is false, the production code never calls:
198+ // - GetRDMADeviceForPCI
199+ // - GetRDMACharDevices
200+ // This test verifies the condition evaluates correctly for non-RDMA devices
201+ })
202+
203+ It ("should handle empty RDMA devices list" , func () {
204+ // Mock GetRDMADeviceForPCI to return empty list
205+ mockHost .EXPECT ().
206+ GetRDMADeviceForPCI (pciAddress ).
207+ Return ([]string {}, nil ).
208+ Times (1 )
209+
210+ // GetRDMACharDevices should NOT be called when no RDMA devices
211+ mockHost .EXPECT ().
212+ GetRDMACharDevices (gomock .Any ()).
213+ Times (0 )
214+
215+ // Verify empty list handling
216+ rdmaDevices , err := mockHost .GetRDMADeviceForPCI (pciAddress )
217+ Expect (err ).ToNot (HaveOccurred ())
218+ Expect (rdmaDevices ).To (BeEmpty ())
219+ })
220+
221+ It ("should handle GetRDMACharDevices returning empty list" , func () {
222+ // Mock returning empty list
223+ mockHost .EXPECT ().
224+ GetRDMACharDevices ("mlx5_5" ).
225+ Return ([]string {}, nil ).
226+ Times (1 )
227+
228+ // Call the mocked method
229+ devices , err := mockHost .GetRDMACharDevices ("mlx5_5" )
230+
231+ // This should not cause errors, just return empty list
232+ Expect (err ).ToNot (HaveOccurred ())
233+ Expect (devices ).To (BeEmpty ())
234+ })
235+
236+ It ("should verify character device types are correctly identified" , func () {
237+ // Test the device type identification logic
238+ testCases := []struct {
239+ path string
240+ expected string
241+ }{
242+ {"/dev/infiniband/uverbs0" , "uverbs" },
243+ {"/dev/infiniband/umad0" , "umad" },
244+ {"/dev/infiniband/issm0" , "issm" },
245+ {"/dev/infiniband/rdma_cm" , "rdma_cm" },
246+ }
247+
248+ for _ , tc := range testCases {
249+ Expect (tc .path ).To (ContainSubstring (tc .expected ))
250+ }
251+ })
252+ })
47253})
0 commit comments