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