Remove main() and __main__ from tests.
[yardstick.git] / tests / unit / network_services / helpers / test_dpdkbindnic_helper.py
1 # Copyright (c) 2016-2017 Intel Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import mock
16 import unittest
17
18 import os
19
20 from yardstick.error import IncorrectConfig, SSHError
21 from yardstick.error import IncorrectNodeSetup
22 from yardstick.error import IncorrectSetup
23 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkInterface
24 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkNode
25 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper
26 from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelperException
27 from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_KERNEL
28 from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_DPDK
29 from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_KERNEL
30 from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_DPDK
31 from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_OTHER
32 from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_OTHER
33
34
35 NAME = "tg_0"
36
37
38 class TestDpdkInterface(unittest.TestCase):
39
40     SAMPLE_NETDEVS = {
41         'enp11s0': {
42             'address': '0a:de:ad:be:ef:f5',
43             'device': '0x1533',
44             'driver': 'igb',
45             'ifindex': '2',
46             'interface_name': 'enp11s0',
47             'operstate': 'down',
48             'pci_bus_id': '0000:0b:00.0',
49             'subsystem_device': '0x1533',
50             'subsystem_vendor': '0x15d9',
51             'vendor': '0x8086'
52         },
53         'lan': {
54             'address': '0a:de:ad:be:ef:f4',
55             'device': '0x153a',
56             'driver': 'e1000e',
57             'ifindex': '3',
58             'interface_name': 'lan',
59             'operstate': 'up',
60             'pci_bus_id': '0000:00:19.0',
61             'subsystem_device': '0x153a',
62             'subsystem_vendor': '0x15d9',
63             'vendor': '0x8086'
64         }
65     }
66
67     SAMPLE_VM_NETDEVS = {
68         'eth1': {
69             'address': 'fa:de:ad:be:ef:5b',
70             'device': '0x0001',
71             'driver': 'virtio_net',
72             'ifindex': '3',
73             'interface_name': 'eth1',
74             'operstate': 'down',
75             'pci_bus_id': '0000:00:04.0',
76             'vendor': '0x1af4'
77         }
78     }
79
80     def test_parse_netdev_info(self):
81         output = """\
82 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/ifindex:2
83 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/address:0a:de:ad:be:ef:f5
84 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/operstate:down
85 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/vendor:0x8086
86 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/device:0x1533
87 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_vendor:0x15d9
88 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_device:0x1533
89 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/driver:igb
90 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/pci_bus_id:0000:0b:00.0
91 /sys/devices/pci0000:00/0000:00:19.0/net/lan/ifindex:3
92 /sys/devices/pci0000:00/0000:00:19.0/net/lan/address:0a:de:ad:be:ef:f4
93 /sys/devices/pci0000:00/0000:00:19.0/net/lan/operstate:up
94 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/vendor:0x8086
95 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/device:0x153a
96 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_vendor:0x15d9
97 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_device:0x153a
98 /sys/devices/pci0000:00/0000:00:19.0/net/lan/driver:e1000e
99 /sys/devices/pci0000:00/0000:00:19.0/net/lan/pci_bus_id:0000:00:19.0
100 """
101         res = DpdkBindHelper.parse_netdev_info(output)
102         self.assertDictEqual(res, self.SAMPLE_NETDEVS)
103
104     def test_parse_netdev_info_virtio(self):
105         output = """\
106 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/ifindex:3
107 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/address:fa:de:ad:be:ef:5b
108 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/operstate:down
109 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/vendor:0x1af4
110 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/device:0x0001
111 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/driver:virtio_net
112 """
113         res = DpdkBindHelper.parse_netdev_info(output)
114         self.assertDictEqual(res, self.SAMPLE_VM_NETDEVS)
115
116     def test_probe_missing_values(self):
117         mock_dpdk_node = mock.Mock()
118         mock_dpdk_node.netdevs = self.SAMPLE_NETDEVS.copy()
119
120         interface = {'local_mac': '0a:de:ad:be:ef:f5'}
121         dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
122
123         dpdk_intf.probe_missing_values()
124         self.assertEqual(interface['vpci'], '0000:0b:00.0')
125
126         interface['local_mac'] = '0a:de:ad:be:ef:f4'
127         dpdk_intf.probe_missing_values()
128         self.assertEqual(interface['vpci'], '0000:00:19.0')
129
130     def test_probe_missing_values_no_update(self):
131         mock_dpdk_node = mock.Mock()
132         mock_dpdk_node.netdevs = self.SAMPLE_NETDEVS.copy()
133         del mock_dpdk_node.netdevs['enp11s0']['driver']
134         del mock_dpdk_node.netdevs['lan']['driver']
135
136         interface = {'local_mac': '0a:de:ad:be:ef:f5'}
137         dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
138
139         dpdk_intf.probe_missing_values()
140         self.assertNotIn('vpci', interface)
141         self.assertNotIn('driver', interface)
142
143     def test_probe_missing_values_negative(self):
144         mock_dpdk_node = mock.Mock()
145         mock_dpdk_node.netdevs.values.side_effect = IncorrectNodeSetup
146
147         interface = {'local_mac': '0a:de:ad:be:ef:f5'}
148         dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
149
150         with self.assertRaises(IncorrectConfig):
151             dpdk_intf.probe_missing_values()
152
153
154 class TestDpdkNode(unittest.TestCase):
155
156     INTERFACES = [
157         {'name': 'name1',
158          'virtual-interface': {
159              'local_mac': 404,
160              'vpci': 'pci10',
161          }},
162         {'name': 'name2',
163          'virtual-interface': {
164              'local_mac': 404,
165              'vpci': 'pci2',
166          }},
167         {'name': 'name3',
168          'virtual-interface': {
169              'local_mac': 404,
170              'vpci': 'some-pci1',
171          }},
172     ]
173
174     def test_probe_dpdk_drivers(self):
175         mock_ssh_helper = mock.Mock()
176         mock_ssh_helper.execute.return_value = 0, '', ''
177
178         interfaces = [
179             {'name': 'name1',
180              'virtual-interface': {
181                  'local_mac': 404,
182                  'vpci': 'pci10',
183              }},
184             {'name': 'name2',
185              'virtual-interface': {
186                  'local_mac': 404,
187                  'vpci': 'pci2',
188              }},
189             {'name': 'name3',
190              'virtual-interface': {
191                  'local_mac': 404,
192                  'vpci': 'some-pci1',
193              }},
194         ]
195
196         dpdk_node = DpdkNode(NAME, interfaces, mock_ssh_helper)
197         dpdk_helper = dpdk_node.dpdk_helper
198
199         dpdk_helper.probe_real_kernel_drivers = mock.Mock()
200         dpdk_helper.real_kernel_interface_driver_map = {
201             'pci1': 'driver1',
202             'pci2': 'driver2',
203             'pci3': 'driver3',
204             'pci4': 'driver1',
205             'pci6': 'driver3',
206         }
207
208         dpdk_node._probe_dpdk_drivers()
209         self.assertNotIn('driver', interfaces[0]['virtual-interface'])
210         self.assertEqual(interfaces[1]['virtual-interface']['driver'], 'driver2')
211         self.assertEqual(interfaces[2]['virtual-interface']['driver'], 'driver1')
212
213     def test_check(self):
214         def update():
215             if not mock_force_rebind.called:
216                 raise IncorrectConfig
217
218             interfaces[0]['virtual-interface'].update({
219                 'vpci': '0000:01:02.1',
220                 'local_ip': '10.20.30.40',
221                 'netmask': '255.255.0.0',
222                 'driver': 'ixgbe',
223             })
224
225         mock_ssh_helper = mock.Mock()
226         mock_ssh_helper.execute.return_value = 0, '', ''
227
228         interfaces = [
229             {'name': 'name1',
230              'virtual-interface': {
231                  'local_mac': 404,
232              }},
233         ]
234
235         dpdk_node = DpdkNode(NAME, interfaces, mock_ssh_helper)
236         dpdk_node._probe_missing_values = mock_probe_missing = mock.Mock(side_effect=update)
237         dpdk_node._force_rebind = mock_force_rebind = mock.Mock()
238
239         self.assertIsNone(dpdk_node.check())
240         self.assertEqual(mock_probe_missing.call_count, 2)
241
242     @mock.patch('yardstick.network_services.helpers.dpdkbindnic_helper.DpdkInterface')
243     def test_check_negative(self, mock_intf_type):
244         mock_ssh_helper = mock.Mock()
245         mock_ssh_helper.execute.return_value = 0, '', ''
246
247         mock_intf_type().check.side_effect = SSHError
248
249         dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
250
251         with self.assertRaises(IncorrectSetup):
252             dpdk_node.check()
253
254     def test_probe_netdevs(self):
255         mock_ssh_helper = mock.Mock()
256         mock_ssh_helper.execute.return_value = 0, '', ''
257
258         expected = {'key1': 500, 'key2': 'hello world'}
259         update = {'key1': 1000, 'key3': []}
260
261         dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
262         dpdk_helper = dpdk_node.dpdk_helper
263         dpdk_helper.find_net_devices = mock.Mock(side_effect=[expected, update])
264
265         self.assertDictEqual(dpdk_node.netdevs, {})
266         dpdk_node._probe_netdevs()
267         self.assertDictEqual(dpdk_node.netdevs, expected)
268
269         expected = {'key1': 1000, 'key2': 'hello world', 'key3': []}
270         dpdk_node._probe_netdevs()
271         self.assertDictEqual(dpdk_node.netdevs, expected)
272
273     def test_probe_netdevs_setup_negative(self):
274         mock_ssh_helper = mock.Mock()
275         mock_ssh_helper.execute.return_value = 0, '', ''
276
277         dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
278         dpdk_helper = dpdk_node.dpdk_helper
279         dpdk_helper.find_net_devices = mock.Mock(side_effect=DpdkBindHelperException)
280
281         with self.assertRaises(DpdkBindHelperException):
282             dpdk_node._probe_netdevs()
283
284     def test_force_rebind(self):
285         mock_ssh_helper = mock.Mock()
286         mock_ssh_helper.execute.return_value = 0, '', ''
287
288         dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
289         dpdk_helper = dpdk_node.dpdk_helper
290         dpdk_helper.force_dpdk_rebind = mock_helper_func = mock.Mock()
291
292         dpdk_node._force_rebind()
293         self.assertEqual(mock_helper_func.call_count, 1)
294
295
296 class TestDpdkBindHelper(unittest.TestCase):
297     bin_path = "/opt/nsb_bin"
298     EXAMPLE_OUTPUT = """
299
300 Network devices using DPDK-compatible driver
301 ============================================
302 0000:00:04.0 'Virtio network device' drv=igb_uio unused=
303 0000:00:05.0 'Virtio network device' drv=igb_uio unused=
304
305 Network devices using kernel driver
306 ===================================
307 0000:00:03.0 'Virtio network device' if=ens3 drv=virtio-pci unused=igb_uio *Active*
308
309 Other network devices
310 =====================
311 <none>
312
313 Crypto devices using DPDK-compatible driver
314 ===========================================
315 <none>
316
317 Crypto devices using kernel driver
318 ==================================
319 <none>
320
321 Other crypto devices
322 ====================
323 <none>
324 """
325
326     PARSED_EXAMPLE = {
327         NETWORK_DPDK: [
328             {'active': False,
329              'dev_type': 'Virtio network device',
330              'driver': 'igb_uio',
331              'iface': None,
332              'unused': '',
333              'vpci': '0000:00:04.0',
334              },
335             {'active': False,
336              'dev_type': 'Virtio network device',
337              'driver': 'igb_uio',
338              'iface': None,
339              'unused': '',
340              'vpci': '0000:00:05.0',
341              }
342         ],
343         NETWORK_KERNEL: [
344             {'active': True,
345              'dev_type': 'Virtio network device',
346              'driver': 'virtio-pci',
347              'iface': 'ens3',
348              'unused': 'igb_uio',
349              'vpci': '0000:00:03.0',
350              }
351         ],
352         CRYPTO_KERNEL: [],
353         CRYPTO_DPDK: [],
354         NETWORK_OTHER: [],
355         CRYPTO_OTHER: [],
356     }
357
358     CLEAN_STATUS = {
359         NETWORK_KERNEL: [],
360         NETWORK_DPDK: [],
361         CRYPTO_KERNEL: [],
362         CRYPTO_DPDK: [],
363         NETWORK_OTHER: [],
364         CRYPTO_OTHER: [],
365     }
366
367     ONE_INPUT_LINE = ("0000:00:03.0 'Virtio network device' if=ens3 "
368                       "drv=virtio-pci unused=igb_uio *Active*")
369
370     ONE_INPUT_LINE_PARSED = [{
371         'vpci': '0000:00:03.0',
372         'dev_type': 'Virtio network device',
373         'iface': 'ens3',
374         'driver': 'virtio-pci',
375         'unused': 'igb_uio',
376         'active': True,
377     }]
378
379     def test___init__(self):
380         conn = mock.Mock()
381         conn.provision_tool = mock.Mock(return_value='path_to_tool')
382         conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND)
383
384         dpdk_bind_helper = DpdkBindHelper(conn)
385
386         self.assertEqual(conn, dpdk_bind_helper.ssh_helper)
387         self.assertEqual(self.CLEAN_STATUS, dpdk_bind_helper.dpdk_status)
388         self.assertIsNone(dpdk_bind_helper.status_nic_row_re)
389         self.assertEqual(dpdk_bind_helper.dpdk_devbind,
390                          os.path.join(self.bin_path, dpdk_bind_helper.DPDK_DEVBIND))
391         self.assertIsNone(dpdk_bind_helper._status_cmd_attr)
392
393     def test__dpdk_execute(self):
394         conn = mock.Mock()
395         conn.execute = mock.Mock(return_value=(0, 'output', 'error'))
396         conn.provision_tool = mock.Mock(return_value='tool_path')
397         dpdk_bind_helper = DpdkBindHelper(conn)
398         self.assertEqual((0, 'output', 'error'), dpdk_bind_helper._dpdk_execute('command'))
399
400     def test__dpdk_execute_failure(self):
401         conn = mock.Mock()
402         conn.execute = mock.Mock(return_value=(1, 'output', 'error'))
403         conn.provision_tool = mock.Mock(return_value='tool_path')
404         dpdk_bind_helper = DpdkBindHelper(conn)
405         with self.assertRaises(DpdkBindHelperException):
406             dpdk_bind_helper._dpdk_execute('command')
407
408     def test__addline(self):
409         conn = mock.Mock()
410
411         dpdk_bind_helper = DpdkBindHelper(conn)
412
413         dpdk_bind_helper._add_line(NETWORK_KERNEL, self.ONE_INPUT_LINE)
414
415         self.assertIsNotNone(dpdk_bind_helper.dpdk_status)
416         self.assertEqual(self.ONE_INPUT_LINE_PARSED, dpdk_bind_helper.dpdk_status[NETWORK_KERNEL])
417
418     def test__switch_active_dict_by_header(self):
419         line = "Crypto devices using DPDK-compatible driver"
420         olddict = 'olddict'
421         self.assertEqual(CRYPTO_DPDK, DpdkBindHelper._switch_active_dict(line, olddict))
422
423     def test__switch_active_dict_by_header_empty(self):
424         line = "<none>"
425         olddict = 'olddict'
426         self.assertEqual(olddict, DpdkBindHelper._switch_active_dict(line, olddict))
427
428     def test_parse_dpdk_status_output(self):
429         conn = mock.Mock()
430
431         dpdk_bind_helper = DpdkBindHelper(conn)
432
433         dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)
434
435         self.maxDiff = None
436         self.assertEqual(self.PARSED_EXAMPLE, dpdk_bind_helper.dpdk_status)
437
438     def test_kernel_bound_pci_addresses(self):
439         mock_ssh_helper = mock.Mock()
440         mock_ssh_helper.execute.return_value = 0, '', ''
441
442         expected = ['a', 'b', 3]
443
444         dpdk_helper = DpdkBindHelper(mock_ssh_helper)
445         dpdk_helper.dpdk_status = {
446             NETWORK_DPDK: [{'vpci': 4}, {'vpci': 5}, {'vpci': 'g'}],
447             NETWORK_KERNEL: [{'vpci': 'a'}, {'vpci': 'b'}, {'vpci': 3}],
448             CRYPTO_DPDK: [],
449         }
450
451         result = dpdk_helper.kernel_bound_pci_addresses
452         self.assertEqual(result, expected)
453
454     def test_find_net_devices_negative(self):
455         mock_ssh_helper = mock.Mock()
456         mock_ssh_helper.execute.return_value = 1, 'error', 'debug'
457
458         dpdk_helper = DpdkBindHelper(mock_ssh_helper)
459
460         self.assertDictEqual(dpdk_helper.find_net_devices(), {})
461
462     def test_read_status(self):
463         conn = mock.Mock()
464         conn.execute = mock.Mock(return_value=(0, self.EXAMPLE_OUTPUT, ''))
465         conn.provision_tool = mock.Mock(return_value='path_to_tool')
466
467         dpdk_bind_helper = DpdkBindHelper(conn)
468
469         self.assertEqual(self.PARSED_EXAMPLE, dpdk_bind_helper.read_status())
470
471     def test__get_bound_pci_addresses(self):
472         conn = mock.Mock()
473
474         dpdk_bind_helper = DpdkBindHelper(conn)
475
476         dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)
477
478         self.assertEqual(['0000:00:04.0', '0000:00:05.0'],
479                           dpdk_bind_helper._get_bound_pci_addresses(NETWORK_DPDK))
480         self.assertEqual(['0000:00:03.0'],
481                           dpdk_bind_helper._get_bound_pci_addresses(NETWORK_KERNEL))
482
483     def test_interface_driver_map(self):
484         conn = mock.Mock()
485
486         dpdk_bind_helper = DpdkBindHelper(conn)
487
488         dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)
489
490         self.assertEqual({'0000:00:04.0': 'igb_uio',
491                           '0000:00:03.0': 'virtio-pci',
492                           '0000:00:05.0': 'igb_uio',
493                           },
494                          dpdk_bind_helper.interface_driver_map)
495
496     def test_bind(self):
497         conn = mock.Mock()
498         conn.execute = mock.Mock(return_value=(0, '', ''))
499         conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND)
500
501         dpdk_bind_helper = DpdkBindHelper(conn)
502         dpdk_bind_helper.read_status = mock.Mock()
503
504         dpdk_bind_helper.bind(['0000:00:03.0', '0000:00:04.0'], 'my_driver')
505
506         conn.execute.assert_called_with('sudo /opt/nsb_bin/dpdk-devbind.py --force '
507                                         '-b my_driver 0000:00:03.0 0000:00:04.0')
508         dpdk_bind_helper.read_status.assert_called_once()
509
510     def test_bind_single_pci(self):
511         conn = mock.Mock()
512         conn.execute = mock.Mock(return_value=(0, '', ''))
513         conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND)
514
515         dpdk_bind_helper = DpdkBindHelper(conn)
516         dpdk_bind_helper.read_status = mock.Mock()
517
518         dpdk_bind_helper.bind('0000:00:03.0', 'my_driver')
519
520         conn.execute.assert_called_with('sudo /opt/nsb_bin/dpdk-devbind.py --force '
521                                         '-b my_driver 0000:00:03.0')
522         dpdk_bind_helper.read_status.assert_called_once()
523
524     def test_rebind_drivers(self):
525         conn = mock.Mock()
526
527         dpdk_bind_helper = DpdkBindHelper(conn)
528
529         dpdk_bind_helper.bind = mock.Mock()
530         dpdk_bind_helper.used_drivers = {
531             'd1': ['0000:05:00.0'],
532             'd3': ['0000:05:01.0', '0000:05:02.0'],
533         }
534
535         dpdk_bind_helper.rebind_drivers()
536
537         dpdk_bind_helper.bind.assert_any_call(['0000:05:00.0'], 'd1', True)
538         dpdk_bind_helper.bind.assert_any_call(['0000:05:01.0', '0000:05:02.0'], 'd3', True)
539
540     def test_save_used_drivers(self):
541         conn = mock.Mock()
542         dpdk_bind_helper = DpdkBindHelper(conn)
543         dpdk_bind_helper.dpdk_status = self.PARSED_EXAMPLE
544
545         dpdk_bind_helper.save_used_drivers()
546
547         expected = {
548             'igb_uio': ['0000:00:04.0', '0000:00:05.0'],
549             'virtio-pci': ['0000:00:03.0'],
550         }
551
552         self.assertDictEqual(expected, dpdk_bind_helper.used_drivers)
553
554     def test_force_dpdk_rebind(self):
555         mock_ssh_helper = mock.Mock()
556         mock_ssh_helper.execute.return_value = 0, '', ''
557
558         dpdk_helper = DpdkBindHelper(mock_ssh_helper, 'driver2')
559         dpdk_helper.dpdk_status = {
560             NETWORK_DPDK: [
561                 {
562                     'vpci': 'pci1',
563                 },
564                 {
565                     'vpci': 'pci3',
566                 },
567                 {
568                     'vpci': 'pci6',
569                 },
570                 {
571                     'vpci': 'pci3',
572                 },
573             ]
574         }
575         dpdk_helper.real_kernel_interface_driver_map = {
576             'pci1': 'real_driver1',
577             'pci2': 'real_driver2',
578             'pci3': 'real_driver1',
579             'pci4': 'real_driver4',
580             'pci6': 'real_driver6',
581         }
582         dpdk_helper.load_dpdk_driver = mock.Mock()
583         dpdk_helper.read_status = mock.Mock()
584         dpdk_helper.save_real_kernel_interface_driver_map = mock.Mock()
585         dpdk_helper.save_used_drivers = mock.Mock()
586         dpdk_helper.bind = mock_bind = mock.Mock()
587
588         dpdk_helper.force_dpdk_rebind()
589         self.assertEqual(mock_bind.call_count, 2)
590
591     def test_save_real_kernel_drivers(self):
592         mock_ssh_helper = mock.Mock()
593         mock_ssh_helper.execute.return_value = 0, '', ''
594
595         dpdk_helper = DpdkBindHelper(mock_ssh_helper)
596         dpdk_helper.real_kernel_drivers = {
597             'abc': '123',
598         }
599         dpdk_helper.real_kernel_interface_driver_map = {
600             'abc': 'AAA',
601             'def': 'DDD',
602             'abs': 'AAA',
603             'ghi': 'GGG',
604         }
605
606         # save_used_drivers must be called before save_real_kernel_drivers can be
607         with self.assertRaises(AttributeError):
608             dpdk_helper.save_real_kernel_drivers()
609
610         dpdk_helper.save_used_drivers()
611
612         expected_used_drivers = {
613             'AAA': ['abc', 'abs'],
614             'DDD': ['def'],
615             'GGG': ['ghi'],
616         }
617         dpdk_helper.save_real_kernel_drivers()
618         self.assertDictEqual(dpdk_helper.used_drivers, expected_used_drivers)
619         self.assertDictEqual(dpdk_helper.real_kernel_drivers, {})
620
621     def test_get_real_kernel_driver(self):
622         mock_ssh_helper = mock.Mock()
623         mock_ssh_helper.execute.side_effect = [
624             (0, 'non-matching text', ''),
625             (0, 'pre Kernel modules: real_driver1', ''),
626             (0, 'before Ethernet middle Virtio network device after', ''),
627         ]
628
629         dpdk_helper = DpdkBindHelper(mock_ssh_helper)
630
631         self.assertIsNone(dpdk_helper.get_real_kernel_driver('abc'))
632         self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'), 'real_driver1')
633         self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'), DpdkBindHelper.VIRTIO_DRIVER)