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