aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick/tests/unit/network_services/vnf_generic
diff options
context:
space:
mode:
Diffstat (limited to 'yardstick/tests/unit/network_services/vnf_generic')
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/__init__.py0
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/test_vnfdgen.py277
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/__init__.py0
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/tc_baremetal_rfc2544_ipv4_1flow_64B.yaml41
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py518
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_base.py348
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py412
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py2378
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py471
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py262
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py1999
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py271
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py298
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py428
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py392
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py313
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py516
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py477
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py371
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py817
20 files changed, 10589 insertions, 0 deletions
diff --git a/yardstick/tests/unit/network_services/vnf_generic/__init__.py b/yardstick/tests/unit/network_services/vnf_generic/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/__init__.py
diff --git a/yardstick/tests/unit/network_services/vnf_generic/test_vnfdgen.py b/yardstick/tests/unit/network_services/vnf_generic/test_vnfdgen.py
new file mode 100644
index 000000000..55b1955bc
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/test_vnfdgen.py
@@ -0,0 +1,277 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from six.moves import range
+import unittest
+
+from yardstick.common.yaml_loader import yaml_load
+from yardstick.network_services.vnf_generic import vnfdgen
+
+
+UPLINK = "uplink"
+DOWNLINK = "downlink"
+
+TREX_VNFD_TEMPLATE = """
+vnfd:vnfd-catalog:
+ vnfd:
+ - id: TrexTrafficGen # ISB class mapping
+ name: trexgen
+ short-name: trexgen
+ description: TRex stateless traffic generator for RFC2544
+ mgmt-interface:
+ vdu-id: trexgen-baremetal
+ user: {{user}} # Value filled by vnfdgen
+ password: {{password}} # Value filled by vnfdgen
+ ip: {{ip}} # Value filled by vnfdgen
+ connection-point:
+ - name: xe0
+ type: VPORT
+ - name: xe1
+ type: VPORT
+ vdu:
+ - id: trexgen-baremetal
+ name: trexgen-baremetal
+ description: TRex stateless traffic generator for RFC2544
+ external-interface:
+ - name: xe0
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ vpci: '{{ interfaces.xe0.vpci}}'
+ local_ip: '{{ interfaces.xe0.local_ip }}'
+ dst_ip: '{{ interfaces.xe0.dst_ip }}'
+ local_mac: '{{ interfaces.xe0.local_mac }}'
+ dst_mac: '{{ interfaces.xe0.dst_mac }}'
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe0
+ - name: xe1
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ vpci: '{{ interfaces.xe1.vpci }}'
+ local_ip: '{{ interfaces.xe1.local_ip }}'
+ dst_ip: '{{ interfaces.xe1.dst_ip }}'
+ local_mac: '{{ interfaces.xe1.local_mac }}'
+ dst_mac: '{{ interfaces.xe1.dst_mac }}'
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe1
+ routing_table: {{ routing_table }}
+ nd_route_tbl: {{ nd_route_tbl }}
+
+ benchmark:
+ kpi:
+ - rx_throughput_fps
+ - tx_throughput_fps
+ - tx_throughput_mbps
+ - rx_throughput_mbps
+ - tx_throughput_pc_linerate
+ - rx_throughput_pc_linerate
+ - min_latency
+ - max_latency
+ - avg_latency
+"""
+
+COMPLETE_TREX_VNFD = \
+ {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{'benchmark':
+ {'kpi':
+ ['rx_throughput_fps',
+ 'tx_throughput_fps',
+ 'tx_throughput_mbps',
+ 'rx_throughput_mbps',
+ 'tx_throughput_pc_linerate',
+ 'rx_throughput_pc_linerate',
+ 'min_latency',
+ 'max_latency',
+ 'avg_latency']},
+ 'connection-point': [{'name': 'xe0',
+ 'type': 'VPORT'},
+ {'name': 'xe1',
+ 'type': 'VPORT'}],
+ 'description': 'TRex stateless traffic generator for RFC2544',
+ 'id': 'TrexTrafficGen',
+ 'mgmt-interface': {'ip': '1.1.1.1',
+ 'password': 'berta',
+ 'user': 'berta',
+ 'vdu-id': 'trexgen-baremetal'},
+ 'name': 'trexgen',
+ 'short-name': 'trexgen',
+ 'vdu': [{'description': 'TRex stateless traffic generator for RFC2544',
+ 'external-interface':
+ [{'name': 'xe0',
+ 'virtual-interface': {'bandwidth': '10 Gbps',
+ 'dst_ip': '1.1.1.1',
+ 'dst_mac': '00:01:02:03:04:05',
+ 'local_ip': '1.1.1.2',
+ 'local_mac': '00:01:02:03:05:05',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vpci': '0000:00:10.2'},
+ 'vnfd-connection-point-ref': 'xe0'},
+ {'name': 'xe1',
+ 'virtual-interface': {'bandwidth': '10 Gbps',
+ 'dst_ip': '2.1.1.1',
+ 'dst_mac': '00:01:02:03:04:06',
+ 'local_ip': '2.1.1.2',
+ 'local_mac': '00:01:02:03:05:06',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vpci': '0000:00:10.1'},
+ 'vnfd-connection-point-ref': 'xe1'}],
+ 'id': 'trexgen-baremetal',
+ 'nd_route_tbl': [{'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ 'netmask': '112',
+ 'network': '0064:ff9b:0:0:0:0:9810:6414'},
+ {'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ 'netmask': '112',
+ 'network': '0064:ff9b:0:0:0:0:9810:2814'}],
+ 'routing_table': [{'gateway': '152.16.100.20',
+ 'if': 'xe0',
+ 'netmask': '255.255.255.0',
+ 'network': '152.16.100.20'},
+ {'gateway': '152.16.40.20',
+ 'if': 'xe1',
+ 'netmask': '255.255.255.0',
+ 'network': '152.16.40.20'}],
+ 'name': 'trexgen-baremetal'}]}]}}
+
+NODE_CFG = {'ip': '1.1.1.1',
+ 'name': 'demeter',
+ 'password': 'berta',
+ 'role': 'TrafficGen',
+ 'user': 'berta',
+ 'interfaces': {'xe0': {'dpdk_port_num': 1,
+ 'dst_ip': '1.1.1.1',
+ 'dst_mac': '00:01:02:03:04:05',
+ 'local_ip': '1.1.1.2',
+ 'local_mac': '00:01:02:03:05:05',
+ 'vpci': '0000:00:10.2'},
+ 'xe1': {'dpdk_port_num': 0,
+ 'dst_ip': '2.1.1.1',
+ 'dst_mac': '00:01:02:03:04:06',
+ 'local_ip': '2.1.1.2',
+ 'local_mac': '00:01:02:03:05:06',
+ 'vpci': '0000:00:10.1'}},
+ 'nd_route_tbl': [{u'gateway': u'0064:ff9b:0:0:0:0:9810:6414',
+ u'if': u'xe0',
+ u'netmask': u'112',
+ u'network': u'0064:ff9b:0:0:0:0:9810:6414'},
+ {u'gateway': u'0064:ff9b:0:0:0:0:9810:2814',
+ u'if': u'xe1',
+ u'netmask': u'112',
+ u'network': u'0064:ff9b:0:0:0:0:9810:2814'}],
+ 'routing_table': [{u'gateway': u'152.16.100.20',
+ u'if': u'xe0',
+ u'netmask': u'255.255.255.0',
+ u'network': u'152.16.100.20'},
+ {u'gateway': u'152.16.40.20',
+ u'if': u'xe1',
+ u'netmask': u'255.255.255.0',
+ u'network': u'152.16.40.20'}],
+ }
+
+
+# need to template, but can't use {} so use %s
+TRAFFIC_PROFILE_TPL = """
+%(0)s:
+ - ipv4:
+ outer_l2:
+ framesize:
+ 64B: "{{ get(imix, '%(0)s.imix_small', 10) }}"
+ 128B: "{{ get(imix, '%(0)s.imix_128B', 10) }}"
+ 256B: "{{ get(imix, '%(0)s.imix_256B', 10) }}"
+ 373B: "{{ get(imix, '%(0)s.imix_373B', 10) }}"
+ 570B: "{{get(imix, '%(0)s.imix_570B', 10) }}"
+ 1400B: "{{get(imix, '%(0)s.imix_1400B', 10) }}"
+ 1518B: "{{get(imix, '%(0)s.imix_1500B', 40) }}"
+""" % {"0": UPLINK}
+
+TRAFFIC_PROFILE = {
+ UPLINK: [{"ipv4": {"outer_l2":
+ {"framesize": {"64B": '10', "128B": '10',
+ "256B": '10', "373B": '10',
+ "570B": '10', "1400B": '10',
+ "1518B": '40'}}}}]}
+
+
+class TestRender(unittest.TestCase):
+
+ def test_render_none(self):
+
+ tmpl = "{{ routing_table }}"
+ self.assertEqual(vnfdgen.render(tmpl, routing_table=None), u'~')
+ self.assertIsNone(
+ yaml_load(vnfdgen.render(tmpl, routing_table=None)))
+
+ def test_render_unicode_dict(self):
+
+ tmpl = "{{ routing_table }}"
+ self.assertEqual(yaml_load(vnfdgen.render(
+ tmpl, **NODE_CFG)), NODE_CFG["routing_table"])
+
+
+class TestVnfdGen(unittest.TestCase):
+ """ Class to verify VNFS testcases """
+
+ def test_generate_vnfd(self):
+ """ Function to verify vnfd generation based on template """
+ self.maxDiff = None
+ generated_vnfd = vnfdgen.generate_vnfd(TREX_VNFD_TEMPLATE, NODE_CFG)
+ self.assertDictEqual(COMPLETE_TREX_VNFD, generated_vnfd)
+
+ def test_generate_tp_no_vars(self):
+ """ Function to verify traffic profile generation without imix """
+
+ self.maxDiff = None
+ generated_tp = vnfdgen.generate_vnfd(TRAFFIC_PROFILE_TPL, {"imix": {}})
+ self.assertDictEqual(TRAFFIC_PROFILE, generated_tp)
+
+ def test_deepgetitem(self):
+ d = {'a': 1, 'b': 2}
+ self.assertEqual(vnfdgen.deepgetitem(d, "a"), 1)
+
+ def test_dict_flatten_int(self):
+ d = {'a': 1, 'b': 2}
+ self.assertEqual(vnfdgen.deepgetitem(d, "a"), 1)
+
+ def test_dict_flatten_str_int_key_first(self):
+ d = {'0': 1, 0: 24, 'b': 2}
+ self.assertEqual(vnfdgen.deepgetitem(d, "0"), 1)
+
+ def test_dict_flatten_int_key_fallback(self):
+ d = {0: 1, 'b': 2}
+ self.assertEqual(vnfdgen.deepgetitem(d, "0"), 1)
+
+ def test_dict_flatten_list(self):
+ d = {'a': 1, 'b': list(range(2))}
+ self.assertEqual(vnfdgen.deepgetitem(d, "b.0"), 0)
+
+ def test_dict_flatten_dict(self):
+ d = {'a': 1, 'b': {x: x for x in list(range(2))}}
+ self.assertEqual(vnfdgen.deepgetitem(d, "b.0"), 0)
+
+ def test_dict_flatten_only_str_key(self):
+ d = {'0': 1, 0: 24, 'b': 2}
+ self.assertRaises(AttributeError, vnfdgen.deepgetitem, d, 0)
+
+ def test_generate_tp_single_var(self):
+ """ Function to verify traffic profile generation with imix """
+
+ generated_tp = \
+ vnfdgen.generate_vnfd(TRAFFIC_PROFILE_TPL,
+ {"imix": {UPLINK: {"imix_small": '20'}}})
+ self.maxDiff = None
+ tp2 = dict(TRAFFIC_PROFILE)
+ tp2[UPLINK][0]["ipv4"]["outer_l2"]["framesize"]["64B"] = '20'
+ self.assertDictEqual(tp2, generated_tp)
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/__init__.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/__init__.py
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/tc_baremetal_rfc2544_ipv4_1flow_64B.yaml b/yardstick/tests/unit/network_services/vnf_generic/vnf/tc_baremetal_rfc2544_ipv4_1flow_64B.yaml
new file mode 100644
index 000000000..fb1be35c1
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/tc_baremetal_rfc2544_ipv4_1flow_64B.yaml
@@ -0,0 +1,41 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+schema: yardstick:task:0.1
+scenarios:
+- type: NSPerf
+ traffic_profile: "../../traffic_profiles/ipv4_throughput_vpe.yaml"
+ topology: vpe_vnf_topology.yaml
+ nodes:
+ tg__1: trafficgen_1.yardstick
+ vnf__1: vnf.yardstick
+ tc_options:
+ rfc2544:
+ allowed_drop_rate: 0.8 - 1
+ vnf_options:
+ vpe:
+ cfg: vpe_config
+ runner:
+ type: Duration
+ duration: 400
+ interval: 35
+ traffic_options:
+ flow: "../../traffic_profiles/ipv4_1flow_Packets_vpe.yaml"
+ imix: "../../traffic_profiles/imix_voice.yaml"
+context:
+ type: Node
+ name: yardstick
+ nfvi_type: baremetal
+ file: /etc/yardstick/nodes/pod.yaml
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py
new file mode 100644
index 000000000..01fc19aa0
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py
@@ -0,0 +1,518 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+import mock
+import os
+import re
+import copy
+
+from yardstick.common import utils
+from yardstick.common import exceptions
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf import acl_vnf
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services.nfvi.resource import ResourceProfile
+from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxSetupEnvSetupEnvHelper
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+
+
+TEST_FILE_YAML = 'nsb_test_case.yaml'
+SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
+
+
+name = 'vnf__1'
+
+
+@mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process")
+class TestAclApproxVnf(unittest.TestCase):
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{'short-name': 'VpeVnf',
+ 'vdu':
+ [{'routing_table':
+ [{'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'},
+ {'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'}],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl':
+ [{'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'},
+ {'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'}],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface':
+ [{'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02'},
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'},
+ {'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01'},
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'}]}],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface':
+ {'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1'},
+ 'benchmark':
+ {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
+ 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
+ {'type': 'VPORT', 'name': 'xe1'}],
+ 'id': 'AclApproxVnf', 'name': 'VPEVnfSsh'}]}}
+
+ scenario_cfg = {'options': {'packetsize': 64, 'traffic_type': 4,
+ 'rfc2544': {'allowed_drop_rate': '0.8 - 1'},
+ 'vnf__1': {'rules': 'acl_1rule.yaml',
+ 'vnf_config': {'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config':
+ '1C/1T',
+ 'worker_threads': 1}}
+ },
+ 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
+ 'task_path': '/tmp',
+ 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
+ 'runner': {'object': 'NetworkServiceTestCase',
+ 'interval': 35,
+ 'output_filename': '/tmp/yardstick.out',
+ 'runner_id': 74476, 'duration': 400,
+ 'type': 'Duration'},
+ 'traffic_profile': 'ipv4_throughput_acl.yaml',
+ 'traffic_options': {'flow': 'ipv4_Packets_acl.yaml',
+ 'imix': 'imix_voice.yaml'},
+ 'type': 'ISB',
+ 'nodes': {'tg__2': 'trafficgen_2.yardstick',
+ 'tg__1': 'trafficgen_1.yardstick',
+ 'vnf__1': 'vnf.yardstick'},
+ 'topology': 'vpe-tg-topology-baremetal.yaml'}
+
+ context_cfg = {'nodes': {'tg__2':
+ {'member-vnf-index': '3',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_2.yardstick',
+ 'vnfd-id-ref': 'tg__2',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens513f0',
+ 'vld_id': acl_vnf.AclApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.20',
+ 'dst_mac': '00:00:00:00:00:01',
+ 'local_mac': '00:00:00:00:00:03',
+ 'dst_ip': '152.16.40.19',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens513f1',
+ 'netmask': '255.255.255.0',
+ 'network': '202.16.100.0',
+ 'local_ip': '202.16.100.20',
+ 'local_mac': '00:1e:67:d0:60:5d',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.1',
+ 'dpdk_port_num': 1}},
+ 'password': 'r00t',
+ 'VNF model': 'l3fwd_vnf.yaml',
+ 'user': 'root'},
+ 'tg__1':
+ {'member-vnf-index': '1',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_1.yardstick',
+ 'vnfd-id-ref': 'tg__1',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens785f0',
+ 'vld_id': acl_vnf.AclApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.20',
+ 'dst_mac': '00:00:00:00:00:02',
+ 'local_mac': '00:00:00:00:00:04',
+ 'dst_ip': '152.16.100.19',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens785f1',
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.21',
+ 'local_mac': '00:00:00:00:00:01',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1}},
+ 'password': 'r00t',
+ 'VNF model': 'tg_rfc2544_tpl.yaml',
+ 'user': 'root'},
+ 'vnf__1':
+ {'name': 'vnf.yardstick',
+ 'vnfd-id-ref': 'vnf__1',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens786f0',
+ 'vld_id': acl_vnf.AclApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.19',
+ 'dst_mac': '00:00:00:00:00:04',
+ 'local_mac': '00:00:00:00:00:02',
+ 'dst_ip': '152.16.100.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens786f1',
+ 'vld_id': acl_vnf.AclApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.19',
+ 'dst_mac': '00:00:00:00:00:03',
+ 'local_mac': '00:00:00:00:00:01',
+ 'dst_ip': '152.16.40.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1}},
+ 'routing_table':
+ [{'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'network': '152.16.100.20',
+ 'if': 'xe0'},
+ {'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'network': '152.16.40.20',
+ 'if': 'xe1'}],
+ 'member-vnf-index': '2',
+ 'host': '1.2.1.1',
+ 'role': 'vnf',
+ 'user': 'root',
+ 'nd_route_tbl':
+ [{'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'},
+ {'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'}],
+ 'password': 'r00t',
+ 'VNF model': 'acl_vnf.yaml'}}}
+
+ def test___init__(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
+ self.assertIsNone(acl_approx_vnf._vnf_process)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
+ acl_approx_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {acl_approx_vnf.name: "mock"}
+ }
+ acl_approx_vnf.q_in = mock.MagicMock()
+ acl_approx_vnf.q_out = mock.MagicMock()
+ acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ acl_approx_vnf.resource = mock.Mock(autospec=ResourceProfile)
+ acl_approx_vnf.vnf_execute = mock.Mock(return_value="")
+ result = {
+ 'physical_node': 'mock_node',
+ 'packets_dropped': 0,
+ 'packets_fwd': 0,
+ 'packets_in': 0
+ }
+ self.assertEqual(result, acl_approx_vnf.collect_kpi())
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch(SSH_HELPER)
+ def test_vnf_execute_command(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
+ acl_approx_vnf.q_in = mock.MagicMock()
+ acl_approx_vnf.q_out = mock.MagicMock()
+ acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ cmd = "quit"
+ self.assertEqual("", acl_approx_vnf.vnf_execute(cmd))
+
+ @mock.patch(SSH_HELPER)
+ def test_get_stats(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
+ acl_approx_vnf.q_in = mock.MagicMock()
+ acl_approx_vnf.q_out = mock.MagicMock()
+ acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ result = "ACL TOTAL: pkts_processed: 100, pkts_drop: 0, spkts_received: 100"
+ acl_approx_vnf.vnf_execute = mock.Mock(return_value=result)
+ self.assertEqual(result, acl_approx_vnf.get_stats())
+
+ def _get_file_abspath(self, filename):
+ curr_path = os.path.dirname(os.path.abspath(__file__))
+ file_path = os.path.join(curr_path, filename)
+ return file_path
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.hex")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.eval")
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.acl_vnf.open')
+ @mock.patch(SSH_HELPER)
+ def test_run_acl(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
+ acl_approx_vnf._build_config = mock.MagicMock()
+ acl_approx_vnf.queue_wrapper = mock.MagicMock()
+ acl_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
+ acl_approx_vnf.vnf_cfg = {'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1}
+ acl_approx_vnf.all_options = {'traffic_type': '4',
+ 'topology': 'nsb_test_case.yaml'}
+ acl_approx_vnf._run()
+ acl_approx_vnf.ssh_helper.run.assert_called_once()
+
+ @mock.patch.object(utils, 'find_relative_file')
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context")
+ @mock.patch(SSH_HELPER)
+ def test_instantiate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
+ acl_approx_vnf.deploy_helper = mock.MagicMock()
+ acl_approx_vnf.resource_helper = mock.MagicMock()
+ acl_approx_vnf._build_config = mock.MagicMock()
+ self.scenario_cfg['vnf_options'] = {'acl': {'cfg': "",
+ 'rules': ""}}
+ acl_approx_vnf.q_out.put("pipeline>")
+ acl_approx_vnf.WAIT_TIME = 0
+ self.scenario_cfg.update({"nodes": {"vnf__1": ""}})
+ self.assertIsNone(acl_approx_vnf.instantiate(self.scenario_cfg,
+ self.context_cfg))
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch(SSH_HELPER)
+ def test_terminate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id')
+ acl_approx_vnf._vnf_process = mock.MagicMock()
+ acl_approx_vnf._vnf_process.terminate = mock.Mock()
+ acl_approx_vnf.used_drivers = {"01:01.0": "i40e",
+ "01:01.1": "i40e"}
+ acl_approx_vnf.vnf_execute = mock.MagicMock()
+ acl_approx_vnf.dpdk_devbind = "dpdk-devbind.py"
+ acl_approx_vnf._resource_collect_stop = mock.Mock()
+ self.assertIsNone(acl_approx_vnf.terminate())
+
+
+class TestAclApproxSetupEnvSetupEnvHelper(unittest.TestCase):
+
+ ACL_CONFIG = {"access-list-entries": [{
+ "actions": [
+ "count",
+ {"fwd": {
+ "port": 0
+ }
+ }
+ ],
+ "matches": {
+ "destination-ipv4-network": "152.16.0.0/24",
+ "destination-port-range": {
+ "lower-port": 0,
+ "upper-port": 65535
+ },
+ "source-ipv4-network": "0.0.0.0/0",
+ "source-port-range": {
+ "lower-port": 0,
+ "upper-port": 65535
+ },
+ "protocol-mask": 255,
+ "protocol": 127,
+ "priority": 1
+ },
+ "rule-name": "rule1588"
+ }
+ ]}
+
+ def test_get_default_flows(self):
+ """Check if default ACL SampleVNF CLI commands are
+ generated correctly"""
+ ssh_helper = mock.Mock()
+ vnfd_helper = VnfdHelper({'vdu': [
+ {'external-interface': [
+ {
+ 'virtual-interface': {
+ 'local_ip': '152.16.100.19',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'dst_ip': '152.16.100.20',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'local_ip': '152.16.40.19',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'dst_ip': '152.16.40.20',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ }
+ ]}
+ ]})
+ setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper, ssh_helper, None)
+ self.check_acl_commands(setup_helper.get_flows_config(), [
+ # format: (<cli pattern>, <number of expected matches>)
+ ("^p action add [0-9]+ accept$", 2),
+ ("^p action add [0-9]+ count$", 2),
+ ("^p action add [0-9]+ fwd 1$", 1),
+ ("^p action add [0-9]+ fwd 0$", 1),
+ ("^p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 [0-9]+$", 1),
+ ("^p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 [0-9]+$", 1),
+ ("^p acl applyruleset$", 1)
+ ])
+
+ @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
+ def test_get_flows_config(self, get_default_flows):
+ """Check if provided ACL config can be converted to
+ ACL SampleVNF CLI commands correctly"""
+ ssh_helper = mock.Mock()
+ setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
+ get_default_flows.return_value = ({}, [])
+ self.check_acl_commands(setup_helper.get_flows_config(self.ACL_CONFIG), [
+ # format: (<cli pattern>, <number of expected matches>)
+ ("^p action add [0-9]+ count$", 1),
+ ("^p action add [0-9]+ fwd 0$", 1),
+ ("^p acl add 1 0.0.0.0 0 152.16.0.0 24 0 65535 0 65535 127 0 [0-9]+$", 1),
+ ("^p acl applyruleset$", 1)
+ ])
+
+ @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
+ def test_get_flows_config_invalid_action(self, get_default_flows):
+ """Check if incorrect ACL config fails to convert
+ to ACL SampleVNF CLI commands"""
+ ssh_helper = mock.Mock()
+ setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
+ get_default_flows.return_value = ({}, [])
+ # duplicate config and add invald action
+ acl_config = copy.deepcopy(self.ACL_CONFIG)
+ acl_config['access-list-entries'][0]["actions"].append({"xnat": {}})
+ self.assertRaises(exceptions.AclUknownActionTemplate,
+ setup_helper.get_flows_config, acl_config)
+
+ @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
+ def test_get_flows_config_invalid_action_param(self, get_default_flows):
+ """Check if ACL config with invalid action parameter fails to convert
+ to ACL SampleVNF CLI commands"""
+ ssh_helper = mock.Mock()
+ setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
+ get_default_flows.return_value = ({}, [])
+ # duplicate config and add action with invalid parameter
+ acl_config = copy.deepcopy(self.ACL_CONFIG)
+ acl_config['access-list-entries'][0]["actions"].append(
+ {"nat": {"xport": 0}})
+ self.assertRaises(exceptions.AclMissingActionArguments,
+ setup_helper.get_flows_config, acl_config)
+
+ def check_acl_commands(self, config, expected_cli_patterns):
+ """Check if expected ACL CLI commands (given as a list of patterns,
+ `expected_cli_patterns` parameter) present in SampleVNF ACL
+ configuration (given as a multiline string, `config` parameter)"""
+ # Example of expected config:
+ # ---------------------------
+ # p action add 1 accept
+ # p action add 1 fwd 1
+ # p action add 2 accept
+ # p action add 2 count
+ # p action add 2 fwd 0
+ # p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 1
+ # p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 2
+ # p acl applyruleset
+ # ---------------------------
+ # NOTE: The config above consists of actions ids, which are actually
+ # unknown (generated at runtime), thus it's incorrect just to compare
+ # the example ACL config above with the configuration returned by
+ # get_flows_config() function. It's more correct to use CLI patterns
+ # (RE) to find the required SampleVNF CLI commands in the multiline
+ # string (SampleVNF ACL configuration).
+ for pattern, num_of_match in expected_cli_patterns:
+ # format: (<cli pattern>, <number of expected matches>)
+ result = re.findall(pattern, config, re.MULTILINE)
+ self.assertEqual(len(result), num_of_match)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open')
+ @mock.patch.object(utils, 'find_relative_file')
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig')
+ @mock.patch.object(utils, 'open_relative_file')
+ def test_build_config(self, *args):
+ vnfd_helper = mock.Mock()
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.vnf_cfg = {'lb_config': 'HW'}
+ scenario_helper.options = {}
+ scenario_helper.all_options = {}
+
+ acl_approx_setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ acl_approx_setup_helper.get_flows_config = mock.Mock()
+ acl_approx_setup_helper.ssh_helper.provision_tool = mock.Mock(return_value='tool_path')
+ acl_approx_setup_helper.ssh_helper.all_ports = mock.Mock()
+ acl_approx_setup_helper.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1])
+ expected = 'sudo tool_path -p 0x3 -f /tmp/acl_config -s /tmp/acl_script --hwlb 3'
+ self.assertEqual(acl_approx_setup_helper.build_config(), expected)
+ acl_approx_setup_helper.get_flows_config.assert_called_once()
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_base.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_base.py
new file mode 100644
index 000000000..2ea13a5e0
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_base.py
@@ -0,0 +1,348 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import multiprocessing
+import os
+import uuid
+
+import mock
+from oslo_config import cfg
+import oslo_messaging
+import unittest
+
+from yardstick.common import messaging
+from yardstick.common.messaging import payloads
+from yardstick.network_services.vnf_generic.vnf import base
+from yardstick.ssh import SSH
+from yardstick.tests.unit import base as ut_base
+
+
+IP_PIPELINE_CFG_FILE_TPL = ("arp_route_tbl = ({port0_local_ip_hex},"
+ "{port0_netmask_hex},1,{port1_local_ip_hex}) "
+ "({port1_local_ip_hex},{port1_netmask_hex},0,"
+ "{port0_local_ip_hex})")
+
+IP_PIPELINE_ND_CFG_FILE_TPL = """
+nd_route_tbl = ({port1_dst_ip_hex6},"""
+"""{port1_dst_netmask_hex6},1,{port1_dst_ip_hex6})"""
+
+_LOCAL_OBJECT = object()
+
+VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01'
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02'
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
+}
+
+VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ]
+ }
+}
+
+
+class _DummyGenericTrafficGen(base.GenericTrafficGen): # pragma: no cover
+
+ def run_traffic(self, *args):
+ pass
+
+ def terminate(self):
+ pass
+
+ def collect_kpi(self):
+ pass
+
+ def instantiate(self, *args):
+ pass
+
+ def scale(self, flavor=''):
+ pass
+
+
+class FileAbsPath(object):
+ def __init__(self, module_file):
+ super(FileAbsPath, self).__init__()
+ self.module_path = os.path.dirname(os.path.abspath(module_file))
+
+ def get_path(self, filename):
+ file_path = os.path.join(self.module_path, filename)
+ return file_path
+
+
+def mock_ssh(mock_ssh_type, spec=None, exec_result=_LOCAL_OBJECT, run_result=_LOCAL_OBJECT):
+ if spec is None:
+ spec = SSH
+
+ if exec_result is _LOCAL_OBJECT:
+ exec_result = 0, "", ""
+
+ if run_result is _LOCAL_OBJECT:
+ run_result = 0, "", ""
+
+ mock_ssh_instance = mock.Mock(autospec=spec)
+ mock_ssh_instance._get_client.return_value = mock.Mock()
+ mock_ssh_instance.execute.return_value = exec_result
+ mock_ssh_instance.run.return_value = run_result
+ mock_ssh_type.from_node.return_value = mock_ssh_instance
+ return mock_ssh_instance
+
+
+class TestQueueFileWrapper(unittest.TestCase):
+ def setUp(self):
+ self.prompt = "pipeline>"
+ self.q_in = multiprocessing.Queue()
+ self.q_out = multiprocessing.Queue()
+
+ def test___init__(self):
+ queue_file_wrapper = \
+ base.QueueFileWrapper(self.q_in, self.q_out, self.prompt)
+ self.assertEqual(queue_file_wrapper.prompt, self.prompt)
+
+ def test_clear(self):
+ queue_file_wrapper = \
+ base.QueueFileWrapper(self.q_in, self.q_out, self.prompt)
+ queue_file_wrapper.bufsize = 5
+ queue_file_wrapper.write("pipeline>")
+ queue_file_wrapper.close()
+ self.assertIsNone(queue_file_wrapper.clear())
+ self.assertIsNotNone(queue_file_wrapper.q_out.empty())
+
+ def test_close(self):
+ queue_file_wrapper = \
+ base.QueueFileWrapper(self.q_in, self.q_out, self.prompt)
+ self.assertIsNone(queue_file_wrapper.close())
+
+ def test_read(self):
+ queue_file_wrapper = \
+ base.QueueFileWrapper(self.q_in, self.q_out, self.prompt)
+ queue_file_wrapper.q_in.put("pipeline>")
+ self.assertEqual("pipeline>", queue_file_wrapper.read(20))
+
+ def test_write(self):
+ queue_file_wrapper = \
+ base.QueueFileWrapper(self.q_in, self.q_out, self.prompt)
+ queue_file_wrapper.write("pipeline>")
+ self.assertIsNotNone(queue_file_wrapper.q_out.empty())
+
+
+class TestGenericVNF(ut_base.BaseUnitTestCase):
+
+ def test_definition(self):
+ """Make sure that the abstract class cannot be instantiated"""
+ with self.assertRaises(TypeError) as exc:
+ # pylint: disable=abstract-class-instantiated
+ base.GenericVNF('vnf1', VNFD['vnfd:vnfd-catalog']['vnfd'][0],
+ 'task_id')
+
+ msg = ("Can't instantiate abstract class GenericVNF with abstract "
+ "methods collect_kpi, instantiate, scale, start_collect, "
+ "stop_collect, terminate, wait_for_instantiate")
+
+ self.assertEqual(msg, str(exc.exception))
+
+
+class GenericTrafficGenTestCase(ut_base.BaseUnitTestCase):
+
+ def test_definition(self):
+ """Make sure that the abstract class cannot be instantiated"""
+ vnfd = VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ name = 'vnf1'
+ with self.assertRaises(TypeError) as exc:
+ # pylint: disable=abstract-class-instantiated
+ base.GenericTrafficGen(name, vnfd, 'task_id')
+ msg = ("Can't instantiate abstract class GenericTrafficGen with "
+ "abstract methods collect_kpi, instantiate, run_traffic, "
+ "scale, terminate")
+ self.assertEqual(msg, str(exc.exception))
+
+ def test_get_mq_producer_id(self):
+ vnfd = {'benchmark': {'kpi': mock.ANY},
+ 'vdu': [{'external-interface': 'ext_int'}]
+ }
+ tg = _DummyGenericTrafficGen('name', vnfd, 'task_id')
+ tg._mq_producer = mock.Mock()
+ tg._mq_producer.id = 'fake_id'
+ self.assertEqual('fake_id', tg.get_mq_producer_id())
+
+
+class TrafficGeneratorProducerTestCase(ut_base.BaseUnitTestCase):
+
+ @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+ @mock.patch.object(oslo_messaging, 'RPCClient')
+ @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+ return_value='rpc_transport')
+ @mock.patch.object(cfg, 'CONF')
+ def test__init(self, mock_config, mock_transport, mock_rpcclient,
+ mock_target):
+ _id = uuid.uuid1().int
+ tg_producer = base.TrafficGeneratorProducer(_id)
+ mock_transport.assert_called_once_with(
+ mock_config, url='rabbit://yardstick:yardstick@localhost:5672/')
+ mock_target.assert_called_once_with(topic=messaging.TOPIC_TG,
+ fanout=True,
+ server=messaging.SERVER)
+ mock_rpcclient.assert_called_once_with('rpc_transport', 'rpc_target')
+ self.assertEqual(_id, tg_producer._id)
+ self.assertEqual(messaging.TOPIC_TG, tg_producer._topic)
+
+ @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+ @mock.patch.object(oslo_messaging, 'RPCClient')
+ @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+ return_value='rpc_transport')
+ @mock.patch.object(payloads, 'TrafficGeneratorPayload',
+ return_value='tg_pload')
+ def test_tg_method_started(self, mock_tg_payload, *args):
+ tg_producer = base.TrafficGeneratorProducer(uuid.uuid1().int)
+ with mock.patch.object(tg_producer, 'send_message') as mock_message:
+ tg_producer.tg_method_started(version=10)
+
+ mock_message.assert_called_once_with(messaging.TG_METHOD_STARTED,
+ 'tg_pload')
+ mock_tg_payload.assert_called_once_with(version=10, iteration=0,
+ kpi={})
+
+ @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+ @mock.patch.object(oslo_messaging, 'RPCClient')
+ @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+ return_value='rpc_transport')
+ @mock.patch.object(payloads, 'TrafficGeneratorPayload',
+ return_value='tg_pload')
+ def test_tg_method_finished(self, mock_tg_payload, *args):
+ tg_producer = base.TrafficGeneratorProducer(uuid.uuid1().int)
+ with mock.patch.object(tg_producer, 'send_message') as mock_message:
+ tg_producer.tg_method_finished(version=20)
+
+ mock_message.assert_called_once_with(messaging.TG_METHOD_FINISHED,
+ 'tg_pload')
+ mock_tg_payload.assert_called_once_with(version=20, iteration=0,
+ kpi={})
+
+ @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target')
+ @mock.patch.object(oslo_messaging, 'RPCClient')
+ @mock.patch.object(oslo_messaging, 'get_rpc_transport',
+ return_value='rpc_transport')
+ @mock.patch.object(payloads, 'TrafficGeneratorPayload',
+ return_value='tg_pload')
+ def test_tg_method_iteration(self, mock_tg_payload, *args):
+ tg_producer = base.TrafficGeneratorProducer(uuid.uuid1().int)
+ with mock.patch.object(tg_producer, 'send_message') as mock_message:
+ tg_producer.tg_method_iteration(100, version=30, kpi={'k': 'v'})
+
+ mock_message.assert_called_once_with(messaging.TG_METHOD_ITERATION,
+ 'tg_pload')
+ mock_tg_payload.assert_called_once_with(version=30, iteration=100,
+ kpi={'k': 'v'})
+
+
+class GenericVNFConsumerTestCase(ut_base.BaseUnitTestCase):
+
+ def test__init(self):
+ endpoints = 'endpoint_1'
+ _ids = [uuid.uuid1().int]
+ gvnf_consumer = base.GenericVNFConsumer(_ids, endpoints)
+ self.assertEqual(_ids, gvnf_consumer._ids)
+ self.assertEqual([endpoints], gvnf_consumer._endpoints)
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py
new file mode 100644
index 000000000..32f5b758d
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py
@@ -0,0 +1,412 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from copy import deepcopy
+import time
+
+import mock
+import unittest
+
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.common import utils
+from yardstick.common import process
+from yardstick.network_services.vnf_generic.vnf import cgnapt_vnf
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+from yardstick.network_services.nfvi import resource
+
+
+TEST_FILE_YAML = 'nsb_test_case.yaml'
+name = 'vnf__0'
+
+
+class TestCgnaptApproxSetupEnvHelper(unittest.TestCase):
+
+ def test__generate_ip_from_pool(self):
+
+ _ip = '1.2.3.4'
+ ip = cgnapt_vnf.CgnaptApproxSetupEnvHelper._generate_ip_from_pool(_ip)
+ self.assertEqual(next(ip), _ip)
+ self.assertEqual(next(ip), '1.2.4.4')
+ self.assertEqual(next(ip), '1.2.5.4')
+
+ def test__update_cgnat_script_file(self):
+
+ sample = """\
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+link 0 down
+link 0 config {port0_local_ip} {port0_prefixlen}
+link 0 up
+link 1 down
+link 1 config {port1_local_ip} {port1_prefixlen}
+link 1 up
+"""
+ header = "This is a header"
+
+ out = cgnapt_vnf.CgnaptApproxSetupEnvHelper._update_cgnat_script_file(
+ header, sample.splitlines())
+ self.assertNotIn("This is a header", out)
+
+ def test__get_cgnapt_config(self):
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.port_pairs.uplink_ports = [{"name": 'a'}, {"name": "b"}, {"name": "c"}]
+
+ helper = cgnapt_vnf.CgnaptApproxSetupEnvHelper(
+ vnfd_helper, mock.Mock(), mock.Mock())
+ result = helper._get_cgnapt_config()
+ self.assertIsNotNone(result)
+
+ def test_scale(self):
+ helper = cgnapt_vnf.CgnaptApproxSetupEnvHelper(
+ mock.Mock(), mock.Mock(), mock.Mock())
+ with self.assertRaises(NotImplementedError):
+ helper.scale()
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open')
+ @mock.patch.object(utils, 'find_relative_file')
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig')
+ @mock.patch.object(utils, 'open_relative_file')
+ def test_build_config(self, *args):
+ vnfd_helper = mock.Mock()
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.vnf_cfg = {'lb_config': 'HW'}
+ scenario_helper.options = {}
+ scenario_helper.all_options = {}
+
+ cgnat_approx_setup_helper = cgnapt_vnf.CgnaptApproxSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+
+ cgnat_approx_setup_helper.ssh_helper.provision_tool = mock.Mock(return_value='tool_path')
+ cgnat_approx_setup_helper.ssh_helper.all_ports = mock.Mock()
+ cgnat_approx_setup_helper.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1])
+ expected = 'sudo tool_path -p 0x3 -f /tmp/cgnapt_config -s /tmp/cgnapt_script --hwlb 3'
+ self.assertEqual(cgnat_approx_setup_helper.build_config(), expected)
+
+
+@mock.patch.object(sample_vnf, 'Process')
+class TestCgnaptApproxVnf(unittest.TestCase):
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{'short-name': 'VpeVnf',
+ 'vdu':
+ [{'routing_table':
+ [{'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'},
+ {'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'}],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl':
+ [{'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'},
+ {'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'}],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface':
+ [{'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02'},
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'},
+ {'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01'},
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'}]}],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface':
+ {'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1'},
+ 'benchmark':
+ {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
+ 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
+ {'type': 'VPORT', 'name': 'xe1'}],
+ 'id': 'CgnaptApproxVnf', 'name': 'VPEVnfSsh'}]}}
+
+ SCENARIO_CFG = {
+ 'options': {
+ 'packetsize': 64,
+ 'traffic_type': 4,
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1',
+ },
+ 'vnf__0': {
+ 'napt': 'dynamic',
+ 'vnf_config': {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config':
+ '1C/1T',
+ 'worker_threads': 1,
+ },
+ },
+ 'flow': {'count': 1,
+ 'dst_ip': [{'tg__1': 'xe0'}],
+ 'public_ip': [''],
+ 'src_ip': [{'tg__0': 'xe0'}]},
+ },
+ 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
+ 'task_path': '/tmp',
+ 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
+ 'runner': {
+ 'object': 'NetworkServiceTestCase',
+ 'interval': 35,
+ 'output_filename': '/tmp/yardstick.out',
+ 'runner_id': 74476,
+ 'duration': 400,
+ 'type': 'Duration',
+ },
+ 'traffic_profile': 'ipv4_throughput_acl.yaml',
+ 'type': 'NSPerf',
+ 'nodes': {
+ 'tg__1': 'trafficgen_1.yardstick',
+ 'tg__0': 'trafficgen_0.yardstick',
+ 'vnf__0': 'vnf.yardstick',
+ },
+ 'topology': 'vpe-tg-topology-baremetal.yaml',
+ }
+
+ context_cfg = {'nodes': {'tg__2':
+ {'member-vnf-index': '3',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_2.yardstick',
+ 'vnfd-id-ref': 'tg__2',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens513f0',
+ 'vld_id': cgnapt_vnf.CgnaptApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.20',
+ 'dst_mac': '00:00:00:00:00:01',
+ 'local_mac': '00:00:00:00:00:03',
+ 'dst_ip': '152.16.40.19',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens513f1',
+ 'netmask': '255.255.255.0',
+ 'network': '202.16.100.0',
+ 'local_ip': '202.16.100.20',
+ 'local_mac': '00:1e:67:d0:60:5d',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.1',
+ 'dpdk_port_num': 1}},
+ 'password': 'r00t',
+ 'VNF model': 'l3fwd_vnf.yaml',
+ 'user': 'root'},
+ 'tg__1':
+ {'member-vnf-index': '1',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_1.yardstick',
+ 'vnfd-id-ref': 'tg__1',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens785f0',
+ 'vld_id': cgnapt_vnf.CgnaptApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.20',
+ 'dst_mac': '00:00:00:00:00:02',
+ 'local_mac': '00:00:00:00:00:04',
+ 'dst_ip': '152.16.100.19',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens785f1',
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.21',
+ 'local_mac': '00:00:00:00:00:01',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1}},
+ 'password': 'r00t',
+ 'VNF model': 'tg_rfc2544_tpl.yaml',
+ 'user': 'root'},
+ 'vnf__0':
+ {'name': 'vnf.yardstick',
+ 'vnfd-id-ref': 'vnf__0',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens786f0',
+ 'vld_id': cgnapt_vnf.CgnaptApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.19',
+ 'dst_mac': '00:00:00:00:00:04',
+ 'local_mac': '00:00:00:00:00:02',
+ 'dst_ip': '152.16.100.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens786f1',
+ 'vld_id': cgnapt_vnf.CgnaptApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.19',
+ 'dst_mac': '00:00:00:00:00:03',
+ 'local_mac': '00:00:00:00:00:01',
+ 'dst_ip': '152.16.40.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1}},
+ 'routing_table':
+ [{'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'network': '152.16.100.20',
+ 'if': 'xe0'},
+ {'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'network': '152.16.40.20',
+ 'if': 'xe1'}],
+ 'member-vnf-index': '2',
+ 'host': '1.2.1.1',
+ 'role': 'vnf',
+ 'user': 'root',
+ 'nd_route_tbl':
+ [{'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'},
+ {'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'}],
+ 'password': 'r00t',
+ 'VNF model': 'cgnapt_vnf.yaml'}}}
+
+ def setUp(self):
+ self.scenario_cfg = deepcopy(self.SCENARIO_CFG)
+
+ def test___init__(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
+ self.assertIsNone(cgnapt_approx_vnf._vnf_process)
+
+ @mock.patch.object(process, 'check_if_process_failed')
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ def test_collect_kpi(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
+ cgnapt_approx_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {cgnapt_approx_vnf.name: "mock"}
+ }
+ cgnapt_approx_vnf._vnf_process = mock.MagicMock(
+ **{"is_alive.return_value": True, "exitcode": None})
+ cgnapt_approx_vnf.q_in = mock.MagicMock()
+ cgnapt_approx_vnf.q_out = mock.MagicMock()
+ cgnapt_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ cgnapt_approx_vnf.resource = mock.Mock(
+ autospec=resource.ResourceProfile)
+ result = {
+ 'physical_node': 'mock_node',
+ 'packets_dropped': 0,
+ 'packets_fwd': 0,
+ 'packets_in': 0
+ }
+ with mock.patch.object(cgnapt_approx_vnf, 'get_stats',
+ return_value=''):
+ self.assertEqual(result, cgnapt_approx_vnf.collect_kpi())
+
+ @mock.patch.object(time, 'sleep')
+ def test_vnf_execute_command(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
+ cgnapt_approx_vnf.q_in = mock.Mock()
+ cgnapt_approx_vnf.q_out = mock.Mock()
+ cgnapt_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ self.assertEqual("", cgnapt_approx_vnf.vnf_execute('quit'))
+
+ def test_get_stats(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
+ with mock.patch.object(cgnapt_approx_vnf, 'vnf_execute') as mock_exec:
+ mock_exec.return_value = 'output'
+ self.assertEqual('output', cgnapt_approx_vnf.get_stats())
+
+ mock_exec.assert_called_once_with('p cgnapt stats')
+
+ def test_run_vcgnapt(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
+ cgnapt_approx_vnf.ssh_helper = mock.Mock()
+ cgnapt_approx_vnf.setup_helper = mock.Mock()
+ with mock.patch.object(cgnapt_approx_vnf, '_build_config'), \
+ mock.patch.object(cgnapt_approx_vnf, '_build_run_kwargs'):
+ cgnapt_approx_vnf._run()
+
+ cgnapt_approx_vnf.ssh_helper.run.assert_called_once()
+ cgnapt_approx_vnf.setup_helper.kill_vnf.assert_called_once()
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server')
+ def test_instantiate(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
+ cgnapt_approx_vnf.deploy_helper = mock.MagicMock()
+ cgnapt_approx_vnf.resource_helper = mock.MagicMock()
+ cgnapt_approx_vnf._build_config = mock.MagicMock()
+ self.scenario_cfg['vnf_options'] = {'acl': {'cfg': "",
+ 'rules': ""}}
+ cgnapt_approx_vnf.q_out.put("pipeline>")
+ cgnapt_vnf.WAIT_TIME = 3
+ self.scenario_cfg.update({"nodes": {"vnf__0": ""}})
+ with mock.patch.object(cgnapt_approx_vnf, '_start_vnf'):
+ self.assertIsNone(cgnapt_approx_vnf.instantiate(
+ self.scenario_cfg, self.context_cfg))
+
+ @mock.patch.object(time, 'sleep')
+ def test__vnf_up_post(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ self.scenario_cfg['options'][name]['napt'] = 'static'
+ cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
+ cgnapt_approx_vnf.vnf_execute = mock.Mock()
+ cgnapt_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
+ with mock.patch.object(cgnapt_approx_vnf, 'setup_helper') as \
+ mock_setup_helper:
+ mock_setup_helper._generate_ip_from_pool.return_value = ['ip1']
+ mock_setup_helper._get_cgnapt_config.return_value = ['gw_ip1']
+ cgnapt_approx_vnf._vnf_up_post()
+
+ def test__vnf_up_post_short(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id')
+ cgnapt_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
+ cgnapt_approx_vnf._vnf_up_post()
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py
new file mode 100644
index 000000000..3b095647c
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py
@@ -0,0 +1,2378 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from itertools import repeat, chain
+import os
+import socket
+import time
+
+import mock
+import unittest
+
+from yardstick.common import utils
+from yardstick.network_services import constants
+from yardstick.network_services.vnf_generic.vnf import base as vnf_base
+from yardstick.network_services.vnf_generic.vnf import prox_helpers
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+
+
+class TestCoreTuple(unittest.TestCase):
+ def test___init__(self):
+ core_tuple = prox_helpers.CoreSocketTuple('core 5s6')
+ self.assertEqual(core_tuple.core_id, 5)
+ self.assertEqual(core_tuple.socket_id, 6)
+ self.assertFalse(core_tuple.is_hyperthread())
+
+ core_tuple = prox_helpers.CoreSocketTuple('core 5s6h')
+ self.assertEqual(core_tuple.core_id, 5)
+ self.assertEqual(core_tuple.socket_id, 6)
+ self.assertTrue(core_tuple.is_hyperthread())
+
+ def test___init__negative(self):
+ bad_inputs = [
+ '',
+ '5',
+ '5s',
+ '6h',
+ '5s6',
+ 'core',
+ 'core h',
+ 'core 5s',
+ 'core 5 6',
+ 'core 5 6h',
+ 'core 5d6',
+ 'core 5d6h',
+ 1,
+ 2.3,
+ [],
+ {},
+ object(),
+ ]
+
+ for bad_input in bad_inputs:
+ with self.assertRaises(ValueError):
+ prox_helpers.CoreSocketTuple(bad_input)
+
+ def test_find_in_topology(self):
+ topology_in = {
+ 6: {
+ 5: {
+ 'key1': ['a', 'b'],
+ 'key2': ['c', 'd'],
+ },
+ },
+ }
+
+ core_tuple = prox_helpers.CoreSocketTuple('core 5s6')
+
+ expected = 'a'
+ result = core_tuple.find_in_topology(topology_in)
+ self.assertEqual(result, expected)
+
+ core_tuple = prox_helpers.CoreSocketTuple('core 5s6h')
+
+ expected = 'c'
+ result = core_tuple.find_in_topology(topology_in)
+ self.assertEqual(result, expected)
+
+ def test_find_in_topology_negative(self):
+ core_tuple = prox_helpers.CoreSocketTuple('core 6s5')
+ with self.assertRaises(ValueError):
+ # no socket key
+ core_tuple.find_in_topology({})
+
+ with self.assertRaises(ValueError):
+ # no core key
+ core_tuple.find_in_topology({5: {}})
+
+ with self.assertRaises(ValueError):
+ # no first value (as needed by non-hyperthread core)
+ core_tuple.find_in_topology({5: {6: {'key1': []}}})
+
+ core_tuple = prox_helpers.CoreSocketTuple('core 6s5h')
+ with self.assertRaises(ValueError):
+ # no second value (as needed by hyperthread core)
+ core_tuple.find_in_topology({5: {6: {'key1': ['e']}}})
+
+
+class TestTotStatsTuple(unittest.TestCase):
+ def test___new___negative(self):
+ with self.assertRaises(TypeError):
+ # no values
+ prox_helpers.TotStatsTuple()
+
+ with self.assertRaises(TypeError):
+ # one, non-integer value
+ prox_helpers.TotStatsTuple('a')
+
+ with self.assertRaises(TypeError):
+ # too many values
+ prox_helpers.TotStatsTuple(3, 4, 5, 6, 7)
+
+
+class TestProxTestDataTuple(unittest.TestCase):
+ def test___init__(self):
+ prox_test_data = prox_helpers.ProxTestDataTuple(
+ 1, 2, 3, 4, 5, 6, 7, 8, 9)
+ self.assertEqual(prox_test_data.tolerated, 1)
+ self.assertEqual(prox_test_data.tsc_hz, 2)
+ self.assertEqual(prox_test_data.delta_rx, 3)
+ self.assertEqual(prox_test_data.delta_tx, 4)
+ self.assertEqual(prox_test_data.delta_tsc, 5)
+ self.assertEqual(prox_test_data.latency, 6)
+ self.assertEqual(prox_test_data.rx_total, 7)
+ self.assertEqual(prox_test_data.tx_total, 8)
+ self.assertEqual(prox_test_data.requested_pps, 9)
+
+ def test_properties(self):
+ prox_test_data = prox_helpers.ProxTestDataTuple(
+ 1, 2, 3, 4, 5, 6, 7, 8, 9)
+ self.assertEqual(prox_test_data.pkt_loss, 12.5)
+ self.assertEqual(prox_test_data.tx_mpps, 1.6 / 1e6)
+ self.assertEqual(prox_test_data.can_be_lost, 0)
+ self.assertEqual(prox_test_data.drop_total, 1)
+ self.assertFalse(prox_test_data.success)
+
+ prox_test_data = prox_helpers.ProxTestDataTuple(
+ 10, 2, 3, 4, 5, 6, 997, 998, 9)
+ self.assertTrue(prox_test_data.success)
+
+ def test_pkt_loss_zero_division(self):
+ prox_test_data = prox_helpers.ProxTestDataTuple(
+ 1, 2, 3, 4, 5, 6, 7, 0, 9)
+ self.assertEqual(prox_test_data.pkt_loss, 100.0)
+
+ def test_get_samples(self):
+ prox_test_data = prox_helpers.ProxTestDataTuple(
+ 1, 2, 3, 4, 5, [6.1, 6.9, 6.4], 7, 8, 9)
+
+ expected = {
+ "Throughput": 1.2 / 1e6,
+ "DropPackets": 12.5,
+ "CurrentDropPackets": 12.5,
+ "RequestedTxThroughput": 9 / 1e6,
+ "TxThroughput": 1.6 / 1e6,
+ "RxThroughput": 1.2 / 1e6,
+ "PktSize": 64,
+ "PortSample": 1,
+ "LatencyMin": 6.1,
+ "LatencyMax": 6.9,
+ "LatencyAvg": 6.4,
+ }
+ result = prox_test_data.get_samples(64, port_samples={"PortSample": 1})
+ self.assertDictEqual(result, expected)
+
+ expected = {
+ "Throughput": 1.2 / 1e6,
+ "DropPackets": 0.123,
+ "CurrentDropPackets": 0.123,
+ "RequestedTxThroughput": 9 / 1e6,
+ "TxThroughput": 1.6 / 1e6,
+ "RxThroughput": 1.2 / 1e6,
+ "PktSize": 64,
+ "LatencyMin": 6.1,
+ "LatencyMax": 6.9,
+ "LatencyAvg": 6.4,
+ }
+ result = prox_test_data.get_samples(64, 0.123)
+ self.assertDictEqual(result, expected)
+
+ @mock.patch('yardstick.LOG_RESULT', create=True)
+ def test_log_data(self, mock_logger):
+ my_mock_logger = mock.MagicMock()
+ prox_test_data = prox_helpers.ProxTestDataTuple(
+ 1, 2, 3, 4, 5, [6.1, 6.9, 6.4], 7, 8, 9)
+ prox_test_data.log_data()
+
+ my_mock_logger.debug.assert_not_called()
+ mock_logger.debug.assert_not_called()
+
+ mock_logger.debug.reset_mock()
+ prox_test_data.log_data(my_mock_logger)
+ my_mock_logger.assert_not_called()
+ mock_logger.debug.assert_not_called()
+
+
+class TestPacketDump(unittest.TestCase):
+ PAYLOAD = "payload"
+
+ def test__init__(self):
+ prox_helpers.PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD)
+
+ def test___str__(self):
+ expected = '<PacketDump port: port_id payload: {}>'.format(self.PAYLOAD)
+ dump1 = prox_helpers.PacketDump(
+ "port_id", len(self.PAYLOAD), self.PAYLOAD)
+ self.assertEqual(str(dump1), expected)
+
+ def test_port_id(self):
+ p = prox_helpers.PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD)
+ self.assertEqual(p.port_id, "port_id")
+
+ def test_data_len(self):
+ p = prox_helpers.PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD)
+ self.assertEqual(p.data_len, len(self.PAYLOAD))
+
+ def test_payload(self):
+ p = prox_helpers.PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD)
+ self.assertEqual(p.payload(), self.PAYLOAD)
+
+ self.assertEqual(p.payload(3), self.PAYLOAD[3:])
+
+ self.assertEqual(p.payload(end=3), self.PAYLOAD[:4])
+
+ self.assertEqual(p.payload(2, 4), self.PAYLOAD[2:5])
+
+
+PACKET_DUMP_1 = """\
+pktdump,3,11
+hello world
+"""
+
+PACKET_DUMP_2 = """\
+pktdump,3,11
+hello world
+pktdump,2,9
+brown fox jumped over
+pktdump,4,8
+lazy
+dog
+"""
+
+PACKET_DUMP_NON_1 = """\
+not_a_dump,1,2
+other data
+"""
+
+PACKET_DUMP_MIXED_1 = """\
+pktdump,3,11
+hello world
+not_a_dump,1,2
+other data
+"""
+
+PACKET_DUMP_BAD_1 = """\
+pktdump,one,12
+bad port id
+"""
+
+PACKET_DUMP_BAD_2 = """\
+pktdump,3,twelve
+bad data length
+"""
+
+PACKET_DUMP_BAD_3 = """\
+pktdump,3
+no data length value
+"""
+
+
+class TestProxSocketHelper(unittest.TestCase):
+
+ def setUp(self):
+ self._mock_time_sleep = mock.patch.object(time, 'sleep')
+ self.mock_time_sleep = self._mock_time_sleep.start()
+ self.addCleanup(self._stop_mocks)
+
+ def _stop_mocks(self):
+ self._mock_time_sleep.stop()
+
+ @mock.patch.object(prox_helpers, 'socket')
+ def test___init__(self, mock_socket):
+ expected = mock_socket.socket()
+ prox = prox_helpers.ProxSocketHelper()
+ result = prox._sock
+ self.assertEqual(result, expected)
+
+ def test_connect(self):
+ mock_sock = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_sock)
+ prox.connect('10.20.30.40', 23456)
+ mock_sock.connect.assert_called_once()
+
+ def test_get_sock(self):
+ mock_sock = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_sock)
+ result = prox.get_socket()
+ self.assertIs(result, mock_sock)
+
+ # TODO(elfoley): Split this into three tests
+ @mock.patch.object(prox_helpers, 'select')
+ def test_get_data(self, mock_select):
+ mock_select.select.side_effect = [[1], [0]]
+ mock_socket = mock.MagicMock()
+ mock_recv = mock_socket.recv()
+ mock_recv.decode.return_value = ""
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ ret = prox.get_data()
+ self.assertEqual(ret, "")
+ self.assertEqual(len(prox._pkt_dumps), 0)
+
+ mock_select.select.reset_mock()
+ mock_select.select.side_effect = chain([['a'], ['']], repeat([1], 3))
+ mock_recv.decode.return_value = PACKET_DUMP_1
+ ret = prox.get_data()
+ self.assertEqual(mock_select.select.call_count, 2)
+ self.assertEqual(ret, 'pktdump,3,11')
+ self.assertEqual(len(prox._pkt_dumps), 1)
+
+ mock_select.select.reset_mock()
+ mock_select.select.side_effect = chain([[object()], [None]], repeat([1], 3))
+ mock_recv.decode.return_value = PACKET_DUMP_2
+ ret = prox.get_data()
+ self.assertEqual(mock_select.select.call_count, 1)
+ self.assertEqual(ret, 'jumped over')
+ self.assertEqual(len(prox._pkt_dumps), 3)
+
+ def test__parse_socket_data_mixed_data(self):
+ prox = prox_helpers.ProxSocketHelper(mock.MagicMock())
+ ret, _ = prox._parse_socket_data(PACKET_DUMP_NON_1, False)
+ self.assertEqual(ret, 'not_a_dump,1,2')
+ self.assertEqual(len(prox._pkt_dumps), 0)
+
+ ret, _ = prox._parse_socket_data(PACKET_DUMP_MIXED_1, False)
+ self.assertEqual(ret, 'not_a_dump,1,2')
+ self.assertEqual(len(prox._pkt_dumps), 1)
+
+ def test__parse_socket_data_bad_data(self):
+ prox = prox_helpers.ProxSocketHelper(mock.MagicMock())
+ with self.assertRaises(ValueError):
+ prox._parse_socket_data(PACKET_DUMP_BAD_1, False)
+
+ with self.assertRaises(ValueError):
+ prox._parse_socket_data(PACKET_DUMP_BAD_2, False)
+
+ ret, _ = prox._parse_socket_data(PACKET_DUMP_BAD_3, False)
+ self.assertEqual(ret, 'pktdump,3')
+
+ def test__parse_socket_data_pkt_dump_only(self):
+ prox = prox_helpers.ProxSocketHelper(mock.MagicMock())
+ ret, _ = prox._parse_socket_data('', True)
+ self.assertFalse(ret)
+
+ ret, _ = prox._parse_socket_data(PACKET_DUMP_1, True)
+ self.assertTrue(ret)
+
+ ret, _ = prox._parse_socket_data(PACKET_DUMP_2, True)
+ self.assertTrue(ret)
+
+ def test_put_command(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.put_command("data")
+ mock_socket.sendall.assert_called_once()
+
+ def test_put_command_socket_error(self):
+ mock_socket = mock.MagicMock()
+ mock_socket.sendall.side_effect = OSError
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.put_command("data")
+ mock_socket.sendall.assert_called_once()
+
+ def test_get_packet_dump(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox._pkt_dumps = []
+ self.assertIsNone(prox.get_packet_dump())
+
+ prox._pkt_dumps = [234]
+ self.assertEqual(prox.get_packet_dump(), 234)
+ self.assertEqual(prox._pkt_dumps, [])
+
+ def test_stop_all_reset(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.stop_all_reset()
+ mock_socket.sendall.assert_called()
+
+ def test_stop_all(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.stop_all()
+ mock_socket.sendall.assert_called()
+
+ def test_stop(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.stop([3, 4, 5], 16)
+ mock_socket.sendall.assert_called()
+
+ def test_start_all(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.start_all()
+ mock_socket.sendall.assert_called()
+
+ def test_start(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.start([3, 4, 5])
+ mock_socket.sendall.assert_called()
+
+ def test_reset_stats(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.reset_stats()
+ mock_socket.sendall.assert_called()
+
+ def test_set_pkt_size(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.set_pkt_size([3, 4, 5], 1024)
+ self.assertEqual(mock_socket.sendall.call_count, 3)
+
+ def test_set_value(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.set_value([3, 4, 5], 10, 20, 30)
+ self.assertEqual(mock_socket.sendall.call_count, 3)
+
+ def test_reset_values(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.reset_values([3, 4, 5])
+ self.assertEqual(mock_socket.sendall.call_count, 3)
+
+ def test_set_speed(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.set_speed([3, 4, 5], 1000)
+ self.assertEqual(mock_socket.sendall.call_count, 3)
+
+ def test_slope_speed(self):
+ core_data = [
+ {
+ 'cores': [3, 4, 5],
+ 'speed': 1000,
+ },
+ {
+ 'cores': [9, 10, 11],
+ 'speed': '500.5',
+ },
+ ]
+
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.set_speed = set_speed = mock.MagicMock()
+ prox.slope_speed(core_data, 5)
+ self.assertEqual(set_speed.call_count, 20)
+
+ set_speed.reset_mock()
+ prox.slope_speed(core_data, 5, 5)
+ self.assertEqual(set_speed.call_count, 10)
+
+ def test_set_pps(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.set_pps([3, 4, 5], 1000, 512)
+ self.assertEqual(mock_socket.sendall.call_count, 3)
+
+ def test_lat_stats(self):
+ latency_output = [
+ '1, 2 , 3', # has white space
+ '4,5', # too short
+ '7,8,9,10.5,11', # too long with float, but float is in unused portion
+ 'twelve,13,14', # value as English word
+ '15,16.2,17', # float in used portion
+ ]
+
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(side_effect=latency_output)
+
+ expected = (
+ {
+ 3: 1,
+ 5: 7,
+ },
+ {
+ 3: 2,
+ 5: 8,
+ },
+ {
+ 3: 3,
+ 5: 9,
+ },
+ )
+ result = prox.lat_stats([3, 4, 5, 6, 7], 16)
+ self.assertEqual(mock_socket.sendall.call_count, 5)
+ self.assertEqual(result, expected)
+
+ def test_get_all_tot_stats_error(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(return_value='3,4,5')
+ expected = [0, 0, 0, 0]
+ result = prox.get_all_tot_stats()
+ self.assertEqual(result, expected)
+
+ def test_get_all_tot_stats(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(return_value='3,4,5,6')
+ expected = 3, 4, 5, 6
+ result = prox.get_all_tot_stats()
+ self.assertEqual(result, expected)
+
+ def test_hz(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(return_value='3,4,5,6')
+ expected = 6
+ result = prox.hz()
+ self.assertEqual(result, expected)
+
+ def test_core_stats(self):
+ core_stats = [
+ '3,4,5,6',
+ '7,8,9,10,NaN',
+ '11,12,13,14,15',
+ ]
+
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(side_effect=core_stats)
+ expected = 21, 24, 27, 14
+ result = prox.core_stats([3, 4, 5], 16)
+ self.assertEqual(result, expected)
+
+ @mock.patch.object(prox_helpers.LOG, 'error')
+ def test_multi_port_stats(self, *args):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(return_value='0,1,2,3,4,5;1,1,2,3,4,5')
+ expected = [[0, 1, 2, 3, 4, 5], [1, 1, 2, 3, 4, 5]]
+ result = prox.multi_port_stats([0, 1])
+ self.assertEqual(result, expected)
+
+ prox.get_data = mock.MagicMock(return_value='0,1,2,3,4,5;1,1,2,3,4,5')
+ result = prox.multi_port_stats([0])
+ expected = [0]
+ self.assertEqual(result, expected)
+
+ prox.get_data = mock.MagicMock(return_value='0,1,2,3;1,1,2,3,4,5')
+ result = prox.multi_port_stats([0, 1])
+ expected = [0] * 2
+ self.assertEqual(result, expected)
+
+ prox.get_data = mock.MagicMock(return_value='99,1,2,3,4,5;1,1,2,3,4,5')
+ expected = [0] * 2
+ result = prox.multi_port_stats([0, 1])
+ self.assertEqual(result, expected)
+
+
+ def test_port_stats(self):
+ port_stats = [
+ ','.join(str(n) for n in range(3, 15)),
+ ','.join(str(n) for n in range(8, 32, 2)),
+ ','.join(str(n) for n in range(5, 89, 7)),
+ ]
+
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(side_effect=port_stats)
+ expected = [16, 26, 36, 46, 56, 66, 76, 86, 96, 106, 116, 126]
+ result = prox.port_stats([3, 4, 5])
+ self.assertEqual(result, expected)
+
+ def test_measure_tot_stats(self):
+ start_tot = 3, 4, 5, 6
+ end_tot = 7, 9, 11, 13
+ delta_tot = 4, 5, 6, 7
+
+ get_data_output = [
+ ','.join(str(n) for n in start_tot),
+ ','.join(str(n) for n in end_tot),
+ ]
+
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(side_effect=get_data_output)
+ expected = {
+ 'start_tot': start_tot,
+ 'end_tot': end_tot,
+ 'delta': delta_tot,
+ }
+ with prox.measure_tot_stats() as result:
+ pass
+ self.assertEqual(result, expected)
+
+ def test_tot_stats(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(return_value='3,4,5,6')
+ expected = 3, 4, 5
+ result = prox.tot_stats()
+ self.assertEqual(result, expected)
+
+ def test_tot_ierrors(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.get_data = mock.MagicMock(return_value='3,4,5,6')
+ expected = 3, 3
+ result = prox.tot_ierrors()
+ self.assertEqual(result, expected)
+
+ def test_set_count(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.set_count(432, [3, 4, 5])
+ self.assertEqual(mock_socket.sendall.call_count, 3)
+
+ def test_dump_rx(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.dump_rx(3, 5, 8)
+ mock_socket.sendall.assert_called_once()
+
+ def test_quit(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.quit()
+ mock_socket.sendall.assert_called()
+
+ def test_force_quit(self):
+ mock_socket = mock.MagicMock()
+ prox = prox_helpers.ProxSocketHelper(mock_socket)
+ prox.force_quit()
+ mock_socket.sendall.assert_called()
+
+
+class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase):
+
+ VNFD0 = {
+ 'short-name': 'ProxVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'description': 'PROX approximation using DPDK',
+ 'name': 'proxvnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'id': 'proxvnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': 'uplink_0',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.19',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0',
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': 'downlink_0',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1',
+ },
+ ],
+ },
+ ],
+ 'description': 'PROX approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'proxvnf-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1',
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'id': 'ProxApproxVnf',
+ 'name': 'ProxVnf',
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD0,
+ ],
+ },
+ }
+
+ def test_global_section(self):
+ setup_helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ mock.MagicMock(), mock.MagicMock(), mock.MagicMock())
+
+ setup_helper._prox_config_data = [('a', [])]
+
+ with self.assertRaises(KeyError):
+ _ = setup_helper.global_section
+
+ global_section = (
+ 'global', [
+ ('not_name', 'other data'),
+ ('name_not', 'more data'),
+ ('name', 'prox type'),
+ ],
+ )
+
+ setup_helper._prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1', []),
+ ('core 2', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ global_section,
+ ('core 3', [
+ ('index', 5),
+ ('mode', 'gen'),
+ ('name', 'tagged'),
+ ]),
+ ('section3', [
+ ('key1', 'value1'),
+ ('key2', 'value2'),
+ ('key3', 'value3'),
+ ]),
+ ('core 4', [
+ ('index', 7),
+ ('mode', 'gen'),
+ ('name', 'udp'),
+ ]),
+ ]
+
+ result = setup_helper.global_section
+ self.assertEqual(result, global_section[1])
+
+ def test_find_in_section(self):
+ setup_helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ mock.MagicMock(), mock.MagicMock(), mock.MagicMock())
+
+ setup_helper._prox_config_data = [
+ ('global', [
+ ('not_name', 'other data'),
+ ('name_not', 'more data'),
+ ('name', 'prox type'),
+ ]),
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1', []),
+ ('core 2', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ ('core 3', [
+ ('index', 5),
+ ('mode', 'gen'),
+ ('name', 'tagged'),
+ ]),
+ ('section3', [
+ ('key1', 'value1'),
+ ('key2', 'value2'),
+ ('key3', 'value3'),
+ ]),
+ ('core 4', [
+ ('index', 7),
+ ('mode', 'gen'),
+ ('name', 'udp'),
+ ]),
+ ]
+
+ expected = 'value3'
+ result = setup_helper.find_in_section('section3', 'key3')
+ self.assertEqual(result, expected)
+
+ expected = 'default value'
+ result = setup_helper.find_in_section('section3', 'key4', 'default value')
+ self.assertEqual(result, expected)
+
+ with self.assertRaises(KeyError):
+ setup_helper.find_in_section('section4', 'key1')
+
+ with self.assertRaises(KeyError):
+ setup_helper.find_in_section('section1', 'key1')
+
+ def test__replace_quoted_with_value(self):
+ # empty string
+ input_str = ''
+ expected = ''
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _replace_quoted_with_value(input_str, 'cat'))
+ self.assertEqual(result, expected)
+
+ # no quoted substring
+ input_str = 'lion tiger bear'
+ expected = 'lion tiger bear'
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _replace_quoted_with_value(input_str, 'cat'))
+ self.assertEqual(result, expected)
+
+ # partially quoted substring
+ input_str = 'lion "tiger bear'
+ expected = 'lion "tiger bear'
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _replace_quoted_with_value(input_str, 'cat'))
+ self.assertEqual(result, expected)
+
+ # one quoted substring
+ input_str = 'lion "tiger" bear'
+ expected = 'lion "cat" bear'
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _replace_quoted_with_value(input_str, 'cat'))
+ self.assertEqual(result, expected)
+
+ # two quoted substrings
+ input_str = 'lion "tiger" bear "shark" whale'
+ expected = 'lion "cat" bear "shark" whale'
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _replace_quoted_with_value(input_str, 'cat'))
+ self.assertEqual(result, expected)
+
+ # two quoted substrings, both replaced
+ input_str = 'lion "tiger" bear "shark" whale'
+ expected = 'lion "cat" bear "cat" whale'
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _replace_quoted_with_value(input_str, 'cat', 2))
+ self.assertEqual(result, expected)
+
+ def test__get_tx_port(self):
+ # no data
+ input_data = {'section1': []}
+ expected = -1
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _get_tx_port('section1', input_data))
+ self.assertEqual(result, expected)
+
+ # data for other section
+ input_data = {
+ 'section1': [],
+ 'section2': [
+ ('rx port', '3'),
+ ('tx port', '4'),
+ ],
+ }
+ expected = -1
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _get_tx_port('section1', input_data))
+ self.assertEqual(result, expected)
+
+ # data for section
+ input_data['section1'] = section1 = [
+ ('rx port', '4', 'more', 432),
+ ('tx port', '3'),
+ ]
+ expected = 3
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _get_tx_port('section1', input_data))
+ self.assertEqual(result, expected)
+
+ # more data for section,
+ section1.extend([
+ ('rx port', '2'),
+ ('tx port', '1', 'and more', 234),
+ ])
+ expected = 1
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ _get_tx_port('section1', input_data))
+ self.assertEqual(result, expected)
+
+ # TODO(elfoley): Split this into several smaller tests
+ def test_write_prox_config(self):
+ input_data = {}
+ expected = ''
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ write_prox_config(input_data))
+ self.assertEqual(result, expected)
+
+ input_data = [
+ [
+ 'section1',
+ [],
+ ],
+ ]
+ expected = '[section1]'
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ write_prox_config(input_data))
+ self.assertEqual(result, expected)
+
+ input_data = [
+ [
+ 'section1',
+ [],
+ ],
+ [
+ 'section2',
+ [
+ ['key1', 'value1'],
+ ['__name__', 'not this one'],
+ ['key2', None],
+ ['key3', 234],
+ ['key4', 'multi-line\nvalue'],
+ ],
+ ],
+ ]
+ expected = os.linesep.join([
+ '[section1]',
+ '[section2]',
+ 'key1=value1',
+ 'key2',
+ 'key3=234',
+ 'key4=multi-line\n\tvalue',
+ ])
+ result = (prox_helpers.ProxDpdkVnfSetupEnvHelper.
+ write_prox_config(input_data))
+ self.assertEqual(result, expected)
+
+ def test_prox_config_data(self):
+ setup_helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ mock.MagicMock(), mock.MagicMock(), mock.MagicMock())
+
+ setup_helper.config_queue = config_queue = mock.MagicMock()
+ config_queue.get.return_value = expected = [('s', [('a', 3), ('b', 45)])]
+
+ result = setup_helper.prox_config_data
+ self.assertEqual(result, expected)
+
+ @mock.patch.object(utils, 'find_relative_file')
+ def test_build_config_file_no_additional_file(self, mock_find_path):
+ vnf1 = {
+ 'prox_args': {'-c': ""},
+ 'prox_path': 'd',
+ 'prox_config': 'e/f',
+ 'prox_generate_parameter': False,
+ }
+
+ mock_find_path.side_effect = ['1', '2']
+
+ vnfd_helper = mock.MagicMock()
+ ssh_helper = mock.MagicMock()
+ scenario_helper = sample_vnf.ScenarioHelper('vnf1')
+ scenario_helper.scenario_cfg = {
+ 'task_path': 'a/b',
+ 'options': {
+ 'vnf1': vnf1,
+ },
+ }
+
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ helper.copy_to_target = mock.MagicMock(return_value='3')
+ helper.generate_prox_config_file = mock.MagicMock(return_value='4')
+ helper.upload_prox_config = mock.MagicMock(return_value='5')
+
+ self.assertEqual(helper.additional_files, {})
+ self.assertNotEqual(helper._prox_config_data, '4')
+ self.assertNotEqual(helper.remote_path, '5')
+ helper.build_config_file()
+ self.assertEqual(helper.additional_files, {})
+ self.assertEqual(helper._prox_config_data, '4')
+ self.assertEqual(helper.remote_path, '5')
+
+ @mock.patch.object(utils, 'find_relative_file')
+ def test_build_config_file_additional_file_string(self, mock_find_path):
+ vnf1 = {
+ 'prox_args': {'-c': ""},
+ 'prox_path': 'd',
+ 'prox_config': 'e/f',
+ 'prox_files': 'g/h.i',
+ 'prox_generate_parameter': True,
+ }
+
+ mock_find_path.side_effect = ['1', '2']
+ vnfd_helper = mock.MagicMock()
+ ssh_helper = mock.MagicMock()
+ scenario_helper = sample_vnf.ScenarioHelper('vnf1')
+ scenario_helper.scenario_cfg = {
+ 'task_path': 'a/b',
+ 'options': {
+ 'vnf1': vnf1,
+ },
+ }
+
+ vnfd_helper.port_pairs.all_ports = ['xe0', 'xe1', 'xe2', 'xe3']
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ helper.copy_to_target = mock.MagicMock(side_effect=['33', '34', '35'])
+ helper.generate_prox_config_file = mock.MagicMock(return_value='44')
+ helper.upload_prox_config = mock.MagicMock(return_value='55')
+
+ self.assertEqual(helper.additional_files, {})
+ expected = {'h.i': '33'}
+ helper.build_config_file()
+ self.assertDictEqual(helper.additional_files, expected)
+
+ @mock.patch.object(utils, 'find_relative_file')
+ def test_build_config_file_additional_file(self, mock_find_path):
+ vnf1 = {
+ 'prox_args': {'-c': ""},
+ 'prox_path': 'd',
+ 'prox_config': 'e/f',
+ 'prox_files': [
+ 'g/h.i',
+ 'j/k/l',
+ 'm_n',
+ ],
+ }
+
+ mock_find_path.side_effect = ['1', '2'] + [str(i) for i in range(len(vnf1['prox_files']))]
+ vnfd_helper = mock.MagicMock()
+ ssh_helper = mock.MagicMock()
+ scenario_helper = sample_vnf.ScenarioHelper('vnf1')
+ scenario_helper.scenario_cfg = {
+ 'task_path': 'a/b',
+ 'options': {
+ 'vnf1': vnf1,
+ },
+ }
+
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ helper.copy_to_target = mock.MagicMock(side_effect=['33', '34', '35'])
+ helper.generate_prox_config_file = mock.MagicMock(return_value='44')
+ helper.upload_prox_config = mock.MagicMock(return_value='55')
+
+ self.assertEqual(helper.additional_files, {})
+ self.assertNotEqual(helper._prox_config_data, '44')
+ self.assertNotEqual(helper.remote_path, '55')
+ expected = {'h.i': '33', 'l': '34', 'm_n': '35'}
+ helper.build_config_file()
+ self.assertDictEqual(helper.additional_files, expected)
+ self.assertEqual(helper._prox_config_data, '44')
+ self.assertEqual(helper.remote_path, '55')
+
+ def test_build_config(self):
+ vnf1 = {
+ 'prox_args': {'-f': ""},
+ 'prox_path': '/opt/nsb_bin/prox',
+ 'prox_config': 'configs/gen_l2fwd-2.cfg',
+ 'prox_files': [
+ 'g/h.i',
+ 'j/k/l',
+ 'm_n',
+ ],
+ }
+
+ vnfd_helper = mock.Mock()
+ ssh_helper = mock.Mock()
+ ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/prox'
+ scenario_helper = sample_vnf.ScenarioHelper('vnf1')
+ scenario_helper.scenario_cfg = {
+ 'task_path': 'a/b',
+ 'options': {
+ 'vnf1': vnf1,
+ },
+ }
+
+ expected = ("sudo bash -c 'cd /opt/nsb_bin; /opt/nsb_bin/prox -o cli "
+ "-f -f /tmp/prox.cfg '")
+
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ with mock.patch.object(helper, 'build_config_file') as mock_cfg_file:
+ helper.remote_path = '/tmp/prox.cfg'
+ prox_cmd = helper.build_config()
+ self.assertEqual(prox_cmd, expected)
+ mock_cfg_file.assert_called_once()
+
+ def test__insert_additional_file(self):
+ vnfd_helper = mock.MagicMock()
+ ssh_helper = mock.MagicMock()
+ scenario_helper = mock.MagicMock()
+
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ helper.additional_files = {"ipv4.lua": "/tmp/ipv4.lua"}
+ res = helper._insert_additional_file('dofile("ipv4.lua")')
+ self.assertEqual(res, 'dofile("/tmp/ipv4.lua")')
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.ConfigParser')
+ def test_generate_prox_config_file(self, mock_parser_type):
+ def init(*args):
+ if sections_data:
+ args[-1].extend(sections_data)
+ return mock.MagicMock()
+
+ sections_data = []
+
+ mock_parser_type.side_effect = init
+
+ vnfd_helper = vnf_base.VnfdHelper(self.VNFD0)
+ ssh_helper = mock.MagicMock()
+ scenario_helper = mock.MagicMock()
+
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ helper.additional_files = {}
+
+ expected = []
+ result = helper.generate_prox_config_file('a/b')
+ self.assertEqual(result, expected)
+
+ helper.additional_files = {"ipv4.lua": "/tmp/ipv4.lua"}
+
+ helper.remote_prox_file_name = 'remote'
+ sections_data = [
+ [
+ 'lua',
+ [
+ ['dofile("ipv4.lua")', ''],
+ ],
+ ],
+ [
+ 'port 0',
+ [
+ ['ip', ''],
+ ['mac', 'foo'],
+ ['dst mac', '@@1'],
+ ['tx port', '1'],
+ ],
+ ],
+ [
+ 'port 2',
+ [
+ ['ip', ''],
+ ['$sut_mac0', '@@dst_mac0'],
+ ['tx port', '0'],
+ ['single', '@'],
+ ['user_table', 'dofile("ipv4.lua")'],
+ ['missing_addtional_file', 'dofile("nosuch")'],
+ ],
+ ],
+ ]
+
+ expected = [
+ [
+ 'lua',
+ [
+ ['dofile("/tmp/ipv4.lua")', ''],
+ ],
+ ],
+ [
+ 'port 0',
+ [
+ ['ip', ''],
+ ['mac', 'hardware'],
+ ['dst mac', '00:00:00:00:00:03'],
+ ['tx port', '1'],
+ ],
+ ],
+ [
+ 'port 2',
+ [
+ ['ip', ''],
+ ['$sut_mac0', '00 00 00 00 00 04'],
+ ['tx port', '0'],
+ ['single', '@'],
+ ['user_table', 'dofile("/tmp/ipv4.lua")'],
+ ['missing_addtional_file', 'dofile("nosuch")'],
+ ],
+ ],
+ ]
+ result = helper.generate_prox_config_file('/c/d/e')
+ self.assertEqual(result, expected, str(result))
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.ConfigParser')
+ def test_generate_prox_config_file_negative(self, mock_parser_type):
+ def init(*args):
+ args[-1].update(sections_data)
+ return mock.MagicMock()
+
+ sections_data = {}
+
+ mock_parser_type.side_effect = init
+
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.interfaces = []
+ ssh_helper = mock.MagicMock()
+ scenario_helper = mock.MagicMock()
+
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ helper.additional_files = {}
+ helper.remote_prox_file_name = 'remote'
+ vnfd_helper.interfaces = [
+ {
+ 'virtual-interface': {
+ 'dpdk_port_num': 3,
+ 'dst_mac': '00:00:00:de:ad:88',
+ },
+ },
+ {
+ 'virtual-interface': {
+ 'dpdk_port_num': 5,
+ 'dst_mac': '00:00:00:de:ad:ff',
+ },
+ },
+ {
+ 'virtual-interface': {
+ 'dpdk_port_num': 7,
+ 'dst_mac': '00:00:00:de:ad:ff',
+ },
+ },
+ ]
+ sections_data = {
+ 'port 3': [
+ ['ip', ''],
+ ['mac', 'foo'],
+ ['dst mac', ''],
+ ],
+ 'port 5': [
+ ['ip', ''],
+ ['dst mac', ''],
+ ['tx port', '0'],
+ ['???', 'dofile "here" 23'],
+ ],
+ }
+
+ with self.assertRaises(Exception):
+ helper.generate_prox_config_file('a/b')
+
+ def test_put_string_to_file(self):
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.interfaces = []
+ ssh_helper = mock.MagicMock()
+ scenario_helper = mock.MagicMock()
+
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+
+ expected = 'a/b'
+ result = helper.put_string_to_file('my long string', 'a/b')
+ self.assertEqual(result, expected)
+
+ def test_copy_to_target(self):
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.interfaces = []
+ ssh_helper = mock.MagicMock()
+ scenario_helper = mock.MagicMock()
+
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ expected = '/tmp/c'
+ result = helper.copy_to_target('a/b', 'c')
+ self.assertEqual(result, expected)
+
+ def test_upload_prox_config(self):
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.interfaces = []
+ ssh_helper = mock.MagicMock()
+ scenario_helper = mock.MagicMock()
+
+ helper = prox_helpers.ProxDpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ helper.write_prox_config = mock.MagicMock(return_value='a long string')
+ expected = '/tmp/a'
+ result = helper.upload_prox_config('a', {})
+ self.assertEqual(result, expected)
+
+
+class TestProxResourceHelper(unittest.TestCase):
+
+ VNFD0 = {
+ 'short-name': 'ProxVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'description': 'PROX approximation using DPDK',
+ 'name': 'proxvnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'id': 'proxvnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': 'uplink_0',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.19',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0',
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': 'downlink_0',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1',
+ },
+ ],
+ },
+ ],
+ 'description': 'PROX approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'proxvnf-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1',
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'id': 'ProxApproxVnf',
+ 'name': 'ProxVnf',
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD0,
+ ],
+ },
+ }
+
+ def test_find_pci(self):
+ input_str_list = [
+ 'no target here',
+ 'nor here',
+ 'and still not',
+ ]
+ result = prox_helpers.ProxResourceHelper.find_pci('target',
+ input_str_list)
+ self.assertFalse(result)
+
+ input_str_list = [
+ 'no target here',
+ 'nor here',
+ 'this is a target',
+ 'did we miss it',
+ ]
+ result = prox_helpers.ProxResourceHelper.find_pci('target',
+ input_str_list)
+ self.assertTrue(result)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.RETRY_INTERVAL', 0)
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.ProxSocketHelper')
+ def test_sut(self, *args):
+ helper = prox_helpers.ProxResourceHelper(mock.MagicMock())
+ self.assertIsNone(helper.client)
+ result = helper.sut
+ self.assertIsNotNone(result)
+ self.assertIs(result, helper.client)
+ self.assertIs(result, helper.sut)
+
+ def test_test_type(self):
+ setup_helper = mock.MagicMock()
+ setup_helper.find_in_section.return_value = expected = 'prox type'
+
+ helper = prox_helpers.ProxResourceHelper(setup_helper)
+
+ self.assertIsNone(helper._test_type)
+ self.assertEqual(helper.test_type, expected)
+ self.assertEqual(helper._test_type, expected)
+ self.assertEqual(helper.test_type, expected)
+
+ def test_collect_collectd_kpi(self):
+ helper = prox_helpers.ProxResourceHelper(mock.MagicMock())
+ helper.resource = resource = mock.MagicMock()
+
+ resource.check_if_system_agent_running.return_value = 0, '1234'
+ resource.amqp_collect_nfvi_kpi.return_value = 543
+ resource.check_if_system_agent_running.return_value = (0, None)
+
+ expected = {'core': 543}
+ result = helper.collect_collectd_kpi()
+ self.assertDictEqual(result, expected)
+
+ def test_collect_kpi(self):
+ helper = prox_helpers.ProxResourceHelper(mock.MagicMock())
+ helper._queue = queue = mock.MagicMock()
+ helper._result = {'z': 123}
+ helper.resource = resource = mock.MagicMock()
+
+ resource.check_if_system_agent_running.return_value = 0, '1234'
+ resource.amqp_collect_nfvi_kpi.return_value = 543
+ resource.check_if_system_agent_running.return_value = (0, None)
+
+ queue.empty.return_value = False
+ queue.get.return_value = {'a': 789}
+
+ expected = {'z': 123, 'a': 789, 'collect_stats': {'core': 543}}
+ result = helper.collect_kpi()
+ self.assertDictEqual(result, expected)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time')
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.ProxSocketHelper')
+ def test__connect(self, mock_socket_helper_type, *args):
+ client = mock_socket_helper_type()
+ client.connect.side_effect = chain(repeat(socket.error, 5), [None])
+
+ setup_helper = mock.MagicMock()
+ setup_helper.vnfd_helper.interfaces = []
+
+ helper = prox_helpers.ProxResourceHelper(setup_helper)
+
+ result = helper._connect()
+ self.assertIs(result, client)
+
+ client.connect.side_effect = chain(repeat(socket.error, 65), [None])
+
+ with self.assertRaises(Exception):
+ helper._connect()
+
+ def test_run_traffic(self):
+ setup_helper = mock.MagicMock()
+ helper = prox_helpers.ProxResourceHelper(setup_helper)
+ traffic_profile = mock.MagicMock(**{"done": True})
+ helper.run_traffic(traffic_profile)
+ self.assertEqual(helper._terminated.value, 1)
+
+ def test__run_traffic_once(self):
+ setup_helper = mock.MagicMock()
+ helper = prox_helpers.ProxResourceHelper(setup_helper)
+ traffic_profile = mock.MagicMock(**{"done": True})
+ helper._run_traffic_once(traffic_profile)
+ self.assertEqual(helper._terminated.value, 1)
+
+ def test_start_collect(self):
+ setup_helper = mock.MagicMock()
+ helper = prox_helpers.ProxResourceHelper(setup_helper)
+ helper.resource = resource = mock.MagicMock()
+ self.assertIsNone(helper.start_collect())
+ resource.start.assert_called_once()
+
+ def test_terminate(self):
+ setup_helper = mock.MagicMock()
+ helper = prox_helpers.ProxResourceHelper(setup_helper)
+ with self.assertRaises(NotImplementedError):
+ helper.terminate()
+
+ def test_up_post(self):
+ setup_helper = mock.MagicMock()
+ helper = prox_helpers.ProxResourceHelper(setup_helper)
+ helper.client = expected = mock.MagicMock()
+ result = helper.up_post()
+ self.assertEqual(result, expected)
+
+ def test_execute(self):
+ setup_helper = mock.MagicMock()
+ helper = prox_helpers.ProxResourceHelper(setup_helper)
+ helper.client = mock.MagicMock()
+
+ expected = helper.client.my_command()
+ result = helper.execute('my_command')
+ self.assertEqual(result, expected)
+
+ # TODO(elfoley): Make this a separate test: test_execute_no_client
+ helper.client = object()
+
+ result = helper.execute('my_command')
+ self.assertIsNone(result)
+
+
+class TestProxDataHelper(unittest.TestCase):
+
+ def test_totals_and_pps(self):
+ pkt_size = 180
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.port_pairs.all_ports = list(range(4))
+
+ sut = mock.MagicMock()
+ sut.multi_port_stats.return_value = [[0, 1, 2, 3, 4, 5], [1, 1, 2, 3, 4, 5],
+ [2, 1, 2, 3, 4, 5], [3, 1, 2, 3, 4, 5]]
+
+ data_helper = prox_helpers.ProxDataHelper(
+ vnfd_helper, sut, pkt_size, 25, None,
+ constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS)
+
+ self.assertEqual(data_helper.rx_total, 4)
+ self.assertEqual(data_helper.tx_total, 8)
+ self.assertEqual(data_helper.requested_pps, 6.25e6)
+
+ def test_samples(self):
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.ports_iter.return_value = [('xe0', 0), ('xe1', 1)]
+
+ sut = mock.MagicMock()
+ sut.multi_port_stats.return_value = [[0, 1, 2, 3, 4, 5], [1, 11, 12, 3, 4, 5]]
+
+ data_helper = prox_helpers.ProxDataHelper(
+ vnfd_helper, sut, None, None, None, None)
+
+ expected = {
+ 'xe0': {
+ 'in_packets': 1,
+ 'out_packets': 2,
+ },
+ 'xe1': {
+ 'in_packets': 11,
+ 'out_packets': 12,
+ },
+ }
+ result = data_helper.samples
+ self.assertDictEqual(result, expected)
+
+ def test___enter__(self):
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.port_pairs.all_ports = list(range(4))
+ vnfd_helper.ports_iter.return_value = [('xe1', 3), ('xe2', 7)]
+
+ sut = mock.MagicMock()
+ sut.port_stats.return_value = list(range(10))
+
+ data_helper = prox_helpers.ProxDataHelper(vnfd_helper, sut, None, None,
+ 5.4, constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS)
+ data_helper._totals_and_pps = 12, 32, 4.5
+ data_helper.tsc_hz = 9.8
+ data_helper.measured_stats = {
+ 'delta': prox_helpers.TotStatsTuple(6.1, 6.2, 6.3, 6.4)}
+ data_helper.latency = 7
+
+ self.assertIsNone(data_helper.result_tuple)
+ self.assertEqual(data_helper.line_speed, 10000000000)
+
+ expected = prox_helpers.ProxTestDataTuple(
+ 5.4, 9.8, 6.1, 6.2, 6.3, 7, 12, 32, 4.5)
+ with data_helper:
+ pass
+
+ result = data_helper.result_tuple
+ self.assertEqual(result, expected)
+
+ data_helper.make_tuple()
+ self.assertIs(data_helper.result_tuple, result)
+
+ def test___enter___negative(self):
+ vnfd_helper = mock.MagicMock()
+
+ data_helper = prox_helpers.ProxDataHelper(
+ vnfd_helper, None, None, None, None, None)
+
+ vnfd_helper.port_pairs.all_ports = []
+ with self.assertRaises(AssertionError):
+ with data_helper:
+ pass
+
+ vnfd_helper.port_pairs.all_ports = [0, 1, 2]
+ with self.assertRaises(AssertionError):
+ with data_helper:
+ pass
+
+ def test_measure_tot_stats(self):
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.port_pairs.all_ports = list(range(4))
+
+ start = (3, 4, 1, 2)
+ end = (9, 7, 6, 8)
+
+ sut = prox_helpers.ProxSocketHelper(mock.MagicMock())
+ sut.get_all_tot_stats = mock.MagicMock(side_effect=[start, end])
+
+ data_helper = prox_helpers.ProxDataHelper(
+ vnfd_helper, sut, None, None, 5.4, None)
+
+ self.assertIsNone(data_helper.measured_stats)
+
+ expected = {
+ 'start_tot': start,
+ 'end_tot': end,
+ 'delta': prox_helpers.TotStatsTuple(6, 3, 5, 6),
+ }
+ with data_helper.measure_tot_stats():
+ pass
+
+ self.assertEqual(data_helper.measured_stats, expected)
+
+ def test_capture_tsc_hz(self):
+ vnfd_helper = mock.MagicMock()
+ vnfd_helper.port_pairs.all_ports = list(range(4))
+
+ sut = mock.MagicMock()
+ sut.hz.return_value = '54.6'
+
+ data_helper = prox_helpers.ProxDataHelper(
+ vnfd_helper, sut, None, None, None, None)
+
+ self.assertIsNone(data_helper.tsc_hz)
+
+ expected = 54.6
+ data_helper.capture_tsc_hz()
+ self.assertEqual(data_helper.tsc_hz, expected)
+
+
+class TestProxProfileHelper(unittest.TestCase):
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.utils')
+ def test_get_cls(self, mock_utils):
+ mock_type1 = mock.MagicMock()
+ mock_type1.__prox_profile_type__ = 'another_type'
+ mock_type2 = mock.MagicMock()
+ mock_type2.__prox_profile_type__ = 'my_type'
+ mock_utils.itersubclasses.return_value = [mock_type1, mock_type2]
+
+ self.assertEqual(prox_helpers.ProxProfileHelper.get_cls('my_type'),
+ mock_type2)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.utils')
+ def test_get_cls_default(self, mock_utils):
+ mock_utils.itersubclasses.return_value = []
+ prox_helpers.ProxProfileHelper.get_cls('my_type')
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.SocketTopology')
+ def test_cpu_topology(self, mock_socket_topology):
+ mock_socket_topology.parse_cpuinfo.return_value = 432
+
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.ssh_helper.execute.return_value = 0, 'output', ''
+
+ helper = prox_helpers.ProxProfileHelper(resource_helper)
+ self.assertIsNone(helper._cpu_topology)
+ result = helper.cpu_topology
+ self.assertEqual(result, 432)
+ self.assertIs(result, helper._cpu_topology)
+ self.assertIs(result, helper.cpu_topology)
+
+ # TODO(elfoley): Split this test; there are two sets of inputs/outputs
+ def test_test_cores(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.prox_config_data = []
+
+ helper = prox_helpers.ProxProfileHelper(resource_helper)
+ helper._cpu_topology = []
+
+ expected = []
+ result = helper.test_cores
+ self.assertEqual(result, expected)
+
+ resource_helper.setup_helper.prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1s3', []),
+ ('core 2s5', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ ('core 3s1', [
+ ('index', 5),
+ ('mode', 'gen'),
+ ]),
+ ('core 4s9h', [
+ ('index', 7),
+ ('mode', 'gen'),
+ ]),
+ ]
+
+ helper = prox_helpers.ProxProfileHelper(resource_helper)
+ helper._cpu_topology = {
+ 1: {
+ 3: {
+ 'key1': (23, 32),
+ 'key2': (12, 21),
+ 'key3': (44, 33),
+ },
+ },
+ 9: {
+ 4: {
+ 'key1': (44, 32),
+ 'key2': (23, 21),
+ 'key3': (12, 33),
+ },
+ },
+ }
+
+ self.assertIsNone(helper._test_cores)
+ expected = [3, 4]
+ result = helper.test_cores
+ self.assertEqual(result, expected)
+ self.assertIs(result, helper._test_cores)
+ self.assertIs(result, helper.test_cores)
+
+ # TODO(elfoley): Split this test; there are two sets of inputs/outputs
+ def test_latency_cores(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.prox_config_data = []
+
+ helper = prox_helpers.ProxProfileHelper(resource_helper)
+ helper._cpu_topology = []
+
+ expected = []
+ result = helper.latency_cores
+ self.assertEqual(result, expected)
+
+ resource_helper.setup_helper.prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1s3', []),
+ ('core 2s5', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ ('core 3s1', [
+ ('index', 5),
+ ('mode', 'lat'),
+ ]),
+ ('core 4s9h', [
+ ('index', 7),
+ ('mode', 'lat'),
+ ]),
+ ]
+
+ helper = prox_helpers.ProxProfileHelper(resource_helper)
+ helper._cpu_topology = {
+ 1: {
+ 3: {
+ 'key1': (23, 32),
+ 'key2': (12, 21),
+ 'key3': (44, 33),
+ },
+ },
+ 9: {
+ 4: {
+ 'key1': (44, 32),
+ 'key2': (23, 21),
+ 'key3': (12, 33),
+ },
+ },
+ }
+
+ self.assertIsNone(helper._latency_cores)
+ expected = [3, 4]
+ result = helper.latency_cores
+ self.assertEqual(result, expected)
+ self.assertIs(result, helper._latency_cores)
+ self.assertIs(result, helper.latency_cores)
+
+ def test_all_rx_cores(self):
+ helper = prox_helpers.ProxBngProfileHelper(mock.MagicMock())
+ helper._latency_cores = expected = [3, 4, 6]
+ helper._test_cores = [5, 2, 1]
+
+ result = helper.all_rx_cores
+ self.assertEqual(result, expected)
+
+ def test_get_cores(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1', []),
+ ('core 2', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ ('core 3', [
+ ('index', 5),
+ ('mode', 'gen'),
+ ]),
+ ('core 4', [
+ ('index', 7),
+ ('mode', 'gen'),
+ ]),
+ ]
+
+ helper = prox_helpers.ProxProfileHelper(resource_helper)
+ helper._cpu_topology = {
+ 0: {
+ 1: {
+ 5: (5, 1, 0)
+ },
+ 2: {
+ 6: (6, 2, 0)
+ },
+ 3: {
+ 7: (7, 3, 0)
+ },
+ 4: {
+ 8: (8, 3, 0)
+ },
+ }
+ }
+
+ expected = [3, 4]
+ result = helper.get_cores(helper.PROX_CORE_GEN_MODE)
+ self.assertEqual(result, expected)
+
+ def test_get_latency(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.vnfd_helper.interfaces = []
+
+ helper = prox_helpers.ProxProfileHelper(resource_helper)
+ helper._latency_cores = []
+
+ expected = []
+ result = helper.get_latency()
+ self.assertEqual(result, expected)
+
+ helper._latency_cores = [1, 2]
+ helper.client = mock.MagicMock()
+
+ expected = helper.sut.lat_stats()
+ result = helper.get_latency()
+ self.assertIs(result, expected)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time')
+ def test_traffic_context(self, *args):
+ setup_helper = mock.MagicMock()
+ setup_helper.vnfd_helper.interfaces = []
+
+ helper = prox_helpers.ProxProfileHelper(setup_helper)
+ helper._cpu_topology = {
+ 0: {
+ 1: {
+ 5: (5, 1, 0)
+ },
+ 2: {
+ 6: (6, 2, 0)
+ },
+ 3: {
+ 7: (7, 3, 0)
+ },
+ 4: {
+ 8: (8, 3, 0)
+ },
+ }
+ }
+
+ setup_helper.prox_config_data = [
+ ('global', [
+ ('not_name', 'other data'),
+ ('name_not', 'more data'),
+ ('name', helper.__prox_profile_type__),
+ ]),
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1', []),
+ ('core 2', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ ('core 3', [
+ ('index', 5),
+ ('mode', 'gen'),
+ ('name', 'tagged'),
+ ]),
+ ('core 4', [
+ ('index', 7),
+ ('mode', 'gen'),
+ ('name', 'udp'),
+ ]),
+ ]
+
+ client = mock.MagicMock()
+ client.hz.return_value = 2
+ client.port_stats.return_value = tuple(range(12))
+
+ helper.client = client
+ helper.get_latency = mock.MagicMock(return_value=[3.3, 3.6, 3.8])
+
+ helper._test_cores = [3, 4]
+
+ with helper.traffic_context(64, 1):
+ pass
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time')
+ def test_run_test(self, _):
+ resource_helper = mock.MagicMock()
+ resource_helper.step_delta = 0.4
+ resource_helper.vnfd_helper.port_pairs.all_ports = list(range(2))
+ resource_helper.sut.port_stats.return_value = list(range(10))
+
+ helper = prox_helpers.ProxProfileHelper(resource_helper)
+
+ helper.run_test(120, 5, 6.5,
+ constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS)
+
+
+class TestProxMplsProfileHelper(unittest.TestCase):
+
+ def test_mpls_cores(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1', []),
+ ('core 2', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ ('core 3', [
+ ('index', 5),
+ ('mode', 'gen'),
+ ('name', 'tagged'),
+ ]),
+ ('core 4', [
+ ('index', 7),
+ ('mode', 'gen'),
+ ('name', 'udp'),
+ ]),
+ ]
+
+ helper = prox_helpers.ProxMplsProfileHelper(resource_helper)
+ helper._cpu_topology = {
+ 0: {
+ 1: {
+ 5: (5, 1, 0)
+ },
+ 2: {
+ 6: (6, 2, 0)
+ },
+ 3: {
+ 7: (7, 3, 0)
+ },
+ 4: {
+ 8: (8, 3, 0)
+ },
+ }
+ }
+
+ expected_tagged = [3]
+ expected_plain = [4]
+ self.assertIsNone(helper._cores_tuple)
+ self.assertEqual(helper.tagged_cores, expected_tagged)
+ self.assertEqual(helper.plain_cores, expected_plain)
+ self.assertEqual(helper._cores_tuple, (expected_tagged, expected_plain))
+
+ def test_traffic_context(self):
+ setup_helper = mock.MagicMock()
+ helper = prox_helpers.ProxMplsProfileHelper(setup_helper)
+
+ with helper.traffic_context(120, 5.4):
+ pass
+
+
+class TestProxBngProfileHelper(unittest.TestCase):
+
+ def test_bng_cores(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1', []),
+ ('core 2', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ ('core 3', [
+ ('index', 5),
+ ('mode', 'gen'),
+ ('name', 'cpe'),
+ ]),
+ ('core 4', [
+ ('index', 7),
+ ('mode', 'gen'),
+ ('name', 'inet'),
+ ]),
+ ('core 6', [
+ ('index', 3),
+ ('mode', 'gen'),
+ ('name', 'arp_task'),
+ ]),
+ ('core 9', [
+ ('index', 2),
+ ('mode', 'gen'),
+ ('name', 'arp'),
+ ]),
+ ]
+
+ helper = prox_helpers.ProxBngProfileHelper(resource_helper)
+ helper._cpu_topology = {
+ 0: {
+ 1: {
+ 5: (5, 1, 0)
+ },
+ 2: {
+ 6: (6, 2, 0)
+ },
+ 3: {
+ 7: (7, 3, 0)
+ },
+ 4: {
+ 8: (8, 3, 0)
+ },
+ 6: {
+ 1: (4, 8, 0)
+ },
+ 9: {
+ 2: (3, 7, 0)
+ },
+ }
+ }
+
+ expected_cpe = [3]
+ expected_inet = [4]
+ expected_arp = [6, 9]
+ expected_arp_task = [0, 6]
+ expected_combined = (expected_cpe, expected_inet, expected_arp, expected_arp_task)
+
+ self.assertIsNone(helper._cores_tuple)
+ self.assertEqual(helper.cpe_cores, expected_cpe)
+ self.assertEqual(helper.inet_cores, expected_inet)
+ self.assertEqual(helper.arp_cores, expected_arp)
+ self.assertEqual(helper.arp_task_cores, expected_arp_task)
+ self.assertEqual(helper._cores_tuple, expected_combined)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time')
+ def test_run_test(self, _):
+ resource_helper = mock.MagicMock()
+ resource_helper.step_delta = 0.4
+ resource_helper.vnfd_helper.port_pairs.all_ports = list(range(2))
+ resource_helper.sut.port_stats.return_value = list(range(10))
+
+ helper = prox_helpers.ProxBngProfileHelper(resource_helper)
+
+ helper.run_test(120, 5, 6.5,
+ constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS)
+
+ # negative pkt_size is the only way to make ratio > 1
+ helper.run_test(-1000, 5, 6.5,
+ constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS)
+
+
+class TestProxVpeProfileHelper(unittest.TestCase):
+
+ def test_vpe_cores(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1', []),
+ ('core 2', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ ('core 3', [
+ ('index', 5),
+ ('mode', 'gen'),
+ ('name', 'cpe'),
+ ]),
+ ('core 4', [
+ ('index', 7),
+ ('mode', 'gen'),
+ ('name', 'inet'),
+ ]),
+ ]
+
+ helper = prox_helpers.ProxVpeProfileHelper(resource_helper)
+ helper._cpu_topology = {
+ 0: {
+ 1: {
+ 5: (5, 1, 0)
+ },
+ 2: {
+ 6: (6, 2, 0)
+ },
+ 3: {
+ 7: (7, 3, 0)
+ },
+ 4: {
+ 8: (8, 3, 0)
+ },
+ }
+ }
+
+ expected_cpe = [3]
+ expected_inet = [4]
+ expected_combined = (expected_cpe, expected_inet)
+
+ self.assertIsNone(helper._cores_tuple)
+ self.assertEqual(helper.cpe_cores, expected_cpe)
+ self.assertEqual(helper.inet_cores, expected_inet)
+ self.assertEqual(helper._cores_tuple, expected_combined)
+
+ def test_vpe_ports(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('port 3', [
+ ('index', '5'),
+ ('name', 'cpe'),
+ ('mac', 'hardware'),
+ ]),
+ ('port 4', [
+ ('index', '7'),
+ ('name', 'inet'),
+ ('mac', 'hardware'),
+ ]),
+ ]
+
+ helper = prox_helpers.ProxVpeProfileHelper(resource_helper)
+ helper._port_list = {
+ 0: {
+ 1: {
+ 5: 'cpe'
+ },
+ 2: {
+ 6: 'inet'
+ },
+ 3: {
+ 7: 'cpe'
+ },
+ 4: {
+ 8: 'inet'
+ },
+ }
+ }
+
+ expected_cpe = [3]
+ expected_inet = [4]
+ expected_combined = (expected_cpe, expected_inet)
+
+ self.assertIsNone(helper._ports_tuple)
+ self.assertEqual(helper.cpe_ports, expected_cpe)
+ self.assertEqual(helper.inet_ports, expected_inet)
+ self.assertEqual(helper._ports_tuple, expected_combined)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time')
+ def test_run_test(self, _):
+ resource_helper = mock.MagicMock()
+ resource_helper.step_delta = 0.4
+ resource_helper.vnfd_helper.port_pairs.all_ports = list(range(2))
+ resource_helper.sut.port_stats.return_value = list(range(10))
+
+ helper = prox_helpers.ProxVpeProfileHelper(resource_helper)
+
+ helper.run_test(120, 5, 6.5)
+ helper.run_test(-1000, 5, 6.5) # negative pkt_size is the only way to make ratio > 1
+
+
+class TestProxlwAFTRProfileHelper(unittest.TestCase):
+
+ def test_lwaftr_cores(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('core 1', []),
+ ('core 2', [
+ ('index', 8),
+ ('mode', ''),
+ ]),
+ ('core 3', [
+ ('index', 5),
+ ('mode', 'gen'),
+ ('name', 'tun'),
+ ]),
+ ('core 4', [
+ ('index', 7),
+ ('mode', 'gen'),
+ ('name', 'inet'),
+ ]),
+ ]
+
+ helper = prox_helpers.ProxlwAFTRProfileHelper(resource_helper)
+ helper._cpu_topology = {
+ 0: {
+ 1: {
+ 5: (5, 1, 0)
+ },
+ 2: {
+ 6: (6, 2, 0)
+ },
+ 3: {
+ 7: (7, 3, 0)
+ },
+ 4: {
+ 8: (8, 3, 0)
+ },
+ }
+ }
+
+ expected_tun = [3]
+ expected_inet = [4]
+ expected_combined = (expected_tun, expected_inet)
+
+ self.assertIsNone(helper._cores_tuple)
+ self.assertEqual(helper.tun_cores, expected_tun)
+ self.assertEqual(helper.inet_cores, expected_inet)
+ self.assertEqual(helper._cores_tuple, expected_combined)
+
+ def test_tun_ports(self):
+ resource_helper = mock.MagicMock()
+ resource_helper.setup_helper.prox_config_data = [
+ ('section1', []),
+ ('section2', [
+ ('a', 'b'),
+ ('c', 'd'),
+ ]),
+ ('port 3', [
+ ('index', '5'),
+ ('name', 'lwB4'),
+ ('mac', 'hardware'),
+ ]),
+ ('port 4', [
+ ('index', '7'),
+ ('name', 'inet'),
+ ('mac', 'hardware'),
+ ]),
+ ]
+
+ helper = prox_helpers.ProxlwAFTRProfileHelper(resource_helper)
+ helper._port_list = {
+ 0: {
+ 1: {
+ 5: 'lwB4'
+ },
+ 2: {
+ 6: 'inet'
+ },
+ 3: {
+ 7: 'lwB4'
+ },
+ 4: {
+ 8: 'inet'
+ },
+ }
+ }
+
+ expected_tun = [3]
+ expected_inet = [4]
+ expected_combined = (expected_tun, expected_inet)
+
+ self.assertIsNone(helper._ports_tuple)
+ self.assertEqual(helper.tun_ports, expected_tun)
+ self.assertEqual(helper.inet_ports, expected_inet)
+ self.assertEqual(helper._ports_tuple, expected_combined)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time')
+ def test_run_test(self, _):
+ resource_helper = mock.MagicMock()
+ resource_helper.step_delta = 0.4
+ resource_helper.vnfd_helper.port_pairs.all_ports = list(range(2))
+ resource_helper.sut.port_stats.return_value = list(range(10))
+
+ helper = prox_helpers.ProxlwAFTRProfileHelper(resource_helper)
+
+ helper.run_test(120, 5, 6.5)
+ helper.run_test(-1000, 5, 6.5) # negative pkt_size is the only way to make ratio > 1
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py
new file mode 100644
index 000000000..f144e8c42
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py
@@ -0,0 +1,471 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import errno
+import os
+import unittest
+import mock
+from copy import deepcopy
+
+from yardstick.tests import STL_MOCKS
+from yardstick.benchmark.contexts import base as ctx_base
+
+
+SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
+
+STLClient = mock.MagicMock()
+stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
+stl_patch.start()
+
+if stl_patch:
+ from yardstick.network_services.vnf_generic.vnf import prox_vnf
+ from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+
+
+NAME = "vnf__1"
+
+
+@mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time')
+class TestProxApproxVnf(unittest.TestCase):
+
+ VNFD0 = {
+ 'short-name': 'ProxVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'description': 'PROX approximation using DPDK',
+ 'name': 'proxvnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'id': 'proxvnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe1',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0',
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe1',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1',
+ },
+ ],
+ },
+ ],
+ 'description': 'PROX approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'proxvnf-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1',
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ 'curr_packets_fwd',
+ 'curr_packets_in'
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'ProxApproxVnf',
+ 'name': 'ProxVnf',
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD0,
+ ],
+ },
+ }
+
+ SCENARIO_CFG = {
+ 'task_path': "",
+ 'nodes': {
+ 'tg__1': 'trafficgen_1.yardstick',
+ 'vnf__1': 'vnf.yardstick'},
+ 'runner': {
+ 'duration': 600, 'type': 'Duration'},
+ 'topology': 'prox-tg-topology-2.yaml',
+ 'traffic_profile': '../../traffic_profiles/prox_binsearch.yaml',
+ 'type': 'NSPerf',
+ 'options': {
+ 'tg__1': {'prox_args': {'-e': '',
+ '-t': ''},
+ 'prox_config': 'configs/l3-gen-2.cfg',
+ 'prox_path':
+ '/root/dppd-PROX-v035/build/prox'},
+ 'vnf__1': {
+ 'prox_args': {'-t': ''},
+ 'prox_config': 'configs/l3-swap-2.cfg',
+ 'prox_path': '/root/dppd-PROX-v035/build/prox'}}}
+
+ CONTEXT_CFG = {
+ 'nodes': {
+ 'tg__2': {
+ 'member-vnf-index': '3',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_2.yardstick',
+ 'vnfd-id-ref': 'tg__2',
+ 'ip': '1.2.1.1',
+ 'interfaces': {
+ 'xe0': {
+ 'local_iface_name': 'ens513f0',
+ 'vld_id': prox_vnf.ProxApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.20',
+ 'dst_mac': '00:00:00:00:00:01',
+ 'local_mac': '00:00:00:00:00:03',
+ 'dst_ip': '152.16.40.19',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'local_iface_name': 'ens513f1',
+ 'netmask': '255.255.255.0',
+ 'network': '202.16.100.0',
+ 'local_ip': '202.16.100.20',
+ 'local_mac': '00:1e:67:d0:60:5d',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'password': 'r00t',
+ 'VNF model': 'l3fwd_vnf.yaml',
+ 'user': 'root',
+ },
+ 'tg__1': {
+ 'member-vnf-index': '1',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_1.yardstick',
+ 'vnfd-id-ref': 'tg__1',
+ 'ip': '1.2.1.1',
+ 'interfaces': {
+ 'xe0': {
+ 'local_iface_name': 'ens785f0',
+ 'vld_id': prox_vnf.ProxApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.20',
+ 'dst_mac': '00:00:00:00:00:02',
+ 'local_mac': '00:00:00:00:00:04',
+ 'dst_ip': '152.16.100.19',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'local_iface_name': 'ens785f1',
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.21',
+ 'local_mac': '00:00:00:00:00:01',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'password': 'r00t',
+ 'VNF model': 'tg_rfc2544_tpl.yaml',
+ 'user': 'root',
+ },
+ 'vnf__1': {
+ 'name': 'vnf.yardstick',
+ 'vnfd-id-ref': 'vnf__1',
+ 'ip': '1.2.1.1',
+ 'interfaces': {
+ 'xe0': {
+ 'local_iface_name': 'ens786f0',
+ 'vld_id': prox_vnf.ProxApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.19',
+ 'dst_mac': '00:00:00:00:00:04',
+ 'local_mac': '00:00:00:00:00:02',
+ 'dst_ip': '152.16.100.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'local_iface_name': 'ens786f1',
+ 'vld_id': prox_vnf.ProxApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.19',
+ 'dst_mac': '00:00:00:00:00:03',
+ 'local_mac': '00:00:00:00:00:01',
+ 'dst_ip': '152.16.40.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'routing_table': [
+ {
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'network': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'network': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'member-vnf-index': '2',
+ 'host': '1.2.1.1',
+ 'role': 'vnf',
+ 'user': 'root',
+ 'nd_route_tbl': [
+ {
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'password': 'r00t',
+ 'VNF model': 'prox_vnf.yaml',
+ },
+ },
+ }
+
+ @mock.patch(SSH_HELPER)
+ def test___init__(self, ssh, *args):
+ mock_ssh(ssh)
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
+ self.assertIsNone(prox_approx_vnf._vnf_process)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi_no_client(self, ssh, *args):
+ mock_ssh(ssh)
+
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
+ prox_approx_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {prox_approx_vnf.name: "mock"}
+ }
+ prox_approx_vnf.resource_helper = None
+ expected = {
+ 'physical_node': 'mock_node',
+ 'packets_in': 0,
+ 'packets_dropped': 0,
+ 'packets_fwd': 0,
+ 'collect_stats': {'core': {}}
+ }
+ result = prox_approx_vnf.collect_kpi()
+ self.assertEqual(result, expected)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, *args):
+ mock_ssh(ssh)
+
+ resource_helper = mock.MagicMock()
+ resource_helper.execute.return_value = [[0, 1, 2, 3, 4, 5], [1, 1, 2, 3, 4, 5],
+ [2, 1, 2, 3, 4, 5], [3, 1, 2, 3, 4, 5]]
+ resource_helper.collect_collectd_kpi.return_value = {'core': {'result': 234}}
+
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
+ prox_approx_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {prox_approx_vnf.name: "mock"}
+ }
+ prox_approx_vnf.resource_helper = resource_helper
+
+ expected = {
+ 'physical_node': 'mock_node',
+ 'packets_in': 4,
+ 'packets_dropped': 4,
+ 'packets_fwd': 8,
+ 'collect_stats': {'core': {'result': 234}},
+ }
+ result = prox_approx_vnf.collect_kpi()
+ self.assertEqual(result['packets_in'], expected['packets_in'])
+ self.assertEqual(result['packets_dropped'], expected['packets_dropped'])
+ self.assertEqual(result['packets_fwd'], expected['packets_fwd'])
+ self.assertNotEqual(result['packets_fwd'], 0)
+ self.assertNotEqual(result['packets_fwd'], 0)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi_error(self, ssh, *args):
+ mock_ssh(ssh)
+
+ resource_helper = mock.MagicMock()
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, deepcopy(self.VNFD0),
+ 'task_id')
+ prox_approx_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {prox_approx_vnf.name: "mock"}
+ }
+ prox_approx_vnf.resource_helper = resource_helper
+ prox_approx_vnf.vnfd_helper['vdu'][0]['external-interface'] = []
+ prox_approx_vnf.vnfd_helper.port_pairs.interfaces = []
+
+ with self.assertRaises(RuntimeError):
+ prox_approx_vnf.collect_kpi()
+
+ def _get_file_abspath(self, filename, *args):
+ curr_path = os.path.dirname(os.path.abspath(__file__))
+ file_path = os.path.join(curr_path, filename)
+ return file_path
+
+ @mock.patch('yardstick.common.utils.open', create=True)
+ @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.open', create=True)
+ @mock.patch('yardstick.network_services.helpers.iniparser.open', create=True)
+ @mock.patch(SSH_HELPER)
+ def test_run_prox(self, ssh, *_):
+ mock_ssh(ssh)
+
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
+ prox_approx_vnf.scenario_helper.scenario_cfg = self.SCENARIO_CFG
+ prox_approx_vnf.ssh_helper.join_bin_path.return_value = '/tool_path12/tool_file34'
+ prox_approx_vnf.setup_helper.remote_path = 'configs/file56.cfg'
+
+ expected = "sudo bash -c 'cd /tool_path12; " \
+ "/tool_path12/tool_file34 -o cli -t -f /tmp/l3-swap-2.cfg '"
+
+ prox_approx_vnf._run()
+ result = prox_approx_vnf.ssh_helper.run.call_args[0][0]
+ self.assertEqual(result, expected)
+
+ @mock.patch(SSH_HELPER)
+ def bad_test_instantiate(self, *args):
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
+ prox_approx_vnf.scenario_helper = mock.MagicMock()
+ prox_approx_vnf.setup_helper = mock.MagicMock()
+ # we can't mock super
+ prox_approx_vnf.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)
+ prox_approx_vnf.setup_helper.build_config.assert_called_once()
+
+ @mock.patch(SSH_HELPER)
+ def test_wait_for_instantiate_panic(self, ssh, *args):
+ mock_ssh(ssh, exec_result=(1, "", ""))
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
+ prox_approx_vnf._vnf_process = mock.MagicMock(**{"is_alive.return_value": True})
+ prox_approx_vnf._run_prox = mock.Mock(return_value=0)
+ prox_approx_vnf.WAIT_TIME = 0
+ prox_approx_vnf.q_out.put("PANIC")
+ with self.assertRaises(RuntimeError):
+ prox_approx_vnf.wait_for_instantiate()
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket')
+ @mock.patch(SSH_HELPER)
+ def test_terminate(self, ssh, *args):
+ mock_ssh(ssh)
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
+ prox_approx_vnf._vnf_process = mock.MagicMock()
+ prox_approx_vnf._vnf_process.terminate = mock.Mock()
+ prox_approx_vnf.ssh_helper = mock.MagicMock()
+ prox_approx_vnf.setup_helper = mock.Mock()
+ prox_approx_vnf.resource_helper = mock.MagicMock()
+
+ self.assertIsNone(prox_approx_vnf.terminate())
+
+ @mock.patch(SSH_HELPER)
+ def test__vnf_up_post(self, ssh, *args):
+ mock_ssh(ssh)
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
+ prox_approx_vnf.resource_helper = resource_helper = mock.Mock()
+
+ prox_approx_vnf._vnf_up_post()
+ resource_helper.up_post.assert_called_once()
+
+ @mock.patch(SSH_HELPER)
+ def test_vnf_execute_oserror(self, ssh, *args):
+ mock_ssh(ssh)
+ prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id')
+ prox_approx_vnf.resource_helper = resource_helper = mock.Mock()
+
+ resource_helper.execute.side_effect = OSError(errno.EPIPE, "")
+ prox_approx_vnf.vnf_execute("", _ignore_errors=True)
+
+ resource_helper.execute.side_effect = OSError(errno.ESHUTDOWN, "")
+ prox_approx_vnf.vnf_execute("", _ignore_errors=True)
+
+ resource_helper.execute.side_effect = OSError(errno.EADDRINUSE, "")
+ with self.assertRaises(OSError):
+ prox_approx_vnf.vnf_execute("", _ignore_errors=True)
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py
new file mode 100644
index 000000000..ad74145b4
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py
@@ -0,0 +1,262 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+import mock
+
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.router_vnf import RouterVNF
+
+
+TEST_FILE_YAML = 'nsb_test_case.yaml'
+SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
+
+
+name = 'vnf__1'
+
+
+class TestRouterVNF(unittest.TestCase):
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{'short-name': 'RouterVNF',
+ 'vdu':
+ [{'routing_table': [],
+ 'description': 'RouterVNF',
+ 'name': 'router-baremetal',
+ 'nd_route_tbl': [],
+ 'id': 'router-baremetal',
+ 'external-interface':
+ [{'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02'},
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'},
+ {'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01'},
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'}]}],
+ 'description': 'RouterVNF',
+ 'mgmt-interface':
+ {'vdu-id': 'router-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1'},
+ 'benchmark':
+ {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
+ 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
+ {'type': 'VPORT', 'name': 'xe1'}],
+ 'id': 'RouterVNF', 'name': 'VPEVnfSsh'}]}}
+
+ scenario_cfg = {'nodes': {'cpt__0': 'compute_0.compute_nodes',
+ 'tg__0': 'trafficgen_1.baremetal',
+ 'vnf__0': 'vnf.yardstick'},
+ 'options': {'flow': {'count': 128000,
+ 'dst_ip': ['10.0.3.26-10.0.3.105'],
+ 'dst_port': ['2001-2004'],
+ 'src_ip': ['10.0.2.26-10.0.2.105'],
+ 'src_port': ['1234-1238']},
+ 'framesize': {'downlink': {'1024B': 100},
+ 'uplink': {'1024B': 100}},
+ 'rfc2544': {'allowed_drop_rate': '0.0001 - 0.1'},
+ 'tg__0': {'queues_per_port': 7},
+ 'traffic_type': 4,
+ 'vnf__0': {'nfvi_enable': True}},
+ 'runner': {'interval': 35,
+ 'iterations': 10,
+ 'type': 'Iteration'},
+ 'topology': 'router-tg-topology.yaml',
+ 'traffic_profile': '../../traffic_profiles/ipv4_throughput.yaml',
+ 'type': 'NSPerf'}
+
+ context_cfg = {'nodes': {'tg__1':
+ {'member-vnf-index': '1',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_1.yardstick',
+ 'vnfd-id-ref': 'tg__1',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens785f0',
+ 'vld_id': RouterVNF.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.20',
+ 'dst_mac': '00:00:00:00:00:02',
+ 'local_mac': '00:00:00:00:00:04',
+ 'dst_ip': '152.16.100.19',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens785f1',
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.21',
+ 'local_mac': '00:00:00:00:00:01',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1}},
+ 'password': 'r00t',
+ 'VNF model': 'tg_rfc2544_tpl.yaml',
+ 'user': 'root'},
+ 'vnf__1':
+ {'name': 'vnf.yardstick',
+ 'vnfd-id-ref': 'vnf__1',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens786f0',
+ 'vld_id': RouterVNF.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.19',
+ 'dst_mac': '00:00:00:00:00:04',
+ 'local_mac': '00:00:00:00:00:02',
+ 'dst_ip': '152.16.100.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens786f1',
+ 'vld_id': RouterVNF.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.19',
+ 'dst_mac': '00:00:00:00:00:03',
+ 'local_mac': '00:00:00:00:00:01',
+ 'dst_ip': '152.16.40.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1}},
+ 'routing_table': [],
+ 'member-vnf-index': '2',
+ 'host': '1.2.1.1',
+ 'role': 'vnf',
+ 'user': 'root',
+ 'nd_route_tbl': [],
+ 'password': 'r00t',
+ 'VNF model': 'router_vnf.yaml'}}}
+
+ IP_SHOW_STATS_OUTPUT = """\
+2: em1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
+ link/ether d4:c9:ef:52:7c:4d brd ff:ff:ff:ff:ff:ff
+ RX: bytes packets errors dropped overrun mcast
+ 2781945429 3202213 0 0 0 30131
+ RX errors: length crc frame fifo missed
+ 0 0 0 0 0
+ TX: bytes packets errors dropped carrier collsns
+ 646221183 2145799 0 0 0 0
+ TX errors: aborted fifo window heartbeat
+ 0 0 0 0
+"""
+ STATS = {
+ 'RX:bytes': '2781945429',
+ 'RX:dropped': '0',
+ 'RX:errors': '0',
+ 'RX:mcast': '30131',
+ 'RX:overrun': '0',
+ 'RX:packets': '3202213',
+ 'RX errors:length': '0',
+ 'RX errors:crc': '0',
+ 'RX errors:frame': '0',
+ 'RX errors:fifo': '0',
+ 'RX errors:missed': '0',
+ 'TX:bytes': '646221183',
+ 'TX:carrier': '0',
+ 'TX:collsns': '0',
+ 'TX:dropped': '0',
+ 'TX:errors': '0',
+ 'TX:packets': '2145799',
+ 'TX errors:aborted': '0',
+ 'TX errors:fifo': '0',
+ 'TX errors:window': '0',
+ 'TX errors:heartbeat': '0',
+ }
+
+ def test___init__(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ router_vnf = RouterVNF(name, vnfd, 'task_id')
+ self.assertIsNone(router_vnf._vnf_process)
+
+ def test_get_stats(self):
+ stats = RouterVNF.get_stats(self.IP_SHOW_STATS_OUTPUT)
+ self.assertDictEqual(stats, self.STATS)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, *args):
+ m = mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ router_vnf = RouterVNF(name, vnfd, 'task_id')
+ router_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {router_vnf.name: "mock"}
+ }
+ router_vnf.ssh_helper = m
+ result = {
+ 'physical_node': 'mock_node',
+ 'packets_dropped': 0,
+ 'packets_fwd': 0,
+ 'packets_in': 0,
+ 'link_stats': {}
+ }
+ self.assertEqual(result, router_vnf.collect_kpi())
+
+ @mock.patch(SSH_HELPER)
+ def test_run_router(self, ssh):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ router_vnf = RouterVNF(name, vnfd, 'task_id')
+ router_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
+ router_vnf._run()
+ router_vnf.ssh_helper.drop_connection.assert_called_once()
+
+ @mock.patch.object(ctx_base, 'Context')
+ @mock.patch(SSH_HELPER)
+ def test_instantiate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ router_vnf = RouterVNF(name, vnfd, 'task_id')
+ router_vnf.WAIT_TIME = 0
+ router_vnf.INTERFACE_WAIT = 0
+ self.scenario_cfg.update({"nodes": {"vnf__1": ""}})
+ self.assertIsNone(router_vnf.instantiate(self.scenario_cfg,
+ self.context_cfg))
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch(SSH_HELPER)
+ def test_terminate(self, ssh, _):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ router_vnf = RouterVNF(name, vnfd, 'task_id')
+ router_vnf._vnf_process = mock.MagicMock()
+ router_vnf._vnf_process.terminate = mock.Mock()
+ self.assertIsNone(router_vnf.terminate())
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py
new file mode 100644
index 000000000..c35d2db35
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py
@@ -0,0 +1,1999 @@
+# Copyright (c) 2017-2018 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from copy import deepcopy
+
+import unittest
+import mock
+import six
+
+from yardstick.common import exceptions as y_exceptions
+from yardstick.common import utils
+from yardstick.network_services.nfvi.resource import ResourceProfile
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFDeployHelper
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ResourceHelper
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SetupEnvHelper
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper
+from yardstick.tests.unit.network_services.vnf_generic.vnf import test_base
+from yardstick.benchmark.contexts import base as ctx_base
+
+
+class MockError(Exception):
+ pass
+
+
+class TestVnfSshHelper(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ]
+ }
+ }
+
+ def assertAll(self, iterable, message=None):
+ self.assertTrue(all(iterable), message)
+
+ def test_get_class(self):
+ self.assertIs(VnfSshHelper.get_class(), VnfSshHelper)
+
+ @mock.patch('yardstick.ssh.paramiko')
+ def test_copy(self, _):
+ ssh_helper = VnfSshHelper(self.VNFD_0['mgmt-interface'], 'my/bin/path')
+ ssh_helper._run = mock.Mock()
+
+ ssh_helper.execute('ls')
+ self.assertTrue(ssh_helper.is_connected)
+ result = ssh_helper.copy()
+ self.assertIsInstance(result, VnfSshHelper)
+ self.assertFalse(result.is_connected)
+ self.assertEqual(result.bin_path, ssh_helper.bin_path)
+ self.assertEqual(result.host, ssh_helper.host)
+ self.assertEqual(result.port, ssh_helper.port)
+ self.assertEqual(result.user, ssh_helper.user)
+ self.assertEqual(result.password, ssh_helper.password)
+ self.assertEqual(result.key_filename, ssh_helper.key_filename)
+
+ @mock.patch('yardstick.ssh.paramiko')
+ def test_upload_config_file(self, mock_paramiko):
+ ssh_helper = VnfSshHelper(self.VNFD_0['mgmt-interface'], 'my/bin/path')
+ ssh_helper._run = mock.MagicMock()
+
+ self.assertFalse(ssh_helper.is_connected)
+ cfg_file = ssh_helper.upload_config_file('my/prefix', 'my content')
+ self.assertTrue(ssh_helper.is_connected)
+ mock_paramiko.SSHClient.assert_called_once()
+ self.assertTrue(cfg_file.startswith('/tmp'))
+
+ cfg_file = ssh_helper.upload_config_file('/my/prefix', 'my content')
+ self.assertTrue(ssh_helper.is_connected)
+ mock_paramiko.SSHClient.assert_called_once()
+ self.assertEqual(cfg_file, '/my/prefix')
+
+ def test_join_bin_path(self):
+ ssh_helper = VnfSshHelper(self.VNFD_0['mgmt-interface'], 'my/bin/path')
+
+ expected_start = 'my'
+ expected_middle_list = ['bin']
+ expected_end = 'path'
+ result = ssh_helper.join_bin_path()
+ self.assertTrue(result.startswith(expected_start))
+ self.assertAll(middle in result for middle in expected_middle_list)
+ self.assertTrue(result.endswith(expected_end))
+
+ expected_middle_list.append(expected_end)
+ expected_end = 'some_file.sh'
+ result = ssh_helper.join_bin_path('some_file.sh')
+ self.assertTrue(result.startswith(expected_start))
+ self.assertAll(middle in result for middle in expected_middle_list)
+ self.assertTrue(result.endswith(expected_end))
+
+ expected_middle_list.append('some_dir')
+ expected_end = 'some_file.sh'
+ result = ssh_helper.join_bin_path('some_dir', 'some_file.sh')
+ self.assertTrue(result.startswith(expected_start))
+ self.assertAll(middle in result for middle in expected_middle_list)
+ self.assertTrue(result.endswith(expected_end))
+
+ @mock.patch('yardstick.ssh.paramiko')
+ @mock.patch('yardstick.ssh.provision_tool')
+ def test_provision_tool(self, mock_provision_tool, mock_paramiko):
+ ssh_helper = VnfSshHelper(self.VNFD_0['mgmt-interface'], 'my/bin/path')
+ ssh_helper._run = mock.MagicMock()
+
+ self.assertFalse(ssh_helper.is_connected)
+ ssh_helper.provision_tool()
+ self.assertTrue(ssh_helper.is_connected)
+ mock_paramiko.SSHClient.assert_called_once()
+ mock_provision_tool.assert_called_once()
+
+ ssh_helper.provision_tool(tool_file='my_tool.sh')
+ self.assertTrue(ssh_helper.is_connected)
+ mock_paramiko.SSHClient.assert_called_once()
+ self.assertEqual(mock_provision_tool.call_count, 2)
+
+ ssh_helper.provision_tool('tool_path', 'my_tool.sh')
+ self.assertTrue(ssh_helper.is_connected)
+ mock_paramiko.SSHClient.assert_called_once()
+ self.assertEqual(mock_provision_tool.call_count, 3)
+
+
+class TestSetupEnvHelper(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
+ }
+
+ def test_build_config(self):
+ setup_env_helper = SetupEnvHelper(mock.Mock(), mock.Mock(), mock.Mock())
+
+ with self.assertRaises(NotImplementedError):
+ setup_env_helper.build_config()
+
+ def test_setup_vnf_environment(self):
+ setup_env_helper = SetupEnvHelper(mock.Mock(), mock.Mock(), mock.Mock())
+ self.assertIsNone(setup_env_helper.setup_vnf_environment())
+
+ def test_tear_down(self):
+ setup_env_helper = SetupEnvHelper(mock.Mock(), mock.Mock(), mock.Mock())
+
+ with self.assertRaises(NotImplementedError):
+ setup_env_helper.tear_down()
+
+
+class TestDpdkVnfSetupEnvHelper(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0,
+ 'driver': 'i40e',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1,
+ 'driver': 'ixgbe',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ]
+ }
+ }
+
+ def test__update_packet_type(self):
+ ip_pipeline_cfg = 'pkt_type = ipv4'
+ pkt_type = {'pkt_type': '1'}
+
+ expected = "pkt_type = 1"
+ result = DpdkVnfSetupEnvHelper._update_packet_type(ip_pipeline_cfg, pkt_type)
+ self.assertEqual(result, expected)
+
+ def test__update_packet_type_no_op(self):
+ ip_pipeline_cfg = 'pkt_type = ipv6'
+ pkt_type = {'pkt_type': '1'}
+
+ expected = "pkt_type = ipv6"
+ result = DpdkVnfSetupEnvHelper._update_packet_type(ip_pipeline_cfg, pkt_type)
+ self.assertEqual(result, expected)
+
+ def test__update_packet_type_multi_op(self):
+ ip_pipeline_cfg = 'pkt_type = ipv4\npkt_type = 1\npkt_type = ipv4'
+ pkt_type = {'pkt_type': '1'}
+
+ expected = 'pkt_type = 1\npkt_type = 1\npkt_type = 1'
+ result = DpdkVnfSetupEnvHelper._update_packet_type(ip_pipeline_cfg, pkt_type)
+ self.assertEqual(result, expected)
+
+ def test__update_traffic_type(self):
+ ip_pipeline_cfg = 'pkt_type = ipv4'
+
+ traffic_options = {"vnf_type": DpdkVnfSetupEnvHelper.APP_NAME, 'traffic_type': 4}
+ expected = "pkt_type = ipv4"
+ result = DpdkVnfSetupEnvHelper._update_traffic_type(ip_pipeline_cfg, traffic_options)
+ self.assertEqual(result, expected)
+
+ def test__update_traffic_type_ipv6(self):
+ ip_pipeline_cfg = 'pkt_type = ipv4'
+
+ traffic_options = {"vnf_type": DpdkVnfSetupEnvHelper.APP_NAME, 'traffic_type': 6}
+ expected = "pkt_type = ipv6"
+ result = DpdkVnfSetupEnvHelper._update_traffic_type(ip_pipeline_cfg, traffic_options)
+ self.assertEqual(result, expected)
+
+ def test__update_traffic_type_not_app_name(self):
+ ip_pipeline_cfg = 'traffic_type = 4'
+
+ vnf_type = ''.join(["Not", DpdkVnfSetupEnvHelper.APP_NAME])
+ traffic_options = {"vnf_type": vnf_type, 'traffic_type': 8}
+ expected = "traffic_type = 8"
+ result = DpdkVnfSetupEnvHelper._update_traffic_type(ip_pipeline_cfg, traffic_options)
+ self.assertEqual(result, expected)
+
+ @mock.patch.object(six, 'BytesIO', return_value=six.BytesIO(b'100\n'))
+ @mock.patch.object(utils, 'read_meminfo',
+ return_value={'Hugepagesize': '2048'})
+ def test__setup_hugepages_no_hugepages_defined(self, mock_meminfo, *args):
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = {}
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(
+ mock.ANY, ssh_helper, scenario_helper)
+ with mock.patch.object(sample_vnf.LOG, 'info') as mock_info:
+ dpdk_setup_helper._setup_hugepages()
+ mock_info.assert_called_once_with(
+ 'Hugepages size (kB): %s, number claimed: %s, number set: '
+ '%s', 2048, 8192, 100)
+ mock_meminfo.assert_called_once_with(ssh_helper)
+
+ @mock.patch.object(six, 'BytesIO', return_value=six.BytesIO(b'100\n'))
+ @mock.patch.object(utils, 'read_meminfo',
+ return_value={'Hugepagesize': '1048576'})
+ def test__setup_hugepages_8gb_hugepages_defined(self, mock_meminfo, *args):
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = {'hugepages_gb': 8}
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(
+ mock.ANY, ssh_helper, scenario_helper)
+ with mock.patch.object(sample_vnf.LOG, 'info') as mock_info:
+ dpdk_setup_helper._setup_hugepages()
+ mock_info.assert_called_once_with(
+ 'Hugepages size (kB): %s, number claimed: %s, number set: '
+ '%s', 1048576, 8, 100)
+ mock_meminfo.assert_called_once_with(ssh_helper)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open')
+ @mock.patch.object(utils, 'find_relative_file')
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig')
+ @mock.patch.object(utils, 'open_relative_file')
+ def test_build_config(self, mock_open_rf, mock_multi_port_config_class, mock_find, *args):
+ mock_multi_port_config = mock_multi_port_config_class()
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.vnf_cfg = {}
+ scenario_helper.options = {}
+ scenario_helper.all_options = {}
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+
+ dpdk_setup_helper.PIPELINE_COMMAND = expected = 'pipeline command'
+ result = dpdk_setup_helper.build_config()
+ self.assertEqual(result, expected)
+ self.assertGreaterEqual(ssh_helper.upload_config_file.call_count, 2)
+ mock_find.assert_called()
+ mock_multi_port_config.generate_config.assert_called()
+ mock_multi_port_config.generate_script.assert_called()
+
+ scenario_helper.options = {'rules': 'fake_file'}
+ scenario_helper.vnf_cfg = {'file': 'fake_file'}
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ mock_open_rf.side_effect = mock.mock_open(read_data='fake_data')
+ dpdk_setup_helper.PIPELINE_COMMAND = expected = 'pipeline command'
+
+ result = dpdk_setup_helper.build_config()
+
+ mock_open_rf.assert_called()
+ self.assertEqual(result, expected)
+ self.assertGreaterEqual(ssh_helper.upload_config_file.call_count, 2)
+ mock_find.assert_called()
+ mock_multi_port_config.generate_config.assert_called()
+ mock_multi_port_config.generate_script.assert_called()
+
+ def test__build_pipeline_kwargs(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.provision_tool.return_value = 'tool_path'
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ dpdk_setup_helper.CFG_CONFIG = 'config'
+ dpdk_setup_helper.CFG_SCRIPT = 'script'
+ dpdk_setup_helper.pipeline_kwargs = {}
+ dpdk_setup_helper.all_ports = [0, 1, 2]
+ dpdk_setup_helper.scenario_helper.vnf_cfg = {'lb_config': 'HW',
+ 'worker_threads': 1}
+
+ expected = {
+ 'cfg_file': 'config',
+ 'script': 'script',
+ 'port_mask_hex': '0x3',
+ 'tool_path': 'tool_path',
+ 'hwlb': ' --hwlb 1',
+ }
+ dpdk_setup_helper._build_pipeline_kwargs()
+ self.assertDictEqual(dpdk_setup_helper.pipeline_kwargs, expected)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time')
+ @mock.patch('yardstick.ssh.SSH')
+ def test_setup_vnf_environment(self, *args):
+ def execute(cmd):
+ if cmd.startswith('which '):
+ return exec_failure
+ return exec_success
+
+ exec_success = (0, 'good output', '')
+ exec_failure = (1, 'bad output', 'error output')
+
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute = execute
+
+ scenario_helper = mock.Mock()
+ scenario_helper.nodes = [None, None]
+ dpdk_vnf_setup_env_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ dpdk_vnf_setup_env_helper._validate_cpu_cfg = mock.Mock(return_value=[])
+
+ with mock.patch.object(dpdk_vnf_setup_env_helper, '_setup_dpdk'):
+ self.assertIsInstance(
+ dpdk_vnf_setup_env_helper.setup_vnf_environment(),
+ ResourceProfile)
+
+ def test__setup_dpdk(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.execute = mock.Mock()
+ ssh_helper.execute.return_value = (0, 0, 0)
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(mock.ANY, ssh_helper, mock.ANY)
+ with mock.patch.object(dpdk_setup_helper, '_setup_hugepages') as \
+ mock_setup_hp:
+ dpdk_setup_helper._setup_dpdk()
+ mock_setup_hp.assert_called_once()
+ ssh_helper.execute.assert_has_calls([
+ mock.call('sudo modprobe uio && sudo modprobe igb_uio'),
+ mock.call('lsmod | grep -i igb_uio')
+ ])
+
+ @mock.patch('yardstick.ssh.SSH')
+ def test__setup_resources(self, _):
+ vnfd_helper = VnfdHelper(deepcopy(self.VNFD_0))
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ dpdk_setup_helper._validate_cpu_cfg = mock.Mock()
+
+ dpdk_setup_helper.bound_pci = [v['virtual-interface']["vpci"] for v in
+ vnfd_helper.interfaces]
+ result = dpdk_setup_helper._setup_resources()
+ self.assertIsInstance(result, ResourceProfile)
+ self.assertEqual(dpdk_setup_helper.socket, 0)
+
+ @mock.patch('yardstick.ssh.SSH')
+ def test__setup_resources_socket_1(self, _):
+ vnfd_helper = VnfdHelper(deepcopy(self.VNFD_0))
+ vnfd_helper.interfaces[0]['virtual-interface']['vpci'] = '0000:55:00.0'
+ vnfd_helper.interfaces[1]['virtual-interface']['vpci'] = '0000:35:00.0'
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ dpdk_setup_helper._validate_cpu_cfg = mock.Mock()
+
+ dpdk_setup_helper.bound_pci = [v['virtual-interface']["vpci"] for v in
+ vnfd_helper.interfaces]
+ result = dpdk_setup_helper._setup_resources()
+ self.assertIsInstance(result, ResourceProfile)
+ self.assertEqual(dpdk_setup_helper.socket, 1)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time')
+ def test__detect_and_bind_drivers(self, *args):
+ vnfd_helper = VnfdHelper(deepcopy(self.VNFD_0))
+ ssh_helper = mock.Mock()
+ # ssh_helper.execute = mock.Mock(return_value = (0, 'text', ''))
+ # ssh_helper.execute.return_value = 0, 'output', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.nodes = [None, None]
+ rv = ['0000:05:00.1', '0000:05:00.0']
+
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ dpdk_setup_helper.dpdk_bind_helper._get_bound_pci_addresses = mock.Mock(return_value=rv)
+ dpdk_setup_helper.dpdk_bind_helper.bind = mock.Mock()
+ dpdk_setup_helper.dpdk_bind_helper.read_status = mock.Mock()
+
+ self.assertIsNone(dpdk_setup_helper._detect_and_bind_drivers())
+
+ intf_0 = vnfd_helper.vdu[0]['external-interface'][0]['virtual-interface']
+ intf_1 = vnfd_helper.vdu[0]['external-interface'][1]['virtual-interface']
+ self.assertEqual(0, intf_0['dpdk_port_num'])
+ self.assertEqual(1, intf_1['dpdk_port_num'])
+
+ def test_tear_down(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.nodes = [None, None]
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ dpdk_setup_helper.dpdk_bind_helper.bind = mock.Mock()
+ dpdk_setup_helper.dpdk_bind_helper.used_drivers = {
+ 'd1': ['0000:05:00.0'],
+ 'd3': ['0000:05:01.0'],
+ }
+
+ self.assertIsNone(dpdk_setup_helper.tear_down())
+ dpdk_setup_helper.dpdk_bind_helper.bind.assert_any_call(['0000:05:00.0'], 'd1', True)
+ dpdk_setup_helper.dpdk_bind_helper.bind.assert_any_call(['0000:05:01.0'], 'd3', True)
+
+
+class TestResourceHelper(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.0',
+ 'driver': 'i40e',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01'
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.1',
+ 'driver': 'ixgbe',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02'
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
+ }
+
+ def test_setup(self):
+ resource = object()
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ dpdk_setup_helper.setup_vnf_environment = mock.Mock(return_value=resource)
+ resource_helper = ResourceHelper(dpdk_setup_helper)
+
+ self.assertIsNone(resource_helper.setup())
+ self.assertIs(resource_helper.resource, resource)
+
+ def test_generate_cfg(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ resource_helper = ResourceHelper(dpdk_setup_helper)
+
+ self.assertIsNone(resource_helper.generate_cfg())
+
+ def test_stop_collect(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ resource_helper = ResourceHelper(dpdk_setup_helper)
+ resource_helper.resource = mock.Mock()
+
+ self.assertIsNone(resource_helper.stop_collect())
+
+ def test_stop_collect_none(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ resource_helper = ResourceHelper(dpdk_setup_helper)
+ resource_helper.resource = None
+
+ self.assertIsNone(resource_helper.stop_collect())
+
+
+class TestClientResourceHelper(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.0',
+ 'driver': 'i40e',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.1',
+ 'driver': 'ixgbe',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:13',
+ 'vpci': '0000:05:00.2',
+ 'driver': 'ixgbe',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 2,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.30',
+ 'local_mac': '00:00:00:00:00:11'
+ },
+ 'vnfd-connection-point-ref': 'xe2',
+ 'name': 'xe2'
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ],
+ },
+ }
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.LOG')
+ @mock.patch.object(sample_vnf, 'STLError', new_callable=lambda: MockError)
+ def test_get_stats_not_connected(self, mock_stl_error, *args):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ client_resource_helper = ClientResourceHelper(dpdk_setup_helper)
+ client_resource_helper.client = mock.Mock()
+ client_resource_helper.client.get_stats.side_effect = mock_stl_error
+
+ self.assertEqual(client_resource_helper.get_stats(), {})
+ client_resource_helper.client.get_stats.assert_called_once()
+
+ def test_clear_stats(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ client_resource_helper = ClientResourceHelper(dpdk_setup_helper)
+ client_resource_helper.client = mock.Mock()
+
+ self.assertIsNone(client_resource_helper.clear_stats())
+ self.assertEqual(
+ client_resource_helper.client.clear_stats.call_count, 1)
+
+ def test_clear_stats_of_ports(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ client_resource_helper = ClientResourceHelper(dpdk_setup_helper)
+ client_resource_helper.client = mock.Mock()
+
+ self.assertIsNone(client_resource_helper.clear_stats([3, 4]))
+ self.assertEqual(
+ client_resource_helper.client.clear_stats.call_count, 1)
+
+ def test_start(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ client_resource_helper = ClientResourceHelper(dpdk_setup_helper)
+ client_resource_helper.client = mock.Mock()
+
+ self.assertIsNone(client_resource_helper.start())
+ client_resource_helper.client.start.assert_called_once()
+
+ def test_start_ports(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+ client_resource_helper = ClientResourceHelper(dpdk_setup_helper)
+ client_resource_helper.client = mock.Mock()
+
+ self.assertIsNone(client_resource_helper.start([3, 4]))
+ client_resource_helper.client.start.assert_called_once()
+
+ def test_collect_kpi_with_queue(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ client_resource_helper = ClientResourceHelper(dpdk_setup_helper)
+ client_resource_helper._result = {'existing': 43, 'replaceable': 12}
+ client_resource_helper._queue = mock.Mock()
+ client_resource_helper._queue.empty.return_value = False
+ client_resource_helper._queue.get.return_value = {'incoming': 34, 'replaceable': 99}
+
+ expected = {
+ 'existing': 43,
+ 'incoming': 34,
+ 'replaceable': 99,
+ }
+ result = client_resource_helper.collect_kpi()
+ self.assertDictEqual(result, expected)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time')
+ @mock.patch.object(sample_vnf, 'STLError')
+ def test__connect_with_failures(self, mock_stl_error, *args):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ client_resource_helper = ClientResourceHelper(dpdk_setup_helper)
+ client = mock.MagicMock()
+ client.connect.side_effect = mock_stl_error(msg='msg')
+
+ self.assertIs(client_resource_helper._connect(client), client)
+
+ @mock.patch.object(ClientResourceHelper, '_build_ports')
+ @mock.patch.object(ClientResourceHelper, '_run_traffic_once')
+ def test_run_traffic(self, mock_run_traffic_once, mock_build_ports):
+ client_resource_helper = ClientResourceHelper(mock.Mock())
+ client = mock.Mock()
+ traffic_profile = mock.Mock()
+ mq_producer = mock.Mock()
+ with mock.patch.object(client_resource_helper, '_connect') \
+ as mock_connect, \
+ mock.patch.object(client_resource_helper, '_terminated') \
+ as mock_terminated:
+ mock_connect.return_value = client
+ type(mock_terminated).value = mock.PropertyMock(
+ side_effect=[0, 1, lambda x: x])
+ client_resource_helper.run_traffic(traffic_profile, mq_producer)
+
+ mock_build_ports.assert_called_once()
+ traffic_profile.register_generator.assert_called_once()
+ mq_producer.tg_method_started.assert_called_once()
+ mq_producer.tg_method_finished.assert_called_once()
+ mq_producer.tg_method_iteration.assert_called_once_with(1)
+ mock_run_traffic_once.assert_called_once_with(traffic_profile)
+
+ @mock.patch.object(ClientResourceHelper, '_build_ports')
+ @mock.patch.object(ClientResourceHelper, '_run_traffic_once',
+ side_effect=Exception)
+ def test_run_traffic_exception(self, mock_run_traffic_once,
+ mock_build_ports):
+ client_resource_helper = ClientResourceHelper(mock.Mock())
+ client = mock.Mock()
+ traffic_profile = mock.Mock()
+ mq_producer = mock.Mock()
+ with mock.patch.object(client_resource_helper, '_connect') \
+ as mock_connect, \
+ mock.patch.object(client_resource_helper, '_terminated') \
+ as mock_terminated:
+ mock_connect.return_value = client
+ type(mock_terminated).value = mock.PropertyMock(return_value=0)
+ mq_producer.reset_mock()
+ # NOTE(ralonsoh): "trex_stl_exceptions.STLError" is mocked
+ with self.assertRaises(Exception):
+ client_resource_helper.run_traffic(traffic_profile,
+ mq_producer)
+
+ mock_build_ports.assert_called_once()
+ traffic_profile.register_generator.assert_called_once()
+ mock_run_traffic_once.assert_called_once_with(traffic_profile)
+ mq_producer.tg_method_started.assert_called_once()
+ mq_producer.tg_method_finished.assert_not_called()
+ mq_producer.tg_method_iteration.assert_not_called()
+
+
+class TestRfc2544ResourceHelper(unittest.TestCase):
+
+ RFC2544_CFG_1 = {
+ 'latency': True,
+ 'correlated_traffic': True,
+ 'allowed_drop_rate': '0.1 - 0.15',
+ }
+
+ RFC2544_CFG_2 = {
+ 'allowed_drop_rate': ' 0.25 - 0.05 ',
+ }
+
+ RFC2544_CFG_3 = {
+ 'allowed_drop_rate': '0.2',
+ }
+
+ RFC2544_CFG_4 = {
+ 'latency': True,
+ }
+
+ SCENARIO_CFG_1 = {
+ 'options': {
+ 'rfc2544': RFC2544_CFG_1,
+ }
+ }
+
+ SCENARIO_CFG_2 = {
+ 'options': {
+ 'rfc2544': RFC2544_CFG_2,
+ }
+ }
+
+ SCENARIO_CFG_3 = {
+ 'options': {
+ 'rfc2544': RFC2544_CFG_3,
+ }
+ }
+
+ SCENARIO_CFG_4 = {
+ 'options': {
+ 'rfc2544': RFC2544_CFG_4,
+ }
+ }
+
+ def test_property_rfc2544(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertIsNone(rfc2544_resource_helper._rfc2544)
+ self.assertDictEqual(rfc2544_resource_helper.rfc2544, self.RFC2544_CFG_1)
+ self.assertDictEqual(rfc2544_resource_helper._rfc2544, self.RFC2544_CFG_1)
+ scenario_helper.scenario_cfg = {} # ensure that resource_helper caches
+ self.assertDictEqual(rfc2544_resource_helper.rfc2544, self.RFC2544_CFG_1)
+
+ def test_property_tolerance_high(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertIsNone(rfc2544_resource_helper._tolerance_high)
+ self.assertEqual(rfc2544_resource_helper.tolerance_high, 0.15)
+ self.assertEqual(rfc2544_resource_helper._tolerance_high, 0.15)
+ scenario_helper.scenario_cfg = {} # ensure that resource_helper caches
+ self.assertEqual(rfc2544_resource_helper.tolerance_high, 0.15)
+
+ def test_property_tolerance_low(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertIsNone(rfc2544_resource_helper._tolerance_low)
+ self.assertEqual(rfc2544_resource_helper.tolerance_low, 0.1)
+ self.assertEqual(rfc2544_resource_helper._tolerance_low, 0.1)
+ scenario_helper.scenario_cfg = {} # ensure that resource_helper caches
+ self.assertEqual(rfc2544_resource_helper.tolerance_low, 0.1)
+
+ def test_property_tolerance_high_range_swap(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_2
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertEqual(rfc2544_resource_helper.tolerance_high, 0.25)
+
+ def test_property_tolerance_low_range_swap(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_2
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertEqual(rfc2544_resource_helper.tolerance_low, 0.05)
+
+ def test_property_tolerance_high_not_range(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_3
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertEqual(rfc2544_resource_helper.tolerance_high, 0.2)
+
+ def test_property_tolerance_low_not_range(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_3
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertEqual(rfc2544_resource_helper.tolerance_low, 0.2)
+
+ def test_property_tolerance_high_default(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_4
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertEqual(rfc2544_resource_helper.tolerance_high, 0.0001)
+
+ def test_property_tolerance_low_default(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_4
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertEqual(rfc2544_resource_helper.tolerance_low, 0.0001)
+
+ def test_property_latency(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertIsNone(rfc2544_resource_helper._latency)
+ self.assertTrue(rfc2544_resource_helper.latency)
+ self.assertTrue(rfc2544_resource_helper._latency)
+ scenario_helper.scenario_cfg = {} # ensure that resource_helper caches
+ self.assertTrue(rfc2544_resource_helper.latency)
+
+ def test_property_latency_default(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_2
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertFalse(rfc2544_resource_helper.latency)
+
+ def test_property_correlated_traffic(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_1
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertIsNone(rfc2544_resource_helper._correlated_traffic)
+ self.assertTrue(rfc2544_resource_helper.correlated_traffic)
+ self.assertTrue(rfc2544_resource_helper._correlated_traffic)
+ scenario_helper.scenario_cfg = {} # ensure that resource_helper caches
+ self.assertTrue(rfc2544_resource_helper.correlated_traffic)
+
+ def test_property_correlated_traffic_default(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = self.SCENARIO_CFG_2
+ rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper)
+
+ self.assertFalse(rfc2544_resource_helper.correlated_traffic)
+
+
+class TestSampleVNFDeployHelper(unittest.TestCase):
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time')
+ @mock.patch('subprocess.check_output')
+ def test_deploy_vnfs_disabled(self, *_):
+ vnfd_helper = mock.Mock()
+ ssh_helper = mock.Mock()
+ ssh_helper.join_bin_path.return_value = 'joined_path'
+ ssh_helper.execute.return_value = 1, 'bad output', 'error output'
+ ssh_helper.put.return_value = None
+ sample_vnf_deploy_helper = SampleVNFDeployHelper(vnfd_helper, ssh_helper)
+
+ self.assertIsNone(sample_vnf_deploy_helper.deploy_vnfs('name1'))
+ sample_vnf_deploy_helper.DISABLE_DEPLOY = True
+ self.assertEqual(ssh_helper.execute.call_count, 5)
+ ssh_helper.put.assert_called_once()
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time')
+ @mock.patch('subprocess.check_output')
+ def test_deploy_vnfs(self, *args):
+ vnfd_helper = mock.Mock()
+ ssh_helper = mock.Mock()
+ ssh_helper.join_bin_path.return_value = 'joined_path'
+ ssh_helper.execute.return_value = 1, 'bad output', 'error output'
+ ssh_helper.put.return_value = None
+ sample_vnf_deploy_helper = SampleVNFDeployHelper(vnfd_helper, ssh_helper)
+ sample_vnf_deploy_helper.DISABLE_DEPLOY = False
+
+ self.assertIsNone(sample_vnf_deploy_helper.deploy_vnfs('name1'))
+ self.assertEqual(ssh_helper.execute.call_count, 5)
+ ssh_helper.put.assert_called_once()
+
+ @mock.patch('subprocess.check_output')
+ def test_deploy_vnfs_early_success(self, *args):
+ vnfd_helper = mock.Mock()
+ ssh_helper = mock.Mock()
+ ssh_helper.join_bin_path.return_value = 'joined_path'
+ ssh_helper.execute.return_value = 0, 'output', ''
+ ssh_helper.put.return_value = None
+ sample_vnf_deploy_helper = SampleVNFDeployHelper(vnfd_helper, ssh_helper)
+ sample_vnf_deploy_helper.DISABLE_DEPLOY = False
+
+ self.assertIsNone(sample_vnf_deploy_helper.deploy_vnfs('name1'))
+ ssh_helper.execute.assert_called_once()
+ ssh_helper.put.assert_not_called()
+
+
+class TestScenarioHelper(unittest.TestCase):
+
+ def test_property_task_path(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = {
+ 'task_path': 'my_path',
+ }
+
+ self.assertEqual(scenario_helper.task_path, 'my_path')
+
+ def test_property_nodes(self):
+ nodes = ['node1', 'node2']
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = {
+ 'nodes': nodes,
+ }
+
+ self.assertEqual(scenario_helper.nodes, nodes)
+
+ def test_property_all_options(self):
+ data = {
+ 'name1': {
+ 'key3': 'value3',
+ },
+ 'name2': {}
+ }
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = {
+ 'options': data,
+ }
+
+ self.assertDictEqual(scenario_helper.all_options, data)
+
+ def test_property_options(self):
+ data = {
+ 'key1': 'value1',
+ 'key2': 'value2',
+ }
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = {
+ 'options': {
+ 'name1': data,
+ },
+ }
+
+ self.assertDictEqual(scenario_helper.options, data)
+
+ def test_property_vnf_cfg(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = {
+ 'options': {
+ 'name1': {
+ 'vnf_config': 'my_config',
+ },
+ },
+ }
+
+ self.assertEqual(scenario_helper.vnf_cfg, 'my_config')
+
+ def test_property_vnf_cfg_default(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = {
+ 'options': {
+ 'name1': {},
+ },
+ }
+
+ self.assertDictEqual(scenario_helper.vnf_cfg, ScenarioHelper.DEFAULT_VNF_CFG)
+
+ def test_property_topology(self):
+ scenario_helper = ScenarioHelper('name1')
+ scenario_helper.scenario_cfg = {
+ 'topology': 'my_topology',
+ }
+
+ self.assertEqual(scenario_helper.topology, 'my_topology')
+
+
+class TestSampleVnf(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01'
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02'
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ]
+ }
+ }
+
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64,
+ },
+ }
+
+ def test___init__(self):
+ sample_vnf = SampleVNF('vnf1', self.VNFD_0, 'task_id')
+
+ self.assertEqual(sample_vnf.name, 'vnf1')
+ self.assertDictEqual(sample_vnf.vnfd_helper, self.VNFD_0)
+
+ # test the default setup helper is SetupEnvHelper, not subclass
+ self.assertEqual(type(sample_vnf.setup_helper), SetupEnvHelper)
+
+ # test the default resource helper is ResourceHelper, not subclass
+ self.assertEqual(type(sample_vnf.resource_helper), ResourceHelper)
+
+ def test___init___alt_types(self):
+ class MySetupEnvHelper(SetupEnvHelper):
+ pass
+
+ class MyResourceHelper(ResourceHelper):
+ pass
+
+ sample_vnf = SampleVNF('vnf1', self.VNFD_0, 'task_id',
+ MySetupEnvHelper, MyResourceHelper)
+
+ self.assertEqual(sample_vnf.name, 'vnf1')
+ self.assertDictEqual(sample_vnf.vnfd_helper, self.VNFD_0)
+
+ # test the default setup helper is MySetupEnvHelper, not subclass
+ self.assertEqual(type(sample_vnf.setup_helper), MySetupEnvHelper)
+
+ # test the default resource helper is MyResourceHelper, not subclass
+ self.assertEqual(type(sample_vnf.resource_helper), MyResourceHelper)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.Process')
+ def test__start_vnf(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf._run = mock.Mock()
+
+ self.assertIsNone(sample_vnf.queue_wrapper)
+ self.assertIsNone(sample_vnf._vnf_process)
+ self.assertIsNone(sample_vnf._start_vnf())
+ self.assertIsNotNone(sample_vnf.queue_wrapper)
+ self.assertIsNotNone(sample_vnf._vnf_process)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
+ @mock.patch("yardstick.ssh.SSH")
+ def test_instantiate(self, ssh, *args):
+ test_base.mock_ssh(ssh)
+ nodes = {
+ 'vnf1': 'name1',
+ 'vnf2': 'name2',
+ }
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {sample_vnf.name: 'mock'}
+ }
+ sample_vnf.APP_NAME = 'sample1'
+ sample_vnf._start_server = mock.Mock(return_value=0)
+ sample_vnf._vnf_process = mock.MagicMock()
+ sample_vnf._vnf_process._is_alive.return_value = 1
+ sample_vnf.ssh_helper = mock.MagicMock()
+ sample_vnf.deploy_helper = mock.MagicMock()
+ sample_vnf.resource_helper.ssh_helper = mock.MagicMock()
+ scenario_cfg = {
+ 'nodes': nodes,
+ }
+
+ self.assertIsNone(sample_vnf.instantiate(scenario_cfg, {}))
+
+ def test__update_collectd_options(self):
+ scenario_cfg = {'options':
+ {'collectd':
+ {'interval': 3,
+ 'plugins':
+ {'plugin3': {'param': 3}}},
+ 'vnf__0':
+ {'collectd':
+ {'interval': 2,
+ 'plugins':
+ {'plugin3': {'param': 2},
+ 'plugin2': {'param': 2}}}}}}
+ context_cfg = {'nodes':
+ {'vnf__0':
+ {'collectd':
+ {'interval': 1,
+ 'plugins':
+ {'plugin3': {'param': 1},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}}}}
+ expected = {'interval': 1,
+ 'plugins':
+ {'plugin3': {'param': 1},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf__0', vnfd, 'task_id')
+ sample_vnf._update_collectd_options(scenario_cfg, context_cfg)
+ self.assertEqual(sample_vnf.setup_helper.collectd_options, expected)
+
+ def test__update_options(self):
+ options1 = {'interval': 1,
+ 'param1': 'value1',
+ 'plugins':
+ {'plugin3': {'param': 3},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}
+ options2 = {'interval': 2,
+ 'param2': 'value2',
+ 'plugins':
+ {'plugin4': {'param': 4},
+ 'plugin2': {'param': 2},
+ 'plugin1': {'param': 2}}}
+ expected = {'interval': 1,
+ 'param1': 'value1',
+ 'param2': 'value2',
+ 'plugins':
+ {'plugin4': {'param': 4},
+ 'plugin3': {'param': 3},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf._update_options(options2, options1)
+ self.assertEqual(options2, expected)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch("yardstick.ssh.SSH")
+ def test_wait_for_instantiate_empty_queue(self, ssh, *args):
+ test_base.mock_ssh(ssh, exec_result=(1, "", ""))
+
+ queue_size_list = [
+ 0,
+ 1,
+ 0,
+ 1,
+ ]
+
+ queue_get_list = [
+ 'some output',
+ 'pipeline> ',
+ ]
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf.APP_NAME = 'sample1'
+ sample_vnf.WAIT_TIME_FOR_SCRIPT = 0
+ sample_vnf._start_server = mock.Mock(return_value=0)
+ sample_vnf._vnf_process = mock.MagicMock()
+ sample_vnf._vnf_process.exitcode = 0
+ sample_vnf._vnf_process._is_alive.return_value = 1
+ sample_vnf.queue_wrapper = mock.Mock()
+ sample_vnf.q_out = mock.Mock()
+ sample_vnf.q_out.qsize.side_effect = iter(queue_size_list)
+ sample_vnf.q_out.get.side_effect = iter(queue_get_list)
+ sample_vnf.ssh_helper = mock.MagicMock()
+ sample_vnf.resource_helper.ssh_helper = mock.MagicMock()
+ sample_vnf.resource_helper.start_collect = mock.MagicMock()
+
+ self.assertEqual(sample_vnf.wait_for_instantiate(), 0)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ def test_vnf_execute_with_queue_data(self, *args):
+ queue_size_list = [
+ 1,
+ 1,
+ 0,
+ ]
+
+ queue_get_list = [
+ 'hello ',
+ 'world'
+ ]
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf.APP_NAME = 'sample1'
+ sample_vnf.q_out = mock.Mock()
+ sample_vnf.q_out.qsize.side_effect = iter(queue_size_list)
+ sample_vnf.q_out.get.side_effect = iter(queue_get_list)
+
+ self.assertEqual(sample_vnf.vnf_execute('my command'), 'hello world')
+
+ def test_terminate_without_vnf_process(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf.APP_NAME = 'sample1'
+ sample_vnf.vnf_execute = mock.Mock()
+ sample_vnf.ssh_helper = mock.Mock()
+ sample_vnf._tear_down = mock.Mock()
+ sample_vnf.resource_helper = mock.Mock()
+
+ self.assertIsNone(sample_vnf.terminate())
+
+ def test_get_stats(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf.APP_NAME = 'sample1'
+ sample_vnf.APP_WORD = 'sample1'
+ sample_vnf.vnf_execute = mock.Mock(return_value='the stats')
+
+ self.assertEqual(sample_vnf.get_stats(), 'the stats')
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ def test_collect_kpi(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {sample_vnf.name: "mock"}
+ }
+ sample_vnf.APP_NAME = 'sample1'
+ sample_vnf.COLLECT_KPI = r'\s(\d+)\D*(\d+)\D*(\d+)'
+ sample_vnf.COLLECT_MAP = {
+ 'k1': 3,
+ 'k2': 1,
+ 'k3': 2,
+ }
+ sample_vnf.get_stats = mock.Mock(return_value='index0: 34 -- 91, 27')
+ sample_vnf.resource_helper = mock.Mock()
+ sample_vnf.resource_helper.collect_kpi.return_value = {}
+
+ expected = {
+ 'k1': 27,
+ 'k2': 34,
+ 'k3': 91,
+ 'collect_stats': {},
+ 'physical_node': 'mock_node'
+ }
+ result = sample_vnf.collect_kpi()
+ self.assertDictEqual(result, expected)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ def test_collect_kpi_default(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {sample_vnf.name: "mock"}
+ }
+ sample_vnf.APP_NAME = 'sample1'
+ sample_vnf.COLLECT_KPI = r'\s(\d+)\D*(\d+)\D*(\d+)'
+ sample_vnf.get_stats = mock.Mock(return_value='')
+
+ expected = {
+ 'physical_node': 'mock_node',
+ 'packets_in': 0,
+ 'packets_fwd': 0,
+ 'packets_dropped': 0,
+ }
+ result = sample_vnf.collect_kpi()
+ self.assertDictEqual(result, expected)
+
+ def test_scale(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ self.assertRaises(y_exceptions.FunctionNotImplemented,
+ sample_vnf.scale)
+
+ def test__run(self):
+ test_cmd = 'test cmd'
+ run_kwargs = {'arg1': 'val1', 'arg2': 'val2'}
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd, 'task_id')
+ sample_vnf.ssh_helper = mock.Mock()
+ sample_vnf.setup_helper = mock.Mock()
+ with mock.patch.object(sample_vnf, '_build_config',
+ return_value=test_cmd), \
+ mock.patch.object(sample_vnf, '_build_run_kwargs'):
+ sample_vnf.run_kwargs = run_kwargs
+ sample_vnf._run()
+ sample_vnf.ssh_helper.drop_connection.assert_called_once()
+ sample_vnf.ssh_helper.run.assert_called_once_with(test_cmd,
+ **run_kwargs)
+ sample_vnf.setup_helper.kill_vnf.assert_called_once()
+
+
+class TestSampleVNFTrafficGen(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.0',
+ 'driver': 'i40e',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01'
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.1',
+ 'driver': 'ixgbe',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02'
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ],
+ },
+ }
+
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64,
+ },
+ }
+
+ def test__check_status(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
+
+ with self.assertRaises(NotImplementedError):
+ sample_vnf_tg._check_status()
+
+ def test_listen_traffic(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
+
+ sample_vnf_tg.listen_traffic(mock.Mock())
+
+ def test_verify_traffic(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
+
+ sample_vnf_tg.verify_traffic(mock.Mock())
+
+ def test_terminate(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
+ sample_vnf_tg._traffic_process = mock.Mock()
+ sample_vnf_tg._tg_process = mock.Mock()
+
+ sample_vnf_tg.terminate()
+
+ def test__wait_for_process(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
+ with mock.patch.object(sample_vnf_tg, '_check_status',
+ return_value=0) as mock_status, \
+ mock.patch.object(sample_vnf_tg, '_tg_process') as mock_proc:
+ mock_proc.is_alive.return_value = True
+ mock_proc.exitcode = 234
+ self.assertEqual(sample_vnf_tg._wait_for_process(), 234)
+ mock_proc.is_alive.assert_called_once()
+ mock_status.assert_called_once()
+
+ def test__wait_for_process_not_alive(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
+ with mock.patch.object(sample_vnf_tg, '_tg_process') as mock_proc:
+ mock_proc.is_alive.return_value = False
+ self.assertRaises(RuntimeError, sample_vnf_tg._wait_for_process)
+ mock_proc.is_alive.assert_called_once()
+
+ def test__wait_for_process_delayed(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
+ with mock.patch.object(sample_vnf_tg, '_check_status',
+ side_effect=[1, 0]) as mock_status, \
+ mock.patch.object(sample_vnf_tg,
+ '_tg_process') as mock_proc:
+ mock_proc.is_alive.return_value = True
+ mock_proc.exitcode = 234
+ self.assertEqual(sample_vnf_tg._wait_for_process(), 234)
+ mock_proc.is_alive.assert_has_calls([mock.call(), mock.call()])
+ mock_status.assert_has_calls([mock.call(), mock.call()])
+
+ def test_scale(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id')
+ self.assertRaises(y_exceptions.FunctionNotImplemented,
+ sample_vnf_tg.scale)
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py
new file mode 100644
index 000000000..53474b96e
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py
@@ -0,0 +1,271 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import subprocess
+
+import mock
+import six
+
+from yardstick import ssh
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.common import utils
+from yardstick.network_services.vnf_generic.vnf import tg_ixload
+from yardstick.network_services.traffic_profile import base as tp_base
+from yardstick.tests.unit import base as ut_base
+
+
+NAME = "tg__1"
+
+
+class TestIxLoadTrafficGen(ut_base.BaseUnitTestCase):
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{'short-name': 'VpeVnf',
+ 'vdu':
+ [{'routing_table':
+ [{'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'},
+ {'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'}],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl':
+ [{'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'},
+ {'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'}],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface':
+ [{'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02'},
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'},
+ {'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01'},
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'}]}],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface':
+ {'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'},
+ 'benchmark':
+ {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
+ 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
+ {'type': 'VPORT', 'name': 'xe1'}],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}}
+
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64}}
+
+ def setUp(self):
+ self._mock_call = mock.patch.object(subprocess, 'call')
+ self.mock_call = self._mock_call.start()
+ self._mock_open = mock.patch.object(tg_ixload, 'open')
+ self.mock_open = self._mock_open.start()
+ self._mock_ssh = mock.patch.object(ssh, 'SSH')
+ self.mock_ssh = self._mock_ssh.start()
+ ssh_obj_mock = mock.Mock(autospec=ssh.SSH)
+ ssh_obj_mock.execute = mock.Mock(return_value=(0, '', ''))
+ ssh_obj_mock.run = mock.Mock(return_value=(0, '', ''))
+ self.mock_ssh.from_node.return_value = ssh_obj_mock
+ self.addCleanup(self._stop_mock)
+
+ def _stop_mock(self):
+ self._mock_call.stop()
+ self._mock_open.stop()
+ self._mock_ssh.stop()
+
+ def test___init__(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+ self.assertIsNone(ixload_traffic_gen.resource_helper.data)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server',
+ return_value='mock_node')
+ def test_collect_kpi(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+ ixload_traffic_gen.scenario_helper.scenario_cfg = {
+ 'nodes': {ixload_traffic_gen.name: "mock"}
+ }
+ ixload_traffic_gen.data = {}
+ result = ixload_traffic_gen.collect_kpi()
+
+ expected = {
+ 'physical_node': 'mock_node',
+ 'collect_stats': {}}
+ self.assertEqual(expected, result)
+
+ def test_listen_traffic(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+ self.assertIsNone(ixload_traffic_gen.listen_traffic({}))
+
+ @mock.patch.object(utils, 'find_relative_file')
+ @mock.patch.object(utils, 'makedirs')
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server')
+ @mock.patch.object(tg_ixload, 'shutil')
+ def test_instantiate(self, mock_shutil, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+ scenario_cfg = {'tc': "nsb_test_case",
+ 'ixia_profile': "ixload.cfg",
+ 'task_path': "/path/to/task"}
+ ixload_traffic_gen.RESULTS_MOUNT = "/tmp/result"
+ mock_shutil.copy = mock.Mock()
+ scenario_cfg.update(
+ {'options':
+ {'packetsize': 64, 'traffic_type': 4,
+ 'rfc2544': {'allowed_drop_rate': '0.8 - 1'},
+ 'vnf__1': {'rules': 'acl_1rule.yaml',
+ 'vnf_config': {'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config':
+ '1C/1T',
+ 'worker_threads': 1}}
+ }
+ }
+ )
+ scenario_cfg.update({'nodes': {ixload_traffic_gen.name: "mock"}})
+ with mock.patch.object(six.moves.builtins, 'open',
+ create=True) as mock_open:
+ mock_open.return_value = mock.MagicMock()
+ ixload_traffic_gen.instantiate(scenario_cfg, {})
+
+ @mock.patch.object(tg_ixload, 'open')
+ @mock.patch.object(tg_ixload, 'min')
+ @mock.patch.object(tg_ixload, 'max')
+ @mock.patch.object(tg_ixload, 'len')
+ @mock.patch.object(tg_ixload, 'shutil')
+ def test_run_traffic(self, *args):
+ mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = '64'
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vnfd['mgmt-interface'].update({'tg-config': {}})
+ vnfd['mgmt-interface']['tg-config'].update({'ixchassis': '1.1.1.1'})
+ vnfd['mgmt-interface']['tg-config'].update({'py_bin_path': '/root'})
+ sut = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+ sut.connection = mock.Mock()
+ sut._traffic_runner = mock.Mock(return_value=0)
+ result = sut.run_traffic(mock_traffic_profile)
+ self.assertIsNone(result)
+
+ @mock.patch.object(tg_ixload, 'open')
+ @mock.patch.object(tg_ixload, 'min')
+ @mock.patch.object(tg_ixload, 'max')
+ @mock.patch.object(tg_ixload, 'len')
+ @mock.patch.object(tg_ixload, 'shutil')
+ def test_run_traffic_csv(self, *args):
+ mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = '64'
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vnfd['mgmt-interface'].update({'tg-config': {}})
+ vnfd['mgmt-interface']['tg-config'].update({'ixchassis': '1.1.1.1'})
+ vnfd['mgmt-interface']['tg-config'].update({'py_bin_path': '/root'})
+ sut = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+ sut.connection = mock.Mock()
+ sut._traffic_runner = mock.Mock(return_value=0)
+ subprocess.call(['touch', '/tmp/1.csv'])
+ sut.rel_bin_path = mock.Mock(return_value='/tmp/*.csv')
+ result = sut.run_traffic(mock_traffic_profile)
+ self.assertIsNone(result)
+
+ def test_terminate(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+ self.assertIsNone(ixload_traffic_gen.terminate())
+
+ def test_parse_csv_read(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ kpi_data = {
+ 'HTTP Total Throughput (Kbps)': 1,
+ 'HTTP Simulated Users': 2,
+ 'HTTP Concurrent Connections': '3',
+ 'HTTP Connection Rate': 4.3,
+ 'HTTP Transaction Rate': True,
+ }
+ http_reader = [kpi_data]
+ ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+ result = ixload_traffic_gen.resource_helper.result
+ ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
+ for k_left, k_right in tg_ixload.IxLoadResourceHelper.KPI_LIST.items():
+ self.assertEqual(result[k_left][-1], int(kpi_data[k_right]))
+
+ def test_parse_csv_read_value_error(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ http_reader = [{
+ 'HTTP Total Throughput (Kbps)': 1,
+ 'HTTP Simulated Users': 2,
+ 'HTTP Concurrent Connections': "not a number",
+ 'HTTP Connection Rate': 4,
+ 'HTTP Transaction Rate': 5,
+ }]
+ ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+ init_value = ixload_traffic_gen.resource_helper.result
+ ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
+ self.assertDictEqual(ixload_traffic_gen.resource_helper.result,
+ init_value)
+
+ def test_parse_csv_read_error(self,):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ http_reader = [{
+ 'HTTP Total Throughput (Kbps)': 1,
+ 'HTTP Simulated Users': 2,
+ 'HTTP Concurrent Connections': 3,
+ 'HTTP Transaction Rate': 5,
+ }]
+ ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id')
+
+ with self.assertRaises(KeyError):
+ ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py
new file mode 100644
index 000000000..434a7b770
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py
@@ -0,0 +1,298 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from multiprocessing import Queue
+import multiprocessing
+
+import mock
+import unittest
+
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.tg_ping import PingParser
+from yardstick.network_services.vnf_generic.vnf.tg_ping import PingTrafficGen
+from yardstick.network_services.vnf_generic.vnf.tg_ping import PingResourceHelper
+from yardstick.network_services.vnf_generic.vnf.tg_ping import PingSetupEnvHelper
+from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper
+
+
+SSH_HELPER = "yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper"
+
+
+class TestPingResourceHelper(unittest.TestCase):
+ def test___init__(self):
+ setup_helper = mock.Mock()
+ helper = PingResourceHelper(setup_helper)
+
+ self.assertIsInstance(helper._queue, multiprocessing.queues.Queue)
+ self.assertIsInstance(helper._parser, PingParser)
+
+ def test_run_traffic(self):
+ setup_helper = mock.Mock()
+ traffic_profile = mock.Mock()
+ traffic_profile.params = {
+ 'traffic_profile': {
+ 'frame_size': 64,
+ },
+ }
+
+ helper = PingResourceHelper(setup_helper)
+ helper.cmd_kwargs = {'target_ip': '10.0.0.2',
+ 'local_ip': '10.0.0.1',
+ 'local_if_name': 'eth0',
+ }
+ helper.ssh_helper = mock.Mock()
+ helper.run_traffic(traffic_profile)
+ helper.ssh_helper.run.called_with('ping-s 64 10.0.0.2')
+
+
+class TestPingParser(unittest.TestCase):
+ def test___init__(self):
+ q_out = Queue()
+ ping_parser = PingParser(q_out)
+ self.assertIsNotNone(ping_parser.queue)
+
+ def test_clear(self):
+ sample_out = """
+64 bytes from 10.102.22.93: icmp_seq=3 ttl=64 time=0.296 ms
+ """
+ q_out = Queue()
+ ping_parser = PingParser(q_out)
+ ping_parser.write(sample_out)
+ ping_parser.clear()
+ self.assertTrue(q_out.empty())
+
+ def test_close(self):
+ q_out = Queue()
+ ping_parser = PingParser(q_out)
+ self.assertIsNone(ping_parser.close())
+
+ def test_write(self):
+ sample_out = """
+64 bytes from 10.102.22.93: icmp_seq=3 ttl=64 time=0.296 ms
+ """
+ q_out = Queue()
+ ping_parser = PingParser(q_out)
+ ping_parser.write(sample_out)
+
+ self.assertEqual({"packets_received": 3.0, "rtt": 0.296}, q_out.get())
+
+
+class TestPingTrafficGen(unittest.TestCase):
+ VNFD_0_EXT_IF_0 = {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': u'152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': u'152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0',
+ }
+
+ VNFD_0_EXT_IF_1 = {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': u'152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': u'152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1',
+ }
+
+ VNFD_0_EXT_IF_LIST = [
+ VNFD_0_EXT_IF_0,
+ VNFD_0_EXT_IF_1,
+ ]
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': u'152.16.100.20',
+ 'netmask': u'255.255.255.0',
+ 'gateway': u'152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'network': u'152.16.40.20',
+ 'netmask': u'255.255.255.0',
+ 'gateway': u'152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': VNFD_0_EXT_IF_LIST,
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1',
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf',
+ 'name': 'VPEVnfSsh',
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ],
+ },
+ }
+
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64,
+ },
+ }
+
+ CMD_KWARGS = {
+ 'target_ip': u'152.16.100.20',
+ 'local_ip': u'152.16.100.19',
+ 'local_if_name': u'xe0_fake',
+ }
+
+ @mock.patch("yardstick.ssh.SSH")
+ def test___init__(self, ssh):
+ ssh.from_node.return_value.execute.return_value = 0, "success", ""
+ ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
+
+ self.assertIsInstance(ping_traffic_gen.setup_helper, PingSetupEnvHelper)
+ self.assertIsInstance(ping_traffic_gen.resource_helper, PingResourceHelper)
+ self.assertEqual(ping_traffic_gen._result, {})
+
+ @mock.patch("yardstick.ssh.SSH")
+ def test__bind_device_kernel_with_failure(self, ssh):
+ mock_ssh(ssh)
+
+ execute_result_data = [
+ (1, 'bad stdout messages', 'error messages'),
+ (0, '', ''),
+ (0, 'if_name_1', ''),
+ (0, 'if_name_2', ''),
+ ]
+ ssh.from_node.return_value.execute.side_effect = iter(execute_result_data)
+ ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
+ ext_ifs = ping_traffic_gen.vnfd_helper.interfaces
+ self.assertNotEqual(ext_ifs[0]['virtual-interface']['local_iface_name'], 'if_name_1')
+ self.assertNotEqual(ext_ifs[1]['virtual-interface']['local_iface_name'], 'if_name_2')
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ @mock.patch("yardstick.ssh.SSH")
+ def test_collect_kpi(self, ssh, *args):
+ mock_ssh(ssh, exec_result=(0, "success", ""))
+
+ ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
+ ping_traffic_gen.scenario_helper.scenario_cfg = {
+ 'nodes': {ping_traffic_gen.name: "mock"}
+ }
+ ping_traffic_gen._queue = Queue()
+ ping_traffic_gen._queue.put({})
+ expected = {
+ 'physical_node': 'mock_node',
+ 'collect_stats': {}
+ }
+ # NOTE: Why we check _result but not collect_kpi() return value
+ # self.assertEqual(ping_traffic_gen._result, {})
+ self.assertEqual(ping_traffic_gen.collect_kpi(), expected)
+
+
+ @mock.patch(SSH_HELPER)
+ def test_instantiate(self, ssh):
+ mock_ssh(ssh, spec=VnfSshHelper, exec_result=(0, "success", ""))
+ ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
+ ping_traffic_gen.setup_helper.ssh_helper = mock.MagicMock(
+ **{"execute.return_value": (0, "xe0_fake", "")})
+ self.assertIsInstance(ping_traffic_gen.ssh_helper, mock.Mock)
+ self.assertEqual(ping_traffic_gen._result, {})
+
+ self.assertIsNone(ping_traffic_gen.instantiate({}, {}))
+
+ self.assertEqual(
+ ping_traffic_gen.vnfd_helper.interfaces[0]['virtual-interface']['local_iface_name'],
+ 'xe0_fake')
+ self.assertEqual(self.CMD_KWARGS, ping_traffic_gen.resource_helper.cmd_kwargs)
+ self.assertIsNotNone(ping_traffic_gen._result)
+
+ def test_listen_traffic(self):
+ ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
+ self.assertIsNone(ping_traffic_gen.listen_traffic({}))
+
+ @mock.patch("yardstick.ssh.SSH")
+ def test_terminate(self, ssh):
+ ssh.from_node.return_value.execute.return_value = 0, "success", ""
+ ssh.from_node.return_value.run.return_value = 0, "success", ""
+
+ ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id')
+ self.assertIsNone(ping_traffic_gen.terminate())
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py
new file mode 100644
index 000000000..5ad182f22
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py
@@ -0,0 +1,428 @@
+# Copyright (c) 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import unittest
+import mock
+
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.tg_prox import ProxTrafficGen
+from yardstick.network_services.traffic_profile.base import TrafficProfile
+
+
+SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
+NAME = 'vnf__1'
+
+
+@mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time')
+class TestProxTrafficGen(unittest.TestCase):
+ VNFD0 = {
+ 'short-name': 'ProxVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'description': 'PROX approximation using DPDK',
+ 'name': 'proxvnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'id': 'proxvnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': '',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0',
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': '',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1',
+ },
+ ],
+ },
+ ],
+ 'description': 'PROX approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'proxvnf-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1',
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'ProxApproxVnf',
+ 'name': 'ProxVnf',
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD0,
+ ],
+ },
+ }
+
+ SCENARIO_CFG = {
+ 'task_path': "",
+ 'nodes': {
+ 'tg__1': 'trafficgen_1.yardstick',
+ 'vnf__1': 'vnf.yardstick'},
+ 'runner': {
+ 'duration': 600, 'type': 'Duration'},
+ 'topology': 'prox-tg-topology-2.yaml',
+ 'traffic_profile': '../../traffic_profiles/prox_binsearch.yaml',
+ 'type': 'NSPerf',
+ 'options': {
+ 'tg__1': {'prox_args': {'-e': '',
+ '-t': ''},
+ 'prox_config': 'configs/l3-gen-2.cfg',
+ 'prox_path':
+ '/root/dppd-PROX-v035/build/prox'},
+ 'vnf__1': {
+ 'prox_args': {'-t': ''},
+ 'prox_config': 'configs/l3-swap-2.cfg',
+ 'prox_path': '/root/dppd-PROX-v035/build/prox'}}}
+
+ CONTEXT_CFG = {
+ 'nodes': {
+ 'tg__2': {
+ 'member-vnf-index': '3',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_2.yardstick',
+ 'vnfd-id-ref': 'tg__2',
+ 'ip': '1.2.1.1',
+ 'interfaces': {
+ 'xe0': {
+ 'local_iface_name': 'ens513f0',
+ 'vld_id': ProxTrafficGen.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.20',
+ 'dst_mac': '00:00:00:00:00:01',
+ 'local_mac': '00:00:00:00:00:03',
+ 'dst_ip': '152.16.40.19',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'local_iface_name': 'ens513f1',
+ 'netmask': '255.255.255.0',
+ 'network': '202.16.100.0',
+ 'local_ip': '202.16.100.20',
+ 'local_mac': '00:1e:67:d0:60:5d',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'password': 'r00t',
+ 'VNF model': 'l3fwd_vnf.yaml',
+ 'user': 'root',
+ },
+ 'tg__1': {
+ 'member-vnf-index': '1',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_1.yardstick',
+ 'vnfd-id-ref': 'tg__1',
+ 'ip': '1.2.1.1',
+ 'interfaces': {
+ 'xe0': {
+ 'local_iface_name': 'ens785f0',
+ 'vld_id': ProxTrafficGen.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.20',
+ 'dst_mac': '00:00:00:00:00:02',
+ 'local_mac': '00:00:00:00:00:04',
+ 'dst_ip': '152.16.100.19',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'local_iface_name': 'ens785f1',
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.21',
+ 'local_mac': '00:00:00:00:00:01',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'password': 'r00t',
+ 'VNF model': 'tg_rfc2544_tpl.yaml',
+ 'user': 'root',
+ },
+ 'vnf__1': {
+ 'name': 'vnf.yardstick',
+ 'vnfd-id-ref': 'vnf__1',
+ 'ip': '1.2.1.1',
+ 'interfaces': {
+ 'xe0': {
+ 'local_iface_name': 'ens786f0',
+ 'vld_id': ProxTrafficGen.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.19',
+ 'dst_mac': '00:00:00:00:00:04',
+ 'local_mac': '00:00:00:00:00:02',
+ 'dst_ip': '152.16.100.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'local_iface_name': 'ens786f1',
+ 'vld_id': ProxTrafficGen.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.19',
+ 'dst_mac': '00:00:00:00:00:03',
+ 'local_mac': '00:00:00:00:00:01',
+ 'dst_ip': '152.16.40.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'routing_table': [
+ {
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'network': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'network': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'member-vnf-index': '2',
+ 'host': '1.2.1.1',
+ 'role': 'vnf',
+ 'user': 'root',
+ 'nd_route_tbl': [
+ {
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'password': 'r00t',
+ 'VNF model': 'prox_vnf.yaml',
+ },
+ },
+ }
+
+ TRAFFIC_PROFILE = {
+ 'description': 'Binary search for max no-drop throughput over given packet sizes',
+ 'name': 'prox_binsearch',
+ 'schema': 'nsb:traffic_profile:0.1',
+ 'traffic_profile': {
+ 'duration': 5,
+ 'lower_bound': 0.0,
+ 'packet_sizes': [64, 65],
+ 'test_precision': 1.0,
+ 'tolerated_loss': 0.0,
+ 'traffic_type': 'ProxBinSearchProfile',
+ 'upper_bound': 100.0}}
+
+ @mock.patch(SSH_HELPER)
+ def test___init__(self, ssh, *args):
+ mock_ssh(ssh)
+ prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0, 'task_id')
+ self.assertIsNone(prox_traffic_gen._tg_process)
+ self.assertIsNone(prox_traffic_gen._traffic_process)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, *args):
+ mock_ssh(ssh)
+ prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0, 'task_id')
+ prox_traffic_gen.scenario_helper.scenario_cfg = {
+ 'nodes': {prox_traffic_gen.name: "mock"}
+ }
+ prox_traffic_gen._vnf_wrapper.resource_helper.resource = mock.MagicMock(
+ **{"self.check_if_system_agent_running.return_value": [False]})
+ prox_traffic_gen._vnf_wrapper.vnf_execute = mock.Mock(return_value="")
+ expected = {
+ 'collect_stats': {},
+ 'physical_node': 'mock_node'
+ }
+ self.assertEqual(prox_traffic_gen.collect_kpi(), expected)
+
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.find_relative_file')
+ @mock.patch(
+ 'yardstick.network_services.vnf_generic.vnf.sample_vnf.CpuSysCores')
+ @mock.patch(SSH_HELPER)
+ def bad_test_instantiate(self, ssh, mock_cpu_sys_cores, *args):
+ mock_ssh(ssh)
+
+ mock_cpu_sys_cores.get_core_socket.return_value = {'0': '01234'}
+
+ mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ prox_traffic_gen = ProxTrafficGen(NAME, vnfd, 'task_id')
+ ssh_helper = mock.MagicMock(
+ **{"execute.return_value": (0, "", ""), "bin_path": ""})
+ prox_traffic_gen.ssh_helper = ssh_helper
+ prox_traffic_gen.setup_helper.dpdk_bind_helper.ssh_helper = ssh_helper
+ prox_traffic_gen.setup_helper._setup_resources = mock.MagicMock()
+ prox_traffic_gen.setup_hugepages = mock.MagicMock()
+ prox_traffic_gen.generate_prox_config_file = mock.MagicMock()
+ prox_traffic_gen.upload_prox_config = mock.MagicMock()
+ prox_traffic_gen.setup_helper._find_used_drivers = mock.MagicMock()
+ prox_traffic_gen.setup_helper.used_drivers = {}
+ prox_traffic_gen.setup_helper.bound_pci = []
+ prox_traffic_gen._start_server = mock.Mock(return_value=0)
+ prox_traffic_gen._tg_process = mock.MagicMock()
+ prox_traffic_gen._tg_process.start = mock.Mock()
+ prox_traffic_gen._tg_process.exitcode = 0
+ prox_traffic_gen._tg_process._is_alive = mock.Mock(return_value=1)
+ prox_traffic_gen.ssh_helper = mock.MagicMock()
+ prox_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ scenario_cfg = {
+ 'task_path': '',
+ 'options': {'tg__1': {'prox_args': {'-e': '',
+ '-t': ''},
+ 'prox_config': 'configs/l3-gen-2.cfg',
+ 'prox_path': '/root/dppd-PROX-v035/build/prox'},
+ 'vnf__1': {'prox_args': {'-t': ''},
+ 'prox_config': 'configs/l3-swap-2.cfg',
+ 'prox_path': '/root/dppd-PROX-v035/build/prox'}
+ }
+ }
+ prox_traffic_gen.instantiate(scenario_cfg, {})
+
+ @mock.patch(SSH_HELPER)
+ def test__traffic_runner(self, ssh, *args):
+ mock_ssh(ssh)
+
+ mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.execute_traffic.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sut = ProxTrafficGen(NAME, vnfd, 'task_id')
+ sut._get_socket = mock.MagicMock()
+ sut.ssh_helper = mock.Mock()
+ sut.ssh_helper.run = mock.Mock()
+ sut.setup_helper.prox_config_dict = {}
+ sut._connect_client = mock.Mock(autospec=mock.Mock())
+ sut._connect_client.get_stats = mock.Mock(return_value="0")
+ sut._setup_mq_producer = mock.Mock(return_value='mq_producer')
+ sut._traffic_runner(mock_traffic_profile, mock.ANY)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket')
+ @mock.patch(SSH_HELPER)
+ def test_listen_traffic(self, ssh, *args):
+ mock_ssh(ssh)
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ prox_traffic_gen = ProxTrafficGen(NAME, vnfd, 'task_id')
+ self.assertIsNone(prox_traffic_gen.listen_traffic(mock.Mock()))
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket')
+ @mock.patch(SSH_HELPER)
+ def test_terminate(self, ssh, *args):
+ mock_ssh(ssh)
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ prox_traffic_gen = ProxTrafficGen(NAME, vnfd, 'task_id')
+ prox_traffic_gen._terminated = mock.MagicMock()
+ prox_traffic_gen._traffic_process = mock.MagicMock()
+ prox_traffic_gen._traffic_process.terminate = mock.Mock()
+ prox_traffic_gen.ssh_helper = mock.MagicMock()
+ prox_traffic_gen.setup_helper = mock.MagicMock()
+ prox_traffic_gen.resource_helper = mock.MagicMock()
+ prox_traffic_gen._vnf_wrapper.setup_helper = mock.MagicMock()
+ prox_traffic_gen._vnf_wrapper._vnf_process = mock.MagicMock()
+ prox_traffic_gen._vnf_wrapper.resource_helper = mock.MagicMock()
+ self.assertIsNone(prox_traffic_gen.terminate())
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py
new file mode 100644
index 000000000..ddb63242e
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py
@@ -0,0 +1,392 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+import mock
+import six
+import unittest
+
+from yardstick.benchmark import contexts
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api
+from yardstick.network_services.traffic_profile import base as tp_base
+from yardstick.network_services.vnf_generic.vnf import tg_rfc2544_ixia
+
+
+TEST_FILE_YAML = 'nsb_test_case.yaml'
+
+NAME = "tg__1"
+
+
+class TestIxiaResourceHelper(unittest.TestCase):
+
+ def setUp(self):
+ self._mock_IxNextgen = mock.patch.object(ixnet_api, 'IxNextgen')
+ self.mock_IxNextgen = self._mock_IxNextgen.start()
+ self.addCleanup(self._stop_mocks)
+
+ def _stop_mocks(self):
+ self._mock_IxNextgen.stop()
+
+ def test___init___with_custom_rfc_helper(self):
+ class MyRfcHelper(tg_rfc2544_ixia.IxiaRfc2544Helper):
+ pass
+
+ ixia_resource_helper = tg_rfc2544_ixia.IxiaResourceHelper(
+ mock.Mock(), MyRfcHelper)
+ self.assertIsInstance(ixia_resource_helper.rfc_helper, MyRfcHelper)
+
+ def test_stop_collect_with_client(self):
+ mock_client = mock.Mock()
+ ixia_resource_helper = tg_rfc2544_ixia.IxiaResourceHelper(mock.Mock())
+ ixia_resource_helper.client = mock_client
+ ixia_resource_helper.stop_collect()
+ self.assertEqual(1, ixia_resource_helper._terminated.value)
+
+ def test_run_traffic(self):
+ mock_tprofile = mock.Mock()
+ mock_tprofile.get_drop_percentage.return_value = True, 'fake_samples'
+ ixia_rhelper = tg_rfc2544_ixia.IxiaResourceHelper(mock.Mock())
+ ixia_rhelper.rfc_helper = mock.Mock()
+ ixia_rhelper.vnfd_helper = mock.Mock()
+ ixia_rhelper.vnfd_helper.port_pairs.all_ports = []
+ with mock.patch.object(ixia_rhelper, 'generate_samples'), \
+ mock.patch.object(ixia_rhelper, '_build_ports'), \
+ mock.patch.object(ixia_rhelper, '_initialize_client'):
+ ixia_rhelper.run_traffic(mock_tprofile)
+
+ self.assertEqual('fake_samples', ixia_rhelper._queue.get())
+
+
+@mock.patch.object(tg_rfc2544_ixia, 'ixnet_api')
+class TestIXIATrafficGen(unittest.TestCase):
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{'short-name': 'VpeVnf',
+ 'vdu':
+ [{'routing_table':
+ [{'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'},
+ {'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'}],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl':
+ [{'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'},
+ {'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'}],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface':
+ [{'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02'},
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'},
+ {'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01'},
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'}]}],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface':
+ {'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'},
+ 'benchmark':
+ {'kpi': ['packets_in', 'packets_fwd',
+ 'packets_dropped']},
+ 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
+ {'type': 'VPORT', 'name': 'xe1'}],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}}
+
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64}}
+
+ TC_YAML = {'scenarios': [{'tc_options':
+ {'rfc2544': {'allowed_drop_rate': '0.8 - 1'}},
+ 'runner': {'duration': 400,
+ 'interval': 35, 'type': 'Duration'},
+ 'traffic_options':
+ {'flow': 'ipv4_1flow_Packets_vpe.yaml',
+ 'imix': 'imix_voice.yaml'},
+ 'vnf_options': {'vpe': {'cfg': 'vpe_config'}},
+ 'traffic_profile': 'ipv4_throughput_vpe.yaml',
+ 'type': 'NSPerf',
+ 'nodes': {'tg__1': 'trafficgen_1.yardstick',
+ 'vnf__1': 'vnf.yardstick'},
+ 'topology': 'vpe_vnf_topology.yaml'}],
+ 'context': {'nfvi_type': 'baremetal',
+ 'type': contexts.CONTEXT_NODE,
+ 'name': 'yardstick',
+ 'file': '/etc/yardstick/nodes/pod.yaml'},
+ 'schema': 'yardstick:task:0.1'}
+
+ def test___init__(self, *args):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ ssh_mock.execute = \
+ mock.Mock(return_value=(0, "", ""))
+ ssh.from_node.return_value = ssh_mock
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ # NOTE(ralonsoh): check the object returned.
+ tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd, 'task_id')
+
+ def test_listen_traffic(self, *args):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ ssh_mock.execute = \
+ mock.Mock(return_value=(0, "", ""))
+ ssh.from_node.return_value = ssh_mock
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd,
+ 'task_id')
+ self.assertIsNone(ixnet_traffic_gen.listen_traffic({}))
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
+ def test_instantiate(self, *args):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ ssh_mock.execute = \
+ mock.Mock(return_value=(0, "", ""))
+ ssh_mock.run = \
+ mock.Mock(return_value=(0, "", ""))
+ ssh.from_node.return_value = ssh_mock
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd,
+ 'task_id')
+ scenario_cfg = {'tc': "nsb_test_case", "topology": "",
+ 'ixia_profile': "ixload.cfg"}
+ scenario_cfg.update(
+ {
+ 'options': {
+ 'packetsize': 64,
+ 'traffic_type': 4,
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1'},
+ 'vnf__1': {
+ 'rules': 'acl_1rule.yaml',
+ 'vnf_config': {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1}}}})
+ scenario_cfg.update({
+ 'nodes': {ixnet_traffic_gen.name: "mock"}
+ })
+ ixnet_traffic_gen.topology = ""
+ ixnet_traffic_gen.get_ixobj = mock.MagicMock()
+ ixnet_traffic_gen._ixia_traffic_gen = mock.MagicMock()
+ ixnet_traffic_gen._ixia_traffic_gen._connect = mock.Mock()
+ self.assertRaises(
+ IOError,
+ ixnet_traffic_gen.instantiate(scenario_cfg, {}))
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ def test_collect_kpi(self, *args):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ ssh_mock.execute = \
+ mock.Mock(return_value=(0, "", ""))
+ ssh.from_node.return_value = ssh_mock
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd,
+ 'task_id')
+ ixnet_traffic_gen.scenario_helper.scenario_cfg = {
+ 'nodes': {ixnet_traffic_gen.name: "mock"}
+ }
+ ixnet_traffic_gen.data = {}
+ restult = ixnet_traffic_gen.collect_kpi()
+
+ expected = {'collect_stats': {},
+ 'physical_node': 'mock_node'}
+
+ self.assertEqual(expected, restult)
+
+ def test_terminate(self, *args):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ ssh_mock.execute = \
+ mock.Mock(return_value=(0, "", ""))
+ ssh.from_node.return_value = ssh_mock
+ ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd,
+ 'task_id')
+ ixnet_traffic_gen._terminated = mock.MagicMock()
+ ixnet_traffic_gen._terminated.value = 0
+ ixnet_traffic_gen._ixia_traffic_gen = mock.MagicMock()
+ ixnet_traffic_gen._ixia_traffic_gen.ix_stop_traffic = mock.Mock()
+ ixnet_traffic_gen._traffic_process = mock.MagicMock()
+ ixnet_traffic_gen._traffic_process.terminate = mock.Mock()
+ self.assertIsNone(ixnet_traffic_gen.terminate())
+
+ def _get_file_abspath(self, filename):
+ curr_path = os.path.dirname(os.path.abspath(__file__))
+ file_path = os.path.join(curr_path, filename)
+ return file_path
+
+ def test__check_status(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sut = tg_rfc2544_ixia.IxiaTrafficGen('vnf1', vnfd, 'task_id')
+ sut._check_status()
+
+ @mock.patch("yardstick.ssh.SSH")
+ def test_traffic_runner(self, mock_ssh, *args):
+ mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+ # traffic_profile.ports is standardized on port_num
+ mock_traffic_profile.ports = [0, 1]
+
+ mock_ssh_instance = mock.Mock(autospec=mock_ssh.SSH)
+ mock_ssh_instance.execute.return_value = 0, "", ""
+ mock_ssh_instance.run.return_value = 0, "", ""
+
+ mock_ssh.from_node.return_value = mock_ssh_instance
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vnfd["mgmt-interface"].update({
+ 'tg-config': {
+ "ixchassis": "1.1.1.1",
+ "py_bin_path": "/root",
+ }
+ })
+
+ samples = {}
+ name = ''
+ for ifname in range(1):
+ name = "xe{}".format(ifname)
+ samples[name] = {
+ "Rx_Rate_Kbps": 20,
+ "Tx_Rate_Kbps": 20,
+ "Rx_Rate_Mbps": 10,
+ "Tx_Rate_Mbps": 10,
+ "RxThroughput": 10,
+ "TxThroughput": 10,
+ "Valid_Frames_Rx": 1000,
+ "Frames_Tx": 1000,
+ "in_packets": 1000,
+ "out_packets": 1000,
+ }
+
+ samples.update({"CurrentDropPercentage": 0.0})
+
+ last_res = [
+ 0,
+ {
+ "Rx_Rate_Kbps": [20, 20],
+ "Tx_Rate_Kbps": [20, 20],
+ "Rx_Rate_Mbps": [10, 10],
+ "Tx_Rate_Mbps": [10, 10],
+ "CurrentDropPercentage": [0, 0],
+ "RxThroughput": [10, 10],
+ "TxThroughput": [10, 10],
+ "Frames_Tx": [1000, 1000],
+ "in_packets": [1000, 1000],
+ "Valid_Frames_Rx": [1000, 1000],
+ "out_packets": [1000, 1000],
+ },
+ ]
+
+ mock_traffic_profile.execute_traffic.return_value = [
+ 'Completed', samples]
+ mock_traffic_profile.get_drop_percentage.return_value = [
+ 'Completed', samples]
+
+ sut = tg_rfc2544_ixia.IxiaTrafficGen(name, vnfd, 'task_id')
+ sut.vnf_port_pairs = [[[0], [1]]]
+ sut.tc_file_name = self._get_file_abspath(TEST_FILE_YAML)
+ sut.topology = ""
+
+ sut.ssh_helper = mock.Mock()
+ sut._traffic_process = mock.MagicMock()
+ sut.generate_port_pairs = mock.Mock()
+
+ sut._ixia_traffic_gen = mock.MagicMock()
+ sut._ixia_traffic_gen.ix_get_statistics.return_value = last_res
+
+ sut.resource_helper.client = mock.MagicMock()
+ sut.resource_helper.client_started = mock.MagicMock()
+ sut.resource_helper.client_started.value = 1
+ sut.resource_helper.rfc_helper.iteration.value = 11
+
+ sut.scenario_helper.scenario_cfg = {
+ 'options': {
+ 'packetsize': 64,
+ 'traffic_type': 4,
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1',
+ 'latency': True
+ },
+ 'vnf__1': {
+ 'rules': 'acl_1rule.yaml',
+ 'vnf_config': {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1,
+ },
+ },
+ },
+ 'ixia_profile': '/path/to/profile',
+ 'task_path': '/path/to/task'
+ }
+
+ @mock.patch.object(six.moves.builtins, 'open', create=True)
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.open',
+ mock.mock_open(), create=True)
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.LOG.exception')
+ def _traffic_runner(*args):
+ sut._setup_mq_producer = mock.Mock(return_value='mq_producer')
+ result = sut._traffic_runner(mock_traffic_profile, mock.ANY)
+ self.assertIsNone(result)
+
+ _traffic_runner()
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py
new file mode 100644
index 000000000..6aba41006
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py
@@ -0,0 +1,313 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import mock
+import unittest
+
+from yardstick.benchmark import contexts
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.traffic_profile import base as tp_base
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+from yardstick.network_services.vnf_generic.vnf import tg_rfc2544_trex
+
+
+class TestTrexRfcResouceHelper(unittest.TestCase):
+
+ def test__run_traffic_once(self):
+ mock_setup_helper = mock.Mock()
+ mock_traffic_profile = mock.Mock()
+ mock_traffic_profile.config.duration = 3
+ mock_traffic_profile.execute_traffic.return_value = ('fake_ports',
+ 'port_pg_id_map')
+ mock_traffic_profile.get_drop_percentage.return_value = 'percentage'
+ rfc_rh = tg_rfc2544_trex.TrexRfcResourceHelper(mock_setup_helper)
+ rfc_rh.TRANSIENT_PERIOD = 0
+ rfc_rh.rfc2544_helper = mock.Mock()
+
+ with mock.patch.object(rfc_rh, '_get_samples') as mock_get_samples:
+ rfc_rh._run_traffic_once(mock_traffic_profile)
+
+ mock_traffic_profile.execute_traffic.assert_called_once_with(rfc_rh)
+ mock_traffic_profile.stop_traffic.assert_called_once_with(rfc_rh)
+ mock_traffic_profile.stop_traffic.assert_called_once()
+ mock_get_samples.assert_has_calls([
+ mock.call('fake_ports', port_pg_id='port_pg_id_map'),
+ mock.call('fake_ports', port_pg_id='port_pg_id_map')])
+
+
+class TestTrexTrafficGenRFC(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'ifname': 'xe0',
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'vld_id': 'uplink_0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:01',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0',
+ },
+ {
+ 'virtual-interface': {
+ 'ifname': 'xe1',
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'vld_id': 'downlink_0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:02'
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1',
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1',
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf',
+ 'name': 'VPEVnfSsh',
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ],
+ },
+ }
+
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64,
+ },
+ }
+
+ TC_YAML = {
+ 'scenarios': [
+ {
+ 'tc_options': {
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1',
+ },
+ },
+ 'runner': {
+ 'duration': 400,
+ 'interval': 35,
+ 'type': 'Duration',
+ },
+ 'traffic_options': {
+ 'flow': 'ipv4_1flow_Packets_vpe.yaml',
+ 'imix': 'imix_voice.yaml',
+ },
+ 'vnf_options': {
+ 'vpe': {
+ 'cfg': 'vpe_config',
+ },
+ },
+ 'traffic_profile': 'ipv4_throughput_vpe.yaml',
+ 'type': 'NSPerf',
+ 'nodes': {
+ 'tg__1': 'trafficgen_1.yardstick',
+ 'vnf__1': 'vnf.yardstick',
+ },
+ 'topology': 'vpe_vnf_topology.yaml',
+ },
+ ],
+ 'context': {
+ 'nfvi_type': 'baremetal',
+ 'type': contexts.CONTEXT_NODE,
+ 'name': 'yardstick',
+ 'file': '/etc/yardstick/nodes/pod.yaml',
+ },
+ 'schema': 'yardstick:task:0.1',
+ }
+
+ def setUp(self):
+ self._mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper')
+ self.mock_ssh_helper = self._mock_ssh_helper.start()
+ self.addCleanup(self._stop_mocks)
+
+ def _stop_mocks(self):
+ self._mock_ssh_helper.stop()
+
+ def test___init__(self):
+ trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC(
+ 'vnf1', self.VNFD_0, 'task_id')
+ self.assertIsNotNone(trex_traffic_gen.resource_helper._terminated.value)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ def test_collect_kpi(self, *args):
+ trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC(
+ 'vnf1', self.VNFD_0, 'task_id')
+ trex_traffic_gen.scenario_helper.scenario_cfg = {
+ 'nodes': {trex_traffic_gen.name: "mock"}
+ }
+ expected = {
+ 'physical_node': 'mock_node',
+ 'collect_stats': {},
+ }
+ self.assertEqual(trex_traffic_gen.collect_kpi(), expected)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
+ def test_instantiate(self, *args):
+ mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+
+ trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC(
+ 'vnf1', self.VNFD_0, 'task_id')
+ trex_traffic_gen._start_server = mock.Mock(return_value=0)
+ trex_traffic_gen.resource_helper = mock.MagicMock()
+ trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
+
+ scenario_cfg = {
+ "tc": "tc_baremetal_rfc2544_ipv4_1flow_64B",
+ "topology": 'nsb_test_case.yaml',
+ 'options': {
+ 'packetsize': 64,
+ 'traffic_type': 4,
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1',
+ },
+ 'vnf__1': {
+ 'rules': 'acl_1rule.yaml',
+ 'vnf_config': {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1
+ },
+ },
+ },
+ }
+ tg_rfc2544_trex.WAIT_TIME = 3
+ scenario_cfg.update({"nodes": {"tg_1": {}, "vnf1": {}}})
+ self.assertIsNone(trex_traffic_gen.instantiate(scenario_cfg, {}))
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
+ def test_instantiate_error(self, *args):
+ mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+
+ trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC(
+ 'vnf1', self.VNFD_0, 'task_id')
+ trex_traffic_gen.resource_helper = mock.MagicMock()
+ trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
+ scenario_cfg = {
+ "tc": "tc_baremetal_rfc2544_ipv4_1flow_64B",
+ "nodes": {
+ "tg_1": {},
+ "vnf1": {}
+ },
+ "topology": 'nsb_test_case.yaml',
+ 'options': {
+ 'packetsize': 64,
+ 'traffic_type': 4,
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1',
+ },
+ 'vnf__1': {
+ 'rules': 'acl_1rule.yaml',
+ 'vnf_config': {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1,
+ },
+ },
+ },
+ }
+ trex_traffic_gen.instantiate(scenario_cfg, {})
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py
new file mode 100644
index 000000000..9ed2abbb9
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py
@@ -0,0 +1,516 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import copy
+
+import mock
+import unittest
+
+from yardstick.network_services.traffic_profile import base as tp_base
+from yardstick.network_services.traffic_profile import rfc2544
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+from yardstick.network_services.vnf_generic.vnf import tg_trex
+from yardstick.benchmark.contexts import base as ctx_base
+
+
+NAME = 'vnf__1'
+
+
+class TestTrexTrafficGen(unittest.TestCase):
+
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{'short-name': 'VpeVnf',
+ 'vdu':
+ [{'routing_table':
+ [{'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'},
+ {'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'}],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl':
+ [{'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'},
+ {'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'}],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface':
+ [{'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe0',
+ 'local_mac': '00:00:00:00:00:02'},
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'},
+ {'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe1',
+ 'local_mac': '00:00:00:00:00:01'},
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'}]}],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface':
+ {'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'},
+ 'benchmark':
+ {'kpi': ['packets_in', 'packets_fwd',
+ 'packets_dropped']},
+ 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
+ {'type': 'VPORT', 'name': 'xe1'}],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}}
+
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64
+ },
+ }
+
+ SCENARIO_CFG = {
+ "options": {
+ "packetsize": 64,
+ "traffic_type": 4,
+ "rfc2544": {
+ "allowed_drop_rate": "0.8 - 1",
+ },
+ "vnf__1": {
+ "rules": "acl_1rule.yaml",
+ "vnf_config": {
+ "lb_config": "SW",
+ "lb_count": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 1,
+ }
+ }
+ },
+ "task_id": "a70bdf4a-8e67-47a3-9dc1-273c14506eb7",
+ "tc": "tc_ipv4_1Mflow_64B_packetsize",
+ "runner": {
+ "object": "NetworkServiceTestCase",
+ "interval": 35,
+ "output_filename": "/tmp/yardstick.out",
+ "runner_id": 74476, "duration": 400,
+ "type": "Duration"
+ },
+ "traffic_profile": "ipv4_throughput_acl.yaml",
+ "traffic_options": {
+ "flow": "ipv4_Packets_acl.yaml",
+ "imix": "imix_voice.yaml"
+ },
+ "type": "ISB",
+ "nodes": {
+ "tg__2": "trafficgen_2.yardstick",
+ "tg__1": "trafficgen_1.yardstick",
+ "vnf__1": "vnf.yardstick"
+ },
+ "topology": "udpreplay-tg-topology-baremetal.yaml"
+ }
+
+ CONTEXT_CFG = {
+ "nodes": {
+ "vnf__1": {
+ "vnfd-id-ref": "vnf__1",
+ "ip": "1.2.1.1",
+ "interfaces": {
+ "xe0": {
+ "local_iface_name": "ens786f0",
+ "vld_id": tp_base.TrafficProfile.UPLINK,
+ "netmask": "255.255.255.0",
+ "vpci": "0000:05:00.0",
+ "local_ip": "152.16.100.19",
+ "driver": "i40e",
+ "dst_ip": "152.16.100.20",
+ "local_mac": "00:00:00:00:00:02",
+ "dst_mac": "00:00:00:00:00:04",
+ "dpdk_port_num": 0
+ },
+ "xe1": {
+ "local_iface_name": "ens786f1",
+ "vld_id": tp_base.TrafficProfile.DOWNLINK,
+ "netmask": "255.255.255.0",
+ "vpci": "0000:05:00.1",
+ "local_ip": "152.16.40.19",
+ "driver": "i40e",
+ "dst_ip": "152.16.40.20",
+ "local_mac": "00:00:00:00:00:01",
+ "dst_mac": "00:00:00:00:00:03",
+ "dpdk_port_num": 1
+ }
+ },
+ "host": "1.2.1.1",
+ "user": "root",
+ "nd_route_tbl": [
+ {
+ "netmask": "112",
+ "if": "xe0",
+ "gateway": "0064:ff9b:0:0:0:0:9810:6414",
+ "network": "0064:ff9b:0:0:0:0:9810:6414"
+ },
+ {
+ "netmask": "112",
+ "if": "xe1",
+ "gateway": "0064:ff9b:0:0:0:0:9810:2814",
+ "network": "0064:ff9b:0:0:0:0:9810:2814"
+ }
+ ],
+ "password": "r00t",
+ "VNF model": "udp_replay.yaml",
+ "name": "vnf.yardstick",
+ "member-vnf-index": "2",
+ "routing_table": [
+ {
+ "netmask": "255.255.255.0",
+ "if": "xe0",
+ "gateway": "152.16.100.20",
+ "network": "152.16.100.20"
+ },
+ {
+ "netmask": "255.255.255.0",
+ "if": "xe1",
+ "gateway": "152.16.40.20",
+ "network": "152.16.40.20"
+ }
+ ],
+ "role": "vnf"
+ },
+ "trafficgen_2.yardstick": {
+ "member-vnf-index": "3",
+ "role": "TrafficGen",
+ "name": "trafficgen_2.yardstick",
+ "vnfd-id-ref": "tg__2",
+ "ip": "1.2.1.1",
+ "interfaces": {
+ "xe0": {
+ "local_iface_name": "ens513f0",
+ "vld_id": tp_base.TrafficProfile.DOWNLINK,
+ "netmask": "255.255.255.0",
+ "vpci": "0000:02:00.0",
+ "local_ip": "152.16.40.20",
+ "driver": "ixgbe",
+ "dst_ip": "152.16.40.19",
+ "local_mac": "00:00:00:00:00:03",
+ "dst_mac": "00:00:00:00:00:01",
+ "dpdk_port_num": 0
+ },
+ "xe1": {
+ "local_iface_name": "ens513f1",
+ "netmask": "255.255.255.0",
+ "network": "202.16.100.0",
+ "local_ip": "202.16.100.20",
+ "driver": "ixgbe",
+ "local_mac": "00:1e:67:d0:60:5d",
+ "vpci": "0000:02:00.1",
+ "dpdk_port_num": 1
+ }
+ },
+ "password": "r00t",
+ "VNF model": "l3fwd_vnf.yaml",
+ "user": "root"
+ },
+ "trafficgen_1.yardstick": {
+ "member-vnf-index": "1",
+ "role": "TrafficGen",
+ "name": "trafficgen_1.yardstick",
+ "vnfd-id-ref": "tg__1",
+ "ip": "1.2.1.1",
+ "interfaces": {
+ "xe0": {
+ "local_iface_name": "ens785f0",
+ "vld_id": tp_base.TrafficProfile.UPLINK,
+ "netmask": "255.255.255.0",
+ "vpci": "0000:05:00.0",
+ "local_ip": "152.16.100.20",
+ "driver": "i40e",
+ "dst_ip": "152.16.100.19",
+ "local_mac": "00:00:00:00:00:04",
+ "dst_mac": "00:00:00:00:00:02",
+ "dpdk_port_num": 0
+ },
+ "xe1": {
+ "local_ip": "152.16.100.21",
+ "driver": "i40e",
+ "vpci": "0000:05:00.1",
+ "dpdk_port_num": 1,
+ "local_iface_name": "ens785f1",
+ "netmask": "255.255.255.0",
+ "local_mac": "00:00:00:00:00:01"
+ }
+ },
+ "password": "r00t",
+ "VNF model": "tg_rfc2544_tpl.yaml",
+ "user": "root"
+ }
+ }
+ }
+
+ def setUp(self):
+ self._mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper')
+ self.mock_ssh_helper = self._mock_ssh_helper.start()
+ self.addCleanup(self._stop_mocks)
+
+ def _stop_mocks(self):
+ self._mock_ssh_helper.stop()
+
+ def test___init__(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ self.assertIsInstance(trex_traffic_gen.resource_helper,
+ tg_trex.TrexResourceHelper)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ def test_collect_kpi(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ trex_traffic_gen.scenario_helper.scenario_cfg = {
+ 'nodes': {trex_traffic_gen.name: "mock"}
+ }
+ trex_traffic_gen.resource_helper._queue.put({})
+ result = trex_traffic_gen.collect_kpi()
+ expected = {
+ 'physical_node': 'mock_node',
+ 'collect_stats': {}
+ }
+ self.assertEqual(expected, result)
+
+ def test_listen_traffic(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ self.assertIsNone(trex_traffic_gen.listen_traffic({}))
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
+ def test_instantiate(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ trex_traffic_gen._start_server = mock.Mock(return_value=0)
+ trex_traffic_gen._tg_process = mock.MagicMock()
+ trex_traffic_gen._tg_process.start = mock.Mock()
+ trex_traffic_gen._tg_process.exitcode = 0
+ trex_traffic_gen._tg_process._is_alive = mock.Mock(return_value=1)
+ trex_traffic_gen.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
+ self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG,
+ self.CONTEXT_CFG))
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context')
+ def test_instantiate_error(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ trex_traffic_gen._start_server = mock.Mock(return_value=0)
+ trex_traffic_gen._tg_process = mock.MagicMock()
+ trex_traffic_gen._tg_process.start = mock.Mock()
+ trex_traffic_gen._tg_process._is_alive = mock.Mock(return_value=0)
+ trex_traffic_gen.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
+ self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG,
+ self.CONTEXT_CFG))
+
+ def test__start_server(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ trex_traffic_gen.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.scenario_helper.scenario_cfg = {}
+ self.assertIsNone(trex_traffic_gen._start_server())
+
+ def test__start_server_multiple_queues(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ trex_traffic_gen.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.scenario_helper.scenario_cfg = {
+ "options": {NAME: {"queues_per_port": 2}}}
+ self.assertIsNone(trex_traffic_gen._start_server())
+
+ def test__traffic_runner(self):
+ mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.execute_traffic.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ self.sut = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ self.sut.ssh_helper = mock.Mock()
+ self.sut.ssh_helper.run = mock.Mock()
+ self.sut._connect_client = mock.Mock()
+ self.sut._connect_client.get_stats = mock.Mock(return_value="0")
+ self.sut.resource_helper.RUN_DURATION = 0
+ self.sut.resource_helper.QUEUE_WAIT_TIME = 0
+ # must generate cfg before we can run traffic so Trex port mapping is
+ # created
+ self.sut.resource_helper.generate_cfg()
+ self.sut._setup_mq_producer = mock.Mock()
+ with mock.patch.object(self.sut.resource_helper, 'run_traffic'):
+ self.sut._traffic_runner(mock_traffic_profile, mock.ANY)
+
+ def test__generate_trex_cfg(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ self.assertIsNone(trex_traffic_gen.resource_helper.generate_cfg())
+
+ def test_build_ports_reversed_pci_ordering(self):
+ vnfd = copy.deepcopy(self.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ vnfd['vdu'][0]['external-interface'] = [
+ {'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 2,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe0',
+ 'local_mac': '00:00:00:00:00:02'},
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'},
+ {'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:04:00.0',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe1',
+ 'local_mac': '00:00:00:00:00:01'},
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'}]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.generate_cfg()
+ trex_traffic_gen.resource_helper._build_ports()
+ self.assertEqual(sorted(trex_traffic_gen.resource_helper.all_ports),
+ [0, 1])
+ # there is a gap in ordering
+ self.assertEqual(
+ {0: 0, 2: 1},
+ dict(trex_traffic_gen.resource_helper.dpdk_to_trex_port_map))
+
+ def test_run_traffic(self):
+ mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ self.sut = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ self.sut.ssh_helper = mock.Mock()
+ self.sut.ssh_helper.run = mock.Mock()
+ self.sut._traffic_runner = mock.Mock(return_value=0)
+ self.sut.resource_helper.client_started.value = 1
+ self.sut.run_traffic(mock_traffic_profile)
+ self.sut._traffic_process.terminate()
+
+ def test_terminate(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ trex_traffic_gen.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ self.assertIsNone(trex_traffic_gen.terminate())
+
+ def test__connect_client(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id')
+ client = mock.Mock()
+ client.connect = mock.Mock(return_value=0)
+ self.assertIsNotNone(trex_traffic_gen.resource_helper._connect(client))
+
+
+class TrexResourceHelperTestCase(unittest.TestCase):
+
+ def test__get_samples(self):
+ mock_setup_helper = mock.Mock()
+ trex_rh = tg_trex.TrexResourceHelper(mock_setup_helper)
+ trex_rh.vnfd_helper.interfaces = [
+ {'name': 'interface1'},
+ {'name': 'interface2'}]
+ stats = {
+ 10: {'rx_pps': 5, 'ipackets': 200},
+ 20: {'rx_pps': 10, 'ipackets': 300},
+ 'latency': {1: {'latency': 'latency_port_10_pg_id_1'},
+ 2: {'latency': 'latency_port_10_pg_id_2'},
+ 3: {'latency': 'latency_port_20_pg_id_3'},
+ 4: {'latency': 'latency_port_20_pg_id_4'}}
+ }
+ port_pg_id = rfc2544.PortPgIDMap()
+ port_pg_id.add_port(10)
+ port_pg_id.increase_pg_id()
+ port_pg_id.increase_pg_id()
+ port_pg_id.add_port(20)
+ port_pg_id.increase_pg_id()
+ port_pg_id.increase_pg_id()
+
+ with mock.patch.object(trex_rh, 'get_stats') as mock_get_stats, \
+ mock.patch.object(trex_rh.vnfd_helper, 'port_num') as \
+ mock_port_num:
+ mock_get_stats.return_value = stats
+ mock_port_num.side_effect = [10, 20]
+ output = trex_rh._get_samples([10, 20], port_pg_id=port_pg_id)
+
+ interface = output['interface1']
+ self.assertEqual(5.0, interface['rx_throughput_fps'])
+ self.assertEqual(200, interface['in_packets'])
+ self.assertEqual('latency_port_10_pg_id_1', interface['latency'][1])
+ self.assertEqual('latency_port_10_pg_id_2', interface['latency'][2])
+
+ interface = output['interface2']
+ self.assertEqual(10.0, interface['rx_throughput_fps'])
+ self.assertEqual(300, interface['in_packets'])
+ self.assertEqual('latency_port_20_pg_id_3', interface['latency'][3])
+ self.assertEqual('latency_port_20_pg_id_4', interface['latency'][4])
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py
new file mode 100644
index 000000000..56c971da6
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py
@@ -0,0 +1,477 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+import mock
+import os
+
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.udp_replay import UdpReplayApproxVnf
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper
+
+
+SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
+
+TEST_FILE_YAML = 'nsb_test_case.yaml'
+
+NAME = "vnf__1"
+
+
+@mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process")
+class TestUdpReplayApproxVnf(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'UdpReplayVnf',
+ 'vdu': [
+ {
+ 'description': 'UDPReplay approximation using DPDK',
+ 'routing_table': [
+ {
+ 'netmask': '255.255.255.0',
+ 'if': 'xe0',
+ 'network': '152.16.100.20',
+ 'gateway': '152.16.100.20',
+ },
+ {
+ 'netmask': '255.255.255.0',
+ 'if': 'xe1',
+ 'network': '152.16.40.20',
+ 'gateway': '152.16.40.20',
+ }
+ ],
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'driver': 'i40e',
+ 'local_iface_name': 'xe0',
+ 'bandwidth': '10 Gbps',
+ 'local_ip': '152.16.100.19',
+ 'local_mac': '00:00:00:00:00:02',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0,
+ 'netmask': '255.255.255.0',
+ 'dst_ip': '152.16.100.20',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0',
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'driver': 'i40e',
+ 'local_iface_name': 'xe1',
+ 'bandwidth': '10 Gbps',
+ 'local_ip': '152.16.40.19',
+ 'local_mac': '00:00:00:00:00:01',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1,
+ 'netmask': '255.255.255.0',
+ 'dst_ip': '152.16.40.20',
+ 'type': 'PCI-PASSTHROUGH',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1',
+ }
+ ],
+ 'nd_route_tbl': [
+ {
+ 'netmask': '112',
+ 'if': 'xe0',
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ },
+ {
+ 'netmask': '112',
+ 'if': 'xe1',
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ }
+ ],
+ 'id': 'udpreplayvnf-baremetal',
+ 'name': 'udpreplayvnf-baremetal',
+ }
+ ],
+ 'description': 'UDPReplay approximation using DPDK',
+ 'name': 'VPEVnfSsh',
+ 'mgmt-interface': {
+ 'vdu-id': 'udpreplay-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1',
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ]
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ }
+ ],
+ 'id': 'UdpReplayApproxVnf',
+ }
+
+ SCENARIO_CFG = {
+ "options": {
+ "packetsize": 64,
+ "traffic_type": 4,
+ "rfc2544": {
+ "allowed_drop_rate": "0.8 - 1",
+ },
+ "vnf__1": {
+ "rules": "acl_1rule.yaml",
+ "vnf_config": {
+ "lb_config": "SW",
+ "lb_count": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 1,
+ },
+ "hw_csum": "false",
+ }
+ },
+ "task_id": "a70bdf4a-8e67-47a3-9dc1-273c14506eb7",
+ "tc": "tc_ipv4_1Mflow_64B_packetsize",
+ "runner": {
+ "object": "NetworkServiceTestCase",
+ "interval": 35,
+ "output_filename": "/tmp/yardstick.out",
+ "runner_id": 74476, "duration": 400,
+ "type": "Duration"
+ },
+ "traffic_profile": "ipv4_throughput_acl.yaml",
+ "traffic_options": {
+ "flow": "ipv4_Packets_acl.yaml",
+ "imix": "imix_voice.yaml"
+ },
+ "type": "ISB",
+ "nodes": {
+ "tg__2": "trafficgen_2.yardstick",
+ "tg__1": "trafficgen_1.yardstick",
+ "vnf__1": "vnf.yardstick"
+ },
+ "topology": "udpreplay-tg-topology-baremetal.yaml"
+ }
+
+ CONTEXT_CFG = {
+ "nodes": {
+ "vnf__1": {
+ "vnfd-id-ref": "vnf__1",
+ "ip": "1.2.1.1",
+ "interfaces": {
+ "xe0": {
+ "local_iface_name": "ens786f0",
+ "vld_id": UdpReplayApproxVnf.UPLINK,
+ "netmask": "255.255.255.0",
+ "vpci": "0000:05:00.0",
+ "local_ip": "152.16.100.19",
+ "driver": "i40e",
+ "dst_ip": "152.16.100.20",
+ "local_mac": "00:00:00:00:00:02",
+ "dst_mac": "00:00:00:00:00:04",
+ "dpdk_port_num": 0
+ },
+ "xe1": {
+ "local_iface_name": "ens786f1",
+ "vld_id": UdpReplayApproxVnf.DOWNLINK,
+ "netmask": "255.255.255.0",
+ "vpci": "0000:05:00.1",
+ "local_ip": "152.16.40.19",
+ "driver": "i40e",
+ "dst_ip": "152.16.40.20",
+ "local_mac": "00:00:00:00:00:01",
+ "dst_mac": "00:00:00:00:00:03",
+ "dpdk_port_num": 1
+ }
+ },
+ "host": "1.2.1.1",
+ "user": "root",
+ "nd_route_tbl": [
+ {
+ "netmask": "112",
+ "if": "xe0",
+ "gateway": "0064:ff9b:0:0:0:0:9810:6414",
+ "network": "0064:ff9b:0:0:0:0:9810:6414"
+ },
+ {
+ "netmask": "112",
+ "if": "xe1",
+ "gateway": "0064:ff9b:0:0:0:0:9810:2814",
+ "network": "0064:ff9b:0:0:0:0:9810:2814"
+ }
+ ],
+ "password": "r00t",
+ "VNF model": "udp_replay.yaml",
+ "name": "vnf.yardstick",
+ "member-vnf-index": "2",
+ "routing_table": [
+ {
+ "netmask": "255.255.255.0",
+ "if": "xe0",
+ "gateway": "152.16.100.20",
+ "network": "152.16.100.20"
+ },
+ {
+ "netmask": "255.255.255.0",
+ "if": "xe1",
+ "gateway": "152.16.40.20",
+ "network": "152.16.40.20"
+ }
+ ],
+ "role": "vnf"
+ },
+ "trafficgen_2.yardstick": {
+ "member-vnf-index": "3",
+ "role": "TrafficGen",
+ "name": "trafficgen_2.yardstick",
+ "vnfd-id-ref": "tg__2",
+ "ip": "1.2.1.1",
+ "interfaces": {
+ "xe0": {
+ "local_iface_name": "ens513f0",
+ "vld_id": UdpReplayApproxVnf.DOWNLINK,
+ "netmask": "255.255.255.0",
+ "vpci": "0000:02:00.0",
+ "local_ip": "152.16.40.20",
+ "driver": "ixgbe",
+ "dst_ip": "152.16.40.19",
+ "local_mac": "00:00:00:00:00:03",
+ "dst_mac": "00:00:00:00:00:01",
+ "dpdk_port_num": 0
+ },
+ "xe1": {
+ "local_iface_name": "ens513f1",
+ "netmask": "255.255.255.0",
+ "network": "202.16.100.0",
+ "local_ip": "202.16.100.20",
+ "driver": "ixgbe",
+ "local_mac": "00:1e:67:d0:60:5d",
+ "vpci": "0000:02:00.1",
+ "dpdk_port_num": 1
+ }
+ },
+ "password": "r00t",
+ "VNF model": "l3fwd_vnf.yaml",
+ "user": "root"
+ },
+ "trafficgen_1.yardstick": {
+ "member-vnf-index": "1",
+ "role": "TrafficGen",
+ "name": "trafficgen_1.yardstick",
+ "vnfd-id-ref": "tg__1",
+ "ip": "1.2.1.1",
+ "interfaces": {
+ "xe0": {
+ "local_iface_name": "ens785f0",
+ "vld_id": UdpReplayApproxVnf.UPLINK,
+ "netmask": "255.255.255.0",
+ "vpci": "0000:05:00.0",
+ "local_ip": "152.16.100.20",
+ "driver": "i40e",
+ "dst_ip": "152.16.100.19",
+ "local_mac": "00:00:00:00:00:04",
+ "dst_mac": "00:00:00:00:00:02",
+ "dpdk_port_num": 0
+ },
+ "xe1": {
+ "local_ip": "152.16.100.21",
+ "driver": "i40e",
+ "vpci": "0000:05:00.1",
+ "dpdk_port_num": 1,
+ "local_iface_name": "ens785f1",
+ "netmask": "255.255.255.0",
+ "local_mac": "00:00:00:00:00:01"
+ }
+ },
+ "password": "r00t",
+ "VNF model": "tg_rfc2544_tpl.yaml",
+ "user": "root"
+ }
+ }
+ }
+
+ def test___init__(self, *args):
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+ 'task_id')
+ self.assertIsNone(udp_replay_approx_vnf._vnf_process)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD_0
+ get_stats_ret_val = \
+ "stats\r\r\n\r\nUDP_Replay stats:\r\n--------------\r\n" \
+ "Port\t\tRx Packet\t\tTx Packet\t\tRx Pkt Drop\t\tTx Pkt Drop \r\n"\
+ "0\t\t7374156\t\t7374136\t\t\t0\t\t\t0\r\n" \
+ "1\t\t7374316\t\t7374315\t\t\t0\t\t\t0\r\n\r\nReplay>\r\r\nReplay>"
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, vnfd, 'task_id')
+ udp_replay_approx_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {udp_replay_approx_vnf.name: "mock"}
+ }
+ udp_replay_approx_vnf.q_in = mock.MagicMock()
+ udp_replay_approx_vnf.q_out = mock.MagicMock()
+ udp_replay_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ udp_replay_approx_vnf.all_ports = ["xe0", "xe1"]
+ udp_replay_approx_vnf.get_stats = mock.Mock(return_value=get_stats_ret_val)
+ result = {
+ 'physical_node': 'mock_node',
+ 'collect_stats': {},
+ 'packets_dropped': 0,
+ 'packets_fwd': 14748451,
+ 'packets_in': 14748472
+ }
+ self.assertEqual(result, udp_replay_approx_vnf.collect_kpi())
+
+ @mock.patch(SSH_HELPER)
+ def test_get_stats(self, ssh, *args):
+ mock_ssh(ssh)
+
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+ 'task_id')
+ udp_replay_approx_vnf.q_in = mock.MagicMock()
+ udp_replay_approx_vnf.q_out = mock.MagicMock()
+ udp_replay_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ mock_result = \
+ "CG-NAPT(.*\n)*Received 100, Missed 0, Dropped 0,Translated 100,ingress"
+
+ udp_replay_approx_vnf.vnf_execute = mock.Mock(return_value=mock_result)
+
+ self.assertEqual(mock_result,
+ udp_replay_approx_vnf.get_stats())
+
+ def _get_file_abspath(self, filename):
+ curr_path = os.path.dirname(os.path.abspath(__file__))
+ file_path = os.path.join(curr_path, filename)
+ return file_path
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server')
+ @mock.patch(SSH_HELPER)
+ def test__build_config(self, ssh, mock_get_ctx, *args):
+ mock_ssh(ssh)
+
+ nfvi_context = mock.Mock()
+ nfvi_context.attrs = {'nfvi_type': 'baremetal'}
+ mock_get_ctx.return_value = nfvi_context
+
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+ 'task_id')
+ udp_replay_approx_vnf.queue_wrapper = mock.MagicMock()
+ udp_replay_approx_vnf.nfvi_context = mock_get_ctx
+ udp_replay_approx_vnf.nfvi_context.attrs = {'nfvi_type': 'baremetal'}
+ udp_replay_approx_vnf.setup_helper.bound_pci = []
+ udp_replay_approx_vnf.ssh_helper.provision_tool = mock.MagicMock(return_value="tool_path")
+ udp_replay_approx_vnf.scenario_helper = ScenarioHelper(name='vnf__1')
+ udp_replay_approx_vnf.scenario_helper.scenario_cfg = self.SCENARIO_CFG
+
+ cmd_line = udp_replay_approx_vnf._build_config()
+
+ expected = \
+ "sudo tool_path --log-level=5 -c 0x7 -n 4 -w -- -p 0x3 --config='(0,0,1),(1,0,2)'"
+ self.assertEqual(cmd_line, expected)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.udp_replay.open')
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server')
+ @mock.patch(SSH_HELPER)
+ def test__build_pipeline_kwargs(self, ssh, mock_get_ctx, *args):
+ mock_ssh(ssh)
+
+ nfvi_context = mock.Mock()
+ nfvi_context.attrs = {'nfvi_type': "baremetal"}
+ mock_get_ctx.return_value = nfvi_context
+
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+ 'task_id')
+ udp_replay_approx_vnf.setup_helper.bound_pci = ['0000:00:0.1', '0000:00:0.3']
+ udp_replay_approx_vnf.all_ports = ["xe0", "xe1"]
+ udp_replay_approx_vnf.ssh_helper.provision_tool = mock.MagicMock(return_value="tool_path")
+ udp_replay_approx_vnf.scenario_helper = ScenarioHelper(name='vnf__1')
+ udp_replay_approx_vnf.scenario_helper.scenario_cfg = self.SCENARIO_CFG
+
+ udp_replay_approx_vnf._build_pipeline_kwargs()
+
+ self.assertEqual(udp_replay_approx_vnf.pipeline_kwargs, {
+ 'config': '(0,0,1),(1,0,2)',
+ 'cpu_mask_hex': '0x7',
+ 'hw_csum': '',
+ 'port_mask_hex': '0x3',
+ 'tool_path': 'tool_path',
+ 'whitelist': '0000:00:0.1 -w 0000:00:0.3'
+ })
+
+ @mock.patch(SSH_HELPER)
+ def test_run_udp_replay(self, ssh, *args):
+ mock_ssh(ssh)
+
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+ 'task_id')
+ udp_replay_approx_vnf._build_config = mock.MagicMock()
+ udp_replay_approx_vnf.queue_wrapper = mock.MagicMock()
+ udp_replay_approx_vnf.scenario_helper = mock.MagicMock()
+
+ udp_replay_approx_vnf._run()
+
+ udp_replay_approx_vnf.ssh_helper.run.assert_called_once()
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server')
+ @mock.patch(SSH_HELPER)
+ def test_instantiate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+ 'task_id')
+ udp_replay_approx_vnf.q_out.put("Replay>")
+ udp_replay_approx_vnf.WAIT_TIME = 0
+ udp_replay_approx_vnf.setup_helper.setup_vnf_environment = mock.Mock()
+
+ udp_replay_approx_vnf.deploy_helper = mock.MagicMock()
+ udp_replay_approx_vnf.deploy_vnfs = mock.MagicMock()
+ self.assertIsNone(udp_replay_approx_vnf.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG))
+
+ udp_replay_approx_vnf._vnf_process.is_alive = mock.Mock(return_value=1)
+ udp_replay_approx_vnf._vnf_process.exitcode = 0
+
+ self.assertEqual(udp_replay_approx_vnf.wait_for_instantiate(), 0)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server')
+ @mock.patch('yardstick.ssh.SSH')
+ @mock.patch(SSH_HELPER)
+ def test_instantiate_panic(self, *args):
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0,
+ 'task_id')
+ udp_replay_approx_vnf.WAIT_TIME = 0
+ udp_replay_approx_vnf.q_out.put("some text PANIC some text")
+ udp_replay_approx_vnf.setup_helper.setup_vnf_environment = mock.Mock()
+
+ udp_replay_approx_vnf.deploy_helper = mock.MagicMock()
+ self.assertIsNone(udp_replay_approx_vnf.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG))
+ with self.assertRaises(RuntimeError):
+ udp_replay_approx_vnf.wait_for_instantiate()
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py
new file mode 100644
index 000000000..efbb7a856
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py
@@ -0,0 +1,371 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+import mock
+import os
+
+from yardstick.common import utils
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxVnf
+from yardstick.network_services.nfvi.resource import ResourceProfile
+from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxSetupEnvHelper
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+
+
+TEST_FILE_YAML = 'nsb_test_case.yaml'
+SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
+
+name = 'vnf__1'
+
+
+@mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process")
+class TestFWApproxVnf(unittest.TestCase):
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{'short-name': 'VpeVnf',
+ 'vdu':
+ [{'routing_table':
+ [{'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'},
+ {'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'}],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl':
+ [{'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'},
+ {'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'}],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface':
+ [{'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02'},
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'},
+ {'virtual-interface':
+ {'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01'},
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'}]}],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface':
+ {'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1'},
+ 'benchmark':
+ {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
+ 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
+ {'type': 'VPORT', 'name': 'xe1'}],
+ 'id': 'FWApproxVnf', 'name': 'VPEVnfSsh'}]}}
+
+ scenario_cfg = {'options': {'packetsize': 64, 'traffic_type': 4,
+ 'rfc2544': {'allowed_drop_rate': '0.8 - 1'},
+ 'vnf__1': {'rules': 'acl_1rule.yaml',
+ 'vnf_config': {'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config':
+ '1C/1T',
+ 'worker_threads': 1}}
+ },
+ 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
+ 'task_path': '/tmp',
+ 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
+ 'runner': {'object': 'NetworkServiceTestCase',
+ 'interval': 35,
+ 'output_filename': '/tmp/yardstick.out',
+ 'runner_id': 74476, 'duration': 400,
+ 'type': 'Duration'},
+ 'traffic_profile': 'ipv4_throughput_vfw.yaml',
+ 'traffic_options': {'flow': 'ipv4_Packets_vfw.yaml',
+ 'imix': 'imix_voice.yaml'},
+ 'type': 'ISB',
+ 'nodes': {'tg__2': 'trafficgen_2.yardstick',
+ 'tg__1': 'trafficgen_1.yardstick',
+ 'vnf__1': 'vnf.yardstick'},
+ 'topology': 'vpe-tg-topology-baremetal.yaml'}
+
+ context_cfg = {'nodes': {'tg__2':
+ {'member-vnf-index': '3',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_2.yardstick',
+ 'vnfd-id-ref': 'tg__2',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens513f0',
+ 'vld_id': FWApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.20',
+ 'dst_mac': '00:00:00:00:00:01',
+ 'local_mac': '00:00:00:00:00:03',
+ 'dst_ip': '152.16.40.19',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens513f1',
+ 'netmask': '255.255.255.0',
+ 'network': '202.16.100.0',
+ 'local_ip': '202.16.100.20',
+ 'local_mac': '00:1e:67:d0:60:5d',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.1',
+ 'dpdk_port_num': 1}},
+ 'password': 'r00t',
+ 'VNF model': 'l3fwd_vnf.yaml',
+ 'user': 'root'},
+ 'tg__1':
+ {'member-vnf-index': '1',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_1.yardstick',
+ 'vnfd-id-ref': 'tg__1',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens785f0',
+ 'vld_id': FWApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.20',
+ 'dst_mac': '00:00:00:00:00:02',
+ 'local_mac': '00:00:00:00:00:04',
+ 'dst_ip': '152.16.100.19',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens785f1',
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.21',
+ 'local_mac': '00:00:00:00:00:01',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1}},
+ 'password': 'r00t',
+ 'VNF model': 'tg_rfc2544_tpl.yaml',
+ 'user': 'root'},
+ 'vnf__1':
+ {'name': 'vnf.yardstick',
+ 'vnfd-id-ref': 'vnf__1',
+ 'ip': '1.2.1.1',
+ 'interfaces':
+ {'xe0': {'local_iface_name': 'ens786f0',
+ 'vld_id': FWApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.19',
+ 'dst_mac': '00:00:00:00:00:04',
+ 'local_mac': '00:00:00:00:00:02',
+ 'dst_ip': '152.16.100.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0},
+ 'xe1': {'local_iface_name': 'ens786f1',
+ 'vld_id': FWApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.19',
+ 'dst_mac': '00:00:00:00:00:03',
+ 'local_mac': '00:00:00:00:00:01',
+ 'dst_ip': '152.16.40.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1}},
+ 'routing_table':
+ [{'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'network': '152.16.100.20',
+ 'if': 'xe0'},
+ {'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'network': '152.16.40.20',
+ 'if': 'xe1'}],
+ 'member-vnf-index': '2',
+ 'host': '1.2.1.1',
+ 'role': 'vnf',
+ 'user': 'root',
+ 'nd_route_tbl':
+ [{'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'},
+ {'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'}],
+ 'password': 'r00t',
+ 'VNF model': 'vfw_vnf.yaml'}}}
+
+ def test___init__(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
+ self.assertIsNone(vfw_approx_vnf._vnf_process)
+
+ STATS = """\
+p vfw stats
+
+VFW Stats
+{"VFW_counters" : {"id" : "PIPELINE4", " pkts_received": 6007180, " pkts_fw_forwarded": 6007180, " pkts_drop_fw": 0, " pkts_acl_forwarded": 6007180, "pkts_drop_without_rule" : 0, "average_pkts_in_batch" : 31, "average_internal_time_in_clocks" : 17427, "average_external_time_in_clocks" : 261120, "total_time_measures" : 189829, "ct_packets_forwarded" : 6007148, "ct_packets_dropped" : 0, "bytes_processed ": 360430800, "ct_sessions" : {"active" : 130050, "open_attempt" : 130050, "re-open_attempt" : 0, "established" : 0, "closed" : 0, "timeout" : 0}, "ct_drops" : {"out_of_window" : 0, "invalid_conn" : 0, "invalid_state_transition" : 0 "RST" : 0}}
+VFW TOTAL: pkts_received: 6007180, "pkts_fw_forwarded": 6007180, "pkts_drop_fw": 0, "fw_drops" : {"TTL_zero" : 0, "bad_size" : 0, "fragmented_packet" : 0, "unsupported_packet_types" : 0, "no_arp_entry" : 6007180}, "pkts_acl_forwarded": 6007180, "pkts_drop_without_rule": 0, "packets_last_sec" : 0, "average_packets_per_sec" : 0, "bytes_last_sec" : 0, "average_bytes_per_sec" : 0, "bytes_processed ": 360430800
+"CT TOTAL: ct_packets_forwarded" : 6007180, " ct_packets_dropped" : 0, "ct_sessions" : {"active" : 130050, "open_attempt" : 130050, "re-open_attempt" : 0, "established" : 0, "closed" : 0, "timeout" : 0}, "ct_drops" : {"out_of_window" : 0, "invalid_conn" : 0, "invalid_state_transition" : 0 "RST" : 0}
+Action ID: 00, packetCount: 2954633, byteCount: 177277980
+Action ID: 01, packetCount: 3052547, byteCount: 183152820
+pipeline>
+
+pipeline>
+""" # noqa
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, *args):
+ mock_ssh(ssh)
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
+ vfw_approx_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {vfw_approx_vnf.name: "mock"}
+ }
+ vfw_approx_vnf.q_in = mock.MagicMock()
+ vfw_approx_vnf.q_out = mock.MagicMock()
+ vfw_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ vfw_approx_vnf.resource = mock.Mock(autospec=ResourceProfile)
+ vfw_approx_vnf.resource_helper = mock.MagicMock(
+ **{'collect_kpi.return_value': {"core": {}}})
+ vfw_approx_vnf.vnf_execute = mock.Mock(return_value=self.STATS)
+ result = {
+ 'physical_node': 'mock_node',
+ 'packets_dropped': 0,
+ 'packets_fwd': 6007180,
+ 'packets_in': 6007180,
+ 'collect_stats': {'core': {}},
+ }
+ self.assertEqual(result, vfw_approx_vnf.collect_kpi())
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch(SSH_HELPER)
+ def test_vnf_execute_command(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
+ vfw_approx_vnf.q_in = mock.MagicMock()
+ vfw_approx_vnf.q_out = mock.MagicMock()
+ vfw_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ cmd = "quit"
+ self.assertEqual(vfw_approx_vnf.vnf_execute(cmd), "")
+
+ @mock.patch(SSH_HELPER)
+ def test_get_stats(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
+ vfw_approx_vnf.q_in = mock.MagicMock()
+ vfw_approx_vnf.q_out = mock.MagicMock()
+ vfw_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ vfw_approx_vnf.vnf_execute = mock.Mock(return_value=self.STATS)
+ self.assertEqual(self.STATS, vfw_approx_vnf.get_stats())
+
+ def _get_file_abspath(self, filename):
+ curr_path = os.path.dirname(os.path.abspath(__file__))
+ file_path = os.path.join(curr_path, filename)
+ return file_path
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.vfw_vnf.hex")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.vfw_vnf.eval")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.vfw_vnf.open")
+ @mock.patch(SSH_HELPER)
+ def test_run_vfw(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
+ vfw_approx_vnf._build_config = mock.MagicMock()
+ vfw_approx_vnf.queue_wrapper = mock.MagicMock()
+ vfw_approx_vnf.ssh_helper = mock.MagicMock()
+ vfw_approx_vnf.ssh_helper.run = mock.MagicMock()
+ vfw_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
+ vfw_approx_vnf.vnf_cfg = {'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1}
+ vfw_approx_vnf.all_options = {'traffic_type': '4',
+ 'topology': 'nsb_test_case.yaml'}
+ vfw_approx_vnf._run()
+ vfw_approx_vnf.ssh_helper.run.assert_called_once()
+
+ @mock.patch.object(utils, 'find_relative_file')
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server')
+ @mock.patch(SSH_HELPER)
+ def test_instantiate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id')
+ vfw_approx_vnf.ssh_helper = ssh
+ vfw_approx_vnf.deploy_helper = mock.MagicMock()
+ vfw_approx_vnf.resource_helper = mock.MagicMock()
+ vfw_approx_vnf._build_config = mock.MagicMock()
+ self.scenario_cfg['vnf_options'] = {'acl': {'cfg': "",
+ 'rules': ""}}
+ self.scenario_cfg.update({"nodes": {"vnf__1": ""}})
+ self.assertIsNone(vfw_approx_vnf.instantiate(self.scenario_cfg, self.context_cfg))
+
+
+class TestFWApproxSetupEnvHelper(unittest.TestCase):
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open')
+ @mock.patch.object(utils, 'find_relative_file')
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig')
+ @mock.patch.object(utils, 'open_relative_file')
+ def test_build_config(self, *args):
+ vnfd_helper = mock.Mock()
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.vnf_cfg = {'lb_config': 'HW'}
+ scenario_helper.options = {}
+ scenario_helper.all_options = {}
+
+ vfw_approx_setup_helper = FWApproxSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper)
+ vfw_approx_setup_helper.get_flows_config = mock.Mock()
+
+ vfw_approx_setup_helper.ssh_helper.provision_tool = mock.Mock(return_value='tool_path')
+ vfw_approx_setup_helper.ssh_helper.all_ports = mock.Mock()
+ vfw_approx_setup_helper.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1])
+ expected = 'sudo tool_path -p 0x3 -f /tmp/vfw_config -s /tmp/vfw_script --hwlb 3'
+ self.assertEqual(vfw_approx_setup_helper.build_config(), expected)
+ vfw_approx_setup_helper.get_flows_config.assert_called_once()
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py
new file mode 100644
index 000000000..7b937dfb5
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py
@@ -0,0 +1,817 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from multiprocessing import Process, Queue
+import time
+
+import mock
+from six.moves import configparser
+import unittest
+
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.nfvi.resource import ResourceProfile
+from yardstick.network_services.vnf_generic.vnf import base as vnf_base
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+from yardstick.network_services.vnf_generic.vnf import vpe_vnf
+from yardstick.tests.unit.network_services.vnf_generic.vnf import test_base
+
+
+TEST_FILE_YAML = 'nsb_test_case.yaml'
+
+NAME = 'vnf_1'
+
+PING_OUTPUT_1 = "Pkts in: 101\r\n\tPkts dropped by AH: 100\r\n\tPkts dropped by other: 100"
+
+MODULE_PATH = test_base.FileAbsPath(__file__)
+get_file_abspath = MODULE_PATH.get_path
+
+
+class TestConfigCreate(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1'
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0'
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1'
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0'
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1'
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
+ }
+
+ def test___init__(self):
+ vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0)
+ config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2)
+ self.assertEqual(config_create.uplink_ports, ['xe0'])
+ self.assertEqual(config_create.downlink_ports, ['xe1'])
+ self.assertEqual(config_create.socket, 2)
+
+ def test_dpdk_port_to_link_id(self):
+ vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0)
+ config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2)
+ self.assertEqual(config_create.dpdk_port_to_link_id_map, {'xe0': 0, 'xe1': 1})
+
+ def test_vpe_initialize(self):
+ vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0)
+ config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2)
+ config = configparser.ConfigParser()
+ config_create.vpe_initialize(config)
+ self.assertEqual(config.get('EAL', 'log_level'), '0')
+ self.assertEqual(config.get('PIPELINE0', 'type'), 'MASTER')
+ self.assertEqual(config.get('PIPELINE0', 'core'), 's2C0')
+ self.assertEqual(config.get('MEMPOOL0', 'pool_size'), '256K')
+ self.assertEqual(config.get('MEMPOOL1', 'pool_size'), '2M')
+
+ def test_vpe_rxq(self):
+ vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0)
+ config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2)
+ config = configparser.ConfigParser()
+ config_create.downlink_ports = ['xe0']
+ config_create.vpe_rxq(config)
+ self.assertEqual(config.get('RXQ0.0', 'mempool'), 'MEMPOOL1')
+
+ def test_get_sink_swq(self):
+ vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0)
+ config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2)
+ config = configparser.ConfigParser()
+ config.add_section('PIPELINE0')
+ config.set('PIPELINE0', 'key1', 'value1')
+ config.set('PIPELINE0', 'key2', 'value2 SINK')
+ config.set('PIPELINE0', 'key3', 'TM value3')
+ config.set('PIPELINE0', 'key4', 'value4')
+ config.set('PIPELINE0', 'key5', 'the SINK value5')
+
+ self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key1', 5), 'SWQ-1')
+ self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key2', 5), 'SWQ-1 SINK0')
+ self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key3', 5), 'SWQ-1 TM5')
+ config_create.sw_q += 1
+ self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key4', 5), 'SWQ0')
+ self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key5', 5), 'SWQ0 SINK1')
+
+ def test_generate_vpe_script(self):
+ vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0)
+ vpe_config_vnf = vpe_vnf.ConfigCreate(vnfd_helper, 2)
+ intf = [
+ {
+ "name": 'xe1',
+ "virtual-interface": {
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "00:00:00:00:00:00:02",
+ },
+ },
+ {
+ "name": 'xe2',
+ "virtual-interface": {
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "00:00:00:00:00:00:02",
+ },
+ },
+ ]
+ vpe_config_vnf.downlink_ports = ['xe1']
+ vpe_config_vnf.uplink_ports = ['xe2']
+ result = vpe_config_vnf.generate_vpe_script(intf)
+ self.assertIsInstance(result, str)
+ self.assertNotEqual(result, '')
+
+ def test_create_vpe_config(self):
+ vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0)
+ config_create = vpe_vnf.ConfigCreate(vnfd_helper, 23)
+ config_create.uplink_ports = ['xe1']
+ with mock.patch.object(config_create, 'vpe_upstream') as mock_up, \
+ mock.patch.object(config_create, 'vpe_downstream') as \
+ mock_down, \
+ mock.patch.object(config_create, 'vpe_tmq') as mock_tmq, \
+ mock.patch.object(config_create, 'vpe_initialize') as \
+ mock_ini, \
+ mock.patch.object(config_create, 'vpe_rxq') as mock_rxq:
+ mock_ini_obj = mock.Mock()
+ mock_rxq_obj = mock.Mock()
+ mock_up_obj = mock.Mock()
+ mock_down_obj = mock.Mock()
+ mock_tmq_obj = mock.Mock()
+ mock_ini.return_value = mock_ini_obj
+ mock_rxq.return_value = mock_rxq_obj
+ mock_up.return_value = mock_up_obj
+ mock_down.return_value = mock_down_obj
+ mock_tmq.return_value = mock_tmq_obj
+ config_create.create_vpe_config('fake_config_file')
+
+ mock_rxq.assert_called_once_with(mock_ini_obj)
+ mock_up.assert_called_once_with('fake_config_file', 0)
+ mock_down.assert_called_once_with('fake_config_file', 0)
+ mock_tmq.assert_called_once_with(mock_down_obj, 0)
+ mock_up_obj.write.assert_called_once()
+ mock_tmq_obj.write.assert_called_once()
+
+
+class TestVpeApproxVnf(unittest.TestCase):
+
+ VNFD_0 = {
+ 'short-name': 'VpeVnf',
+ 'vdu': [
+ {
+ 'routing_table': [
+ {
+ 'network': '152.16.100.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '152.16.40.20',
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'description': 'VPE approximation using DPDK',
+ 'name': 'vpevnf-baremetal',
+ 'nd_route_tbl': [
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'id': 'vpevnf-baremetal',
+ 'external-interface': [
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:04',
+ 'vpci': '0000:05:00.0',
+ 'local_ip': '152.16.100.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 0,
+ 'bandwidth': '10 Gbps',
+ 'driver': "i40e",
+ 'dst_ip': '152.16.100.20',
+ 'local_iface_name': 'xe0',
+ 'local_mac': '00:00:00:00:00:02',
+ 'vld_id': 'uplink_0',
+ 'ifname': 'xe0',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ 'name': 'xe0',
+ },
+ {
+ 'virtual-interface': {
+ 'dst_mac': '00:00:00:00:00:03',
+ 'vpci': '0000:05:00.1',
+ 'local_ip': '152.16.40.19',
+ 'type': 'PCI-PASSTHROUGH',
+ 'driver': "i40e",
+ 'netmask': '255.255.255.0',
+ 'dpdk_port_num': 1,
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '152.16.40.20',
+ 'local_iface_name': 'xe1',
+ 'local_mac': '00:00:00:00:00:01',
+ 'vld_id': 'downlink_0',
+ 'ifname': 'xe1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ 'name': 'xe1',
+ },
+ ],
+ },
+ ],
+ 'description': 'Vpe approximation using DPDK',
+ 'mgmt-interface': {
+ 'vdu-id': 'vpevnf-baremetal',
+ 'host': '1.2.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.2.1.1',
+ },
+ 'benchmark': {
+ 'kpi': [
+ 'packets_in',
+ 'packets_fwd',
+ 'packets_dropped',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'type': 'VPORT',
+ 'name': 'xe0',
+ },
+ {
+ 'type': 'VPORT',
+ 'name': 'xe1',
+ },
+ ],
+ 'id': 'VpeApproxVnf',
+ 'name': 'VPEVnfSsh',
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ],
+ },
+ }
+
+ SCENARIO_CFG = {
+ 'options': {
+ 'packetsize': 64,
+ 'traffic_type': 4,
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1',
+ },
+ 'vnf__1': {
+ 'cfg': 'acl_1rule.yaml',
+ 'vnf_config': {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config':
+ '1C/1T',
+ 'worker_threads': 1,
+ },
+ }
+ },
+ 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
+ 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
+ 'runner': {
+ 'object': 'NetworkServiceTestCase',
+ 'interval': 35,
+ 'output_filename': '/tmp/yardstick.out',
+ 'runner_id': 74476,
+ 'duration': 400,
+ 'type': 'Duration',
+ },
+ 'traffic_profile': 'ipv4_throughput_vpe.yaml',
+ 'traffic_options': {
+ 'flow': 'ipv4_Packets_vpe.yaml',
+ 'imix': 'imix_voice.yaml',
+ },
+ 'type': 'ISB',
+ 'nodes': {
+ 'tg__2': 'trafficgen_2.yardstick',
+ 'tg__1': 'trafficgen_1.yardstick',
+ 'vnf__1': 'vnf.yardstick',
+ },
+ 'topology': 'vpe-tg-topology-baremetal.yaml',
+ }
+
+ CONTEXT_CFG = {
+ 'nodes': {
+ 'tg__2': {
+ 'member-vnf-index': '3',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_2.yardstick',
+ 'vnfd-id-ref': 'tg__2',
+ 'ip': '1.2.1.1',
+ 'interfaces': {
+ 'xe0': {
+ 'local_iface_name': 'ens513f0',
+ 'vld_id': vpe_vnf.VpeApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.20',
+ 'dst_mac': '00:00:00:00:00:01',
+ 'local_mac': '00:00:00:00:00:03',
+ 'dst_ip': '152.16.40.19',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'local_iface_name': 'ens513f1',
+ 'netmask': '255.255.255.0',
+ 'network': '202.16.100.0',
+ 'local_ip': '202.16.100.20',
+ 'local_mac': '00:1e:67:d0:60:5d',
+ 'driver': 'ixgbe',
+ 'vpci': '0000:02:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'password': 'r00t',
+ 'VNF model': 'l3fwd_vnf.yaml',
+ 'user': 'root',
+ },
+ 'tg__1': {
+ 'member-vnf-index': '1',
+ 'role': 'TrafficGen',
+ 'name': 'trafficgen_1.yardstick',
+ 'vnfd-id-ref': 'tg__1',
+ 'ip': '1.2.1.1',
+ 'interfaces': {
+ 'xe0': {
+ 'local_iface_name': 'ens785f0',
+ 'vld_id': vpe_vnf.VpeApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.20',
+ 'dst_mac': '00:00:00:00:00:02',
+ 'local_mac': '00:00:00:00:00:04',
+ 'dst_ip': '152.16.100.19',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'local_iface_name': 'ens785f1',
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.21',
+ 'local_mac': '00:00:00:00:00:01',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'password': 'r00t',
+ 'VNF model': 'tg_rfc2544_tpl.yaml',
+ 'user': 'root',
+ },
+ 'vnf__1': {
+ 'name': 'vnf.yardstick',
+ 'vnfd-id-ref': 'vnf__1',
+ 'ip': '1.2.1.1',
+ 'interfaces': {
+ 'xe0': {
+ 'local_iface_name': 'ens786f0',
+ 'vld_id': vpe_vnf.VpeApproxVnf.UPLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.19',
+ 'dst_mac': '00:00:00:00:00:04',
+ 'local_mac': '00:00:00:00:00:02',
+ 'dst_ip': '152.16.100.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'local_iface_name': 'ens786f1',
+ 'vld_id': vpe_vnf.VpeApproxVnf.DOWNLINK,
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.19',
+ 'dst_mac': '00:00:00:00:00:03',
+ 'local_mac': '00:00:00:00:00:01',
+ 'dst_ip': '152.16.40.20',
+ 'driver': 'i40e',
+ 'vpci': '0000:05:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'routing_table': [
+ {
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'network': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'network': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'member-vnf-index': '2',
+ 'host': '1.2.1.1',
+ 'role': 'vnf',
+ 'user': 'root',
+ 'nd_route_tbl': [
+ {
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ 'password': 'r00t',
+ 'VNF model': 'vpe_vnf.yaml',
+ },
+ },
+ }
+
+ def setUp(self):
+ self._mock_time_sleep = mock.patch.object(time, 'sleep')
+ self.mock_time_sleep = self._mock_time_sleep.start()
+ self.addCleanup(self._stop_mocks)
+
+ def _stop_mocks(self):
+ self._mock_time_sleep.stop()
+
+ def test___init__(self):
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ self.assertIsNone(vpe_approx_vnf._vnf_process)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server',
+ return_value='mock_node')
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_collect_kpi_sa_not_running(self, ssh, *args):
+ test_base.mock_ssh(ssh)
+
+ resource = mock.Mock(autospec=ResourceProfile)
+ resource.check_if_system_agent_running.return_value = 1, ''
+ resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234}
+ resource.check_if_system_agent_running.return_value = (1, None)
+
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {vpe_approx_vnf.name: "mock"}
+ }
+ vpe_approx_vnf.q_in = mock.MagicMock()
+ vpe_approx_vnf.q_out = mock.MagicMock()
+ vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ vpe_approx_vnf.resource_helper.resource = resource
+
+ expected = {
+ 'physical_node': 'mock_node',
+ 'pkt_in_down_stream': 0,
+ 'pkt_in_up_stream': 0,
+ 'pkt_drop_down_stream': 0,
+ 'pkt_drop_up_stream': 0,
+ 'collect_stats': {'core': {}},
+ }
+ self.assertEqual(vpe_approx_vnf.collect_kpi(), expected)
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server',
+ return_value='mock_node')
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_collect_kpi_sa_running(self, ssh, *args):
+ test_base.mock_ssh(ssh)
+
+ resource = mock.Mock(autospec=ResourceProfile)
+ resource.check_if_system_agent_running.return_value = 0, '1234'
+ resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234}
+
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {vpe_approx_vnf.name: "mock"}
+ }
+ vpe_approx_vnf.q_in = mock.MagicMock()
+ vpe_approx_vnf.q_out = mock.MagicMock()
+ vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ vpe_approx_vnf.resource_helper.resource = resource
+
+ expected = {
+ 'physical_node': 'mock_node',
+ 'pkt_in_down_stream': 0,
+ 'pkt_in_up_stream': 0,
+ 'pkt_drop_down_stream': 0,
+ 'pkt_drop_up_stream': 0,
+ 'collect_stats': {'core': {'foo': 234}},
+ }
+ self.assertEqual(vpe_approx_vnf.collect_kpi(), expected)
+
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_vnf_execute(self, ssh):
+ test_base.mock_ssh(ssh)
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf.q_in = mock.MagicMock()
+ vpe_approx_vnf.q_out = mock.MagicMock()
+ vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
+ self.assertEqual(vpe_approx_vnf.vnf_execute("quit", 0), '')
+
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_run_vpe(self, ssh):
+ test_base.mock_ssh(ssh)
+
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf.tc_file_name = get_file_abspath(TEST_FILE_YAML)
+ vpe_approx_vnf.vnf_cfg = {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1,
+ }
+ vpe_approx_vnf.scenario_helper.scenario_cfg = {
+ 'options': {
+ NAME: {
+ 'traffic_type': '4',
+ 'topology': 'nsb_test_case.yaml',
+ 'vnf_config': 'vpe_config',
+ }
+ }
+ }
+ vpe_approx_vnf.topology = "nsb_test_case.yaml"
+ vpe_approx_vnf.nfvi_type = "baremetal"
+ vpe_approx_vnf._provide_config_file = mock.Mock()
+ vpe_approx_vnf._build_config = mock.MagicMock()
+
+ self.assertIsInstance(vpe_approx_vnf.ssh_helper, mock.Mock)
+ self.assertIsInstance(vpe_approx_vnf.ssh_helper, mock.Mock)
+ self.assertIsNone(vpe_approx_vnf._run())
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.vpe_vnf.ConfigCreate")
+ @mock.patch("six.moves.builtins.open")
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_build_config(self, ssh, *args):
+ test_base.mock_ssh(ssh)
+ vpe_approx_vnf = vpe_vnf.VpeApproxSetupEnvHelper(
+ mock.MagicMock(), mock.MagicMock(), mock.MagicMock())
+ vpe_approx_vnf.tc_file_name = get_file_abspath(TEST_FILE_YAML)
+ vpe_approx_vnf.generate_port_pairs = mock.Mock()
+ vpe_approx_vnf.vnf_cfg = {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1,
+ }
+ vpe_approx_vnf.scenario_helper.scenario_cfg = {
+ 'options': {
+ NAME: {
+ 'traffic_type': '4',
+ 'topology': 'nsb_test_case.yaml',
+ 'vnf_config': 'vpe_config',
+ }
+ }
+ }
+ vpe_approx_vnf.topology = "nsb_test_case.yaml"
+ vpe_approx_vnf.nfvi_type = "baremetal"
+ vpe_approx_vnf._provide_config_file = mock.Mock()
+
+ vpe_approx_vnf.ssh_helper = mock.MagicMock()
+ vpe_approx_vnf.scenario_helper = mock.MagicMock()
+ vpe_approx_vnf.ssh_helper.bin_path = mock.Mock()
+ vpe_approx_vnf.ssh_helper.upload_config_file = mock.MagicMock()
+ self.assertIsNone(vpe_approx_vnf._build_vnf_ports())
+
+ vpe_approx_vnf.ssh_helper.provision_tool = mock.Mock(return_value='tool_path')
+ vpe_approx_vnf.ssh_helper.all_ports = mock.Mock()
+ vpe_approx_vnf.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1])
+ vpe_approx_vnf.scenario_helper.vnf_cfg = {'lb_config': 'HW'}
+
+ expected = 'sudo tool_path -p 0x3 -f /tmp/vpe_config -s /tmp/vpe_script --hwlb 3'
+ self.assertEqual(vpe_approx_vnf.build_config(), expected)
+
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_wait_for_instantiate(self, ssh):
+ test_base.mock_ssh(ssh)
+
+ mock_process = mock.Mock(autospec=Process)
+ mock_process.is_alive.return_value = True
+ mock_process.exitcode = 432
+
+ mock_q_out = mock.Mock(autospec=Queue)
+ mock_q_out.get.side_effect = iter(["pipeline>"])
+ mock_q_out.qsize.side_effect = range(1, -1, -1)
+
+ mock_resource = mock.MagicMock()
+
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf._vnf_process = mock_process
+ vpe_approx_vnf.q_out = mock_q_out
+ vpe_approx_vnf.queue_wrapper = mock.Mock(
+ autospec=vnf_base.QueueFileWrapper)
+ vpe_approx_vnf.resource_helper.resource = mock_resource
+
+ vpe_approx_vnf.q_out.put("pipeline>")
+ self.assertEqual(vpe_approx_vnf.wait_for_instantiate(), 432)
+
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_wait_for_instantiate_fragmented(self, ssh):
+ test_base.mock_ssh(ssh)
+
+ mock_process = mock.Mock(autospec=Process)
+ mock_process.is_alive.return_value = True
+ mock_process.exitcode = 432
+
+ # test that fragmented pipeline prompt is recognized
+ mock_q_out = mock.Mock(autospec=Queue)
+ mock_q_out.get.side_effect = iter(["wow pipel", "ine>"])
+ mock_q_out.qsize.side_effect = range(2, -1, -1)
+
+ mock_resource = mock.MagicMock()
+
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf._vnf_process = mock_process
+ vpe_approx_vnf.q_out = mock_q_out
+ vpe_approx_vnf.queue_wrapper = mock.Mock(
+ autospec=vnf_base.QueueFileWrapper)
+ vpe_approx_vnf.resource_helper.resource = mock_resource
+
+ self.assertEqual(vpe_approx_vnf.wait_for_instantiate(), 432)
+
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_wait_for_instantiate_crash(self, ssh):
+ test_base.mock_ssh(ssh, exec_result=(1, "", ""))
+
+ mock_process = mock.Mock(autospec=Process)
+ mock_process.is_alive.return_value = False
+ mock_process.exitcode = 432
+
+ mock_resource = mock.MagicMock()
+
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf._vnf_process = mock_process
+ vpe_approx_vnf.resource_helper.resource = mock_resource
+
+ with self.assertRaises(RuntimeError) as raised:
+ vpe_approx_vnf.wait_for_instantiate()
+
+ self.assertIn('VNF process died', str(raised.exception))
+
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_wait_for_instantiate_panic(self, ssh):
+ test_base.mock_ssh(ssh, exec_result=(1, "", ""))
+
+ mock_process = mock.Mock(autospec=Process)
+ mock_process.is_alive.return_value = True
+ mock_process.exitcode = 432
+
+ mock_resource = mock.MagicMock()
+
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf._vnf_process = mock_process
+ vpe_approx_vnf.resource_helper.resource = mock_resource
+
+ vpe_approx_vnf.q_out.put("PANIC")
+ with self.assertRaises(RuntimeError) as raised:
+ vpe_approx_vnf.wait_for_instantiate()
+
+ self.assertIn('Error starting', str(raised.exception))
+
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_wait_for_instantiate_panic_fragmented(self, ssh):
+ test_base.mock_ssh(ssh, exec_result=(1, "", ""))
+
+ mock_process = mock.Mock(autospec=Process)
+ mock_process.is_alive.return_value = True
+ mock_process.exitcode = 432
+
+ # test that fragmented PANIC is recognized
+ mock_q_out = mock.Mock(autospec=Queue)
+ mock_q_out.get.side_effect = iter(["omg PA", "NIC this is bad"])
+ mock_q_out.qsize.side_effect = range(2, -1, -1)
+
+ mock_resource = mock.MagicMock()
+
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf._vnf_process = mock_process
+ vpe_approx_vnf.q_out = mock_q_out
+ vpe_approx_vnf.resource_helper.resource = mock_resource
+
+ with self.assertRaises(RuntimeError) as raised:
+ vpe_approx_vnf.wait_for_instantiate()
+
+ self.assertIn('Error starting', str(raised.exception))
+
+ @mock.patch.object(sample_vnf, 'VnfSshHelper')
+ def test_terminate(self, ssh):
+ test_base.mock_ssh(ssh)
+
+ vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
+ vpe_approx_vnf._vnf_process = mock.MagicMock()
+ vpe_approx_vnf._resource_collect_stop = mock.Mock()
+ vpe_approx_vnf.resource_helper = mock.MagicMock()
+
+ self.assertIsNone(vpe_approx_vnf.terminate())