3 # Copyright (c) 2016-2017 Intel Corporation
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
18 from __future__ import absolute_import
23 import six.moves.configparser as configparser
25 from multiprocessing import Process, Queue
27 from yardstick.network_services.vnf_generic.vnf.base import QueueFileWrapper
29 SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
32 'stl': mock.MagicMock(),
33 'stl.trex_stl_lib': mock.MagicMock(),
34 'stl.trex_stl_lib.base64': mock.MagicMock(),
35 'stl.trex_stl_lib.binascii': mock.MagicMock(),
36 'stl.trex_stl_lib.collections': mock.MagicMock(),
37 'stl.trex_stl_lib.copy': mock.MagicMock(),
38 'stl.trex_stl_lib.datetime': mock.MagicMock(),
39 'stl.trex_stl_lib.functools': mock.MagicMock(),
40 'stl.trex_stl_lib.imp': mock.MagicMock(),
41 'stl.trex_stl_lib.inspect': mock.MagicMock(),
42 'stl.trex_stl_lib.json': mock.MagicMock(),
43 'stl.trex_stl_lib.linecache': mock.MagicMock(),
44 'stl.trex_stl_lib.math': mock.MagicMock(),
45 'stl.trex_stl_lib.os': mock.MagicMock(),
46 'stl.trex_stl_lib.platform': mock.MagicMock(),
47 'stl.trex_stl_lib.pprint': mock.MagicMock(),
48 'stl.trex_stl_lib.random': mock.MagicMock(),
49 'stl.trex_stl_lib.re': mock.MagicMock(),
50 'stl.trex_stl_lib.scapy': mock.MagicMock(),
51 'stl.trex_stl_lib.socket': mock.MagicMock(),
52 'stl.trex_stl_lib.string': mock.MagicMock(),
53 'stl.trex_stl_lib.struct': mock.MagicMock(),
54 'stl.trex_stl_lib.sys': mock.MagicMock(),
55 'stl.trex_stl_lib.threading': mock.MagicMock(),
56 'stl.trex_stl_lib.time': mock.MagicMock(),
57 'stl.trex_stl_lib.traceback': mock.MagicMock(),
58 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(),
59 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(),
60 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(),
61 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(),
62 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(),
63 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(),
64 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(),
65 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(),
66 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(),
67 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(),
68 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(),
69 'stl.trex_stl_lib.types': mock.MagicMock(),
70 'stl.trex_stl_lib.utils': mock.MagicMock(),
71 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(),
72 'stl.trex_stl_lib.utils.collections': mock.MagicMock(),
73 'stl.trex_stl_lib.utils.common': mock.MagicMock(),
74 'stl.trex_stl_lib.utils.json': mock.MagicMock(),
75 'stl.trex_stl_lib.utils.os': mock.MagicMock(),
76 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(),
77 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(),
78 'stl.trex_stl_lib.utils.random': mock.MagicMock(),
79 'stl.trex_stl_lib.utils.re': mock.MagicMock(),
80 'stl.trex_stl_lib.utils.string': mock.MagicMock(),
81 'stl.trex_stl_lib.utils.sys': mock.MagicMock(),
82 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(),
83 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(),
84 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(),
85 'stl.trex_stl_lib.warnings': mock.MagicMock(),
86 'stl.trex_stl_lib.yaml': mock.MagicMock(),
87 'stl.trex_stl_lib.zlib': mock.MagicMock(),
88 'stl.trex_stl_lib.zmq': mock.MagicMock(),
91 STLClient = mock.MagicMock()
92 stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
96 from yardstick.network_services.vnf_generic.vnf.vpe_vnf import ConfigCreate
97 from yardstick.network_services.nfvi.resource import ResourceProfile
98 from yardstick.network_services.vnf_generic.vnf import vpe_vnf
99 from yardstick.network_services.vnf_generic.vnf.vpe_vnf import VpeApproxVnf
101 from tests.unit.network_services.vnf_generic.vnf.test_base import FileAbsPath
102 from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
105 TEST_FILE_YAML = 'nsb_test_case.yaml'
109 PING_OUTPUT_1 = "Pkts in: 101\r\n\tPkts dropped by AH: 100\r\n\tPkts dropped by other: 100"
111 MODULE_PATH = FileAbsPath(__file__)
112 get_file_abspath = MODULE_PATH.get_path
115 class TestConfigCreate(unittest.TestCase):
117 def test___init__(self):
118 config_create = ConfigCreate([0], [1], 2)
119 self.assertEqual(config_create.priv_ports, [0])
120 self.assertEqual(config_create.pub_ports, [1])
121 self.assertEqual(config_create.socket, 2)
123 def test_vpe_initialize(self):
124 config_create = ConfigCreate([0], [1], 2)
125 config = configparser.ConfigParser()
126 config_create.vpe_initialize(config)
127 self.assertEqual(config.get('EAL', 'log_level'), '0')
128 self.assertEqual(config.get('PIPELINE0', 'type'), 'MASTER')
129 self.assertEqual(config.get('PIPELINE0', 'core'), 's2C0')
130 self.assertEqual(config.get('MEMPOOL0', 'pool_size'), '256K')
131 self.assertEqual(config.get('MEMPOOL1', 'pool_size'), '2M')
133 def test_vpe_rxq(self):
134 config_create = ConfigCreate([0], [1, 2], 3)
135 config = configparser.ConfigParser()
136 config_create.vpe_rxq(config)
137 self.assertEqual(config.get('RXQ1.0', 'mempool'), 'MEMPOOL1')
138 self.assertEqual(config.get('RXQ2.0', 'mempool'), 'MEMPOOL1')
140 def test_get_sink_swq(self):
141 config_create = ConfigCreate([0], [1], 2)
142 config = configparser.ConfigParser()
143 config.add_section('PIPELINE0')
144 config.set('PIPELINE0', 'key1', 'value1')
145 config.set('PIPELINE0', 'key2', 'value2 SINK')
146 config.set('PIPELINE0', 'key3', 'TM value3')
147 config.set('PIPELINE0', 'key4', 'value4')
148 config.set('PIPELINE0', 'key5', 'the SINK value5')
150 self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key1', 5), 'SWQ-1')
151 self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key2', 5), 'SWQ-1 SINK0')
152 self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key3', 5), 'SWQ-1 TM5')
153 config_create.sw_q += 1
154 self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key4', 5), 'SWQ0')
155 self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key5', 5), 'SWQ0 SINK1')
157 def test_generate_vpe_script(self):
158 vpe_config_vnf = ConfigCreate([0], [0], 0)
161 "virtual-interface": {
163 "dst_mac": "00:00:00:00:00:00:02",
167 result = vpe_config_vnf.generate_vpe_script(intf)
168 self.assertIsInstance(result, str)
169 self.assertNotEqual(result, '')
171 def test_create_vpe_config(self):
194 config_create = ConfigCreate(priv_ports, pub_ports, 23)
195 curr_path = os.path.dirname(os.path.abspath(__file__))
196 vpe_cfg = "samples/vnf_samples/nsut/vpe/vpe_config"
197 vnf_cfg = os.path.join(curr_path, "../../../../..", vpe_cfg)
198 config_create.create_vpe_config(vnf_cfg)
199 os.system("git checkout -- %s" % vnf_cfg)
202 @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time')
203 class TestVpeApproxVnf(unittest.TestCase):
206 'short-name': 'VpeVnf',
211 'network': '152.16.100.20',
212 'netmask': '255.255.255.0',
213 'gateway': '152.16.100.20',
217 'network': '152.16.40.20',
218 'netmask': '255.255.255.0',
219 'gateway': '152.16.40.20',
223 'description': 'VPE approximation using DPDK',
224 'name': 'vpevnf-baremetal',
227 'network': '0064:ff9b:0:0:0:0:9810:6414',
229 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
233 'network': '0064:ff9b:0:0:0:0:9810:2814',
235 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
239 'id': 'vpevnf-baremetal',
240 'external-interface': [
242 'virtual-interface': {
243 'dst_mac': '00:00:00:00:00:04',
244 'vpci': '0000:05:00.0',
245 'local_ip': '152.16.100.19',
246 'type': 'PCI-PASSTHROUGH',
248 'netmask': '255.255.255.0',
249 'dpdk_port_num': '0',
250 'bandwidth': '10 Gbps',
252 'dst_ip': '152.16.100.20',
253 'local_iface_name': 'xe0',
254 'local_mac': '00:00:00:00:00:02',
256 'vnfd-connection-point-ref': 'xe0',
260 'virtual-interface': {
261 'dst_mac': '00:00:00:00:00:03',
262 'vpci': '0000:05:00.1',
263 'local_ip': '152.16.40.19',
264 'type': 'PCI-PASSTHROUGH',
267 'netmask': '255.255.255.0',
268 'dpdk_port_num': '1',
269 'bandwidth': '10 Gbps',
270 'dst_ip': '152.16.40.20',
271 'local_iface_name': 'xe1',
272 'local_mac': '00:00:00:00:00:01',
274 'vnfd-connection-point-ref': 'xe1',
280 'description': 'Vpe approximation using DPDK',
282 'vdu-id': 'vpevnf-baremetal',
295 'connection-point': [
305 'id': 'VpeApproxVnf',
310 'vnfd:vnfd-catalog': {
322 'allowed_drop_rate': '0.8 - 1',
325 'cfg': 'acl_1rule.yaml',
335 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
336 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
338 'object': 'NetworkServiceTestCase',
340 'output_filename': '/tmp/yardstick.out',
345 'traffic_profile': 'ipv4_throughput_vpe.yaml',
347 'flow': 'ipv4_Packets_vpe.yaml',
348 'imix': 'imix_voice.yaml',
352 'tg__2': 'trafficgen_2.yardstick',
353 'tg__1': 'trafficgen_1.yardstick',
354 'vnf__1': 'vnf.yardstick',
356 'topology': 'vpe-tg-topology-baremetal.yaml',
362 'member-vnf-index': '3',
363 'role': 'TrafficGen',
364 'name': 'trafficgen_2.yardstick',
365 'vnfd-id-ref': 'tg__2',
369 'local_iface_name': 'ens513f0',
371 'netmask': '255.255.255.0',
372 'local_ip': '152.16.40.20',
373 'dst_mac': '00:00:00:00:00:01',
374 'local_mac': '00:00:00:00:00:03',
375 'dst_ip': '152.16.40.19',
377 'vpci': '0000:02:00.0',
381 'local_iface_name': 'ens513f1',
382 'netmask': '255.255.255.0',
383 'network': '202.16.100.0',
384 'local_ip': '202.16.100.20',
385 'local_mac': '00:1e:67:d0:60:5d',
387 'vpci': '0000:02:00.1',
392 'VNF model': 'l3fwd_vnf.yaml',
396 'member-vnf-index': '1',
397 'role': 'TrafficGen',
398 'name': 'trafficgen_1.yardstick',
399 'vnfd-id-ref': 'tg__1',
403 'local_iface_name': 'ens785f0',
405 'netmask': '255.255.255.0',
406 'local_ip': '152.16.100.20',
407 'dst_mac': '00:00:00:00:00:02',
408 'local_mac': '00:00:00:00:00:04',
409 'dst_ip': '152.16.100.19',
411 'vpci': '0000:05:00.0',
415 'local_iface_name': 'ens785f1',
416 'netmask': '255.255.255.0',
417 'local_ip': '152.16.100.21',
418 'local_mac': '00:00:00:00:00:01',
420 'vpci': '0000:05:00.1',
425 'VNF model': 'tg_rfc2544_tpl.yaml',
429 'name': 'vnf.yardstick',
430 'vnfd-id-ref': 'vnf__1',
434 'local_iface_name': 'ens786f0',
436 'netmask': '255.255.255.0',
437 'local_ip': '152.16.100.19',
438 'dst_mac': '00:00:00:00:00:04',
439 'local_mac': '00:00:00:00:00:02',
440 'dst_ip': '152.16.100.20',
442 'vpci': '0000:05:00.0',
446 'local_iface_name': 'ens786f1',
448 'netmask': '255.255.255.0',
449 'local_ip': '152.16.40.19',
450 'dst_mac': '00:00:00:00:00:03',
451 'local_mac': '00:00:00:00:00:01',
452 'dst_ip': '152.16.40.20',
454 'vpci': '0000:05:00.1',
460 'netmask': '255.255.255.0',
461 'gateway': '152.16.100.20',
462 'network': '152.16.100.20',
466 'netmask': '255.255.255.0',
467 'gateway': '152.16.40.20',
468 'network': '152.16.40.20',
472 'member-vnf-index': '2',
479 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
480 'network': '0064:ff9b:0:0:0:0:9810:6414',
485 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
486 'network': '0064:ff9b:0:0:0:0:9810:2814',
491 'VNF model': 'vpe_vnf.yaml',
496 def test___init__(self, _):
497 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
498 self.assertIsNone(vpe_approx_vnf._vnf_process)
500 @mock.patch(SSH_HELPER)
501 def test_collect_kpi_sa_not_running(self, ssh, _):
504 resource = mock.Mock(autospec=ResourceProfile)
505 resource.check_if_sa_running.return_value = False, 'error'
506 resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234}
508 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
509 vpe_approx_vnf.q_in = mock.MagicMock()
510 vpe_approx_vnf.q_out = mock.MagicMock()
511 vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
512 vpe_approx_vnf.resource_helper.resource = resource
515 'pkt_in_down_stream': 0,
516 'pkt_in_up_stream': 0,
517 'pkt_drop_down_stream': 0,
518 'pkt_drop_up_stream': 0,
519 'collect_stats': {'core': {}},
521 self.assertEqual(vpe_approx_vnf.collect_kpi(), expected)
523 @mock.patch(SSH_HELPER)
524 def test_collect_kpi_sa_running(self, ssh, _):
527 resource = mock.Mock(autospec=ResourceProfile)
528 resource.check_if_sa_running.return_value = True, 'good'
529 resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234}
531 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
532 vpe_approx_vnf.q_in = mock.MagicMock()
533 vpe_approx_vnf.q_out = mock.MagicMock()
534 vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
535 vpe_approx_vnf.resource_helper.resource = resource
538 'pkt_in_down_stream': 0,
539 'pkt_in_up_stream': 0,
540 'pkt_drop_down_stream': 0,
541 'pkt_drop_up_stream': 0,
542 'collect_stats': {'core': {'foo': 234}},
544 self.assertEqual(vpe_approx_vnf.collect_kpi(), expected)
546 @mock.patch(SSH_HELPER)
547 def test_vnf_execute(self, ssh, _):
549 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
550 vpe_approx_vnf.q_in = mock.MagicMock()
551 vpe_approx_vnf.q_out = mock.MagicMock()
552 vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
553 self.assertEqual(vpe_approx_vnf.vnf_execute("quit", 0), '')
555 @mock.patch(SSH_HELPER)
556 def test_run_vpe(self, ssh, _):
559 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
560 vpe_approx_vnf.tc_file_name = get_file_abspath(TEST_FILE_YAML)
561 vpe_approx_vnf.generate_port_pairs = mock.Mock()
562 vpe_approx_vnf.tg_port_pairs = [[[0], [1]]]
563 vpe_approx_vnf.vnf_port_pairs = [[[0], [1]]]
564 vpe_approx_vnf.vnf_cfg = {
567 'worker_config': '1C/1T',
570 vpe_approx_vnf.scenario_helper.scenario_cfg = {
574 'topology': 'nsb_test_case.yaml',
578 vpe_approx_vnf.topology = "nsb_test_case.yaml"
579 vpe_approx_vnf.nfvi_type = "baremetal"
580 vpe_approx_vnf._provide_config_file = mock.Mock()
582 self.assertIsInstance(vpe_approx_vnf.ssh_helper, mock.Mock)
583 self.assertIsNone(vpe_approx_vnf._run())
585 @mock.patch(SSH_HELPER)
586 def test_wait_for_instantiate(self, ssh, _):
589 mock_process = mock.Mock(autospec=Process)
590 mock_process.is_alive.return_value = True
591 mock_process.exitcode = 432
593 mock_q_out = mock.Mock(autospec=Queue)
594 mock_q_out.get.side_effect = iter(["pipeline>"])
595 mock_q_out.qsize.side_effect = range(1, -1, -1)
597 mock_resource = mock.MagicMock()
599 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
600 vpe_approx_vnf._vnf_process = mock_process
601 vpe_approx_vnf.q_out = mock_q_out
602 vpe_approx_vnf.queue_wrapper = mock.Mock(autospec=QueueFileWrapper)
603 vpe_approx_vnf.resource_helper.resource = mock_resource
605 vpe_approx_vnf.q_out.put("pipeline>")
606 self.assertEqual(vpe_approx_vnf.wait_for_instantiate(), 432)
608 @mock.patch(SSH_HELPER)
609 def test_wait_for_instantiate_fragmented(self, ssh, _):
612 mock_process = mock.Mock(autospec=Process)
613 mock_process.is_alive.return_value = True
614 mock_process.exitcode = 432
616 # test that fragmented pipeline prompt is recognized
617 mock_q_out = mock.Mock(autospec=Queue)
618 mock_q_out.get.side_effect = iter(["wow pipel", "ine>"])
619 mock_q_out.qsize.side_effect = range(2, -1, -1)
621 mock_resource = mock.MagicMock()
623 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
624 vpe_approx_vnf._vnf_process = mock_process
625 vpe_approx_vnf.q_out = mock_q_out
626 vpe_approx_vnf.queue_wrapper = mock.Mock(autospec=QueueFileWrapper)
627 vpe_approx_vnf.resource_helper.resource = mock_resource
629 self.assertEqual(vpe_approx_vnf.wait_for_instantiate(), 432)
631 @mock.patch(SSH_HELPER)
632 def test_wait_for_instantiate_crash(self, ssh, _):
633 mock_ssh(ssh, exec_result=(1, "", ""))
635 mock_process = mock.Mock(autospec=Process)
636 mock_process.is_alive.return_value = False
637 mock_process.exitcode = 432
639 mock_resource = mock.MagicMock()
641 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
642 vpe_approx_vnf._vnf_process = mock_process
643 vpe_approx_vnf.resource_helper.resource = mock_resource
645 with self.assertRaises(RuntimeError) as raised:
646 vpe_approx_vnf.wait_for_instantiate()
648 self.assertIn('VNF process died', str(raised.exception))
650 @mock.patch(SSH_HELPER)
651 def test_wait_for_instantiate_panic(self, ssh, _):
652 mock_ssh(ssh, exec_result=(1, "", ""))
654 mock_process = mock.Mock(autospec=Process)
655 mock_process.is_alive.return_value = True
656 mock_process.exitcode = 432
658 mock_resource = mock.MagicMock()
660 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
661 vpe_approx_vnf._vnf_process = mock_process
662 vpe_approx_vnf.resource_helper.resource = mock_resource
664 vpe_approx_vnf.q_out.put("PANIC")
665 with self.assertRaises(RuntimeError) as raised:
666 vpe_approx_vnf.wait_for_instantiate()
668 self.assertIn('Error starting', str(raised.exception))
670 @mock.patch(SSH_HELPER)
671 def test_wait_for_instantiate_panic_fragmented(self, ssh, _):
672 mock_ssh(ssh, exec_result=(1, "", ""))
674 mock_process = mock.Mock(autospec=Process)
675 mock_process.is_alive.return_value = True
676 mock_process.exitcode = 432
678 # test that fragmented PANIC is recognized
679 mock_q_out = mock.Mock(autospec=Queue)
680 mock_q_out.get.side_effect = iter(["omg PA", "NIC this is bad"])
681 mock_q_out.qsize.side_effect = range(2, -1, -1)
683 mock_resource = mock.MagicMock()
685 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
686 vpe_approx_vnf._vnf_process = mock_process
687 vpe_approx_vnf.q_out = mock_q_out
688 vpe_approx_vnf.resource_helper.resource = mock_resource
690 with self.assertRaises(RuntimeError) as raised:
691 vpe_approx_vnf.wait_for_instantiate()
693 self.assertIn('Error starting', str(raised.exception))
695 def test_scale(self, _):
696 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
697 with self.assertRaises(NotImplementedError):
698 vpe_approx_vnf.scale('')
700 def test_terminate(self, _):
701 vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
702 vpe_approx_vnf.vnf_execute = mock.Mock()
703 vpe_approx_vnf._vnf_process = mock.MagicMock()
704 vpe_approx_vnf._vnf_process.terminate = mock.Mock()
705 vpe_approx_vnf._resource_collect_stop = mock.Mock()
706 vpe_approx_vnf.resource_helper = mock.MagicMock()
707 vpe_approx_vnf.ssh_helper = mock.MagicMock()
709 self.assertIsNone(vpe_approx_vnf.terminate())
712 if __name__ == '__main__':