Merge "Adding 2 node ixia generic scale-out test case generation"
[yardstick.git] / tests / unit / benchmark / scenarios / networking / test_vnf_generic.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2016-2017 Intel Corporation
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #      http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 # Unittest for yardstick.benchmark.scenarios.networking.test_vnf_generic
19
20 from __future__ import absolute_import
21
22 import os
23 import errno
24 import unittest
25 import mock
26
27 from copy import deepcopy
28
29 from tests.unit import STL_MOCKS
30 from yardstick.benchmark.scenarios.networking.vnf_generic import \
31     SshManager, NetworkServiceTestCase, IncorrectConfig, \
32     open_relative_file
33 from yardstick.network_services.collector.subscriber import Collector
34 from yardstick.network_services.vnf_generic.vnf.base import \
35     GenericTrafficGen, GenericVNF
36
37
38 COMPLETE_TREX_VNFD = {
39     'vnfd:vnfd-catalog': {
40         'vnfd': [
41             {
42                 'benchmark': {
43                     'kpi': [
44                         'rx_throughput_fps',
45                         'tx_throughput_fps',
46                         'tx_throughput_mbps',
47                         'rx_throughput_mbps',
48                         'tx_throughput_pc_linerate',
49                         'rx_throughput_pc_linerate',
50                         'min_latency',
51                         'max_latency',
52                         'avg_latency',
53                     ],
54                 },
55                 'connection-point': [
56                     {
57                         'name': 'xe0',
58                         'type': 'VPORT',
59                     },
60                     {
61                         'name': 'xe1',
62                         'type': 'VPORT',
63                     },
64                 ],
65                 'description': 'TRex stateless traffic generator for RFC2544',
66                 'id': 'TrexTrafficGen',
67                 'mgmt-interface': {
68                     'ip': '1.1.1.1',
69                     'password': 'berta',
70                     'user': 'berta',
71                     'vdu-id': 'trexgen-baremetal',
72                 },
73                 'name': 'trexgen',
74                 'short-name': 'trexgen',
75                 'class-name': 'TrexTrafficGen',
76                 'vdu': [
77                     {
78                         'description': 'TRex stateless traffic generator for RFC2544',
79                         'external-interface': [
80                             {
81                                 'name': 'xe0',
82                                 'virtual-interface': {
83                                     'bandwidth': '10 Gbps',
84                                     'dst_ip': '1.1.1.1',
85                                     'dst_mac': '00:01:02:03:04:05',
86                                     'local_ip': '1.1.1.2',
87                                     'local_mac': '00:01:02:03:05:05',
88                                     'type': 'PCI-PASSTHROUGH',
89                                     'netmask': "255.255.255.0",
90                                     'driver': 'i40',
91                                     'vpci': '0000:00:10.2',
92                                 },
93                                 'vnfd-connection-point-ref': 'xe0',
94                             },
95                             {
96                                 'name': 'xe1',
97                                 'virtual-interface': {
98                                     'bandwidth': '10 Gbps',
99                                     'dst_ip': '2.1.1.1',
100                                     'dst_mac': '00:01:02:03:04:06',
101                                     'local_ip': '2.1.1.2',
102                                     'local_mac': '00:01:02:03:05:06',
103                                     'type': 'PCI-PASSTHROUGH',
104                                     'netmask': "255.255.255.0",
105                                     'driver': 'i40',
106                                     'vpci': '0000:00:10.1',
107                                 },
108                                 'vnfd-connection-point-ref': 'xe1',
109                             },
110                         ],
111                         'id': 'trexgen-baremetal',
112                         'name': 'trexgen-baremetal',
113                     },
114                 ],
115             },
116         ],
117     },
118 }
119
120 IP_ADDR_SHOW = """
121 28: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP \
122 group default qlen 1000
123     link/ether 90:e2:ba:a7:6a:c8 brd ff:ff:ff:ff:ff:ff
124     inet 1.1.1.1/8 brd 1.255.255.255 scope global eth1
125     inet6 fe80::92e2:baff:fea7:6ac8/64 scope link
126        valid_lft forever preferred_lft forever
127 29: eth5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP \
128 group default qlen 1000
129     link/ether 90:e2:ba:a7:6a:c9 brd ff:ff:ff:ff:ff:ff
130     inet 2.1.1.1/8 brd 2.255.255.255 scope global eth5
131     inet6 fe80::92e2:baff:fea7:6ac9/64 scope link tentative
132        valid_lft forever preferred_lft forever
133 """
134
135 SYS_CLASS_NET = """
136 lrwxrwxrwx 1 root root 0 sie 10 14:16 eth1 -> \
137 ../../devices/pci0000:80/0000:80:02.2/0000:84:00.1/net/eth1
138 lrwxrwxrwx 1 root root 0 sie  3 10:37 eth2 -> \
139 ../../devices/pci0000:00/0000:00:01.1/0000:84:00.2/net/eth5
140 """
141
142 TRAFFIC_PROFILE = {
143     "schema": "isb:traffic_profile:0.1",
144     "name": "fixed",
145     "description": "Fixed traffic profile to run UDP traffic",
146     "traffic_profile": {
147         "traffic_type": "FixedTraffic",
148         "frame_rate": 100,  # pps
149         "flow_number": 10,
150         "frame_size": 64,
151     },
152 }
153
154
155 class TestNetworkServiceTestCase(unittest.TestCase):
156
157     def setUp(self):
158         self.tg__1 = {
159             'name': 'trafficgen_1.yardstick',
160             'ip': '10.10.10.11',
161             'role': 'TrafficGen',
162             'user': 'root',
163             'password': 'r00t',
164             'interfaces': {
165                 'xe0': {
166                     'netmask': '255.255.255.0',
167                     'local_ip': '152.16.100.20',
168                     'local_mac': '00:00:00:00:00:01',
169                     'driver': 'i40e',
170                     'vpci': '0000:07:00.0',
171                     'dpdk_port_num': 0,
172                 },
173                 'xe1': {
174                     'netmask': '255.255.255.0',
175                     'local_ip': '152.16.40.20',
176                     'local_mac': '00:00:00:00:00:02',
177                     'driver': 'i40e',
178                     'vpci': '0000:07:00.1',
179                     'dpdk_port_num': 1,
180                 },
181             },
182         }
183
184         self.vnf__1 = {
185             'name': 'vnf.yardstick',
186             'ip': '10.10.10.12',
187             'host': '10.223.197.164',
188             'role': 'vnf',
189             'user': 'root',
190             'password': 'r00t',
191             'interfaces': {
192                 'xe0': {
193                     'netmask': '255.255.255.0',
194                     'local_ip': '152.16.100.19',
195                     'local_mac': '00:00:00:00:00:03',
196                     'driver': 'i40e',
197                     'vpci': '0000:07:00.0',
198                     'dpdk_port_num': 0,
199                 },
200                 'xe1': {
201                     'netmask': '255.255.255.0',
202                     'local_ip': '152.16.40.19',
203                     'local_mac': '00:00:00:00:00:04',
204                     'driver': 'i40e',
205                     'vpci': '0000:07:00.1',
206                     'dpdk_port_num': 1,
207                 },
208             },
209             'routing_table': [
210                 {
211                     'netmask': '255.255.255.0',
212                     'gateway': '152.16.100.20',
213                     'network': '152.16.100.20',
214                     'if': 'xe0',
215                 },
216                 {
217                     'netmask': '255.255.255.0',
218                     'gateway': '152.16.40.20',
219                     'network': '152.16.40.20',
220                     'if': 'xe1',
221                 },
222             ],
223             'nd_route_tbl': [
224                 {
225                     'netmask': '112',
226                     'gateway': '0064:ff9b:0:0:0:0:9810:6414',
227                     'network': '0064:ff9b:0:0:0:0:9810:6414',
228                     'if': 'xe0',
229                 },
230                 {
231                     'netmask': '112',
232                     'gateway': '0064:ff9b:0:0:0:0:9810:2814',
233                     'network': '0064:ff9b:0:0:0:0:9810:2814',
234                     'if': 'xe1',
235                 },
236             ],
237         }
238
239         self.context_cfg = {
240             'nodes': {
241                 'tg__1': self.tg__1,
242                 'vnf__1': self.vnf__1,
243             },
244             'networks': {
245                 GenericVNF.UPLINK: {
246                     'vld_id': GenericVNF.UPLINK,
247                 },
248                 GenericVNF.DOWNLINK: {
249                     'vld_id': GenericVNF.DOWNLINK,
250                 },
251             },
252         }
253
254         self.vld0 = {
255             'vnfd-connection-point-ref': [
256                 {
257                     'vnfd-connection-point-ref': 'xe0',
258                     'member-vnf-index-ref': '1',
259                     'vnfd-id-ref': 'trexgen'
260                 },
261                 {
262                     'vnfd-connection-point-ref': 'xe0',
263                     'member-vnf-index-ref': '2',
264                     'vnfd-id-ref': 'trexgen'
265                 }
266             ],
267             'type': 'ELAN',
268             'id': GenericVNF.UPLINK,
269             'name': 'tg__1 to vnf__1 link 1'
270         }
271
272         self.vld1 = {
273             'vnfd-connection-point-ref': [
274                 {
275                     'vnfd-connection-point-ref': 'xe1',
276                     'member-vnf-index-ref': '1',
277                     'vnfd-id-ref': 'trexgen'
278                 },
279                 {
280                     'vnfd-connection-point-ref': 'xe1',
281                     'member-vnf-index-ref': '2',
282                     'vnfd-id-ref': 'trexgen'
283                 }
284             ],
285             'type': 'ELAN',
286             'id': GenericVNF.DOWNLINK,
287             'name': 'vnf__1 to tg__1 link 2'
288         }
289
290         self.topology = {
291             'id': 'trex-tg-topology',
292             'short-name': 'trex-tg-topology',
293             'name': 'trex-tg-topology',
294             'description': 'trex-tg-topology',
295             'constituent-vnfd': [
296                 {
297                     'member-vnf-index': '1',
298                     'VNF model': 'tg_trex_tpl.yaml',
299                     'vnfd-id-ref': 'tg__1',
300                 },
301                 {
302                     'member-vnf-index': '2',
303                     'VNF model': 'tg_trex_tpl.yaml',
304                     'vnfd-id-ref': 'vnf__1',
305                 },
306             ],
307             'vld': [self.vld0, self.vld1],
308         }
309
310         self.scenario_cfg = {
311             'task_path': "",
312             "topology": self._get_file_abspath("vpe_vnf_topology.yaml"),
313             'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
314             'tc': 'tc_ipv4_1Mflow_64B_packetsize',
315             'traffic_profile': 'ipv4_throughput_vpe.yaml',
316             'type': 'ISB',
317             'tc_options': {
318                 'rfc2544': {
319                     'allowed_drop_rate': '0.8 - 1',
320                 },
321             },
322             'options': {
323                 'framesize': {'64B': 100}
324             },
325             'runner': {
326                 'object': 'NetworkServiceTestCase',
327                 'interval': 35,
328                 'output_filename': 'yardstick.out',
329                 'runner_id': 74476,
330                 'duration': 400,
331                 'type': 'Duration',
332             },
333             'traffic_options': {
334                 'flow': 'ipv4_1flow_Packets_vpe.yaml',
335                 'imix': 'imix_voice.yaml'
336             },
337             'nodes': {
338                 'tg__2': 'trafficgen_2.yardstick',
339                 'tg__1': 'trafficgen_1.yardstick',
340                 'vnf__1': 'vnf.yardstick',
341             },
342         }
343
344         self.s = NetworkServiceTestCase(self.scenario_cfg, self.context_cfg)
345
346     def _get_file_abspath(self, filename):
347         curr_path = os.path.dirname(os.path.abspath(__file__))
348         file_path = os.path.join(curr_path, filename)
349         return file_path
350
351     def test_ssh_manager(self):
352         with mock.patch("yardstick.ssh.SSH") as ssh:
353             ssh_mock = mock.Mock(autospec=ssh.SSH)
354             ssh_mock.execute = \
355                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
356             ssh.from_node.return_value = ssh_mock
357             for node, node_dict in self.context_cfg["nodes"].items():
358                 with SshManager(node_dict) as conn:
359                     self.assertIsNotNone(conn)
360
361     def test___init__(self):
362         assert self.topology
363
364     def test__get_ip_flow_range_string(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('152.16.100.2-152.16.100.254'))
369
370     def test__get_ip_flow_range(self):
371         self.scenario_cfg["traffic_options"]["flow"] = \
372             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
373         result = '152.16.100.2-152.16.100.254'
374         self.assertEqual(result, self.s._get_ip_flow_range({"tg__1": 'xe0'}))
375
376     @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.ipaddress')
377     def test__get_ip_flow_range_no_node_data(self, mock_ipaddress):
378         scenario_cfg = deepcopy(self.scenario_cfg)
379         scenario_cfg["traffic_options"]["flow"] = \
380             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
381
382         mock_ipaddress.ip_network.return_value = ipaddr = mock.Mock()
383         ipaddr.hosts.return_value = []
384
385         expected = '0.0.0.0'
386         result = self.s._get_ip_flow_range({"tg__2": 'xe0'})
387         self.assertEqual(result, expected)
388
389     def test__get_ip_flow_range_no_nodes(self):
390         expected = '0.0.0.0'
391         result = self.s._get_ip_flow_range({})
392         self.assertEqual(result, expected)
393
394     def test___get_traffic_flow(self):
395         self.scenario_cfg["traffic_options"]["flow"] = \
396             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
397         self.scenario_cfg["options"] = {}
398         self.scenario_cfg['options'] = {
399             'flow': {
400               'src_ip': [
401                 {
402                   'tg__1': 'xe0',
403                 },
404               ],
405               'dst_ip': [
406                 {
407                   'tg__1': 'xe1',
408                 },
409               ],
410               'public_ip': ['1.1.1.1'],
411             },
412         }
413         result = {'flow': {'dst_ip0': '152.16.40.2-152.16.40.254',
414                            'src_ip0': '152.16.100.2-152.16.100.254'}}
415
416         self.assertEqual({'flow': {}}, self.s._get_traffic_flow())
417
418     def test___get_traffic_flow_error(self):
419         self.scenario_cfg["traffic_options"]["flow"] = \
420             "ipv4_1flow_Packets_vpe.yaml1"
421         self.assertEqual({'flow': {}}, self.s._get_traffic_flow())
422
423     def test_get_vnf_imp(self):
424         vnfd = COMPLETE_TREX_VNFD['vnfd:vnfd-catalog']['vnfd'][0]['class-name']
425         with mock.patch.dict("sys.modules", STL_MOCKS):
426             self.assertIsNotNone(self.s.get_vnf_impl(vnfd))
427
428             with self.assertRaises(IncorrectConfig) as raised:
429                 self.s.get_vnf_impl('NonExistentClass')
430
431             exc_str = str(raised.exception)
432             print(exc_str)
433             self.assertIn('No implementation', exc_str)
434             self.assertIn('found in', exc_str)
435
436     def test_load_vnf_models_invalid(self):
437         self.context_cfg["nodes"]['tg__1']['VNF model'] = \
438             self._get_file_abspath("tg_trex_tpl.yaml")
439         self.context_cfg["nodes"]['vnf__1']['VNF model'] = \
440             self._get_file_abspath("tg_trex_tpl.yaml")
441
442         vnf = mock.Mock(autospec=GenericVNF)
443         self.s.get_vnf_impl = mock.Mock(return_value=vnf)
444
445         self.assertIsNotNone(
446             self.s.load_vnf_models(self.scenario_cfg, self.context_cfg))
447
448     def test_load_vnf_models_no_model(self):
449         vnf = mock.Mock(autospec=GenericVNF)
450         self.s.get_vnf_impl = mock.Mock(return_value=vnf)
451
452         self.assertIsNotNone(
453             self.s.load_vnf_models(self.scenario_cfg, self.context_cfg))
454
455     def test_map_topology_to_infrastructure(self):
456         with mock.patch("yardstick.ssh.SSH") as ssh:
457             ssh_mock = mock.Mock(autospec=ssh.SSH)
458             ssh_mock.execute = \
459                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
460             ssh.from_node.return_value = ssh_mock
461             self.s.map_topology_to_infrastructure()
462
463         nodes = self.context_cfg["nodes"]
464         self.assertEqual("../../vnf_descriptors/tg_rfc2544_tpl.yaml", nodes['tg__1']['VNF model'])
465         self.assertEqual("../../vnf_descriptors/vpe_vnf.yaml", nodes['vnf__1']['VNF model'])
466
467     def test_map_topology_to_infrastructure_insufficient_nodes(self):
468         del self.context_cfg['nodes']['vnf__1']
469         with mock.patch("yardstick.ssh.SSH") as ssh:
470             ssh_mock = mock.Mock(autospec=ssh.SSH)
471             ssh_mock.execute = \
472                 mock.Mock(return_value=(1, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
473             ssh.from_node.return_value = ssh_mock
474
475             with self.assertRaises(IncorrectConfig):
476                 self.s.map_topology_to_infrastructure()
477
478     def test_map_topology_to_infrastructure_config_invalid(self):
479         cfg = dict(self.context_cfg)
480         del cfg['nodes']['vnf__1']['interfaces']['xe0']['local_mac']
481         with mock.patch("yardstick.ssh.SSH") as ssh:
482             ssh_mock = mock.Mock(autospec=ssh.SSH)
483             ssh_mock.execute = \
484                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
485             ssh.from_node.return_value = ssh_mock
486
487             with self.assertRaises(IncorrectConfig):
488                 self.s.map_topology_to_infrastructure()
489
490     def test__resolve_topology_invalid_config(self):
491         with mock.patch("yardstick.ssh.SSH") as ssh:
492             ssh_mock = mock.Mock(autospec=ssh.SSH)
493             ssh_mock.execute = \
494                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
495             ssh.from_node.return_value = ssh_mock
496
497             # purge an important key from the data structure
498             for interface in self.tg__1['interfaces'].values():
499                 del interface['local_mac']
500
501             with mock.patch(
502                 "yardstick.benchmark.scenarios.networking.vnf_generic.LOG") as mock_log:
503                 with self.assertRaises(IncorrectConfig) as raised:
504                     self.s._resolve_topology()
505
506             self.assertIn('not found', str(raised.exception))
507
508             # restore local_mac
509             for index, interface in enumerate(self.tg__1['interfaces'].values()):
510                 interface['local_mac'] = '00:00:00:00:00:{:2x}'.format(index)
511
512             # make a connection point ref with 3 points
513             self.s.topology["vld"][0]['vnfd-connection-point-ref'].append(
514                 self.s.topology["vld"][0]['vnfd-connection-point-ref'][0])
515
516             with mock.patch(
517                 "yardstick.benchmark.scenarios.networking.vnf_generic.LOG") as mock_log:
518                 with self.assertRaises(IncorrectConfig) as raised:
519                     self.s._resolve_topology()
520
521             self.assertIn('wrong endpoint count', str(raised.exception))
522
523             # make a connection point ref with 1 point
524             self.s.topology["vld"][0]['vnfd-connection-point-ref'] = \
525                 self.s.topology["vld"][0]['vnfd-connection-point-ref'][:1]
526
527             with mock.patch(
528                 "yardstick.benchmark.scenarios.networking.vnf_generic.LOG") as mock_log:
529                 with self.assertRaises(IncorrectConfig) as raised:
530                     self.s._resolve_topology()
531
532             self.assertIn('wrong endpoint count', str(raised.exception))
533
534     def test_run(self):
535         tgen = mock.Mock(autospec=GenericTrafficGen)
536         tgen.traffic_finished = True
537         verified_dict = {"verified": True}
538         tgen.verify_traffic = lambda x: verified_dict
539         tgen.name = "tgen__1"
540         vnf = mock.Mock(autospec=GenericVNF)
541         vnf.runs_traffic = False
542         self.s.vnfs = [tgen, vnf]
543         self.s.traffic_profile = mock.Mock()
544         self.s.collector = mock.Mock(autospec=Collector)
545         self.s.collector.get_kpi = \
546             mock.Mock(return_value={tgen.name: verified_dict})
547         result = {}
548         self.s.run(result)
549         self.assertDictEqual(result, {tgen.name: verified_dict})
550
551     def test_setup(self):
552         with mock.patch("yardstick.ssh.SSH") as ssh:
553             ssh_mock = mock.Mock(autospec=ssh.SSH)
554             ssh_mock.execute = \
555                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
556             ssh.from_node.return_value = ssh_mock
557
558             tgen = mock.Mock(autospec=GenericTrafficGen)
559             tgen.traffic_finished = True
560             verified_dict = {"verified": True}
561             tgen.verify_traffic = lambda x: verified_dict
562             tgen.terminate = mock.Mock(return_value=True)
563             tgen.name = "tgen__1"
564             vnf = mock.Mock(autospec=GenericVNF)
565             vnf.runs_traffic = False
566             vnf.terminate = mock.Mock(return_value=True)
567             self.s.vnfs = [tgen, vnf]
568             self.s.traffic_profile = mock.Mock()
569             self.s.collector = mock.Mock(autospec=Collector)
570             self.s.collector.get_kpi = \
571                 mock.Mock(return_value={tgen.name: verified_dict})
572             self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
573             self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
574             self.s._fill_traffic_profile = \
575                 mock.Mock(return_value=TRAFFIC_PROFILE)
576             self.assertEqual(None, self.s.setup())
577
578     def test_setup_exception(self):
579         with mock.patch("yardstick.ssh.SSH") as ssh:
580             ssh_mock = mock.Mock(autospec=ssh.SSH)
581             ssh_mock.execute = \
582                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
583             ssh.from_node.return_value = ssh_mock
584
585             tgen = mock.Mock(autospec=GenericTrafficGen)
586             tgen.traffic_finished = True
587             verified_dict = {"verified": True}
588             tgen.verify_traffic = lambda x: verified_dict
589             tgen.terminate = mock.Mock(return_value=True)
590             tgen.name = "tgen__1"
591             vnf = mock.Mock(autospec=GenericVNF)
592             vnf.runs_traffic = False
593             vnf.instantiate.side_effect = RuntimeError("error during instantiate")
594             vnf.terminate = mock.Mock(return_value=True)
595             self.s.vnfs = [tgen, vnf]
596             self.s.traffic_profile = mock.Mock()
597             self.s.collector = mock.Mock(autospec=Collector)
598             self.s.collector.get_kpi = \
599                 mock.Mock(return_value={tgen.name: verified_dict})
600             self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
601             self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
602             self.s._fill_traffic_profile = \
603                 mock.Mock(return_value=TRAFFIC_PROFILE)
604             with self.assertRaises(RuntimeError):
605                 self.s.setup()
606
607     def test__get_traffic_profile(self):
608         self.scenario_cfg["traffic_profile"] = \
609             self._get_file_abspath("ipv4_throughput_vpe.yaml")
610         self.assertIsNotNone(self.s._get_traffic_profile())
611
612     def test__get_traffic_profile_exception(self):
613         with mock.patch.dict(self.scenario_cfg, {'traffic_profile': ''}):
614             with self.assertRaises(IOError):
615                 self.s._get_traffic_profile()
616
617     def test___get_traffic_imix_exception(self):
618         with mock.patch.dict(self.scenario_cfg["traffic_options"], {'imix': ''}):
619             self.assertEqual({'imix': {'64B': 100}}, self.s._get_traffic_imix())
620
621     def test__fill_traffic_profile(self):
622         with mock.patch.dict("sys.modules", STL_MOCKS):
623             self.scenario_cfg["traffic_profile"] = \
624                 self._get_file_abspath("ipv4_throughput_vpe.yaml")
625             self.scenario_cfg["traffic_options"]["flow"] = \
626                 self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
627             self.scenario_cfg["traffic_options"]["imix"] = \
628                 self._get_file_abspath("imix_voice.yaml")
629             self.assertIsNotNone(self.s._fill_traffic_profile())
630
631     def test_teardown(self):
632         vnf = mock.Mock(autospec=GenericVNF)
633         vnf.terminate = mock.Mock(return_value=True)
634         vnf.name = str(vnf)
635         self.s.vnfs = [vnf]
636         self.s.traffic_profile = mock.Mock()
637         self.s.collector = mock.Mock(autospec=Collector)
638         self.s.collector.stop = \
639             mock.Mock(return_value=True)
640         self.assertIsNone(self.s.teardown())
641
642     def test_teardown_exception(self):
643         vnf = mock.Mock(autospec=GenericVNF)
644         vnf.terminate = mock.Mock(side_effect=RuntimeError("error duing terminate"))
645         vnf.name = str(vnf)
646         self.s.vnfs = [vnf]
647         self.s.traffic_profile = mock.Mock()
648         self.s.collector = mock.Mock(autospec=Collector)
649         self.s.collector.stop = \
650             mock.Mock(return_value=True)
651         with self.assertRaises(RuntimeError):
652             self.s.teardown()
653
654     SAMPLE_NETDEVS = {
655         'enp11s0': {
656             'address': '0a:de:ad:be:ef:f5',
657             'device': '0x1533',
658             'driver': 'igb',
659             'ifindex': '2',
660             'interface_name': 'enp11s0',
661             'operstate': 'down',
662             'pci_bus_id': '0000:0b:00.0',
663             'subsystem_device': '0x1533',
664             'subsystem_vendor': '0x15d9',
665             'vendor': '0x8086'
666         },
667         'lan': {
668             'address': '0a:de:ad:be:ef:f4',
669             'device': '0x153a',
670             'driver': 'e1000e',
671             'ifindex': '3',
672             'interface_name': 'lan',
673             'operstate': 'up',
674             'pci_bus_id': '0000:00:19.0',
675             'subsystem_device': '0x153a',
676             'subsystem_vendor': '0x15d9',
677             'vendor': '0x8086'
678         }
679     }
680
681     SAMPLE_VM_NETDEVS = {
682         'eth1': {
683             'address': 'fa:de:ad:be:ef:5b',
684             'device': '0x0001',
685             'driver': 'virtio_net',
686             'ifindex': '3',
687             'interface_name': 'eth1',
688             'operstate': 'down',
689             'pci_bus_id': '0000:00:04.0',
690             'vendor': '0x1af4'
691         }
692     }
693
694     def test_parse_netdev_info(self):
695         output = """\
696 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/ifindex:2
697 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/address:0a:de:ad:be:ef:f5
698 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/operstate:down
699 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/vendor:0x8086
700 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/device:0x1533
701 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_vendor:0x15d9
702 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_device:0x1533
703 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/driver:igb
704 /sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/pci_bus_id:0000:0b:00.0
705 /sys/devices/pci0000:00/0000:00:19.0/net/lan/ifindex:3
706 /sys/devices/pci0000:00/0000:00:19.0/net/lan/address:0a:de:ad:be:ef:f4
707 /sys/devices/pci0000:00/0000:00:19.0/net/lan/operstate:up
708 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/vendor:0x8086
709 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/device:0x153a
710 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_vendor:0x15d9
711 /sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_device:0x153a
712 /sys/devices/pci0000:00/0000:00:19.0/net/lan/driver:e1000e
713 /sys/devices/pci0000:00/0000:00:19.0/net/lan/pci_bus_id:0000:00:19.0
714 """
715         res = NetworkServiceTestCase.parse_netdev_info(output)
716         assert res == self.SAMPLE_NETDEVS
717
718     def test_parse_netdev_info_virtio(self):
719         output = """\
720 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/ifindex:3
721 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/address:fa:de:ad:be:ef:5b
722 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/operstate:down
723 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/vendor:0x1af4
724 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/device:0x0001
725 /sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/driver:virtio_net
726 """
727         res = NetworkServiceTestCase.parse_netdev_info(output)
728         assert res == self.SAMPLE_VM_NETDEVS
729
730     def test_probe_missing_values(self):
731         netdevs = self.SAMPLE_NETDEVS.copy()
732         network = {'local_mac': '0a:de:ad:be:ef:f5'}
733         NetworkServiceTestCase._probe_missing_values(netdevs, network)
734         assert network['vpci'] == '0000:0b:00.0'
735
736         network = {'local_mac': '0a:de:ad:be:ef:f4'}
737         NetworkServiceTestCase._probe_missing_values(netdevs, network)
738         assert network['vpci'] == '0000:00:19.0'
739
740     def test_open_relative_path(self):
741         mock_open = mock.mock_open()
742         mock_open_result = mock_open()
743         mock_open_call_count = 1  # initial call to get result
744
745         module_name = \
746             'yardstick.benchmark.scenarios.networking.vnf_generic.open'
747
748         # test
749         with mock.patch(module_name, mock_open, create=True):
750             self.assertEqual(open_relative_file('foo', 'bar'), mock_open_result)
751
752             mock_open_call_count += 1  # one more call expected
753             self.assertEqual(mock_open.call_count, mock_open_call_count)
754             self.assertIn('foo', mock_open.call_args_list[-1][0][0])
755             self.assertNotIn('bar', mock_open.call_args_list[-1][0][0])
756
757             def open_effect(*args, **kwargs):
758                 if kwargs.get('name', args[0]) == os.path.join('bar', 'foo'):
759                     return mock_open_result
760                 raise IOError(errno.ENOENT, 'not found')
761
762             mock_open.side_effect = open_effect
763             self.assertEqual(open_relative_file('foo', 'bar'), mock_open_result)
764
765             mock_open_call_count += 2  # two more calls expected
766             self.assertEqual(mock_open.call_count, mock_open_call_count)
767             self.assertIn('foo', mock_open.call_args_list[-1][0][0])
768             self.assertIn('bar', mock_open.call_args_list[-1][0][0])
769
770             # test an IOError of type ENOENT
771             mock_open.side_effect = IOError(errno.ENOENT, 'not found')
772             with self.assertRaises(IOError):
773                 # the second call still raises
774                 open_relative_file('foo', 'bar')
775
776             mock_open_call_count += 2  # two more calls expected
777             self.assertEqual(mock_open.call_count, mock_open_call_count)
778             self.assertIn('foo', mock_open.call_args_list[-1][0][0])
779             self.assertIn('bar', mock_open.call_args_list[-1][0][0])
780
781             # test an IOError other than ENOENT
782             mock_open.side_effect = IOError(errno.EBUSY, 'busy')
783             with self.assertRaises(IOError):
784                 open_relative_file('foo', 'bar')
785
786             mock_open_call_count += 1  # one more call expected
787             self.assertEqual(mock_open.call_count, mock_open_call_count)