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
24 from yardstick import tests
25 from yardstick.common import utils
26 from yardstick.network_services.collector.subscriber import Collector
27 from yardstick.network_services.traffic_profile import base
28 from yardstick.network_services.vnf_generic import vnfdgen
29 from yardstick.network_services.vnf_generic.vnf.base import \
30 GenericTrafficGen, GenericVNF
33 stl_patch = mock.patch.dict(sys.modules, tests.STL_MOCKS)
37 from yardstick.benchmark.scenarios.networking import vnf_generic
39 # pylint: disable=unused-argument
40 # disable this for now because I keep forgetting mock patch arg ordering
43 COMPLETE_TREX_VNFD = {
44 'vnfd:vnfd-catalog': {
53 'tx_throughput_pc_linerate',
54 'rx_throughput_pc_linerate',
70 'description': 'TRex stateless traffic generator for RFC2544',
71 'id': 'TrexTrafficGen',
76 'vdu-id': 'trexgen-baremetal',
79 'short-name': 'trexgen',
80 'class-name': 'TrexTrafficGen',
83 'description': 'TRex stateless traffic generator for RFC2544',
84 'external-interface': [
87 'virtual-interface': {
88 'bandwidth': '10 Gbps',
90 'dst_mac': '00:01:02:03:04:05',
91 'local_ip': '1.1.1.2',
92 'local_mac': '00:01:02:03:05:05',
93 'type': 'PCI-PASSTHROUGH',
94 'netmask': "255.255.255.0",
96 'vpci': '0000:00:10.2',
98 'vnfd-connection-point-ref': 'xe0',
102 'virtual-interface': {
103 'bandwidth': '10 Gbps',
105 'dst_mac': '00:01:02:03:04:06',
106 'local_ip': '2.1.1.2',
107 'local_mac': '00:01:02:03:05:06',
108 'type': 'PCI-PASSTHROUGH',
109 'netmask': "255.255.255.0",
111 'vpci': '0000:00:10.1',
113 'vnfd-connection-point-ref': 'xe1',
116 'id': 'trexgen-baremetal',
117 'name': 'trexgen-baremetal',
126 28: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP \
127 group default qlen 1000
128 link/ether 90:e2:ba:a7:6a:c8 brd ff:ff:ff:ff:ff:ff
129 inet 1.1.1.1/8 brd 1.255.255.255 scope global eth1
130 inet6 fe80::92e2:baff:fea7:6ac8/64 scope link
131 valid_lft forever preferred_lft forever
132 29: eth5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP \
133 group default qlen 1000
134 link/ether 90:e2:ba:a7:6a:c9 brd ff:ff:ff:ff:ff:ff
135 inet 2.1.1.1/8 brd 2.255.255.255 scope global eth5
136 inet6 fe80::92e2:baff:fea7:6ac9/64 scope link tentative
137 valid_lft forever preferred_lft forever
141 lrwxrwxrwx 1 root root 0 sie 10 14:16 eth1 -> \
142 ../../devices/pci0000:80/0000:80:02.2/0000:84:00.1/net/eth1
143 lrwxrwxrwx 1 root root 0 sie 3 10:37 eth2 -> \
144 ../../devices/pci0000:00/0000:00:01.1/0000:84:00.2/net/eth5
148 "schema": "isb:traffic_profile:0.1",
150 "description": "Fixed traffic profile to run UDP traffic",
152 "traffic_type": "FixedTraffic",
153 "frame_rate": 100, # pps
160 class TestNetworkServiceTestCase(unittest.TestCase):
164 'name': 'trafficgen_1.yardstick',
166 'role': 'TrafficGen',
171 'netmask': '255.255.255.0',
172 'local_ip': '152.16.100.20',
173 'local_mac': '00:00:00:00:00:01',
175 'vpci': '0000:07:00.0',
179 'netmask': '255.255.255.0',
180 'local_ip': '152.16.40.20',
181 'local_mac': '00:00:00:00:00:02',
183 'vpci': '0000:07:00.1',
190 'name': 'vnf.yardstick',
192 'host': '10.223.197.164',
198 'netmask': '255.255.255.0',
199 'local_ip': '152.16.100.19',
200 'local_mac': '00:00:00:00:00:03',
202 'vpci': '0000:07:00.0',
206 'netmask': '255.255.255.0',
207 'local_ip': '152.16.40.19',
208 'local_mac': '00:00:00:00:00:04',
210 'vpci': '0000:07:00.1',
216 'netmask': '255.255.255.0',
217 'gateway': '152.16.100.20',
218 'network': '152.16.100.20',
222 'netmask': '255.255.255.0',
223 'gateway': '152.16.40.20',
224 'network': '152.16.40.20',
231 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
232 'network': '0064:ff9b:0:0:0:0:9810:6414',
237 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
238 'network': '0064:ff9b:0:0:0:0:9810:2814',
247 'vnf__1': self.vnf__1,
251 'vld_id': GenericVNF.UPLINK,
253 GenericVNF.DOWNLINK: {
254 'vld_id': GenericVNF.DOWNLINK,
260 'vnfd-connection-point-ref': [
262 'vnfd-connection-point-ref': 'xe0',
263 'member-vnf-index-ref': '1',
264 'vnfd-id-ref': 'trexgen'
267 'vnfd-connection-point-ref': 'xe0',
268 'member-vnf-index-ref': '2',
269 'vnfd-id-ref': 'trexgen'
273 'id': GenericVNF.UPLINK,
274 'name': 'tg__1 to vnf__1 link 1'
278 'vnfd-connection-point-ref': [
280 'vnfd-connection-point-ref': 'xe1',
281 'member-vnf-index-ref': '1',
282 'vnfd-id-ref': 'trexgen'
285 'vnfd-connection-point-ref': 'xe1',
286 'member-vnf-index-ref': '2',
287 'vnfd-id-ref': 'trexgen'
291 'id': GenericVNF.DOWNLINK,
292 'name': 'vnf__1 to tg__1 link 2'
296 'id': 'trex-tg-topology',
297 'short-name': 'trex-tg-topology',
298 'name': 'trex-tg-topology',
299 'description': 'trex-tg-topology',
300 'constituent-vnfd': [
302 'member-vnf-index': '1',
303 'VNF model': 'tg_trex_tpl.yaml',
304 'vnfd-id-ref': 'tg__1',
307 'member-vnf-index': '2',
308 'VNF model': 'tg_trex_tpl.yaml',
309 'vnfd-id-ref': 'vnf__1',
312 'vld': [self.vld0, self.vld1],
315 self.scenario_cfg = {
317 "topology": self._get_file_abspath("vpe_vnf_topology.yaml"),
318 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
319 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
320 'traffic_profile': 'ipv4_throughput_vpe.yaml',
321 'extra_args': {'arg1': 'value1', 'arg2': 'value2'},
325 'allowed_drop_rate': '0.8 - 1',
329 'framesize': {'64B': 100}
332 'object': 'NetworkServiceTestCase',
334 'output_filename': 'yardstick.out',
340 'flow': 'ipv4_1flow_Packets_vpe.yaml',
341 'imix': 'imix_voice.yaml'
344 'tg__2': 'trafficgen_2.yardstick',
345 'tg__1': 'trafficgen_1.yardstick',
346 'vnf__1': 'vnf.yardstick',
350 self.s = vnf_generic.NetworkServiceTestCase(self.scenario_cfg,
353 def _get_file_abspath(self, filename):
354 curr_path = os.path.dirname(os.path.abspath(__file__))
355 file_path = os.path.join(curr_path, filename)
358 def test_ssh_manager(self):
359 with mock.patch("yardstick.ssh.SSH") as ssh:
360 ssh_mock = mock.Mock(autospec=ssh.SSH)
362 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
363 ssh.from_node.return_value = ssh_mock
364 for node_dict in self.context_cfg["nodes"].values():
365 with vnf_generic.SshManager(node_dict) as conn:
366 self.assertIsNotNone(conn)
368 def test___init__(self):
371 def test__get_ip_flow_range_string(self):
372 self.scenario_cfg["traffic_options"]["flow"] = \
373 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
374 result = '152.16.100.2-152.16.100.254'
375 self.assertEqual(result, self.s._get_ip_flow_range(
376 '152.16.100.2-152.16.100.254'))
378 def test__get_ip_flow_range(self):
379 self.scenario_cfg["traffic_options"]["flow"] = \
380 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
381 result = '152.16.100.2-152.16.100.254'
382 self.assertEqual(result, self.s._get_ip_flow_range({"tg__1": 'xe0'}))
384 @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.ipaddress')
385 def test__get_ip_flow_range_no_node_data(self, mock_ipaddress):
386 scenario_cfg = deepcopy(self.scenario_cfg)
387 scenario_cfg["traffic_options"]["flow"] = \
388 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
390 mock_ipaddress.ip_network.return_value = ipaddr = mock.Mock()
391 ipaddr.hosts.return_value = []
394 result = self.s._get_ip_flow_range({"tg__2": 'xe0'})
395 self.assertEqual(result, expected)
397 def test__get_ip_flow_range_no_nodes(self):
399 result = self.s._get_ip_flow_range({})
400 self.assertEqual(result, expected)
402 def test___get_traffic_flow(self):
403 self.scenario_cfg["traffic_options"]["flow"] = \
404 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
405 self.scenario_cfg["options"] = {}
406 self.scenario_cfg['options'] = {
418 'public_ip': ['1.1.1.1'],
421 # NOTE(ralonsoh): check the expected output. This test could be
423 # result = {'flow': {'dst_ip0': '152.16.40.2-152.16.40.254',
424 # 'src_ip0': '152.16.100.2-152.16.100.254'}}
425 self.assertEqual({'flow': {}}, self.s._get_traffic_flow())
427 def test___get_traffic_flow_error(self):
428 self.scenario_cfg["traffic_options"]["flow"] = \
429 "ipv4_1flow_Packets_vpe.yaml1"
430 self.assertEqual({'flow': {}}, self.s._get_traffic_flow())
432 def test_get_vnf_imp(self):
433 vnfd = COMPLETE_TREX_VNFD['vnfd:vnfd-catalog']['vnfd'][0]['class-name']
434 with mock.patch.dict(sys.modules, tests.STL_MOCKS):
435 self.assertIsNotNone(self.s.get_vnf_impl(vnfd))
437 with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
438 self.s.get_vnf_impl('NonExistentClass')
440 exc_str = str(raised.exception)
442 self.assertIn('No implementation', exc_str)
443 self.assertIn('found in', exc_str)
445 def test_load_vnf_models_invalid(self):
446 self.context_cfg["nodes"]['tg__1']['VNF model'] = \
447 self._get_file_abspath("tg_trex_tpl.yaml")
448 self.context_cfg["nodes"]['vnf__1']['VNF model'] = \
449 self._get_file_abspath("tg_trex_tpl.yaml")
451 vnf = mock.Mock(autospec=GenericVNF)
452 self.s.get_vnf_impl = mock.Mock(return_value=vnf)
454 self.assertIsNotNone(
455 self.s.load_vnf_models(self.scenario_cfg, self.context_cfg))
457 def test_load_vnf_models_no_model(self):
458 vnf = mock.Mock(autospec=GenericVNF)
459 self.s.get_vnf_impl = mock.Mock(return_value=vnf)
461 self.assertIsNotNone(
462 self.s.load_vnf_models(self.scenario_cfg, self.context_cfg))
464 def test_map_topology_to_infrastructure(self):
465 with mock.patch("yardstick.ssh.SSH") as ssh:
466 ssh_mock = mock.Mock(autospec=ssh.SSH)
468 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
469 ssh.from_node.return_value = ssh_mock
470 self.s.map_topology_to_infrastructure()
472 nodes = self.context_cfg["nodes"]
473 self.assertEqual('../../vnf_descriptors/tg_rfc2544_tpl.yaml',
474 nodes['tg__1']['VNF model'])
475 self.assertEqual('../../vnf_descriptors/vpe_vnf.yaml',
476 nodes['vnf__1']['VNF model'])
478 def test_map_topology_to_infrastructure_insufficient_nodes(self):
479 del self.context_cfg['nodes']['vnf__1']
480 with mock.patch("yardstick.ssh.SSH") as ssh:
481 ssh_mock = mock.Mock(autospec=ssh.SSH)
483 mock.Mock(return_value=(1, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
484 ssh.from_node.return_value = ssh_mock
486 with self.assertRaises(vnf_generic.IncorrectConfig):
487 self.s.map_topology_to_infrastructure()
489 def test_map_topology_to_infrastructure_config_invalid(self):
490 cfg = dict(self.context_cfg)
491 del cfg['nodes']['vnf__1']['interfaces']['xe0']['local_mac']
492 with mock.patch("yardstick.ssh.SSH") as ssh:
493 ssh_mock = mock.Mock(autospec=ssh.SSH)
495 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
496 ssh.from_node.return_value = ssh_mock
498 with self.assertRaises(vnf_generic.IncorrectConfig):
499 self.s.map_topology_to_infrastructure()
501 def test__resolve_topology_invalid_config(self):
502 with mock.patch("yardstick.ssh.SSH") as ssh:
503 ssh_mock = mock.Mock(autospec=ssh.SSH)
505 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
506 ssh.from_node.return_value = ssh_mock
508 # purge an important key from the data structure
509 for interface in self.tg__1['interfaces'].values():
510 del interface['local_mac']
512 with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
513 self.s._resolve_topology()
515 self.assertIn('not found', str(raised.exception))
518 for index, interface in enumerate(self.tg__1['interfaces'].values()):
519 interface['local_mac'] = '00:00:00:00:00:{:2x}'.format(index)
521 # make a connection point ref with 3 points
522 self.s.topology["vld"][0]['vnfd-connection-point-ref'].append(
523 self.s.topology["vld"][0]['vnfd-connection-point-ref'][0])
525 with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
526 self.s._resolve_topology()
528 self.assertIn('wrong endpoint count', str(raised.exception))
530 # make a connection point ref with 1 point
531 self.s.topology["vld"][0]['vnfd-connection-point-ref'] = \
532 self.s.topology["vld"][0]['vnfd-connection-point-ref'][:1]
534 with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
535 self.s._resolve_topology()
537 self.assertIn('wrong endpoint count', str(raised.exception))
540 tgen = mock.Mock(autospec=GenericTrafficGen)
541 tgen.traffic_finished = True
542 verified_dict = {"verified": True}
543 tgen.verify_traffic = lambda x: verified_dict
544 tgen.name = "tgen__1"
545 vnf = mock.Mock(autospec=GenericVNF)
546 vnf.runs_traffic = False
547 self.s.vnfs = [tgen, vnf]
548 self.s.traffic_profile = mock.Mock()
549 self.s.collector = mock.Mock(autospec=Collector)
550 self.s.collector.get_kpi = \
551 mock.Mock(return_value={tgen.name: verified_dict})
554 self.assertDictEqual(result, {tgen.name: verified_dict})
556 def test_setup(self):
557 with mock.patch("yardstick.ssh.SSH") as ssh:
558 ssh_mock = mock.Mock(autospec=ssh.SSH)
560 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
561 ssh.from_node.return_value = ssh_mock
563 tgen = mock.Mock(autospec=GenericTrafficGen)
564 tgen.traffic_finished = True
565 verified_dict = {"verified": True}
566 tgen.verify_traffic = lambda x: verified_dict
567 tgen.terminate = mock.Mock(return_value=True)
568 tgen.name = "tgen__1"
569 vnf = mock.Mock(autospec=GenericVNF)
570 vnf.runs_traffic = False
571 vnf.terminate = mock.Mock(return_value=True)
572 self.s.vnfs = [tgen, vnf]
573 self.s.traffic_profile = mock.Mock()
574 self.s.collector = mock.Mock(autospec=Collector)
575 self.s.collector.get_kpi = \
576 mock.Mock(return_value={tgen.name: verified_dict})
577 self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
578 self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
579 self.s._fill_traffic_profile = \
580 mock.Mock(return_value=TRAFFIC_PROFILE)
581 self.assertEqual(None, self.s.setup())
583 def test_setup_exception(self):
584 with mock.patch("yardstick.ssh.SSH") as ssh:
585 ssh_mock = mock.Mock(autospec=ssh.SSH)
587 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
588 ssh.from_node.return_value = ssh_mock
590 tgen = mock.Mock(autospec=GenericTrafficGen)
591 tgen.traffic_finished = True
592 verified_dict = {"verified": True}
593 tgen.verify_traffic = lambda x: verified_dict
594 tgen.terminate = mock.Mock(return_value=True)
595 tgen.name = "tgen__1"
596 vnf = mock.Mock(autospec=GenericVNF)
597 vnf.runs_traffic = False
598 vnf.instantiate.side_effect = RuntimeError(
599 "error during instantiate")
600 vnf.terminate = mock.Mock(return_value=True)
601 self.s.vnfs = [tgen, vnf]
602 self.s.traffic_profile = mock.Mock()
603 self.s.collector = mock.Mock(autospec=Collector)
604 self.s.collector.get_kpi = \
605 mock.Mock(return_value={tgen.name: verified_dict})
606 self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
607 self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
608 self.s._fill_traffic_profile = \
609 mock.Mock(return_value=TRAFFIC_PROFILE)
610 with self.assertRaises(RuntimeError):
613 def test__get_traffic_profile(self):
614 self.scenario_cfg["traffic_profile"] = \
615 self._get_file_abspath("ipv4_throughput_vpe.yaml")
616 self.assertIsNotNone(self.s._get_traffic_profile())
618 def test__get_traffic_profile_exception(self):
619 with mock.patch.dict(self.scenario_cfg, {'traffic_profile': ''}):
620 with self.assertRaises(IOError):
621 self.s._get_traffic_profile()
623 def test___get_traffic_imix_exception(self):
624 with mock.patch.dict(self.scenario_cfg["traffic_options"], {'imix': ''}):
625 self.assertEqual({'imix': {'64B': 100}},
626 self.s._get_traffic_imix())
628 @mock.patch.object(base.TrafficProfile, 'get')
629 @mock.patch.object(vnfdgen, 'generate_vnfd')
630 def test__fill_traffic_profile(self, mock_generate, mock_tprofile_get):
631 fake_tprofile = mock.Mock()
632 fake_vnfd = mock.Mock()
633 with mock.patch.object(self.s, '_get_traffic_profile',
634 return_value=fake_tprofile) as mock_get_tp:
635 mock_generate.return_value = fake_vnfd
636 self.s._fill_traffic_profile()
637 mock_get_tp.assert_called_once()
638 mock_generate.assert_called_once_with(
641 'extra_args': {'arg1': 'value1', 'arg2': 'value2'},
642 'flow': {'flow': {}},
643 'imix': {'imix': {'64B': 100}},
646 mock_tprofile_get.assert_called_once_with(fake_vnfd)
648 @mock.patch.object(utils, 'open_relative_file')
649 def test__get_topology(self, mock_open_path):
650 self.s.scenario_cfg['topology'] = 'fake_topology'
651 self.s.scenario_cfg['task_path'] = 'fake_path'
652 mock_open_path.side_effect = mock.mock_open(read_data='fake_data')
653 self.assertEqual('fake_data', self.s._get_topology())
654 mock_open_path.assert_called_once_with('fake_topology', 'fake_path')
656 @mock.patch.object(vnfdgen, 'generate_vnfd')
657 def test__render_topology(self, mock_generate):
658 fake_topology = 'fake_topology'
659 mock_generate.return_value = {'nsd:nsd-catalog': {'nsd': ['fake_nsd']}}
660 with mock.patch.object(self.s, '_get_topology',
661 return_value=fake_topology) as mock_get_topology:
662 self.s._render_topology()
663 mock_get_topology.assert_called_once()
665 mock_generate.assert_called_once_with(
667 {'extra_args': {'arg1': 'value1', 'arg2': 'value2'}}
669 self.assertEqual(self.s.topology, 'fake_nsd')
671 def test_teardown(self):
672 vnf = mock.Mock(autospec=GenericVNF)
673 vnf.terminate = mock.Mock(return_value=True)
676 self.s.traffic_profile = mock.Mock()
677 self.s.collector = mock.Mock(autospec=Collector)
678 self.s.collector.stop = \
679 mock.Mock(return_value=True)
680 self.assertIsNone(self.s.teardown())
682 def test_teardown_exception(self):
683 vnf = mock.Mock(autospec=GenericVNF)
684 vnf.terminate = mock.Mock(
685 side_effect=RuntimeError("error duing terminate"))
688 self.s.traffic_profile = mock.Mock()
689 self.s.collector = mock.Mock(autospec=Collector)
690 self.s.collector.stop = \
691 mock.Mock(return_value=True)
692 with self.assertRaises(RuntimeError):
697 'address': '0a:de:ad:be:ef:f5',
701 'interface_name': 'enp11s0',
703 'pci_bus_id': '0000:0b:00.0',
704 'subsystem_device': '0x1533',
705 'subsystem_vendor': '0x15d9',
709 'address': '0a:de:ad:be:ef:f4',
713 'interface_name': 'lan',
715 'pci_bus_id': '0000:00:19.0',
716 'subsystem_device': '0x153a',
717 'subsystem_vendor': '0x15d9',
722 SAMPLE_VM_NETDEVS = {
724 'address': 'fa:de:ad:be:ef:5b',
726 'driver': 'virtio_net',
728 'interface_name': 'eth1',
730 'pci_bus_id': '0000:00:04.0',
735 def test_parse_netdev_info(self):
737 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/ifindex:2
738 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/address:0a:de:ad:be:ef:f5
739 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/operstate:down
740 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/vendor:0x8086
741 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/device:0x1533
742 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_vendor:0x15d9
743 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_device:0x1533
744 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/driver:igb
745 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/pci_bus_id:0000:0b:00.0
746 /sys/devices/pci0000:00/0000:00:19.0/net/lan/ifindex:3
747 /sys/devices/pci0000:00/0000:00:19.0/net/lan/address:0a:de:ad:be:ef:f4
748 /sys/devices/pci0000:00/0000:00:19.0/net/lan/operstate:up
749 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/vendor:0x8086
750 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/device:0x153a
751 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_vendor:0x15d9
752 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_device:0x153a
753 /sys/devices/pci0000:00/0000:00:19.0/net/lan/driver:e1000e
754 /sys/devices/pci0000:00/0000:00:19.0/net/lan/pci_bus_id:0000:00:19.0
756 res = vnf_generic.NetworkServiceTestCase.parse_netdev_info(output)
757 assert res == self.SAMPLE_NETDEVS
759 def test_parse_netdev_info_virtio(self):
761 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/ifindex:3
762 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/address:fa:de:ad:be:ef:5b
763 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/operstate:down
764 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/vendor:0x1af4
765 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/device:0x0001
766 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/driver:virtio_net
768 res = vnf_generic.NetworkServiceTestCase.parse_netdev_info(output)
769 assert res == self.SAMPLE_VM_NETDEVS
771 def test_probe_missing_values(self):
772 netdevs = self.SAMPLE_NETDEVS.copy()
773 network = {'local_mac': '0a:de:ad:be:ef:f5'}
774 vnf_generic.NetworkServiceTestCase._probe_missing_values(netdevs,
776 assert network['vpci'] == '0000:0b:00.0'
778 network = {'local_mac': '0a:de:ad:be:ef:f4'}
779 vnf_generic.NetworkServiceTestCase._probe_missing_values(netdevs,
781 assert network['vpci'] == '0000:00:19.0'
783 @mock.patch.object(six.moves.builtins, 'open')
784 def test_open_relative_path(self, mock_open):
785 # NOTE(ralonsoh): the mocked function is not properly used and tested.
786 mock_open_result = mock_open()
787 mock_open_call_count = 1 # initial call to get result
788 self.assertEqual(utils.open_relative_file('foo', 'bar'),
791 mock_open_call_count += 1 # one more call expected
792 self.assertEqual(mock_open.call_count, mock_open_call_count)
793 self.assertIn('foo', mock_open.call_args_list[-1][0][0])
794 self.assertNotIn('bar', mock_open.call_args_list[-1][0][0])
796 def open_effect(*args, **kwargs):
797 if kwargs.get('name', args[0]) == os.path.join('bar', 'foo'):
798 return mock_open_result
799 raise IOError(errno.ENOENT, 'not found')
801 mock_open.side_effect = open_effect
802 self.assertEqual(utils.open_relative_file('foo', 'bar'),
805 mock_open_call_count += 2 # two more calls expected
806 self.assertEqual(mock_open.call_count, mock_open_call_count)
807 self.assertIn('foo', mock_open.call_args_list[-1][0][0])
808 self.assertIn('bar', mock_open.call_args_list[-1][0][0])
810 # test an IOError of type ENOENT
811 mock_open.side_effect = IOError(errno.ENOENT, 'not found')
812 with self.assertRaises(IOError):
813 # the second call still raises
814 utils.open_relative_file('foo', 'bar')
816 mock_open_call_count += 2 # two more calls expected
817 self.assertEqual(mock_open.call_count, mock_open_call_count)
818 self.assertIn('foo', mock_open.call_args_list[-1][0][0])
819 self.assertIn('bar', mock_open.call_args_list[-1][0][0])
821 # test an IOError other than ENOENT
822 mock_open.side_effect = IOError(errno.EBUSY, 'busy')
823 with self.assertRaises(IOError):
824 utils.open_relative_file('foo', 'bar')
826 mock_open_call_count += 1 # one more call expected
827 self.assertEqual(mock_open.call_count, mock_open_call_count)