1 # Copyright (c) 2016-2017 Intel Corporation
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 from copy import deepcopy
23 from yardstick.common import utils
24 from yardstick.benchmark.scenarios.networking import vnf_generic
25 from yardstick.network_services.collector.subscriber import Collector
26 from yardstick.network_services.vnf_generic.vnf.base import \
27 GenericTrafficGen, GenericVNF
30 COMPLETE_TREX_VNFD = {
31 'vnfd:vnfd-catalog': {
40 'tx_throughput_pc_linerate',
41 'rx_throughput_pc_linerate',
57 'description': 'TRex stateless traffic generator for RFC2544',
58 'id': 'TrexTrafficGen',
63 'vdu-id': 'trexgen-baremetal',
66 'short-name': 'trexgen',
67 'class-name': 'TrexTrafficGen',
70 'description': 'TRex stateless traffic generator for RFC2544',
71 'external-interface': [
74 'virtual-interface': {
75 'bandwidth': '10 Gbps',
77 'dst_mac': '00:01:02:03:04:05',
78 'local_ip': '1.1.1.2',
79 'local_mac': '00:01:02:03:05:05',
80 'type': 'PCI-PASSTHROUGH',
81 'netmask': "255.255.255.0",
83 'vpci': '0000:00:10.2',
85 'vnfd-connection-point-ref': 'xe0',
89 'virtual-interface': {
90 'bandwidth': '10 Gbps',
92 'dst_mac': '00:01:02:03:04:06',
93 'local_ip': '2.1.1.2',
94 'local_mac': '00:01:02:03:05:06',
95 'type': 'PCI-PASSTHROUGH',
96 'netmask': "255.255.255.0",
98 'vpci': '0000:00:10.1',
100 'vnfd-connection-point-ref': 'xe1',
103 'id': 'trexgen-baremetal',
104 'name': 'trexgen-baremetal',
113 28: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP \
114 group default qlen 1000
115 link/ether 90:e2:ba:a7:6a:c8 brd ff:ff:ff:ff:ff:ff
116 inet 1.1.1.1/8 brd 1.255.255.255 scope global eth1
117 inet6 fe80::92e2:baff:fea7:6ac8/64 scope link
118 valid_lft forever preferred_lft forever
119 29: eth5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP \
120 group default qlen 1000
121 link/ether 90:e2:ba:a7:6a:c9 brd ff:ff:ff:ff:ff:ff
122 inet 2.1.1.1/8 brd 2.255.255.255 scope global eth5
123 inet6 fe80::92e2:baff:fea7:6ac9/64 scope link tentative
124 valid_lft forever preferred_lft forever
128 lrwxrwxrwx 1 root root 0 sie 10 14:16 eth1 -> \
129 ../../devices/pci0000:80/0000:80:02.2/0000:84:00.1/net/eth1
130 lrwxrwxrwx 1 root root 0 sie 3 10:37 eth2 -> \
131 ../../devices/pci0000:00/0000:00:01.1/0000:84:00.2/net/eth5
135 "schema": "isb:traffic_profile:0.1",
137 "description": "Fixed traffic profile to run UDP traffic",
139 "traffic_type": "FixedTraffic",
140 "frame_rate": 100, # pps
147 class TestNetworkServiceTestCase(unittest.TestCase):
151 'name': 'trafficgen_1.yardstick',
153 'role': 'TrafficGen',
158 'netmask': '255.255.255.0',
159 'local_ip': '152.16.100.20',
160 'local_mac': '00:00:00:00:00:01',
162 'vpci': '0000:07:00.0',
166 'netmask': '255.255.255.0',
167 'local_ip': '152.16.40.20',
168 'local_mac': '00:00:00:00:00:02',
170 'vpci': '0000:07:00.1',
177 'name': 'vnf.yardstick',
179 'host': '10.223.197.164',
185 'netmask': '255.255.255.0',
186 'local_ip': '152.16.100.19',
187 'local_mac': '00:00:00:00:00:03',
189 'vpci': '0000:07:00.0',
193 'netmask': '255.255.255.0',
194 'local_ip': '152.16.40.19',
195 'local_mac': '00:00:00:00:00:04',
197 'vpci': '0000:07:00.1',
203 'netmask': '255.255.255.0',
204 'gateway': '152.16.100.20',
205 'network': '152.16.100.20',
209 'netmask': '255.255.255.0',
210 'gateway': '152.16.40.20',
211 'network': '152.16.40.20',
218 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
219 'network': '0064:ff9b:0:0:0:0:9810:6414',
224 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
225 'network': '0064:ff9b:0:0:0:0:9810:2814',
234 'vnf__1': self.vnf__1,
238 'vld_id': GenericVNF.UPLINK,
240 GenericVNF.DOWNLINK: {
241 'vld_id': GenericVNF.DOWNLINK,
247 'vnfd-connection-point-ref': [
249 'vnfd-connection-point-ref': 'xe0',
250 'member-vnf-index-ref': '1',
251 'vnfd-id-ref': 'trexgen'
254 'vnfd-connection-point-ref': 'xe0',
255 'member-vnf-index-ref': '2',
256 'vnfd-id-ref': 'trexgen'
260 'id': GenericVNF.UPLINK,
261 'name': 'tg__1 to vnf__1 link 1'
265 'vnfd-connection-point-ref': [
267 'vnfd-connection-point-ref': 'xe1',
268 'member-vnf-index-ref': '1',
269 'vnfd-id-ref': 'trexgen'
272 'vnfd-connection-point-ref': 'xe1',
273 'member-vnf-index-ref': '2',
274 'vnfd-id-ref': 'trexgen'
278 'id': GenericVNF.DOWNLINK,
279 'name': 'vnf__1 to tg__1 link 2'
283 'id': 'trex-tg-topology',
284 'short-name': 'trex-tg-topology',
285 'name': 'trex-tg-topology',
286 'description': 'trex-tg-topology',
287 'constituent-vnfd': [
289 'member-vnf-index': '1',
290 'VNF model': 'tg_trex_tpl.yaml',
291 'vnfd-id-ref': 'tg__1',
294 'member-vnf-index': '2',
295 'VNF model': 'tg_trex_tpl.yaml',
296 'vnfd-id-ref': 'vnf__1',
299 'vld': [self.vld0, self.vld1],
302 self.scenario_cfg = {
304 "topology": self._get_file_abspath("vpe_vnf_topology.yaml"),
305 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
306 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
307 'traffic_profile': 'ipv4_throughput_vpe.yaml',
311 'allowed_drop_rate': '0.8 - 1',
315 'framesize': {'64B': 100}
318 'object': 'NetworkServiceTestCase',
320 'output_filename': 'yardstick.out',
326 'flow': 'ipv4_1flow_Packets_vpe.yaml',
327 'imix': 'imix_voice.yaml'
330 'tg__2': 'trafficgen_2.yardstick',
331 'tg__1': 'trafficgen_1.yardstick',
332 'vnf__1': 'vnf.yardstick',
336 self.s = vnf_generic.NetworkServiceTestCase(self.scenario_cfg,
339 def _get_file_abspath(self, filename):
340 curr_path = os.path.dirname(os.path.abspath(__file__))
341 file_path = os.path.join(curr_path, filename)
344 def test_ssh_manager(self):
345 with mock.patch("yardstick.ssh.SSH") as ssh:
346 ssh_mock = mock.Mock(autospec=ssh.SSH)
348 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
349 ssh.from_node.return_value = ssh_mock
350 for node_dict in self.context_cfg["nodes"].values():
351 with vnf_generic.SshManager(node_dict) as conn:
352 self.assertIsNotNone(conn)
354 def test___init__(self):
357 def test__get_ip_flow_range_string(self):
358 self.scenario_cfg["traffic_options"]["flow"] = \
359 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
360 result = '152.16.100.2-152.16.100.254'
361 self.assertEqual(result, self.s._get_ip_flow_range(
362 '152.16.100.2-152.16.100.254'))
364 def test__get_ip_flow_range(self):
365 self.scenario_cfg["traffic_options"]["flow"] = \
366 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
367 result = '152.16.100.2-152.16.100.254'
368 self.assertEqual(result, self.s._get_ip_flow_range({"tg__1": 'xe0'}))
370 @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.ipaddress')
371 def test__get_ip_flow_range_no_node_data(self, mock_ipaddress):
372 scenario_cfg = deepcopy(self.scenario_cfg)
373 scenario_cfg["traffic_options"]["flow"] = \
374 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
376 mock_ipaddress.ip_network.return_value = ipaddr = mock.Mock()
377 ipaddr.hosts.return_value = []
380 result = self.s._get_ip_flow_range({"tg__2": 'xe0'})
381 self.assertEqual(result, expected)
383 def test__get_ip_flow_range_no_nodes(self):
385 result = self.s._get_ip_flow_range({})
386 self.assertEqual(result, expected)
388 def test___get_traffic_flow(self):
389 self.scenario_cfg["traffic_options"]["flow"] = \
390 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
391 self.scenario_cfg["options"] = {}
392 self.scenario_cfg['options'] = {
404 'public_ip': ['1.1.1.1'],
408 # NOTE(ralonsoh): this variable is not used in the test case and maybe
410 #result = {'flow': {'dst_ip0': '152.16.40.2-152.16.40.254',
411 # 'src_ip0': '152.16.100.2-152.16.100.254'}}
412 self.assertEqual({'flow': {}}, self.s._get_traffic_flow())
414 def test___get_traffic_flow_error(self):
415 self.scenario_cfg["traffic_options"]["flow"] = \
416 "ipv4_1flow_Packets_vpe.yaml1"
417 self.assertEqual({'flow': {}}, self.s._get_traffic_flow())
419 def test_get_vnf_imp(self):
420 vnfd = COMPLETE_TREX_VNFD['vnfd:vnfd-catalog']['vnfd'][0]['class-name']
421 self.assertIsNotNone(self.s.get_vnf_impl(vnfd))
423 with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
424 self.s.get_vnf_impl('NonExistentClass')
426 exc_str = str(raised.exception)
428 self.assertIn('No implementation', exc_str)
429 self.assertIn('found in', exc_str)
431 def test_load_vnf_models_invalid(self):
432 self.context_cfg["nodes"]['tg__1']['VNF model'] = \
433 self._get_file_abspath("tg_trex_tpl.yaml")
434 self.context_cfg["nodes"]['vnf__1']['VNF model'] = \
435 self._get_file_abspath("tg_trex_tpl.yaml")
437 vnf = mock.Mock(autospec=GenericVNF)
438 self.s.get_vnf_impl = mock.Mock(return_value=vnf)
440 self.assertIsNotNone(
441 self.s.load_vnf_models(self.scenario_cfg, self.context_cfg))
443 def test_load_vnf_models_no_model(self):
444 vnf = mock.Mock(autospec=GenericVNF)
445 self.s.get_vnf_impl = mock.Mock(return_value=vnf)
447 self.assertIsNotNone(
448 self.s.load_vnf_models(self.scenario_cfg, self.context_cfg))
450 def test_map_topology_to_infrastructure(self):
451 with mock.patch("yardstick.ssh.SSH") as ssh:
452 ssh_mock = mock.Mock(autospec=ssh.SSH)
454 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
455 ssh.from_node.return_value = ssh_mock
456 self.s.map_topology_to_infrastructure()
458 nodes = self.context_cfg["nodes"]
460 "../../vnf_descriptors/tg_rfc2544_tpl.yaml", nodes['tg__1']['VNF model'])
461 self.assertEqual("../../vnf_descriptors/vpe_vnf.yaml",
462 nodes['vnf__1']['VNF model'])
464 def test_map_topology_to_infrastructure_insufficient_nodes(self):
465 del self.context_cfg['nodes']['vnf__1']
466 with mock.patch("yardstick.ssh.SSH") as ssh:
467 ssh_mock = mock.Mock(autospec=ssh.SSH)
469 mock.Mock(return_value=(1, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
470 ssh.from_node.return_value = ssh_mock
472 with self.assertRaises(vnf_generic.IncorrectConfig):
473 self.s.map_topology_to_infrastructure()
475 def test_map_topology_to_infrastructure_config_invalid(self):
476 cfg = dict(self.context_cfg)
477 del cfg['nodes']['vnf__1']['interfaces']['xe0']['local_mac']
478 with mock.patch("yardstick.ssh.SSH") as ssh:
479 ssh_mock = mock.Mock(autospec=ssh.SSH)
481 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
482 ssh.from_node.return_value = ssh_mock
484 with self.assertRaises(vnf_generic.IncorrectConfig):
485 self.s.map_topology_to_infrastructure()
487 def test__resolve_topology_invalid_config(self):
488 with mock.patch("yardstick.ssh.SSH") as ssh:
489 ssh_mock = mock.Mock(autospec=ssh.SSH)
491 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
492 ssh.from_node.return_value = ssh_mock
494 # purge an important key from the data structure
495 for interface in self.tg__1['interfaces'].values():
496 del interface['local_mac']
499 "yardstick.benchmark.scenarios.networking.vnf_generic.LOG"):
500 with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
501 self.s._resolve_topology()
503 self.assertIn('not found', str(raised.exception))
506 for index, interface in enumerate(self.tg__1['interfaces'].values()):
507 interface['local_mac'] = '00:00:00:00:00:{:2x}'.format(index)
509 # make a connection point ref with 3 points
510 self.s.topology["vld"][0]['vnfd-connection-point-ref'].append(
511 self.s.topology["vld"][0]['vnfd-connection-point-ref'][0])
513 with mock.patch.object(vnf_generic, 'LOG'):
514 with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
515 self.s._resolve_topology()
517 self.assertIn('wrong endpoint count', str(raised.exception))
519 # make a connection point ref with 1 point
520 self.s.topology["vld"][0]['vnfd-connection-point-ref'] = \
521 self.s.topology["vld"][0]['vnfd-connection-point-ref'][:1]
523 with mock.patch.object(vnf_generic, 'LOG'):
524 with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
525 self.s._resolve_topology()
527 self.assertIn('wrong endpoint count', str(raised.exception))
530 tgen = mock.Mock(autospec=GenericTrafficGen)
531 tgen.traffic_finished = True
532 verified_dict = {"verified": True}
533 tgen.verify_traffic = lambda x: verified_dict
534 tgen.name = "tgen__1"
535 vnf = mock.Mock(autospec=GenericVNF)
536 vnf.runs_traffic = False
537 self.s.vnfs = [tgen, vnf]
538 self.s.traffic_profile = mock.Mock()
539 self.s.collector = mock.Mock(autospec=Collector)
540 self.s.collector.get_kpi = \
541 mock.Mock(return_value={tgen.name: verified_dict})
544 self.assertDictEqual(result, {tgen.name: verified_dict})
546 def test_setup(self):
547 with mock.patch("yardstick.ssh.SSH") as ssh:
548 ssh_mock = mock.Mock(autospec=ssh.SSH)
550 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
551 ssh.from_node.return_value = ssh_mock
553 tgen = mock.Mock(autospec=GenericTrafficGen)
554 tgen.traffic_finished = True
555 verified_dict = {"verified": True}
556 tgen.verify_traffic = lambda x: verified_dict
557 tgen.terminate = mock.Mock(return_value=True)
558 tgen.name = "tgen__1"
559 vnf = mock.Mock(autospec=GenericVNF)
560 vnf.runs_traffic = False
561 vnf.terminate = mock.Mock(return_value=True)
562 self.s.vnfs = [tgen, vnf]
563 self.s.traffic_profile = mock.Mock()
564 self.s.collector = mock.Mock(autospec=Collector)
565 self.s.collector.get_kpi = \
566 mock.Mock(return_value={tgen.name: verified_dict})
567 self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
568 self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
569 self.s._fill_traffic_profile = \
570 mock.Mock(return_value=TRAFFIC_PROFILE)
571 self.assertEqual(None, self.s.setup())
573 def test_setup_exception(self):
574 with mock.patch("yardstick.ssh.SSH") as ssh:
575 ssh_mock = mock.Mock(autospec=ssh.SSH)
577 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
578 ssh.from_node.return_value = ssh_mock
580 tgen = mock.Mock(autospec=GenericTrafficGen)
581 tgen.traffic_finished = True
582 verified_dict = {"verified": True}
583 tgen.verify_traffic = lambda x: verified_dict
584 tgen.terminate = mock.Mock(return_value=True)
585 tgen.name = "tgen__1"
586 vnf = mock.Mock(autospec=GenericVNF)
587 vnf.runs_traffic = False
588 vnf.instantiate.side_effect = RuntimeError(
589 "error during instantiate")
590 vnf.terminate = mock.Mock(return_value=True)
591 self.s.vnfs = [tgen, vnf]
592 self.s.traffic_profile = mock.Mock()
593 self.s.collector = mock.Mock(autospec=Collector)
594 self.s.collector.get_kpi = \
595 mock.Mock(return_value={tgen.name: verified_dict})
596 self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
597 self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
598 self.s._fill_traffic_profile = \
599 mock.Mock(return_value=TRAFFIC_PROFILE)
600 with self.assertRaises(RuntimeError):
603 def test__get_traffic_profile(self):
604 self.scenario_cfg["traffic_profile"] = \
605 self._get_file_abspath("ipv4_throughput_vpe.yaml")
606 self.assertIsNotNone(self.s._get_traffic_profile())
608 def test__get_traffic_profile_exception(self):
609 with mock.patch.dict(self.scenario_cfg, {'traffic_profile': ''}):
610 with self.assertRaises(IOError):
611 self.s._get_traffic_profile()
613 def test___get_traffic_imix_exception(self):
614 with mock.patch.dict(self.scenario_cfg["traffic_options"], {'imix': ''}):
615 self.assertEqual({'imix': {'64B': 100}},
616 self.s._get_traffic_imix())
618 def test__fill_traffic_profile(self):
619 self.scenario_cfg["traffic_profile"] = \
620 self._get_file_abspath("ipv4_throughput_vpe.yaml")
621 self.scenario_cfg["traffic_options"]["flow"] = \
622 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
623 self.scenario_cfg["traffic_options"]["imix"] = \
624 self._get_file_abspath("imix_voice.yaml")
625 self.assertIsNotNone(self.s._fill_traffic_profile())
627 def test_teardown(self):
628 vnf = mock.Mock(autospec=GenericVNF)
629 vnf.terminate = mock.Mock(return_value=True)
632 self.s.traffic_profile = mock.Mock()
633 self.s.collector = mock.Mock(autospec=Collector)
634 self.s.collector.stop = \
635 mock.Mock(return_value=True)
636 self.assertIsNone(self.s.teardown())
638 def test_teardown_exception(self):
639 vnf = mock.Mock(autospec=GenericVNF)
640 vnf.terminate = mock.Mock(
641 side_effect=RuntimeError("error duing terminate"))
644 self.s.traffic_profile = mock.Mock()
645 self.s.collector = mock.Mock(autospec=Collector)
646 self.s.collector.stop = \
647 mock.Mock(return_value=True)
648 with self.assertRaises(RuntimeError):
653 'address': '0a:de:ad:be:ef:f5',
657 'interface_name': 'enp11s0',
659 'pci_bus_id': '0000:0b:00.0',
660 'subsystem_device': '0x1533',
661 'subsystem_vendor': '0x15d9',
665 'address': '0a:de:ad:be:ef:f4',
669 'interface_name': 'lan',
671 'pci_bus_id': '0000:00:19.0',
672 'subsystem_device': '0x153a',
673 'subsystem_vendor': '0x15d9',
678 SAMPLE_VM_NETDEVS = {
680 'address': 'fa:de:ad:be:ef:5b',
682 'driver': 'virtio_net',
684 'interface_name': 'eth1',
686 'pci_bus_id': '0000:00:04.0',
691 def test_parse_netdev_info(self):
693 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/ifindex:2
694 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/address:0a:de:ad:be:ef:f5
695 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/operstate:down
696 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/vendor:0x8086
697 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/device:0x1533
698 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_vendor:0x15d9
699 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_device:0x1533
700 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/driver:igb
701 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/pci_bus_id:0000:0b:00.0
702 /sys/devices/pci0000:00/0000:00:19.0/net/lan/ifindex:3
703 /sys/devices/pci0000:00/0000:00:19.0/net/lan/address:0a:de:ad:be:ef:f4
704 /sys/devices/pci0000:00/0000:00:19.0/net/lan/operstate:up
705 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/vendor:0x8086
706 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/device:0x153a
707 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_vendor:0x15d9
708 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_device:0x153a
709 /sys/devices/pci0000:00/0000:00:19.0/net/lan/driver:e1000e
710 /sys/devices/pci0000:00/0000:00:19.0/net/lan/pci_bus_id:0000:00:19.0
712 res = vnf_generic.NetworkServiceTestCase.parse_netdev_info(output)
713 assert res == self.SAMPLE_NETDEVS
715 def test_parse_netdev_info_virtio(self):
717 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/ifindex:3
718 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/address:fa:de:ad:be:ef:5b
719 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/operstate:down
720 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/vendor:0x1af4
721 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/device:0x0001
722 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/driver:virtio_net
724 res = vnf_generic.NetworkServiceTestCase.parse_netdev_info(output)
725 assert res == self.SAMPLE_VM_NETDEVS
727 def test_probe_missing_values(self):
728 netdevs = self.SAMPLE_NETDEVS.copy()
729 network = {'local_mac': '0a:de:ad:be:ef:f5'}
730 vnf_generic.NetworkServiceTestCase._probe_missing_values(netdevs,
732 assert network['vpci'] == '0000:0b:00.0'
734 network = {'local_mac': '0a:de:ad:be:ef:f4'}
735 vnf_generic.NetworkServiceTestCase._probe_missing_values(netdevs,
737 assert network['vpci'] == '0000:00:19.0'
739 @mock.patch.object(six.moves.builtins, 'open')
740 def test_open_relative_path(self, mock_open):
741 # NOTE(ralonsoh): the mocked function is not properly used and tested.
742 mock_open_result = mock_open()
743 mock_open_call_count = 1 # initial call to get result
744 self.assertEqual(utils.open_relative_file('foo', 'bar'),
747 mock_open_call_count += 1 # one more call expected
748 self.assertEqual(mock_open.call_count, mock_open_call_count)
749 self.assertIn('foo', mock_open.call_args_list[-1][0][0])
750 self.assertNotIn('bar', mock_open.call_args_list[-1][0][0])
752 def open_effect(*args, **kwargs):
753 if kwargs.get('name', args[0]) == os.path.join('bar', 'foo'):
754 return mock_open_result
755 raise IOError(errno.ENOENT, 'not found')
757 mock_open.side_effect = open_effect
758 self.assertEqual(utils.open_relative_file('foo', 'bar'),
761 mock_open_call_count += 2 # two more calls expected
762 self.assertEqual(mock_open.call_count, mock_open_call_count)
763 self.assertIn('foo', mock_open.call_args_list[-1][0][0])
764 self.assertIn('bar', mock_open.call_args_list[-1][0][0])
766 # test an IOError of type ENOENT
767 mock_open.side_effect = IOError(errno.ENOENT, 'not found')
768 with self.assertRaises(IOError):
769 # the second call still raises
770 utils.open_relative_file('foo', 'bar')
772 mock_open_call_count += 2 # two more calls expected
773 self.assertEqual(mock_open.call_count, mock_open_call_count)
774 self.assertIn('foo', mock_open.call_args_list[-1][0][0])
775 self.assertIn('bar', mock_open.call_args_list[-1][0][0])
777 # test an IOError other than ENOENT
778 mock_open.side_effect = IOError(errno.EBUSY, 'busy')
779 with self.assertRaises(IOError):
780 utils.open_relative_file('foo', 'bar')
782 mock_open_call_count += 1 # one more call expected
783 self.assertEqual(mock_open.call_count, mock_open_call_count)