Merge "[docs] Add vEPC test case preparation steps"
[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 from copy import deepcopy
16 import os
17 import sys
18
19 import mock
20 import unittest
21
22 from yardstick import tests
23 from yardstick.common import exceptions
24 from yardstick.common import utils
25 from yardstick.network_services.collector.subscriber import Collector
26 from yardstick.network_services.traffic_profile import base
27 from yardstick.network_services.vnf_generic import vnfdgen
28 from yardstick.network_services.vnf_generic.vnf.base import GenericTrafficGen
29 from yardstick.network_services.vnf_generic.vnf.base import GenericVNF
30
31
32 stl_patch = mock.patch.dict(sys.modules, tests.STL_MOCKS)
33 stl_patch.start()
34
35 if stl_patch:
36     from yardstick.benchmark.scenarios.networking import vnf_generic
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             'extra_args': {'arg1': 'value1', 'arg2': 'value2'},
321             'type': 'ISB',
322             'tc_options': {
323                 'rfc2544': {
324                     'allowed_drop_rate': '0.8 - 1',
325                 },
326             },
327             'options': {
328                 'framesize': {'64B': 100}
329             },
330             'runner': {
331                 'object': 'NetworkServiceTestCase',
332                 'interval': 35,
333                 'output_filename': 'yardstick.out',
334                 'runner_id': 74476,
335                 'duration': 400,
336                 'type': 'Duration',
337             },
338             'traffic_options': {
339                 'flow': 'ipv4_1flow_Packets_vpe.yaml',
340                 'imix': 'imix_voice.yaml'
341             },
342             'nodes': {
343                 'tg__2': 'trafficgen_2.yardstick',
344                 'tg__1': 'trafficgen_1.yardstick',
345                 'vnf__1': 'vnf.yardstick',
346             },
347         }
348
349         self.s = vnf_generic.NetworkServiceTestCase(self.scenario_cfg,
350                                                     self.context_cfg)
351
352     def _get_file_abspath(self, filename):
353         curr_path = os.path.dirname(os.path.abspath(__file__))
354         file_path = os.path.join(curr_path, filename)
355         return file_path
356
357     def test___init__(self):
358         self.assertIsNotNone(self.topology)
359
360     def test__get_ip_flow_range_string(self):
361         result = '152.16.100.2-152.16.100.254'
362         self.assertEqual(result, self.s._get_ip_flow_range(
363             '152.16.100.2-152.16.100.254'))
364
365     def test__get_ip_flow_range_no_nodes(self):
366         self.assertEqual('0.0.0.0', self.s._get_ip_flow_range({}))
367
368     def test__get_ip_flow_range_no_node_data(self):
369         node_data = {'tg__0': 'xe0'}
370         self.s.context_cfg['nodes']['tg__0'] = {}
371         result = self.s._get_ip_flow_range(node_data)
372         self.assertEqual('0.0.0.2-0.0.0.254', result)
373
374     def test__et_ip_flow_range_ipv4(self):
375         node_data = {'tg__0': 'xe0'}
376         self.s.context_cfg['nodes']['tg__0'] = {
377             'interfaces': {
378                 'xe0': {'local_ip': '192.168.1.15',
379                         'netmask': '255.255.255.128'}
380             }
381         }
382         result = self.s._get_ip_flow_range(node_data)
383         self.assertEqual('192.168.1.2-192.168.1.126', result)
384
385     def test__get_ip_flow_range_ipv4_mask_30(self):
386         node_data = {'tg__0': 'xe0'}
387         self.s.context_cfg['nodes']['tg__0'] = {
388             'interfaces': {
389                 'xe0': {'local_ip': '192.168.1.15', 'netmask': 30}
390             }
391         }
392         result = self.s._get_ip_flow_range(node_data)
393         self.assertEqual('192.168.1.15', result)
394
395     def test__get_ip_flow_range_ipv6(self):
396         node_data = {'tg__0': 'xe0'}
397         self.s.context_cfg['nodes']['tg__0'] = {
398             'interfaces': {
399                 'xe0': {'local_ip': '2001::11', 'netmask': 64}
400             }
401         }
402         result = self.s._get_ip_flow_range(node_data)
403         self.assertEqual('2001::2-2001::ffff:ffff:ffff:fffe', result)
404
405     def test___get_traffic_flow(self):
406         self.scenario_cfg["traffic_options"]["flow"] = \
407             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
408         self.scenario_cfg['options'] = {
409             'flow': {
410                 'src_ip': [
411                     {
412                         'tg__1': 'xe0',
413                     },
414                 ],
415                 'dst_ip': [
416                     {
417                         'tg__1': 'xe1',
418                     },
419                 ],
420                 'public_ip': ['1.1.1.1'],
421             },
422         }
423         expected_flow = {'flow': {'dst_ip_0': '152.16.40.2-152.16.40.254',
424                                   'public_ip_0': '1.1.1.1',
425                                   'src_ip_0': '152.16.100.2-152.16.100.254'}}
426         self.assertEqual(expected_flow, self.s._get_traffic_flow())
427
428     def test___get_traffic_flow_error(self):
429         self.scenario_cfg["traffic_options"]["flow"] = \
430             "ipv4_1flow_Packets_vpe.yaml1"
431         self.assertEqual({'flow': {}}, self.s._get_traffic_flow())
432
433     def test_get_vnf_imp(self):
434         vnfd = COMPLETE_TREX_VNFD['vnfd:vnfd-catalog']['vnfd'][0]['class-name']
435         with mock.patch.dict(sys.modules, tests.STL_MOCKS):
436             self.assertIsNotNone(self.s.get_vnf_impl(vnfd))
437
438         with self.assertRaises(exceptions.IncorrectConfig) as raised:
439             self.s.get_vnf_impl('NonExistentClass')
440
441         exc_str = str(raised.exception)
442         print(exc_str)
443         self.assertIn('No implementation', exc_str)
444         self.assertIn('found in', exc_str)
445
446     def test_load_vnf_models_invalid(self):
447         self.context_cfg["nodes"]['tg__1']['VNF model'] = \
448             self._get_file_abspath("tg_trex_tpl.yaml")
449         self.context_cfg["nodes"]['vnf__1']['VNF model'] = \
450             self._get_file_abspath("tg_trex_tpl.yaml")
451         self.context_cfg['task_id'] = 'fake_task_id'
452
453         vnf = mock.Mock(autospec=GenericVNF)
454         self.s.get_vnf_impl = mock.Mock(return_value=vnf)
455
456         self.assertIsNotNone(
457             self.s.load_vnf_models(self.scenario_cfg, self.context_cfg))
458
459     def test_load_vnf_models_no_model(self):
460         vnf = mock.Mock(autospec=GenericVNF)
461         self.s.get_vnf_impl = mock.Mock(return_value=vnf)
462
463         self.assertIsNotNone(
464             self.s.load_vnf_models(self.scenario_cfg, self.context_cfg))
465
466     def test_map_topology_to_infrastructure(self):
467         self.s.map_topology_to_infrastructure()
468
469         nodes = self.context_cfg["nodes"]
470         self.assertEqual('../../vnf_descriptors/tg_rfc2544_tpl.yaml',
471                          nodes['tg__1']['VNF model'])
472         self.assertEqual('../../vnf_descriptors/vpe_vnf.yaml',
473                          nodes['vnf__1']['VNF model'])
474
475     def test_map_topology_to_infrastructure_insufficient_nodes(self):
476         cfg = deepcopy(self.context_cfg)
477         del cfg['nodes']['vnf__1']
478
479         cfg_patch = mock.patch.object(self.s, 'context_cfg', cfg)
480         with cfg_patch:
481             with self.assertRaises(exceptions.IncorrectConfig):
482                 self.s.map_topology_to_infrastructure()
483
484     def test_map_topology_to_infrastructure_config_invalid(self):
485         ssh_mock = mock.Mock()
486         ssh_mock.execute.return_value = 0, SYS_CLASS_NET + IP_ADDR_SHOW, ""
487
488         cfg = deepcopy(self.s.context_cfg)
489
490         # delete all, we don't know which will come first
491         del cfg['nodes']['vnf__1']['interfaces']['xe0']['local_mac']
492         del cfg['nodes']['vnf__1']['interfaces']['xe1']['local_mac']
493         del cfg['nodes']['tg__1']['interfaces']['xe0']['local_mac']
494         del cfg['nodes']['tg__1']['interfaces']['xe1']['local_mac']
495
496         config_patch = mock.patch.object(self.s, 'context_cfg', cfg)
497         with config_patch:
498             with self.assertRaises(exceptions.IncorrectConfig):
499                 self.s.map_topology_to_infrastructure()
500
501     def test__resolve_topology_invalid_config(self):
502         with mock.patch("yardstick.ssh.SSH") as ssh:
503             ssh_mock = mock.Mock(autospec=ssh.SSH)
504             ssh_mock.execute = \
505                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
506             ssh.from_node.return_value = ssh_mock
507
508             # purge an important key from the data structure
509             for interface in self.tg__1['interfaces'].values():
510                 del interface['local_mac']
511
512             with self.assertRaises(exceptions.IncorrectConfig) as raised:
513                 self.s._resolve_topology()
514
515             self.assertIn('not found', str(raised.exception))
516
517             # restore local_mac
518             for index, interface in enumerate(self.tg__1['interfaces'].values()):
519                 interface['local_mac'] = '00:00:00:00:00:{:2x}'.format(index)
520
521             # make a connection point ref with 3 points
522             self.s.topology["vld"][0]['vnfd-connection-point-ref'].append(
523                 self.s.topology["vld"][0]['vnfd-connection-point-ref'][0])
524
525             with self.assertRaises(exceptions.IncorrectConfig) as raised:
526                 self.s._resolve_topology()
527
528             self.assertIn('wrong endpoint count', str(raised.exception))
529
530             # make a connection point ref with 1 point
531             self.s.topology["vld"][0]['vnfd-connection-point-ref'] = \
532                 self.s.topology["vld"][0]['vnfd-connection-point-ref'][:1]
533
534             with self.assertRaises(exceptions.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             tgen.run_traffic.return_value = 'tg_id'
570             vnf = mock.Mock(autospec=GenericVNF)
571             vnf.runs_traffic = False
572             vnf.terminate = mock.Mock(return_value=True)
573             self.s.vnfs = [tgen, vnf]
574             self.s.traffic_profile = mock.Mock()
575             self.s.collector = mock.Mock(autospec=Collector)
576             self.s.collector.get_kpi = \
577                 mock.Mock(return_value={tgen.name: verified_dict})
578             self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
579             self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
580             self.s._fill_traffic_profile = \
581                 mock.Mock(return_value=TRAFFIC_PROFILE)
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     @mock.patch.object(base.TrafficProfile, 'get')
629     @mock.patch.object(vnfdgen, 'generate_vnfd')
630     def test__fill_traffic_profile(self, mock_generate, mock_tprofile_get):
631         fake_tprofile = mock.Mock()
632         fake_vnfd = mock.MagicMock()
633         with mock.patch.object(self.s, '_get_traffic_profile',
634                                return_value=fake_tprofile) as mock_get_tp:
635             mock_generate.return_value = fake_vnfd
636             self.s._fill_traffic_profile()
637             mock_get_tp.assert_called_once()
638             mock_generate.assert_called_once_with(
639                 fake_tprofile,
640                 {'downlink': {},
641                  'extra_args': {'arg1': 'value1', 'arg2': 'value2'},
642                  'flow': {'flow': {}},
643                  'imix': {'imix': {'64B': 100}},
644                  'uplink': {},
645                  'duration': 30}
646             )
647             mock_tprofile_get.assert_called_once_with(fake_vnfd)
648
649     @mock.patch.object(base.TrafficProfile, 'get')
650     @mock.patch.object(vnfdgen, 'generate_vnfd')
651     def test__fill_traffic_profile2(self, mock_generate, mock_tprofile_get):
652         fake_tprofile = mock.Mock()
653         fake_vnfd = {}
654         with mock.patch.object(self.s, '_get_traffic_profile',
655                                return_value=fake_tprofile) as mock_get_tp:
656             mock_generate.return_value = fake_vnfd
657
658             self.s.scenario_cfg["options"] = {"traffic_config": {"duration": 99899}}
659             self.s._fill_traffic_profile()
660             mock_get_tp.assert_called_once()
661             self.assertIn("traffic_profile", fake_vnfd)
662             self.assertIn("duration", fake_vnfd["traffic_profile"])
663             self.assertEqual(99899, fake_vnfd["traffic_profile"]["duration"])
664
665     @mock.patch.object(utils, 'open_relative_file')
666     def test__get_topology(self, mock_open_path):
667         self.s.scenario_cfg['topology'] = 'fake_topology'
668         self.s.scenario_cfg['task_path'] = 'fake_path'
669         mock_open_path.side_effect = mock.mock_open(read_data='fake_data')
670         self.assertEqual('fake_data', self.s._get_topology())
671         mock_open_path.assert_called_once_with('fake_topology', 'fake_path')
672
673     @mock.patch.object(vnfdgen, 'generate_vnfd')
674     def test__render_topology(self, mock_generate):
675         fake_topology = 'fake_topology'
676         mock_generate.return_value = {'nsd:nsd-catalog': {'nsd': ['fake_nsd']}}
677         with mock.patch.object(self.s, '_get_topology',
678                                return_value=fake_topology) as mock_get_topology:
679             self.s._render_topology()
680             mock_get_topology.assert_called_once()
681
682         mock_generate.assert_called_once_with(
683             fake_topology,
684             {'extra_args': {'arg1': 'value1', 'arg2': 'value2'}}
685         )
686         self.assertEqual(self.s.topology, 'fake_nsd')
687
688     def test_get_mq_ids(self):
689         self.assertEqual(self.s._mq_ids, self.s.get_mq_ids())
690
691     def test_teardown(self):
692         vnf = mock.Mock(autospec=GenericVNF)
693         vnf.terminate = mock.Mock(return_value=True)
694         vnf.name = str(vnf)
695         self.s.vnfs = [vnf]
696         self.s.traffic_profile = mock.Mock()
697         self.s.collector = mock.Mock(autospec=Collector)
698         self.s.collector.stop = \
699             mock.Mock(return_value=True)
700         self.assertIsNone(self.s.teardown())
701
702     def test_teardown_exception(self):
703         vnf = mock.Mock(autospec=GenericVNF)
704         vnf.terminate = mock.Mock(
705             side_effect=RuntimeError("error duing terminate"))
706         vnf.name = str(vnf)
707         self.s.vnfs = [vnf]
708         self.s.traffic_profile = mock.Mock()
709         self.s.collector = mock.Mock(autospec=Collector)
710         self.s.collector.stop = \
711             mock.Mock(return_value=True)
712         with self.assertRaises(RuntimeError):
713             self.s.teardown()