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