Merge "Modify the Docker diff file for ARM64"
[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 utils
24 from yardstick.network_services.collector.subscriber import Collector
25 from yardstick.network_services.traffic_profile import base
26 from yardstick.network_services.vnf_generic import vnfdgen
27 from yardstick.error import IncorrectConfig
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         self.scenario_cfg["traffic_options"]["flow"] = \
362             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
363         result = '152.16.100.2-152.16.100.254'
364         self.assertEqual(result, self.s._get_ip_flow_range(
365             '152.16.100.2-152.16.100.254'))
366
367     def test__get_ip_flow_range(self):
368         self.scenario_cfg["traffic_options"]["flow"] = \
369             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
370         result = '152.16.100.2-152.16.100.254'
371         self.assertEqual(result, self.s._get_ip_flow_range({"tg__1": 'xe0'}))
372
373     @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.ipaddress')
374     def test__get_ip_flow_range_no_node_data(self, mock_ipaddress):
375         scenario_cfg = deepcopy(self.scenario_cfg)
376         scenario_cfg["traffic_options"]["flow"] = \
377             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
378
379         mock_ipaddress.ip_network.return_value = ipaddr = mock.Mock()
380         ipaddr.hosts.return_value = []
381
382         expected = '0.0.0.0'
383         result = self.s._get_ip_flow_range({"tg__2": 'xe0'})
384         self.assertEqual(result, expected)
385
386     def test__get_ip_flow_range_no_nodes(self):
387         expected = '0.0.0.0'
388         result = self.s._get_ip_flow_range({})
389         self.assertEqual(result, expected)
390
391     def test___get_traffic_flow(self):
392         self.scenario_cfg["traffic_options"]["flow"] = \
393             self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml")
394         self.scenario_cfg["options"] = {}
395         self.scenario_cfg['options'] = {
396             'flow': {
397                 'src_ip': [
398                     {
399                         'tg__1': 'xe0',
400                     },
401                 ],
402                 'dst_ip': [
403                     {
404                         'tg__1': 'xe1',
405                     },
406                 ],
407                 'public_ip': ['1.1.1.1'],
408             },
409         }
410         # NOTE(ralonsoh): check the expected output. This test could be
411         # incorrect
412         # result = {'flow': {'dst_ip0': '152.16.40.2-152.16.40.254',
413         #                    'src_ip0': '152.16.100.2-152.16.100.254'}}
414         self.assertEqual({'flow': {}}, self.s._get_traffic_flow())
415
416     def test___get_traffic_flow_error(self):
417         self.scenario_cfg["traffic_options"]["flow"] = \
418             "ipv4_1flow_Packets_vpe.yaml1"
419         self.assertEqual({'flow': {}}, self.s._get_traffic_flow())
420
421     def test_get_vnf_imp(self):
422         vnfd = COMPLETE_TREX_VNFD['vnfd:vnfd-catalog']['vnfd'][0]['class-name']
423         with mock.patch.dict(sys.modules, tests.STL_MOCKS):
424             self.assertIsNotNone(self.s.get_vnf_impl(vnfd))
425
426         with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
427             self.s.get_vnf_impl('NonExistentClass')
428
429         exc_str = str(raised.exception)
430         print(exc_str)
431         self.assertIn('No implementation', exc_str)
432         self.assertIn('found in', exc_str)
433
434     def test_load_vnf_models_invalid(self):
435         self.context_cfg["nodes"]['tg__1']['VNF model'] = \
436             self._get_file_abspath("tg_trex_tpl.yaml")
437         self.context_cfg["nodes"]['vnf__1']['VNF model'] = \
438             self._get_file_abspath("tg_trex_tpl.yaml")
439
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_load_vnf_models_no_model(self):
447         vnf = mock.Mock(autospec=GenericVNF)
448         self.s.get_vnf_impl = mock.Mock(return_value=vnf)
449
450         self.assertIsNotNone(
451             self.s.load_vnf_models(self.scenario_cfg, self.context_cfg))
452
453     def test_map_topology_to_infrastructure(self):
454         self.s.map_topology_to_infrastructure()
455
456         nodes = self.context_cfg["nodes"]
457         self.assertEqual('../../vnf_descriptors/tg_rfc2544_tpl.yaml',
458                          nodes['tg__1']['VNF model'])
459         self.assertEqual('../../vnf_descriptors/vpe_vnf.yaml',
460                          nodes['vnf__1']['VNF model'])
461
462     def test_map_topology_to_infrastructure_insufficient_nodes(self):
463         cfg = deepcopy(self.context_cfg)
464         del cfg['nodes']['vnf__1']
465
466         cfg_patch = mock.patch.object(self.s, 'context_cfg', cfg)
467         with cfg_patch:
468             with self.assertRaises(IncorrectConfig):
469                 self.s.map_topology_to_infrastructure()
470
471     def test_map_topology_to_infrastructure_config_invalid(self):
472         ssh_mock = mock.Mock()
473         ssh_mock.execute.return_value = 0, SYS_CLASS_NET + IP_ADDR_SHOW, ""
474
475         cfg = deepcopy(self.s.context_cfg)
476
477         # delete all, we don't know which will come first
478         del cfg['nodes']['vnf__1']['interfaces']['xe0']['local_mac']
479         del cfg['nodes']['vnf__1']['interfaces']['xe1']['local_mac']
480         del cfg['nodes']['tg__1']['interfaces']['xe0']['local_mac']
481         del cfg['nodes']['tg__1']['interfaces']['xe1']['local_mac']
482
483         config_patch = mock.patch.object(self.s, 'context_cfg', cfg)
484         with config_patch:
485             with self.assertRaises(IncorrectConfig):
486                 self.s.map_topology_to_infrastructure()
487
488     def test__resolve_topology_invalid_config(self):
489         with mock.patch("yardstick.ssh.SSH") as ssh:
490             ssh_mock = mock.Mock(autospec=ssh.SSH)
491             ssh_mock.execute = \
492                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
493             ssh.from_node.return_value = ssh_mock
494
495             # purge an important key from the data structure
496             for interface in self.tg__1['interfaces'].values():
497                 del interface['local_mac']
498
499             with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
500                 self.s._resolve_topology()
501
502             self.assertIn('not found', str(raised.exception))
503
504             # restore local_mac
505             for index, interface in enumerate(self.tg__1['interfaces'].values()):
506                 interface['local_mac'] = '00:00:00:00:00:{:2x}'.format(index)
507
508             # make a connection point ref with 3 points
509             self.s.topology["vld"][0]['vnfd-connection-point-ref'].append(
510                 self.s.topology["vld"][0]['vnfd-connection-point-ref'][0])
511
512             with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
513                 self.s._resolve_topology()
514
515             self.assertIn('wrong endpoint count', str(raised.exception))
516
517             # make a connection point ref with 1 point
518             self.s.topology["vld"][0]['vnfd-connection-point-ref'] = \
519                 self.s.topology["vld"][0]['vnfd-connection-point-ref'][:1]
520
521             with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
522                 self.s._resolve_topology()
523
524             self.assertIn('wrong endpoint count', str(raised.exception))
525
526     def test_run(self):
527         tgen = mock.Mock(autospec=GenericTrafficGen)
528         tgen.traffic_finished = True
529         verified_dict = {"verified": True}
530         tgen.verify_traffic = lambda x: verified_dict
531         tgen.name = "tgen__1"
532         vnf = mock.Mock(autospec=GenericVNF)
533         vnf.runs_traffic = False
534         self.s.vnfs = [tgen, vnf]
535         self.s.traffic_profile = mock.Mock()
536         self.s.collector = mock.Mock(autospec=Collector)
537         self.s.collector.get_kpi = \
538             mock.Mock(return_value={tgen.name: verified_dict})
539         result = {}
540         self.s.run(result)
541         self.assertDictEqual(result, {tgen.name: verified_dict})
542
543     def test_setup(self):
544         with mock.patch("yardstick.ssh.SSH") as ssh:
545             ssh_mock = mock.Mock(autospec=ssh.SSH)
546             ssh_mock.execute = \
547                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
548             ssh.from_node.return_value = ssh_mock
549
550             tgen = mock.Mock(autospec=GenericTrafficGen)
551             tgen.traffic_finished = True
552             verified_dict = {"verified": True}
553             tgen.verify_traffic = lambda x: verified_dict
554             tgen.terminate = mock.Mock(return_value=True)
555             tgen.name = "tgen__1"
556             vnf = mock.Mock(autospec=GenericVNF)
557             vnf.runs_traffic = False
558             vnf.terminate = mock.Mock(return_value=True)
559             self.s.vnfs = [tgen, vnf]
560             self.s.traffic_profile = mock.Mock()
561             self.s.collector = mock.Mock(autospec=Collector)
562             self.s.collector.get_kpi = \
563                 mock.Mock(return_value={tgen.name: verified_dict})
564             self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
565             self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
566             self.s._fill_traffic_profile = \
567                 mock.Mock(return_value=TRAFFIC_PROFILE)
568             self.assertIsNone(self.s.setup())
569
570     def test_setup_exception(self):
571         with mock.patch("yardstick.ssh.SSH") as ssh:
572             ssh_mock = mock.Mock(autospec=ssh.SSH)
573             ssh_mock.execute = \
574                 mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
575             ssh.from_node.return_value = ssh_mock
576
577             tgen = mock.Mock(autospec=GenericTrafficGen)
578             tgen.traffic_finished = True
579             verified_dict = {"verified": True}
580             tgen.verify_traffic = lambda x: verified_dict
581             tgen.terminate = mock.Mock(return_value=True)
582             tgen.name = "tgen__1"
583             vnf = mock.Mock(autospec=GenericVNF)
584             vnf.runs_traffic = False
585             vnf.instantiate.side_effect = RuntimeError(
586                 "error during instantiate")
587             vnf.terminate = mock.Mock(return_value=True)
588             self.s.vnfs = [tgen, vnf]
589             self.s.traffic_profile = mock.Mock()
590             self.s.collector = mock.Mock(autospec=Collector)
591             self.s.collector.get_kpi = \
592                 mock.Mock(return_value={tgen.name: verified_dict})
593             self.s.map_topology_to_infrastructure = mock.Mock(return_value=0)
594             self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs)
595             self.s._fill_traffic_profile = \
596                 mock.Mock(return_value=TRAFFIC_PROFILE)
597             with self.assertRaises(RuntimeError):
598                 self.s.setup()
599
600     def test__get_traffic_profile(self):
601         self.scenario_cfg["traffic_profile"] = \
602             self._get_file_abspath("ipv4_throughput_vpe.yaml")
603         self.assertIsNotNone(self.s._get_traffic_profile())
604
605     def test__get_traffic_profile_exception(self):
606         with mock.patch.dict(self.scenario_cfg, {'traffic_profile': ''}):
607             with self.assertRaises(IOError):
608                 self.s._get_traffic_profile()
609
610     def test___get_traffic_imix_exception(self):
611         with mock.patch.dict(self.scenario_cfg["traffic_options"], {'imix': ''}):
612             self.assertEqual({'imix': {'64B': 100}},
613                              self.s._get_traffic_imix())
614
615     @mock.patch.object(base.TrafficProfile, 'get')
616     @mock.patch.object(vnfdgen, 'generate_vnfd')
617     def test__fill_traffic_profile(self, mock_generate, mock_tprofile_get):
618         fake_tprofile = mock.Mock()
619         fake_vnfd = mock.Mock()
620         with mock.patch.object(self.s, '_get_traffic_profile',
621                                return_value=fake_tprofile) as mock_get_tp:
622             mock_generate.return_value = fake_vnfd
623             self.s._fill_traffic_profile()
624             mock_get_tp.assert_called_once()
625             mock_generate.assert_called_once_with(
626                 fake_tprofile,
627                 {'downlink': {},
628                  'extra_args': {'arg1': 'value1', 'arg2': 'value2'},
629                  'flow': {'flow': {}},
630                  'imix': {'imix': {'64B': 100}},
631                  'uplink': {}}
632             )
633             mock_tprofile_get.assert_called_once_with(fake_vnfd)
634
635     @mock.patch.object(utils, 'open_relative_file')
636     def test__get_topology(self, mock_open_path):
637         self.s.scenario_cfg['topology'] = 'fake_topology'
638         self.s.scenario_cfg['task_path'] = 'fake_path'
639         mock_open_path.side_effect = mock.mock_open(read_data='fake_data')
640         self.assertEqual('fake_data', self.s._get_topology())
641         mock_open_path.assert_called_once_with('fake_topology', 'fake_path')
642
643     @mock.patch.object(vnfdgen, 'generate_vnfd')
644     def test__render_topology(self, mock_generate):
645         fake_topology = 'fake_topology'
646         mock_generate.return_value = {'nsd:nsd-catalog': {'nsd': ['fake_nsd']}}
647         with mock.patch.object(self.s, '_get_topology',
648                                return_value=fake_topology) as mock_get_topology:
649             self.s._render_topology()
650             mock_get_topology.assert_called_once()
651
652         mock_generate.assert_called_once_with(
653             fake_topology,
654             {'extra_args': {'arg1': 'value1', 'arg2': 'value2'}}
655         )
656         self.assertEqual(self.s.topology, 'fake_nsd')
657
658     def test_teardown(self):
659         vnf = mock.Mock(autospec=GenericVNF)
660         vnf.terminate = mock.Mock(return_value=True)
661         vnf.name = str(vnf)
662         self.s.vnfs = [vnf]
663         self.s.traffic_profile = mock.Mock()
664         self.s.collector = mock.Mock(autospec=Collector)
665         self.s.collector.stop = \
666             mock.Mock(return_value=True)
667         self.assertIsNone(self.s.teardown())
668
669     def test_teardown_exception(self):
670         vnf = mock.Mock(autospec=GenericVNF)
671         vnf.terminate = mock.Mock(
672             side_effect=RuntimeError("error duing terminate"))
673         vnf.name = str(vnf)
674         self.s.vnfs = [vnf]
675         self.s.traffic_profile = mock.Mock()
676         self.s.collector = mock.Mock(autospec=Collector)
677         self.s.collector.stop = \
678             mock.Mock(return_value=True)
679         with self.assertRaises(RuntimeError):
680             self.s.teardown()