Merge "NSB: Improve get_url in ansible scripts"
[yardstick.git] / yardstick / tests / unit / network_services / vnf_generic / vnf / test_sample_vnf.py
1 # Copyright (c) 2017-2019 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
17 import unittest
18 import mock
19 import six
20 import time
21 import subprocess
22
23 import paramiko
24
25 from yardstick.common import exceptions as y_exceptions
26 from yardstick.common import utils
27 from yardstick.network_services.nfvi import resource
28 from yardstick.network_services.vnf_generic.vnf import base
29 from yardstick.network_services.vnf_generic.vnf import sample_vnf
30 from yardstick.network_services.vnf_generic.vnf import vnf_ssh_helper
31 from yardstick.network_services.vnf_generic.vnf.sample_vnf import ResourceHelper
32 from yardstick.network_services.vnf_generic.vnf.sample_vnf import SetupEnvHelper
33 from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF
34 from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen
35 from yardstick.tests.unit.network_services.vnf_generic.vnf import test_base
36 from yardstick.benchmark.contexts import base as ctx_base
37 from yardstick import ssh
38
39
40 class MockError(Exception):
41     pass
42
43
44 class TestVnfSshHelper(unittest.TestCase):
45
46     VNFD_0 = {
47         'short-name': 'VpeVnf',
48         'vdu': [
49             {
50                 'routing_table': [
51                     {
52                         'network': '152.16.100.20',
53                         'netmask': '255.255.255.0',
54                         'gateway': '152.16.100.20',
55                         'if': 'xe0'
56                     },
57                     {
58                         'network': '152.16.40.20',
59                         'netmask': '255.255.255.0',
60                         'gateway': '152.16.40.20',
61                         'if': 'xe1'
62                     },
63                 ],
64                 'description': 'VPE approximation using DPDK',
65                 'name': 'vpevnf-baremetal',
66                 'nd_route_tbl': [
67                     {
68                         'network': '0064:ff9b:0:0:0:0:9810:6414',
69                         'netmask': '112',
70                         'gateway': '0064:ff9b:0:0:0:0:9810:6414',
71                         'if': 'xe0'
72                     },
73                     {
74                         'network': '0064:ff9b:0:0:0:0:9810:2814',
75                         'netmask': '112',
76                         'gateway': '0064:ff9b:0:0:0:0:9810:2814',
77                         'if': 'xe1'
78                     },
79                 ],
80                 'id': 'vpevnf-baremetal',
81                 'external-interface': [
82                     {
83                         'virtual-interface': {
84                             'dst_mac': '00:00:00:00:00:03',
85                             'vpci': '0000:05:00.0',
86                             'dpdk_port_num': 0,
87                             'driver': 'i40e',
88                             'local_ip': '152.16.100.19',
89                             'type': 'PCI-PASSTHROUGH',
90                             'netmask': '255.255.255.0',
91                             'bandwidth': '10 Gbps',
92                             'dst_ip': '152.16.100.20',
93                             'local_mac': '00:00:00:00:00:01',
94                             'vld_id': 'uplink_0',
95                             'ifname': 'xe0',
96                         },
97                         'vnfd-connection-point-ref': 'xe0',
98                         'name': 'xe0'
99                     },
100                     {
101                         'virtual-interface': {
102                             'dst_mac': '00:00:00:00:00:04',
103                             'vpci': '0000:05:00.1',
104                             'dpdk_port_num': 1,
105                             'driver': 'ixgbe',
106                             'local_ip': '152.16.40.19',
107                             'type': 'PCI-PASSTHROUGH',
108                             'netmask': '255.255.255.0',
109                             'bandwidth': '10 Gbps',
110                             'dst_ip': '152.16.40.20',
111                             'local_mac': '00:00:00:00:00:02',
112                             'vld_id': 'downlink_0',
113                             'ifname': 'xe1',
114                         },
115                         'vnfd-connection-point-ref': 'xe1',
116                         'name': 'xe1'
117                     },
118                 ],
119             },
120         ],
121         'description': 'Vpe approximation using DPDK',
122         'mgmt-interface': {
123             'vdu-id': 'vpevnf-baremetal',
124             'host': '1.1.1.1',
125             'password': 'r00t',
126             'user': 'root',
127             'ip': '1.1.1.1'
128         },
129         'benchmark': {
130             'kpi': [
131                 'packets_in',
132                 'packets_fwd',
133                 'packets_dropped',
134             ],
135         },
136         'connection-point': [
137             {
138                 'type': 'VPORT',
139                 'name': 'xe0',
140             },
141             {
142                 'type': 'VPORT',
143                 'name': 'xe1',
144             },
145         ],
146         'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
147     }
148
149     VNFD = {
150         'vnfd:vnfd-catalog': {
151             'vnfd': [
152                 VNFD_0,
153             ]
154         }
155     }
156
157     def setUp(self):
158         self.ssh_helper = vnf_ssh_helper.VnfSshHelper(
159             self.VNFD_0['mgmt-interface'], 'my/bin/path')
160         self.ssh_helper._run = mock.Mock()
161
162     def assertAll(self, iterable, message=None):
163         self.assertTrue(all(iterable), message)
164
165     def test_get_class(self):
166         self.assertIs(vnf_ssh_helper.VnfSshHelper.get_class(),
167                       vnf_ssh_helper.VnfSshHelper)
168
169     @mock.patch.object(ssh, 'paramiko')
170     def test_copy(self, _):
171         self.ssh_helper.execute('ls')
172         self.assertTrue(self.ssh_helper.is_connected)
173         result = self.ssh_helper.copy()
174         self.assertIsInstance(result, vnf_ssh_helper.VnfSshHelper)
175         self.assertFalse(result.is_connected)
176         self.assertEqual(result.bin_path, self.ssh_helper.bin_path)
177         self.assertEqual(result.host, self.ssh_helper.host)
178         self.assertEqual(result.port, self.ssh_helper.port)
179         self.assertEqual(result.user, self.ssh_helper.user)
180         self.assertEqual(result.password, self.ssh_helper.password)
181         self.assertEqual(result.key_filename, self.ssh_helper.key_filename)
182
183     @mock.patch.object(paramiko, 'SSHClient')
184     def test_upload_config_file(self, mock_paramiko):
185         self.assertFalse(self.ssh_helper.is_connected)
186         cfg_file = self.ssh_helper.upload_config_file('/my/prefix', 'my content')
187         self.assertTrue(self.ssh_helper.is_connected)
188         mock_paramiko.assert_called_once()
189         self.assertEqual(cfg_file, '/my/prefix')
190
191     @mock.patch.object(paramiko, 'SSHClient')
192     def test_upload_config_file_path_does_not_exist(self, mock_paramiko):
193         self.assertFalse(self.ssh_helper.is_connected)
194         cfg_file = self.ssh_helper.upload_config_file('my/prefix', 'my content')
195         self.assertTrue(self.ssh_helper.is_connected)
196         mock_paramiko.assert_called_once()
197         self.assertTrue(cfg_file.startswith('/tmp'))
198
199     def test_join_bin_path(self):
200         expected_start = 'my'
201         expected_middle_list = ['bin']
202         expected_end = 'path'
203         result = self.ssh_helper.join_bin_path()
204         self.assertTrue(result.startswith(expected_start))
205         self.assertAll(middle in result for middle in expected_middle_list)
206         self.assertTrue(result.endswith(expected_end))
207
208         expected_middle_list.append(expected_end)
209         expected_end = 'some_file.sh'
210         result = self.ssh_helper.join_bin_path('some_file.sh')
211         self.assertTrue(result.startswith(expected_start))
212         self.assertAll(middle in result for middle in expected_middle_list)
213         self.assertTrue(result.endswith(expected_end))
214
215         expected_middle_list.append('some_dir')
216         expected_end = 'some_file.sh'
217         result = self.ssh_helper.join_bin_path('some_dir', 'some_file.sh')
218         self.assertTrue(result.startswith(expected_start))
219         self.assertAll(middle in result for middle in expected_middle_list)
220         self.assertTrue(result.endswith(expected_end))
221
222     @mock.patch.object(paramiko, 'SSHClient')
223     @mock.patch.object(ssh, 'provision_tool')
224     def test_provision_tool(self, mock_provision_tool, mock_paramiko):
225         self.assertFalse(self.ssh_helper.is_connected)
226         self.ssh_helper.provision_tool()
227         self.assertTrue(self.ssh_helper.is_connected)
228         mock_paramiko.assert_called_once()
229         mock_provision_tool.assert_called_once()
230
231         self.ssh_helper.provision_tool(tool_file='my_tool.sh')
232         self.assertTrue(self.ssh_helper.is_connected)
233         mock_paramiko.assert_called_once()
234         self.assertEqual(mock_provision_tool.call_count, 2)
235
236         self.ssh_helper.provision_tool('tool_path', 'my_tool.sh')
237         self.assertTrue(self.ssh_helper.is_connected)
238         mock_paramiko.assert_called_once()
239         self.assertEqual(mock_provision_tool.call_count, 3)
240
241
242 class TestSetupEnvHelper(unittest.TestCase):
243
244     VNFD_0 = {
245         'short-name': 'VpeVnf',
246         'vdu': [
247             {
248                 'routing_table': [
249                     {
250                         'network': '152.16.100.20',
251                         'netmask': '255.255.255.0',
252                         'gateway': '152.16.100.20',
253                         'if': 'xe0'
254                     },
255                     {
256                         'network': '152.16.40.20',
257                         'netmask': '255.255.255.0',
258                         'gateway': '152.16.40.20',
259                         'if': 'xe1'
260                     },
261                 ],
262                 'description': 'VPE approximation using DPDK',
263                 'name': 'vpevnf-baremetal',
264                 'nd_route_tbl': [
265                     {
266                         'network': '0064:ff9b:0:0:0:0:9810:6414',
267                         'netmask': '112',
268                         'gateway': '0064:ff9b:0:0:0:0:9810:6414',
269                         'if': 'xe0'
270                     },
271                     {
272                         'network': '0064:ff9b:0:0:0:0:9810:2814',
273                         'netmask': '112',
274                         'gateway': '0064:ff9b:0:0:0:0:9810:2814',
275                         'if': 'xe1'
276                     },
277                 ],
278                 'id': 'vpevnf-baremetal',
279                 'external-interface': [
280                     {
281                         'virtual-interface': {
282                             'dst_mac': '00:00:00:00:00:03',
283                             'vpci': '0000:05:00.0',
284                             'local_ip': '152.16.100.19',
285                             'type': 'PCI-PASSTHROUGH',
286                             'netmask': '255.255.255.0',
287                             'dpdk_port_num': 0,
288                             'bandwidth': '10 Gbps',
289                             'dst_ip': '152.16.100.20',
290                             'local_mac': '00:00:00:00:00:01',
291                             'vld_id': 'uplink_0',
292                             'ifname': 'xe0',
293                         },
294                         'vnfd-connection-point-ref': 'xe0',
295                         'name': 'xe0'
296                     },
297                     {
298                         'virtual-interface': {
299                             'dst_mac': '00:00:00:00:00:04',
300                             'vpci': '0000:05:00.1',
301                             'local_ip': '152.16.40.19',
302                             'type': 'PCI-PASSTHROUGH',
303                             'netmask': '255.255.255.0',
304                             'dpdk_port_num': 1,
305                             'bandwidth': '10 Gbps',
306                             'dst_ip': '152.16.40.20',
307                             'local_mac': '00:00:00:00:00:02',
308                             'vld_id': 'downlink_0',
309                             'ifname': 'xe1',
310                         },
311                         'vnfd-connection-point-ref': 'xe1',
312                         'name': 'xe1'
313                     },
314                 ],
315             },
316         ],
317         'description': 'Vpe approximation using DPDK',
318         'mgmt-interface': {
319             'vdu-id': 'vpevnf-baremetal',
320             'host': '1.1.1.1',
321             'password': 'r00t',
322             'user': 'root',
323             'ip': '1.1.1.1'
324         },
325         'benchmark': {
326             'kpi': [
327                 'packets_in',
328                 'packets_fwd',
329                 'packets_dropped',
330             ],
331         },
332         'connection-point': [
333             {
334                 'type': 'VPORT',
335                 'name': 'xe0',
336             },
337             {
338                 'type': 'VPORT',
339                 'name': 'xe1',
340             },
341         ],
342         'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
343     }
344
345     def test_build_config(self):
346         setup_env_helper = SetupEnvHelper(mock.Mock(), mock.Mock(), mock.Mock())
347
348         with self.assertRaises(NotImplementedError):
349             setup_env_helper.build_config()
350
351     def test_setup_vnf_environment(self):
352         setup_env_helper = SetupEnvHelper(mock.Mock(), mock.Mock(), mock.Mock())
353         self.assertIsNone(setup_env_helper.setup_vnf_environment())
354
355     def test_tear_down(self):
356         setup_env_helper = SetupEnvHelper(mock.Mock(), mock.Mock(), mock.Mock())
357
358         with self.assertRaises(NotImplementedError):
359             setup_env_helper.tear_down()
360
361
362 class TestDpdkVnfSetupEnvHelper(unittest.TestCase):
363
364     VNFD_0 = TestVnfSshHelper.VNFD_0
365
366     VNFD = TestVnfSshHelper.VNFD
367
368     def setUp(self):
369         self.vnfd_helper = base.VnfdHelper(deepcopy(self.VNFD_0))
370         self.scenario_helper = mock.Mock()
371         self.ssh_helper = mock.Mock()
372         self.dpdk_setup_helper = sample_vnf.DpdkVnfSetupEnvHelper(
373             self.vnfd_helper, self.ssh_helper, self.scenario_helper)
374
375     def test__update_packet_type(self):
376         ip_pipeline_cfg = 'pkt_type = ipv4'
377         pkt_type = {'pkt_type': '1'}
378
379         expected = "pkt_type = 1"
380         result = self.dpdk_setup_helper._update_packet_type(
381             ip_pipeline_cfg, pkt_type)
382         self.assertEqual(result, expected)
383
384     def test__update_packet_type_no_op(self):
385         ip_pipeline_cfg = 'pkt_type = ipv6'
386         pkt_type = {'pkt_type': '1'}
387
388         expected = "pkt_type = ipv6"
389         result = self.dpdk_setup_helper._update_packet_type(
390             ip_pipeline_cfg, pkt_type)
391         self.assertEqual(result, expected)
392
393     def test__update_packet_type_multi_op(self):
394         ip_pipeline_cfg = 'pkt_type = ipv4\npkt_type = 1\npkt_type = ipv4'
395         pkt_type = {'pkt_type': '1'}
396         expected = 'pkt_type = 1\npkt_type = 1\npkt_type = 1'
397
398         result = self.dpdk_setup_helper._update_packet_type(
399             ip_pipeline_cfg, pkt_type)
400         self.assertEqual(result, expected)
401
402     def test__update_traffic_type(self):
403         ip_pipeline_cfg = 'pkt_type = ipv4'
404         traffic_options = {
405             "vnf_type": sample_vnf.DpdkVnfSetupEnvHelper.APP_NAME,
406             "traffic_type": 4}
407         expected = "pkt_type = ipv4"
408
409         result = self.dpdk_setup_helper._update_traffic_type(
410             ip_pipeline_cfg, traffic_options)
411         self.assertEqual(result, expected)
412
413     def test__update_traffic_type_ipv6(self):
414         ip_pipeline_cfg = 'pkt_type = ipv4'
415         traffic_options = {
416             "vnf_type": sample_vnf.DpdkVnfSetupEnvHelper.APP_NAME,
417             "traffic_type": 6}
418         expected = "pkt_type = ipv6"
419
420         result = self.dpdk_setup_helper._update_traffic_type(
421             ip_pipeline_cfg, traffic_options)
422         self.assertEqual(result, expected)
423
424     def test__update_traffic_type_not_app_name(self):
425         ip_pipeline_cfg = 'traffic_type = 4'
426         vnf_type = ''.join(["Not", sample_vnf.DpdkVnfSetupEnvHelper.APP_NAME])
427         traffic_options = {"vnf_type": vnf_type, 'traffic_type': 8}
428         expected = "traffic_type = 8"
429
430         result = self.dpdk_setup_helper._update_traffic_type(
431             ip_pipeline_cfg, traffic_options)
432         self.assertEqual(result, expected)
433
434     @mock.patch.object(six.moves.builtins, 'open')
435     @mock.patch.object(utils, 'find_relative_file')
436     @mock.patch.object(sample_vnf, 'MultiPortConfig')
437     def test_build_config(self, mock_multi_port_config_class,
438                           mock_find, *args):
439         mock_multi_port_config = mock_multi_port_config_class()
440         self.scenario_helper.vnf_cfg = {}
441         self.scenario_helper.options = {}
442         self.scenario_helper.all_options = {}
443
444         self.dpdk_setup_helper.PIPELINE_COMMAND = expected = 'pipeline command'
445         result = self.dpdk_setup_helper.build_config()
446         self.assertEqual(result, expected)
447         self.assertGreaterEqual(self.ssh_helper.upload_config_file.call_count, 2)
448         mock_find.assert_called()
449         mock_multi_port_config.generate_config.assert_called()
450         mock_multi_port_config.generate_script.assert_called()
451
452     @mock.patch.object(six.moves.builtins, 'open')
453     @mock.patch.object(utils, 'find_relative_file')
454     @mock.patch.object(sample_vnf, 'MultiPortConfig')
455     @mock.patch.object(utils, 'open_relative_file')
456     def test_build_config2(self, mock_open_rf, mock_multi_port_config_class,
457                           mock_find, *args):
458         mock_multi_port_config = mock_multi_port_config_class()
459         self.scenario_helper.options = {'rules': 'fake_file'}
460         self.scenario_helper.vnf_cfg = {'file': 'fake_file'}
461         self.scenario_helper.all_options = {}
462         mock_open_rf.side_effect = mock.mock_open(read_data='fake_data')
463         self.dpdk_setup_helper.PIPELINE_COMMAND = expected = 'pipeline command'
464
465         result = self.dpdk_setup_helper.build_config()
466
467         mock_open_rf.assert_called()
468         self.assertEqual(result, expected)
469         self.assertGreaterEqual(self.ssh_helper.upload_config_file.call_count, 2)
470         mock_find.assert_called()
471         mock_multi_port_config.generate_config.assert_called()
472         mock_multi_port_config.generate_script.assert_called()
473
474     def test__build_pipeline_kwargs(self):
475         self.ssh_helper.provision_tool.return_value = 'tool_path'
476         self.dpdk_setup_helper.CFG_CONFIG = 'config'
477         self.dpdk_setup_helper.CFG_SCRIPT = 'script'
478         self.dpdk_setup_helper.pipeline_kwargs = {}
479         self.dpdk_setup_helper.all_ports = [0, 1, 2]
480         self.dpdk_setup_helper.scenario_helper.vnf_cfg = {'lb_config': 'HW',
481                                                           'worker_threads': 1}
482
483         expected = {
484             'cfg_file': 'config',
485             'script': 'script',
486             'port_mask_hex': '0x3',
487             'tool_path': 'tool_path',
488             'hwlb': ' --hwlb 1',
489         }
490         self.dpdk_setup_helper._build_pipeline_kwargs()
491         self.assertDictEqual(self.dpdk_setup_helper.pipeline_kwargs, expected)
492
493     @mock.patch.object(time, 'sleep')
494     @mock.patch.object(ssh, 'SSH')
495     def test_setup_vnf_environment(self, *args):
496         self.scenario_helper.nodes = [None, None]
497
498         def execute(cmd):
499             if cmd.startswith('which '):
500                 return exec_failure
501             return exec_success
502
503         exec_success = (0, 'good output', '')
504         exec_failure = (1, 'bad output', 'error output')
505         self.ssh_helper.execute = execute
506
507         self.dpdk_setup_helper._validate_cpu_cfg = mock.Mock(return_value=[])
508
509         with mock.patch.object(self.dpdk_setup_helper, '_setup_dpdk'):
510             self.assertIsInstance(
511                 self.dpdk_setup_helper.setup_vnf_environment(),
512                 resource.ResourceProfile)
513
514     @mock.patch.object(utils, 'setup_hugepages')
515     def test__setup_dpdk(self, mock_setup_hugepages):
516         self.ssh_helper.execute = mock.Mock()
517         self.ssh_helper.execute.return_value = (0, 0, 0)
518         self.scenario_helper.all_options = {'hugepages_gb': 8}
519         self.dpdk_setup_helper._setup_dpdk()
520         mock_setup_hugepages.assert_called_once_with(
521             self.ssh_helper, 8*1024*1024)
522         self.ssh_helper.execute.assert_has_calls([
523             mock.call('sudo modprobe uio && sudo modprobe igb_uio'),
524             mock.call('lsmod | grep -i igb_uio')
525         ])
526
527     @mock.patch.object(ssh, 'SSH')
528     def test__setup_resources(self, _):
529         self.dpdk_setup_helper._validate_cpu_cfg = mock.Mock()
530         self.dpdk_setup_helper.bound_pci = [v['virtual-interface']["vpci"] for v in
531                                             self.vnfd_helper.interfaces]
532         result = self.dpdk_setup_helper._setup_resources()
533         self.assertIsInstance(result, resource.ResourceProfile)
534         self.assertEqual(self.dpdk_setup_helper.socket, 0)
535
536     @mock.patch.object(ssh, 'SSH')
537     def test__setup_resources_socket_1(self, _):
538         self.vnfd_helper.interfaces[0]['virtual-interface']['vpci'] = \
539             '0000:55:00.0'
540         self.vnfd_helper.interfaces[1]['virtual-interface']['vpci'] = \
541             '0000:35:00.0'
542
543         self.dpdk_setup_helper._validate_cpu_cfg = mock.Mock()
544         self.dpdk_setup_helper.bound_pci = [v['virtual-interface']["vpci"] for v in
545                                             self.vnfd_helper.interfaces]
546         result = self.dpdk_setup_helper._setup_resources()
547         self.assertIsInstance(result, resource.ResourceProfile)
548         self.assertEqual(self.dpdk_setup_helper.socket, 1)
549
550     @mock.patch.object(time, 'sleep')
551     def test__detect_and_bind_drivers(self, *args):
552         self.scenario_helper.nodes = [None, None]
553         rv = ['0000:05:00.1', '0000:05:00.0']
554
555         self.dpdk_setup_helper.dpdk_bind_helper._get_bound_pci_addresses = \
556             mock.Mock(return_value=rv)
557         self.dpdk_setup_helper.dpdk_bind_helper.bind = mock.Mock()
558         self.dpdk_setup_helper.dpdk_bind_helper.read_status = mock.Mock()
559
560         self.assertIsNone(self.dpdk_setup_helper._detect_and_bind_drivers())
561
562         intf_0 = self.vnfd_helper.vdu[0]['external-interface'][0]['virtual-interface']
563         intf_1 = self.vnfd_helper.vdu[0]['external-interface'][1]['virtual-interface']
564         self.assertEqual(0, intf_0['dpdk_port_num'])
565         self.assertEqual(1, intf_1['dpdk_port_num'])
566
567     def test_tear_down(self):
568         self.scenario_helper.nodes = [None, None]
569
570         self.dpdk_setup_helper.dpdk_bind_helper.bind = mock.Mock()
571         self.dpdk_setup_helper.dpdk_bind_helper.used_drivers = {
572             'd1': ['0000:05:00.0'],
573             'd3': ['0000:05:01.0'],
574         }
575
576         self.assertIsNone(self.dpdk_setup_helper.tear_down())
577         self.dpdk_setup_helper.dpdk_bind_helper.bind.assert_any_call(
578             ['0000:05:00.0'], 'd1', True)
579         self.dpdk_setup_helper.dpdk_bind_helper.bind.assert_any_call(
580             ['0000:05:01.0'], 'd3', True)
581
582
583 class TestResourceHelper(unittest.TestCase):
584
585     VNFD_0 = {
586         'short-name': 'VpeVnf',
587         'vdu': [
588             {
589                 'routing_table': [
590                     {
591                         'network': '152.16.100.20',
592                         'netmask': '255.255.255.0',
593                         'gateway': '152.16.100.20',
594                         'if': 'xe0'
595                     },
596                     {
597                         'network': '152.16.40.20',
598                         'netmask': '255.255.255.0',
599                         'gateway': '152.16.40.20',
600                         'if': 'xe1'
601                     },
602                 ],
603                 'description': 'VPE approximation using DPDK',
604                 'name': 'vpevnf-baremetal',
605                 'nd_route_tbl': [
606                     {
607                         'network': '0064:ff9b:0:0:0:0:9810:6414',
608                         'netmask': '112',
609                         'gateway': '0064:ff9b:0:0:0:0:9810:6414',
610                         'if': 'xe0'
611                     },
612                     {
613                         'network': '0064:ff9b:0:0:0:0:9810:2814',
614                         'netmask': '112',
615                         'gateway': '0064:ff9b:0:0:0:0:9810:2814',
616                         'if': 'xe1'
617                     },
618                 ],
619                 'id': 'vpevnf-baremetal',
620                 'external-interface': [
621                     {
622                         'virtual-interface': {
623                             'dst_mac': '00:00:00:00:00:03',
624                             'vpci': '0000:05:00.0',
625                             'driver': 'i40e',
626                             'local_ip': '152.16.100.19',
627                             'type': 'PCI-PASSTHROUGH',
628                             'netmask': '255.255.255.0',
629                             'dpdk_port_num': 0,
630                             'bandwidth': '10 Gbps',
631                             'dst_ip': '152.16.100.20',
632                             'local_mac': '00:00:00:00:00:01'
633                         },
634                         'vnfd-connection-point-ref': 'xe0',
635                         'name': 'xe0'
636                     },
637                     {
638                         'virtual-interface': {
639                             'dst_mac': '00:00:00:00:00:04',
640                             'vpci': '0000:05:00.1',
641                             'driver': 'ixgbe',
642                             'local_ip': '152.16.40.19',
643                             'type': 'PCI-PASSTHROUGH',
644                             'netmask': '255.255.255.0',
645                             'dpdk_port_num': 1,
646                             'bandwidth': '10 Gbps',
647                             'dst_ip': '152.16.40.20',
648                             'local_mac': '00:00:00:00:00:02'
649                         },
650                         'vnfd-connection-point-ref': 'xe1',
651                         'name': 'xe1'
652                     },
653                 ],
654             },
655         ],
656         'description': 'Vpe approximation using DPDK',
657         'mgmt-interface': {
658             'vdu-id': 'vpevnf-baremetal',
659             'host': '1.1.1.1',
660             'password': 'r00t',
661             'user': 'root',
662             'ip': '1.1.1.1'
663         },
664         'benchmark': {
665             'kpi': [
666                 'packets_in',
667                 'packets_fwd',
668                 'packets_dropped',
669             ],
670         },
671         'connection-point': [
672             {
673                 'type': 'VPORT',
674                 'name': 'xe0',
675             },
676             {
677                 'type': 'VPORT',
678                 'name': 'xe1',
679             },
680         ],
681         'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
682     }
683
684     def setUp(self):
685         self.vnfd_helper = base.VnfdHelper(self.VNFD_0)
686         self.dpdk_setup_helper = sample_vnf.DpdkVnfSetupEnvHelper(
687             self.vnfd_helper, mock.Mock(), mock.Mock())
688         self.resource_helper = sample_vnf.ResourceHelper(self.dpdk_setup_helper)
689
690     def test_setup(self):
691         resource = object()
692         self.dpdk_setup_helper.setup_vnf_environment = (
693             mock.Mock(return_value=resource))
694         resource_helper = sample_vnf.ResourceHelper(self.dpdk_setup_helper)
695
696         self.assertIsNone(resource_helper.setup())
697         self.assertIs(resource_helper.resource, resource)
698
699     def test_generate_cfg(self):
700         self.assertIsNone(self.resource_helper.generate_cfg())
701
702     def test_stop_collect(self):
703         self.resource_helper.resource = mock.Mock()
704
705         self.assertIsNone(self.resource_helper.stop_collect())
706
707     def test_stop_collect_none(self):
708         self.resource_helper.resource = None
709
710         self.assertIsNone(self.resource_helper.stop_collect())
711
712
713 class TestClientResourceHelper(unittest.TestCase):
714
715     VNFD_0 = {
716         'short-name': 'VpeVnf',
717         'vdu': [
718             {
719                 'routing_table': [
720                     {
721                         'network': '152.16.100.20',
722                         'netmask': '255.255.255.0',
723                         'gateway': '152.16.100.20',
724                         'if': 'xe0'
725                     },
726                     {
727                         'network': '152.16.40.20',
728                         'netmask': '255.255.255.0',
729                         'gateway': '152.16.40.20',
730                         'if': 'xe1'
731                     },
732                 ],
733                 'description': 'VPE approximation using DPDK',
734                 'name': 'vpevnf-baremetal',
735                 'nd_route_tbl': [
736                     {
737                         'network': '0064:ff9b:0:0:0:0:9810:6414',
738                         'netmask': '112',
739                         'gateway': '0064:ff9b:0:0:0:0:9810:6414',
740                         'if': 'xe0'
741                     },
742                     {
743                         'network': '0064:ff9b:0:0:0:0:9810:2814',
744                         'netmask': '112',
745                         'gateway': '0064:ff9b:0:0:0:0:9810:2814',
746                         'if': 'xe1'
747                     },
748                 ],
749                 'id': 'vpevnf-baremetal',
750                 'external-interface': [
751                     {
752                         'virtual-interface': {
753                             'dst_mac': '00:00:00:00:00:03',
754                             'vpci': '0000:05:00.0',
755                             'driver': 'i40e',
756                             'local_ip': '152.16.100.19',
757                             'type': 'PCI-PASSTHROUGH',
758                             'netmask': '255.255.255.0',
759                             'dpdk_port_num': 0,
760                             'bandwidth': '10 Gbps',
761                             'dst_ip': '152.16.100.20',
762                             'local_mac': '00:00:00:00:00:01',
763                             'vld_id': 'uplink_0',
764                             'ifname': 'xe0',
765                         },
766                         'vnfd-connection-point-ref': 'xe0',
767                         'name': 'xe0'
768                     },
769                     {
770                         'virtual-interface': {
771                             'dst_mac': '00:00:00:00:00:04',
772                             'vpci': '0000:05:00.1',
773                             'driver': 'ixgbe',
774                             'local_ip': '152.16.40.19',
775                             'type': 'PCI-PASSTHROUGH',
776                             'netmask': '255.255.255.0',
777                             'dpdk_port_num': 1,
778                             'bandwidth': '10 Gbps',
779                             'dst_ip': '152.16.40.20',
780                             'local_mac': '00:00:00:00:00:02',
781                             'vld_id': 'downlink_0',
782                             'ifname': 'xe1',
783                         },
784                         'vnfd-connection-point-ref': 'xe1',
785                         'name': 'xe1'
786                     },
787                     {
788                         'virtual-interface': {
789                             'dst_mac': '00:00:00:00:00:13',
790                             'vpci': '0000:05:00.2',
791                             'driver': 'ixgbe',
792                             'local_ip': '152.16.40.19',
793                             'type': 'PCI-PASSTHROUGH',
794                             'netmask': '255.255.255.0',
795                             'dpdk_port_num': 2,
796                             'bandwidth': '10 Gbps',
797                             'dst_ip': '152.16.40.30',
798                             'local_mac': '00:00:00:00:00:11'
799                         },
800                         'vnfd-connection-point-ref': 'xe2',
801                         'name': 'xe2'
802                     },
803                 ],
804             },
805         ],
806         'description': 'Vpe approximation using DPDK',
807         'mgmt-interface': {
808             'vdu-id': 'vpevnf-baremetal',
809             'host': '1.1.1.1',
810             'password': 'r00t',
811             'user': 'root',
812             'ip': '1.1.1.1'
813         },
814         'benchmark': {
815             'kpi': [
816                 'packets_in',
817                 'packets_fwd',
818                 'packets_dropped',
819             ],
820         },
821         'connection-point': [
822             {
823                 'type': 'VPORT',
824                 'name': 'xe0',
825             },
826             {
827                 'type': 'VPORT',
828                 'name': 'xe1',
829             },
830         ],
831         'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
832     }
833
834     VNFD = {
835         'vnfd:vnfd-catalog': {
836             'vnfd': [
837                 VNFD_0,
838             ],
839         },
840     }
841
842     def setUp(self):
843         vnfd_helper = base.VnfdHelper(self.VNFD_0)
844         ssh_helper = mock.Mock()
845         scenario_helper = mock.Mock()
846         dpdk_setup_helper = sample_vnf.DpdkVnfSetupEnvHelper(
847             vnfd_helper, ssh_helper, scenario_helper)
848         self.client_resource_helper = (
849             sample_vnf.ClientResourceHelper(dpdk_setup_helper))
850
851     @mock.patch.object(sample_vnf, 'LOG')
852     @mock.patch.object(sample_vnf, 'STLError', new_callable=lambda: MockError)
853     def test_get_stats_not_connected(self, mock_stl_error, *args):
854         self.client_resource_helper.client = mock.Mock()
855         self.client_resource_helper.client.get_stats.side_effect = \
856             mock_stl_error
857
858         self.assertEqual(self.client_resource_helper.get_stats(), {})
859         self.client_resource_helper.client.get_stats.assert_called_once()
860
861     def test_clear_stats(self):
862         self.client_resource_helper.client = mock.Mock()
863
864         self.assertIsNone(self.client_resource_helper.clear_stats())
865         self.assertEqual(
866             self.client_resource_helper.client.clear_stats.call_count, 1)
867
868     def test_clear_stats_of_ports(self):
869         self.client_resource_helper.client = mock.Mock()
870
871         self.assertIsNone(self.client_resource_helper.clear_stats([3, 4]))
872         self.client_resource_helper.client.clear_stats.assert_called_once()
873
874     def test_start(self):
875         self.client_resource_helper.client = mock.Mock()
876
877         self.assertIsNone(self.client_resource_helper.start())
878         self.client_resource_helper.client.start.assert_called_once()
879
880     def test_start_ports(self):
881         self.client_resource_helper.client = mock.Mock()
882
883         self.assertIsNone(self.client_resource_helper.start([3, 4]))
884         self.client_resource_helper.client.start.assert_called_once()
885
886     def test_collect_kpi_with_queue(self):
887         self.client_resource_helper._result = {
888             'existing': 43,
889             'replaceable': 12}
890         self.client_resource_helper._queue = mock.Mock()
891         self.client_resource_helper._queue.empty.return_value = False
892         self.client_resource_helper._queue.get.return_value = {
893             'incoming': 34,
894             'replaceable': 99}
895
896         expected = {
897             'existing': 43,
898             'incoming': 34,
899             'replaceable': 99,
900         }
901         result = self.client_resource_helper.collect_kpi()
902         self.assertEqual(result, expected)
903
904     @mock.patch.object(time, 'sleep')
905     @mock.patch.object(sample_vnf, 'STLError')
906     def test__connect_with_failures(self, mock_stl_error, *args):
907         client = mock.MagicMock()
908         client.connect.side_effect = mock_stl_error(msg='msg')
909
910         self.assertIs(self.client_resource_helper._connect(client), client)
911
912
913 class TestRfc2544ResourceHelper(unittest.TestCase):
914
915     RFC2544_CFG_1 = {
916         'latency': True,
917         'correlated_traffic': True,
918         'allowed_drop_rate': '0.1 - 0.15',
919     }
920
921     RFC2544_CFG_2 = {
922         'allowed_drop_rate': '  0.25    -   0.05  ',
923     }
924
925     RFC2544_CFG_3 = {
926         'allowed_drop_rate': '0.2',
927     }
928
929     RFC2544_CFG_4 = {
930         'latency': True,
931     }
932
933     SCENARIO_CFG_1 = {
934         'options': {
935             'rfc2544': RFC2544_CFG_1,
936         }
937     }
938
939     SCENARIO_CFG_2 = {
940         'options': {
941             'rfc2544': RFC2544_CFG_2,
942         }
943     }
944
945     SCENARIO_CFG_3 = {
946         'options': {
947             'rfc2544': RFC2544_CFG_3,
948         }
949     }
950
951     SCENARIO_CFG_4 = {
952         'options': {
953             'rfc2544': RFC2544_CFG_4,
954         }
955     }
956
957     def setUp(self):
958         self.scenario_helper = sample_vnf.ScenarioHelper('name1')
959         self.rfc2544_resource_helper = \
960             sample_vnf.Rfc2544ResourceHelper(self.scenario_helper)
961
962     def test_property_rfc2544(self):
963         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
964
965         self.assertIsNone(self.rfc2544_resource_helper._rfc2544)
966         self.assertEqual(self.rfc2544_resource_helper.rfc2544,
967                          self.RFC2544_CFG_1)
968         self.assertEqual(self.rfc2544_resource_helper._rfc2544,
969                          self.RFC2544_CFG_1)
970         # ensure that resource_helper caches
971         self.scenario_helper.scenario_cfg = {}
972         self.assertEqual(self.rfc2544_resource_helper.rfc2544,
973                          self.RFC2544_CFG_1)
974
975     def test_property_tolerance_high(self):
976         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
977
978         self.assertIsNone(self.rfc2544_resource_helper._tolerance_high)
979         self.assertEqual(self.rfc2544_resource_helper.tolerance_high, 0.15)
980         self.assertEqual(self.rfc2544_resource_helper._tolerance_high, 0.15)
981         self.assertEqual(self.rfc2544_resource_helper._tolerance_precision, 2)
982         # ensure that resource_helper caches
983         self.scenario_helper.scenario_cfg = {}
984         self.assertEqual(self.rfc2544_resource_helper.tolerance_high, 0.15)
985
986     def test_property_tolerance_low(self):
987         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
988
989         self.assertIsNone(self.rfc2544_resource_helper._tolerance_low)
990         self.assertEqual(self.rfc2544_resource_helper.tolerance_low, 0.1)
991         self.assertEqual(self.rfc2544_resource_helper._tolerance_low, 0.1)
992         # ensure that resource_helper caches
993         self.scenario_helper.scenario_cfg = {}
994         self.assertEqual(self.rfc2544_resource_helper.tolerance_low, 0.1)
995
996     def test_property_tolerance_high_range_swap(self):
997         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_2
998
999         self.assertEqual(self.rfc2544_resource_helper.tolerance_high, 0.25)
1000
1001     def test_property_tolerance_low_range_swap(self):
1002         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_2
1003
1004         self.assertEqual(self.rfc2544_resource_helper.tolerance_low, 0.05)
1005
1006     def test_property_tolerance_high_not_range(self):
1007         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_3
1008
1009         self.assertEqual(self.rfc2544_resource_helper.tolerance_high, 0.2)
1010         self.assertEqual(self.rfc2544_resource_helper._tolerance_precision, 1)
1011
1012     def test_property_tolerance_low_not_range(self):
1013         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_3
1014
1015         self.assertEqual(self.rfc2544_resource_helper.tolerance_low, 0.2)
1016
1017     def test_property_tolerance_high_default(self):
1018         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_4
1019
1020         self.assertEqual(self.rfc2544_resource_helper.tolerance_high, 0.0001)
1021
1022     def test_property_tolerance_low_default(self):
1023         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_4
1024
1025         self.assertEqual(self.rfc2544_resource_helper.tolerance_low, 0.0001)
1026
1027     def test_property_latency(self):
1028         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
1029
1030         self.assertIsNone(self.rfc2544_resource_helper._latency)
1031         self.assertTrue(self.rfc2544_resource_helper.latency)
1032         self.assertTrue(self.rfc2544_resource_helper._latency)
1033         # ensure that resource_helper caches
1034         self.scenario_helper.scenario_cfg = {}
1035         self.assertTrue(self.rfc2544_resource_helper.latency)
1036
1037     def test_property_latency_default(self):
1038         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_2
1039
1040         self.assertFalse(self.rfc2544_resource_helper.latency)
1041
1042     def test_property_correlated_traffic(self):
1043         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
1044
1045         self.assertIsNone(self.rfc2544_resource_helper._correlated_traffic)
1046         self.assertTrue(self.rfc2544_resource_helper.correlated_traffic)
1047         self.assertTrue(self.rfc2544_resource_helper._correlated_traffic)
1048         # ensure that resource_helper caches
1049         self.scenario_helper.scenario_cfg = {}
1050         self.assertTrue(self.rfc2544_resource_helper.correlated_traffic)
1051
1052     def test_property_correlated_traffic_default(self):
1053         self.scenario_helper.scenario_cfg = self.SCENARIO_CFG_2
1054
1055         self.assertFalse(self.rfc2544_resource_helper.correlated_traffic)
1056
1057
1058 class TestSampleVNFDeployHelper(unittest.TestCase):
1059
1060     def setUp(self):
1061         self._mock_time_sleep = mock.patch.object(time, 'sleep')
1062         self.mock_time_sleep = self._mock_time_sleep.start()
1063         self._mock_check_output = mock.patch.object(subprocess, 'check_output')
1064         self.mock_check_output = self._mock_check_output.start()
1065         self.addCleanup(self._stop_mocks)
1066
1067         self.ssh_helper = mock.Mock()
1068         self.sample_vnf_deploy_helper = sample_vnf.SampleVNFDeployHelper(
1069             mock.Mock(), self.ssh_helper)
1070         self.ssh_helper.join_bin_path.return_value = 'joined_path'
1071         self.ssh_helper.put.return_value = None
1072
1073     def _stop_mocks(self):
1074         self._mock_time_sleep.stop()
1075         self._mock_check_output.stop()
1076
1077     def test_deploy_vnfs_disabled(self):
1078         self.ssh_helper.execute.return_value = 1, 'bad output', 'error output'
1079
1080         self.sample_vnf_deploy_helper.deploy_vnfs('name1')
1081         self.sample_vnf_deploy_helper.DISABLE_DEPLOY = True
1082         self.assertEqual(self.ssh_helper.execute.call_count, 5)
1083         self.ssh_helper.put.assert_called_once()
1084
1085     def test_deploy_vnfs(self):
1086         self.ssh_helper.execute.return_value = 1, 'bad output', 'error output'
1087         self.sample_vnf_deploy_helper.DISABLE_DEPLOY = False
1088
1089         self.sample_vnf_deploy_helper.deploy_vnfs('name1')
1090         self.assertEqual(self.ssh_helper.execute.call_count, 5)
1091         self.ssh_helper.put.assert_called_once()
1092
1093     def test_deploy_vnfs_early_success(self):
1094         self.ssh_helper.execute.return_value = 0, 'output', ''
1095         self.sample_vnf_deploy_helper.DISABLE_DEPLOY = False
1096
1097         self.sample_vnf_deploy_helper.deploy_vnfs('name1')
1098         self.ssh_helper.execute.assert_called_once()
1099         self.ssh_helper.put.assert_not_called()
1100
1101
1102 class TestScenarioHelper(unittest.TestCase):
1103
1104     def setUp(self):
1105         self.scenario_helper = sample_vnf.ScenarioHelper('name1')
1106
1107     def test_property_task_path(self):
1108         self.scenario_helper.scenario_cfg = {
1109             'task_path': 'my_path',
1110         }
1111
1112         self.assertEqual(self.scenario_helper.task_path, 'my_path')
1113
1114     def test_property_nodes(self):
1115         nodes = ['node1', 'node2']
1116         self.scenario_helper.scenario_cfg = {
1117             'nodes': nodes,
1118         }
1119
1120         self.assertEqual(self.scenario_helper.nodes, nodes)
1121
1122     def test_property_all_options(self):
1123         data = {
1124             'name1': {
1125                 'key3': 'value3',
1126             },
1127             'name2': {}
1128         }
1129         self.scenario_helper.scenario_cfg = {
1130             'options': data,
1131         }
1132
1133         self.assertDictEqual(self.scenario_helper.all_options, data)
1134
1135     def test_property_options(self):
1136         data = {
1137             'key1': 'value1',
1138             'key2': 'value2',
1139         }
1140         self.scenario_helper.scenario_cfg = {
1141             'options': {
1142                 'name1': data,
1143             },
1144         }
1145
1146         self.assertDictEqual(self.scenario_helper.options, data)
1147
1148     def test_property_vnf_cfg(self):
1149         self.scenario_helper.scenario_cfg = {
1150             'options': {
1151                 'name1': {
1152                     'vnf_config': 'my_config',
1153                 },
1154             },
1155         }
1156
1157         self.assertEqual(self.scenario_helper.vnf_cfg, 'my_config')
1158
1159     def test_property_vnf_cfg_default(self):
1160         self.scenario_helper.scenario_cfg = {
1161             'options': {
1162                 'name1': {},
1163             },
1164         }
1165
1166         self.assertEqual(self.scenario_helper.vnf_cfg,
1167                          sample_vnf.ScenarioHelper.DEFAULT_VNF_CFG)
1168
1169     def test_property_topology(self):
1170         self.scenario_helper.scenario_cfg = {
1171             'topology': 'my_topology',
1172         }
1173
1174         self.assertEqual(self.scenario_helper.topology, 'my_topology')
1175
1176
1177 class TestSampleVnf(unittest.TestCase):
1178
1179     VNFD_0 = {
1180         'short-name': 'VpeVnf',
1181         'vdu': [
1182             {
1183                 'routing_table': [
1184                     {
1185                         'network': '152.16.100.20',
1186                         'netmask': '255.255.255.0',
1187                         'gateway': '152.16.100.20',
1188                         'if': 'xe0'
1189                     },
1190                     {
1191                         'network': '152.16.40.20',
1192                         'netmask': '255.255.255.0',
1193                         'gateway': '152.16.40.20',
1194                         'if': 'xe1'
1195                     },
1196                 ],
1197                 'description': 'VPE approximation using DPDK',
1198                 'name': 'vpevnf-baremetal',
1199                 'nd_route_tbl': [
1200                     {
1201                         'network': '0064:ff9b:0:0:0:0:9810:6414',
1202                         'netmask': '112',
1203                         'gateway': '0064:ff9b:0:0:0:0:9810:6414',
1204                         'if': 'xe0'
1205                     },
1206                     {
1207                         'network': '0064:ff9b:0:0:0:0:9810:2814',
1208                         'netmask': '112',
1209                         'gateway': '0064:ff9b:0:0:0:0:9810:2814',
1210                         'if': 'xe1'
1211                     },
1212                 ],
1213                 'id': 'vpevnf-baremetal',
1214                 'external-interface': [
1215                     {
1216                         'virtual-interface': {
1217                             'dst_mac': '00:00:00:00:00:03',
1218                             'vpci': '0000:05:00.0',
1219                             'local_ip': '152.16.100.19',
1220                             'type': 'PCI-PASSTHROUGH',
1221                             'netmask': '255.255.255.0',
1222                             'dpdk_port_num': 0,
1223                             'bandwidth': '10 Gbps',
1224                             'dst_ip': '152.16.100.20',
1225                             'local_mac': '00:00:00:00:00:01'
1226                         },
1227                         'vnfd-connection-point-ref': 'xe0',
1228                         'name': 'xe0'
1229                     },
1230                     {
1231                         'virtual-interface': {
1232                             'dst_mac': '00:00:00:00:00:04',
1233                             'vpci': '0000:05:00.1',
1234                             'local_ip': '152.16.40.19',
1235                             'type': 'PCI-PASSTHROUGH',
1236                             'netmask': '255.255.255.0',
1237                             'dpdk_port_num': 1,
1238                             'bandwidth': '10 Gbps',
1239                             'dst_ip': '152.16.40.20',
1240                             'local_mac': '00:00:00:00:00:02'
1241                         },
1242                         'vnfd-connection-point-ref': 'xe1',
1243                         'name': 'xe1'
1244                     },
1245                 ],
1246             },
1247         ],
1248         'description': 'Vpe approximation using DPDK',
1249         'mgmt-interface': {
1250             'vdu-id': 'vpevnf-baremetal',
1251             'host': '1.1.1.1',
1252             'password': 'r00t',
1253             'user': 'root',
1254             'ip': '1.1.1.1'
1255         },
1256         'benchmark': {
1257             'kpi': [
1258                 'packets_in',
1259                 'packets_fwd',
1260                 'packets_dropped',
1261             ],
1262         },
1263         'connection-point': [
1264             {
1265                 'type': 'VPORT',
1266                 'name': 'xe0',
1267             },
1268             {
1269                 'type': 'VPORT',
1270                 'name': 'xe1',
1271             },
1272         ],
1273         'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
1274     }
1275
1276     VNFD = {
1277         'vnfd:vnfd-catalog': {
1278             'vnfd': [
1279                 VNFD_0,
1280             ]
1281         }
1282     }
1283
1284     TRAFFIC_PROFILE = {
1285         "schema": "isb:traffic_profile:0.1",
1286         "name": "fixed",
1287         "description": "Fixed traffic profile to run UDP traffic",
1288         "traffic_profile": {
1289             "traffic_type": "FixedTraffic",
1290             "frame_rate": 100,  # pps
1291             "flow_number": 10,
1292             "frame_size": 64,
1293         },
1294     }
1295
1296     def test___init__(self):
1297         sample_vnf = SampleVNF('vnf1', self.VNFD_0)
1298
1299         self.assertEqual(sample_vnf.name, 'vnf1')
1300         self.assertDictEqual(sample_vnf.vnfd_helper, self.VNFD_0)
1301
1302         # test the default setup helper is SetupEnvHelper, not subclass
1303         self.assertEqual(type(sample_vnf.setup_helper), SetupEnvHelper)
1304
1305         # test the default resource helper is ResourceHelper, not subclass
1306         self.assertEqual(type(sample_vnf.resource_helper), ResourceHelper)
1307
1308     def test___init___alt_types(self):
1309         class MySetupEnvHelper(SetupEnvHelper):
1310             pass
1311
1312         class MyResourceHelper(ResourceHelper):
1313             pass
1314
1315         sample_vnf = SampleVNF('vnf1', self.VNFD_0, MySetupEnvHelper, MyResourceHelper)
1316
1317         self.assertEqual(sample_vnf.name, 'vnf1')
1318         self.assertDictEqual(sample_vnf.vnfd_helper, self.VNFD_0)
1319
1320         # test the default setup helper is MySetupEnvHelper, not subclass
1321         self.assertEqual(type(sample_vnf.setup_helper), MySetupEnvHelper)
1322
1323         # test the default resource helper is MyResourceHelper, not subclass
1324         self.assertEqual(type(sample_vnf.resource_helper), MyResourceHelper)
1325
1326     @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.Process')
1327     def test__start_vnf(self, *args):
1328         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1329         sample_vnf = SampleVNF('vnf1', vnfd)
1330         sample_vnf._run = mock.Mock()
1331
1332         self.assertIsNone(sample_vnf.queue_wrapper)
1333         self.assertIsNone(sample_vnf._vnf_process)
1334         self.assertIsNone(sample_vnf._start_vnf())
1335         self.assertIsNotNone(sample_vnf.queue_wrapper)
1336         self.assertIsNotNone(sample_vnf._vnf_process)
1337
1338     @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
1339     @mock.patch("yardstick.ssh.SSH")
1340     def test_instantiate(self, ssh, *args):
1341         test_base.mock_ssh(ssh)
1342         nodes = {
1343             'vnf1': 'name1',
1344             'vnf2': 'name2',
1345         }
1346
1347         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1348         sample_vnf = SampleVNF('vnf1', vnfd)
1349         sample_vnf.scenario_helper.scenario_cfg = {
1350             'nodes': {sample_vnf.name: 'mock'}
1351         }
1352         sample_vnf.APP_NAME = 'sample1'
1353         sample_vnf._start_server = mock.Mock(return_value=0)
1354         sample_vnf._vnf_process = mock.MagicMock()
1355         sample_vnf._vnf_process._is_alive.return_value = 1
1356         sample_vnf.ssh_helper = mock.MagicMock()
1357         sample_vnf.deploy_helper = mock.MagicMock()
1358         sample_vnf.resource_helper.ssh_helper = mock.MagicMock()
1359         scenario_cfg = {
1360             'nodes': nodes,
1361         }
1362
1363         self.assertIsNone(sample_vnf.instantiate(scenario_cfg, {}))
1364
1365     def test__update_collectd_options(self):
1366         scenario_cfg = {'options':
1367                             {'collectd':
1368                                  {'interval': 3,
1369                                   'plugins':
1370                                       {'plugin3': {'param': 3}}},
1371                              'vnf__0':
1372                                  {'collectd':
1373                                       {'interval': 2,
1374                                        'plugins':
1375                                            {'plugin3': {'param': 2},
1376                                             'plugin2': {'param': 2}}}}}}
1377         context_cfg = {'nodes':
1378                            {'vnf__0':
1379                                 {'collectd':
1380                                      {'interval': 1,
1381                                       'plugins':
1382                                           {'plugin3': {'param': 1},
1383                                            'plugin2': {'param': 1},
1384                                            'plugin1': {'param': 1}}}}}}
1385         expected = {'interval': 1,
1386                     'plugins':
1387                         {'plugin3': {'param': 1},
1388                          'plugin2': {'param': 1},
1389                          'plugin1': {'param': 1}}}
1390
1391         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1392         sample_vnf = SampleVNF('vnf__0', vnfd)
1393         sample_vnf._update_collectd_options(scenario_cfg, context_cfg)
1394         self.assertEqual(sample_vnf.setup_helper.collectd_options, expected)
1395
1396     def test__update_options(self):
1397         options1 = {'interval': 1,
1398                     'param1': 'value1',
1399                     'plugins':
1400                         {'plugin3': {'param': 3},
1401                          'plugin2': {'param': 1},
1402                          'plugin1': {'param': 1}}}
1403         options2 = {'interval': 2,
1404                     'param2': 'value2',
1405                     'plugins':
1406                         {'plugin4': {'param': 4},
1407                          'plugin2': {'param': 2},
1408                          'plugin1': {'param': 2}}}
1409         expected = {'interval': 1,
1410                     'param1': 'value1',
1411                     'param2': 'value2',
1412                     'plugins':
1413                         {'plugin4': {'param': 4},
1414                          'plugin3': {'param': 3},
1415                          'plugin2': {'param': 1},
1416                          'plugin1': {'param': 1}}}
1417
1418         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1419         sample_vnf = SampleVNF('vnf1', vnfd)
1420         sample_vnf._update_options(options2, options1)
1421         self.assertEqual(options2, expected)
1422
1423     @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
1424     @mock.patch("yardstick.ssh.SSH")
1425     def test_wait_for_instantiate_empty_queue(self, ssh, *args):
1426         test_base.mock_ssh(ssh, exec_result=(1, "", ""))
1427
1428         queue_size_list = [
1429             0,
1430             1,
1431             0,
1432             1,
1433         ]
1434
1435         queue_get_list = [
1436             'some output',
1437             'pipeline> ',
1438         ]
1439
1440         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1441         sample_vnf = SampleVNF('vnf1', vnfd)
1442         sample_vnf.APP_NAME = 'sample1'
1443         sample_vnf.WAIT_TIME_FOR_SCRIPT = 0
1444         sample_vnf._start_server = mock.Mock(return_value=0)
1445         sample_vnf._vnf_process = mock.MagicMock()
1446         sample_vnf._vnf_process.exitcode = 0
1447         sample_vnf._vnf_process._is_alive.return_value = 1
1448         sample_vnf.queue_wrapper = mock.Mock()
1449         sample_vnf.q_out = mock.Mock()
1450         sample_vnf.q_out.qsize.side_effect = iter(queue_size_list)
1451         sample_vnf.q_out.get.side_effect = iter(queue_get_list)
1452         sample_vnf.ssh_helper = mock.MagicMock()
1453         sample_vnf.resource_helper.ssh_helper = mock.MagicMock()
1454         sample_vnf.resource_helper.start_collect = mock.MagicMock()
1455
1456         self.assertEqual(sample_vnf.wait_for_instantiate(), 0)
1457
1458     @mock.patch.object(time, 'sleep')
1459     @mock.patch.object(ssh, 'SSH')
1460     def test_wait_for_initialize(self, ssh, *args):
1461         test_base.mock_ssh(ssh, exec_result=(1, "", ""))
1462         queue_get_list = [
1463             'some output',
1464             'pipeline> ',
1465             'run non_existent_script_name',
1466             'Cannot open file "non_existent_script_name"'
1467         ]
1468         queue_size_list = [
1469             0,
1470             len(queue_get_list[0]),
1471             0,
1472             len(queue_get_list[1]),
1473             len(queue_get_list[2]),
1474             0,
1475             len(queue_get_list[3])
1476         ]
1477         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1478         sample_vnf = SampleVNF('vnf1', vnfd)
1479         sample_vnf.APP_NAME = 'sample1'
1480         sample_vnf.WAIT_TIME_FOR_SCRIPT = 0
1481         sample_vnf._vnf_process = mock.Mock()
1482         sample_vnf._vnf_process.exitcode = 0
1483         sample_vnf._vnf_process._is_alive.return_value = 1
1484         sample_vnf.queue_wrapper = mock.Mock()
1485         sample_vnf.q_in = mock.Mock()
1486         sample_vnf.q_out = mock.Mock()
1487         sample_vnf.q_out.qsize.side_effect = iter(queue_size_list)
1488         sample_vnf.q_out.get.side_effect = iter(queue_get_list)
1489         sample_vnf.wait_for_initialize()
1490
1491     @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
1492     def test_vnf_execute_with_queue_data(self, *args):
1493         queue_size_list = [
1494             1,
1495             1,
1496             0,
1497         ]
1498
1499         queue_get_list = [
1500             'hello ',
1501             'world'
1502         ]
1503
1504         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1505         sample_vnf = SampleVNF('vnf1', vnfd)
1506         sample_vnf.APP_NAME = 'sample1'
1507         sample_vnf.q_out = mock.Mock()
1508         sample_vnf.q_out.qsize.side_effect = iter(queue_size_list)
1509         sample_vnf.q_out.get.side_effect = iter(queue_get_list)
1510
1511         self.assertEqual(sample_vnf.vnf_execute('my command'), 'hello world')
1512
1513     def test_terminate_without_vnf_process(self):
1514         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1515         sample_vnf = SampleVNF('vnf1', vnfd)
1516         sample_vnf.APP_NAME = 'sample1'
1517         sample_vnf.vnf_execute = mock.Mock()
1518         sample_vnf.ssh_helper = mock.Mock()
1519         sample_vnf._tear_down = mock.Mock()
1520         sample_vnf.resource_helper = mock.Mock()
1521
1522         self.assertIsNone(sample_vnf.terminate())
1523
1524     def test_get_stats(self):
1525         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1526         sample_vnf = SampleVNF('vnf1', vnfd)
1527         sample_vnf.APP_NAME = 'sample1'
1528         sample_vnf.APP_WORD = 'sample1'
1529         sample_vnf.vnf_execute = mock.Mock(return_value='the stats')
1530
1531         self.assertEqual(sample_vnf.get_stats(), 'the stats')
1532
1533     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
1534     def test_collect_kpi(self, *args):
1535         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1536         sample_vnf = SampleVNF('vnf1', vnfd)
1537         sample_vnf.scenario_helper.scenario_cfg = {
1538             'nodes': {sample_vnf.name: "mock"}
1539         }
1540         sample_vnf.APP_NAME = 'sample1'
1541         sample_vnf.COLLECT_KPI = r'\s(\d+)\D*(\d+)\D*(\d+)'
1542         sample_vnf.COLLECT_MAP = {
1543             'k1': 3,
1544             'k2': 1,
1545             'k3': 2,
1546         }
1547         sample_vnf.get_stats = mock.Mock(return_value='index0: 34 -- 91, 27')
1548         sample_vnf.resource_helper = mock.Mock()
1549         sample_vnf.resource_helper.collect_kpi.return_value = {}
1550
1551         expected = {
1552             'k1': 27,
1553             'k2': 34,
1554             'k3': 91,
1555             'collect_stats': {},
1556             'physical_node': 'mock_node'
1557         }
1558         result = sample_vnf.collect_kpi()
1559         self.assertDictEqual(result, expected)
1560
1561     @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
1562     def test_collect_kpi_default(self, *args):
1563         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1564         sample_vnf = SampleVNF('vnf1', vnfd)
1565         sample_vnf.scenario_helper.scenario_cfg = {
1566             'nodes': {sample_vnf.name: "mock"}
1567         }
1568         sample_vnf.APP_NAME = 'sample1'
1569         sample_vnf.COLLECT_KPI = r'\s(\d+)\D*(\d+)\D*(\d+)'
1570         sample_vnf.get_stats = mock.Mock(return_value='')
1571
1572         expected = {
1573             'physical_node': 'mock_node',
1574             'packets_in': 0,
1575             'packets_fwd': 0,
1576             'packets_dropped': 0,
1577         }
1578         result = sample_vnf.collect_kpi()
1579         self.assertDictEqual(result, expected)
1580
1581     def test_scale(self):
1582         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1583         sample_vnf = SampleVNF('vnf1', vnfd)
1584         self.assertRaises(y_exceptions.FunctionNotImplemented,
1585                           sample_vnf.scale)
1586
1587     def test__run(self):
1588         test_cmd = 'test cmd'
1589         run_kwargs = {'arg1': 'val1', 'arg2': 'val2'}
1590         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1591         sample_vnf = SampleVNF('vnf1', vnfd)
1592         sample_vnf.ssh_helper = mock.Mock()
1593         sample_vnf.setup_helper = mock.Mock()
1594         with mock.patch.object(sample_vnf, '_build_config',
1595                                return_value=test_cmd), \
1596                 mock.patch.object(sample_vnf, '_build_run_kwargs'):
1597             sample_vnf.run_kwargs = run_kwargs
1598             sample_vnf._run()
1599         sample_vnf.ssh_helper.drop_connection.assert_called_once()
1600         sample_vnf.ssh_helper.run.assert_called_once_with(test_cmd,
1601                                                           **run_kwargs)
1602         sample_vnf.setup_helper.kill_vnf.assert_called_once()
1603
1604
1605 class TestSampleVNFTrafficGen(unittest.TestCase):
1606
1607     VNFD_0 = {
1608         'short-name': 'VpeVnf',
1609         'vdu': [
1610             {
1611                 'routing_table': [
1612                     {
1613                         'network': '152.16.100.20',
1614                         'netmask': '255.255.255.0',
1615                         'gateway': '152.16.100.20',
1616                         'if': 'xe0'
1617                     },
1618                     {
1619                         'network': '152.16.40.20',
1620                         'netmask': '255.255.255.0',
1621                         'gateway': '152.16.40.20',
1622                         'if': 'xe1'
1623                     },
1624                 ],
1625                 'description': 'VPE approximation using DPDK',
1626                 'name': 'vpevnf-baremetal',
1627                 'nd_route_tbl': [
1628                     {
1629                         'network': '0064:ff9b:0:0:0:0:9810:6414',
1630                         'netmask': '112',
1631                         'gateway': '0064:ff9b:0:0:0:0:9810:6414',
1632                         'if': 'xe0'
1633                     },
1634                     {
1635                         'network': '0064:ff9b:0:0:0:0:9810:2814',
1636                         'netmask': '112',
1637                         'gateway': '0064:ff9b:0:0:0:0:9810:2814',
1638                         'if': 'xe1'
1639                     },
1640                 ],
1641                 'id': 'vpevnf-baremetal',
1642                 'external-interface': [
1643                     {
1644                         'virtual-interface': {
1645                             'dst_mac': '00:00:00:00:00:03',
1646                             'vpci': '0000:05:00.0',
1647                             'driver': 'i40e',
1648                             'local_ip': '152.16.100.19',
1649                             'type': 'PCI-PASSTHROUGH',
1650                             'netmask': '255.255.255.0',
1651                             'dpdk_port_num': 0,
1652                             'bandwidth': '10 Gbps',
1653                             'dst_ip': '152.16.100.20',
1654                             'local_mac': '00:00:00:00:00:01'
1655                         },
1656                         'vnfd-connection-point-ref': 'xe0',
1657                         'name': 'xe0'
1658                     },
1659                     {
1660                         'virtual-interface': {
1661                             'dst_mac': '00:00:00:00:00:04',
1662                             'vpci': '0000:05:00.1',
1663                             'driver': 'ixgbe',
1664                             'local_ip': '152.16.40.19',
1665                             'type': 'PCI-PASSTHROUGH',
1666                             'netmask': '255.255.255.0',
1667                             'dpdk_port_num': 1,
1668                             'bandwidth': '10 Gbps',
1669                             'dst_ip': '152.16.40.20',
1670                             'local_mac': '00:00:00:00:00:02'
1671                         },
1672                         'vnfd-connection-point-ref': 'xe1',
1673                         'name': 'xe1'
1674                     },
1675                 ],
1676             },
1677         ],
1678         'description': 'Vpe approximation using DPDK',
1679         'mgmt-interface': {
1680             'vdu-id': 'vpevnf-baremetal',
1681             'host': '1.1.1.1',
1682             'password': 'r00t',
1683             'user': 'root',
1684             'ip': '1.1.1.1'
1685         },
1686         'benchmark': {
1687             'kpi': [
1688                 'packets_in',
1689                 'packets_fwd',
1690                 'packets_dropped',
1691             ],
1692         },
1693         'connection-point': [
1694             {
1695                 'type': 'VPORT',
1696                 'name': 'xe0',
1697             },
1698             {
1699                 'type': 'VPORT',
1700                 'name': 'xe1',
1701             },
1702         ],
1703         'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
1704     }
1705
1706     VNFD = {
1707         'vnfd:vnfd-catalog': {
1708             'vnfd': [
1709                 VNFD_0,
1710             ],
1711         },
1712     }
1713
1714     TRAFFIC_PROFILE = {
1715         "schema": "isb:traffic_profile:0.1",
1716         "name": "fixed",
1717         "description": "Fixed traffic profile to run UDP traffic",
1718         "traffic_profile": {
1719             "traffic_type": "FixedTraffic",
1720             "frame_rate": 100,  # pps
1721             "flow_number": 10,
1722             "frame_size": 64,
1723         },
1724     }
1725
1726     def test__check_status(self):
1727         sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
1728
1729         with self.assertRaises(NotImplementedError):
1730             sample_vnf_tg._check_status()
1731
1732     def test_listen_traffic(self):
1733         sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
1734
1735         sample_vnf_tg.listen_traffic(mock.Mock())
1736
1737     def test_verify_traffic(self):
1738         sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
1739
1740         sample_vnf_tg.verify_traffic(mock.Mock())
1741
1742     def test_terminate(self):
1743         sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
1744         sample_vnf_tg._traffic_process = mock.Mock()
1745         sample_vnf_tg._tg_process = mock.Mock()
1746
1747         sample_vnf_tg.terminate()
1748
1749     def test__wait_for_process(self):
1750         sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
1751         with mock.patch.object(sample_vnf_tg, '_check_status',
1752                                return_value=0) as mock_status, \
1753                 mock.patch.object(sample_vnf_tg, '_tg_process') as mock_proc:
1754             mock_proc.is_alive.return_value = True
1755             mock_proc.exitcode = 234
1756             self.assertEqual(sample_vnf_tg._wait_for_process(), 234)
1757             mock_proc.is_alive.assert_called_once()
1758             mock_status.assert_called_once()
1759
1760     def test__wait_for_process_not_alive(self):
1761         sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
1762         with mock.patch.object(sample_vnf_tg, '_tg_process') as mock_proc:
1763             mock_proc.is_alive.return_value = False
1764             self.assertRaises(RuntimeError, sample_vnf_tg._wait_for_process)
1765             mock_proc.is_alive.assert_called_once()
1766
1767     def test__wait_for_process_delayed(self):
1768         sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
1769         with mock.patch.object(sample_vnf_tg, '_check_status',
1770                                side_effect=[1, 0]) as mock_status, \
1771                 mock.patch.object(sample_vnf_tg,
1772                                   '_tg_process') as mock_proc:
1773             mock_proc.is_alive.return_value = True
1774             mock_proc.exitcode = 234
1775             self.assertEqual(sample_vnf_tg._wait_for_process(), 234)
1776             mock_proc.is_alive.assert_has_calls([mock.call(), mock.call()])
1777             mock_status.assert_has_calls([mock.call(), mock.call()])
1778
1779     def test_scale(self):
1780         sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
1781         self.assertRaises(y_exceptions.FunctionNotImplemented,
1782                           sample_vnf_tg.scale)