aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick
diff options
context:
space:
mode:
Diffstat (limited to 'yardstick')
-rw-r--r--yardstick/benchmark/contexts/base.py22
-rw-r--r--yardstick/benchmark/contexts/heat.py2
-rw-r--r--yardstick/benchmark/contexts/kubernetes.py10
-rw-r--r--yardstick/benchmark/contexts/node.py2
-rw-r--r--yardstick/benchmark/contexts/standalone/ovs_dpdk.py2
-rw-r--r--yardstick/benchmark/contexts/standalone/sriov.py2
-rw-r--r--yardstick/benchmark/core/task.py33
-rwxr-xr-xyardstick/benchmark/runners/arithmetic.py11
-rw-r--r--yardstick/benchmark/runners/duration.py7
-rwxr-xr-xyardstick/benchmark/runners/dynamictp.py7
-rw-r--r--yardstick/benchmark/runners/iteration.py7
-rw-r--r--yardstick/benchmark/runners/search.py9
-rw-r--r--yardstick/benchmark/runners/sequence.py9
-rw-r--r--yardstick/benchmark/scenarios/availability/scenario_general.py8
-rwxr-xr-xyardstick/benchmark/scenarios/availability/serviceha.py9
-rw-r--r--yardstick/benchmark/scenarios/base.py6
-rw-r--r--yardstick/benchmark/scenarios/compute/cyclictest.py4
-rw-r--r--yardstick/benchmark/scenarios/compute/lmbench.py6
-rw-r--r--yardstick/benchmark/scenarios/compute/perf.py20
-rw-r--r--yardstick/benchmark/scenarios/compute/qemu_migrate.py4
-rw-r--r--yardstick/benchmark/scenarios/compute/ramspeed.py6
-rw-r--r--yardstick/benchmark/scenarios/compute/unixbench.py2
-rw-r--r--yardstick/benchmark/scenarios/networking/iperf3.py17
-rw-r--r--yardstick/benchmark/scenarios/networking/moongen_testpmd.py7
-rwxr-xr-xyardstick/benchmark/scenarios/networking/netperf.py6
-rwxr-xr-xyardstick/benchmark/scenarios/networking/netperf_node.py7
-rw-r--r--yardstick/benchmark/scenarios/networking/nstat.py2
-rw-r--r--yardstick/benchmark/scenarios/networking/ping.py20
-rw-r--r--yardstick/benchmark/scenarios/networking/ping6.py13
-rw-r--r--yardstick/benchmark/scenarios/networking/pktgen.py124
-rw-r--r--yardstick/benchmark/scenarios/networking/pktgen_dpdk.py7
-rw-r--r--yardstick/benchmark/scenarios/networking/pktgen_dpdk_throughput.py8
-rw-r--r--yardstick/benchmark/scenarios/networking/vnf_generic.py47
-rw-r--r--yardstick/benchmark/scenarios/networking/vsperf.py14
-rw-r--r--yardstick/benchmark/scenarios/networking/vsperf_dpdk.py16
-rw-r--r--yardstick/benchmark/scenarios/storage/fio.py2
-rw-r--r--yardstick/common/exceptions.py61
-rw-r--r--yardstick/common/kubernetes_utils.py6
-rw-r--r--yardstick/common/utils.py39
-rw-r--r--yardstick/error.py48
-rw-r--r--yardstick/network_services/helpers/dpdkbindnic_helper.py28
-rw-r--r--yardstick/network_services/helpers/samplevnf_helper.py121
-rw-r--r--yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py334
-rw-r--r--yardstick/network_services/libs/ixia_libs/ixnet/__init__.py (renamed from yardstick/network_services/libs/ixia_libs/IxNet/__init__.py)0
-rw-r--r--yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py470
-rw-r--r--yardstick/network_services/traffic_profile/base.py28
-rw-r--r--yardstick/network_services/traffic_profile/http_ixload.py23
-rw-r--r--yardstick/network_services/traffic_profile/ixia_rfc2544.py108
-rw-r--r--yardstick/network_services/traffic_profile/rfc2544.py398
-rw-r--r--yardstick/network_services/traffic_profile/trex_traffic_profile.py122
-rw-r--r--yardstick/network_services/vnf_generic/vnf/acl_vnf.py207
-rw-r--r--yardstick/network_services/vnf_generic/vnf/sample_vnf.py51
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py110
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py87
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_trex.py26
-rw-r--r--yardstick/network_services/vnf_generic/vnf/vfw_vnf.py18
-rw-r--r--yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py1
-rw-r--r--yardstick/network_services/vnf_generic/vnf/vpe_vnf.py6
-rw-r--r--yardstick/network_services/yang_model.py108
-rw-r--r--yardstick/orchestrator/kubernetes.py112
-rw-r--r--yardstick/ssh.py61
-rw-r--r--yardstick/tests/unit/benchmark/contexts/standalone/test_model.py2
-rw-r--r--yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py9
-rw-r--r--yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py9
-rw-r--r--yardstick/tests/unit/benchmark/contexts/test_base.py49
-rw-r--r--yardstick/tests/unit/benchmark/contexts/test_dummy.py8
-rw-r--r--yardstick/tests/unit/benchmark/contexts/test_heat.py12
-rw-r--r--yardstick/tests/unit/benchmark/contexts/test_kubernetes.py35
-rw-r--r--yardstick/tests/unit/benchmark/contexts/test_node.py9
-rw-r--r--yardstick/tests/unit/benchmark/core/test_report.py10
-rw-r--r--yardstick/tests/unit/benchmark/core/test_task.py14
-rw-r--r--yardstick/tests/unit/benchmark/runner/test_duration.py39
-rw-r--r--yardstick/tests/unit/benchmark/runner/test_search.py50
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py18
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/availability/test_scenario_general.py11
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/availability/test_serviceha.py19
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py7
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py5
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py7
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py5
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py5
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py5
-rwxr-xr-xyardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py3
-rwxr-xr-xyardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py3
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py3
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py3
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py94
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py21
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py3
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py17
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py199
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py45
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py5
-rw-r--r--yardstick/tests/unit/common/test_exceptions.py28
-rw-r--r--yardstick/tests/unit/common/test_utils.py20
-rw-r--r--yardstick/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py17
-rw-r--r--yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py62
-rw-r--r--yardstick/tests/unit/network_services/libs/ixia_libs/test_IxNet.py874
-rw-r--r--yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py512
-rw-r--r--yardstick/tests/unit/network_services/nfvi/test_resource.py12
-rw-r--r--yardstick/tests/unit/network_services/test_yang_model.py129
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_base.py19
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_fixed.py3
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_http.py29
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py320
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py2
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py463
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py154
-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/acl_1rule.yaml47
-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.py517
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_base.py236
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py403
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py2335
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py455
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py260
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py1951
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py321
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py292
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py426
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py371
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py293
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py505
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py464
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py376
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py799
-rw-r--r--yardstick/tests/unit/orchestrator/test_kubernetes.py112
-rw-r--r--yardstick/tests/unit/service/test_environment.py20
-rw-r--r--yardstick/tests/unit/test_cmd/commands/test_env.py70
-rw-r--r--yardstick/tests/unit/test_ssh.py67
133 files changed, 13684 insertions, 3373 deletions
diff --git a/yardstick/benchmark/contexts/base.py b/yardstick/benchmark/contexts/base.py
index 692c16892..64cee8376 100644
--- a/yardstick/benchmark/contexts/base.py
+++ b/yardstick/benchmark/contexts/base.py
@@ -45,20 +45,12 @@ class Context(object):
list = []
SHORT_TASK_ID_LEN = 8
- @staticmethod
- def split_name(name, sep='.'):
- try:
- name_iter = iter(name.split(sep))
- except AttributeError:
- # name is not a string
- return None, None
- return next(name_iter), next(name_iter, None)
-
- def __init__(self):
+ def __init__(self, host_name_separator='.'):
Context.list.append(self)
self._flags = Flags()
self._name = None
self._task_id = None
+ self._host_name_separator = host_name_separator
def init(self, attrs):
"""Initiate context"""
@@ -68,6 +60,12 @@ class Context(object):
self._name_task_id = '{}-{}'.format(
self._name, self._task_id[:self.SHORT_TASK_ID_LEN])
+ def split_host_name(self, name):
+ if (isinstance(name, six.string_types)
+ and self._host_name_separator in name):
+ return tuple(name.split(self._host_name_separator, 1))
+ return None, None
+
@property
def name(self):
if self._flags.no_setup or self._flags.no_teardown:
@@ -79,6 +77,10 @@ class Context(object):
def assigned_name(self):
return self._name
+ @property
+ def host_name_separator(self):
+ return self._host_name_separator
+
@staticmethod
def get_cls(context_type):
"""Return class of specified type."""
diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py
index 82861829e..cc87176d5 100644
--- a/yardstick/benchmark/contexts/heat.py
+++ b/yardstick/benchmark/contexts/heat.py
@@ -465,7 +465,7 @@ class HeatContext(Context):
with attribute name mapping when using external heat templates
"""
if isinstance(attr_name, collections.Mapping):
- node_name, cname = self.split_name(attr_name['name'])
+ node_name, cname = self.split_host_name(attr_name['name'])
if cname is None or cname != self.name:
return None
diff --git a/yardstick/benchmark/contexts/kubernetes.py b/yardstick/benchmark/contexts/kubernetes.py
index 4bea991ea..d322954b2 100644
--- a/yardstick/benchmark/contexts/kubernetes.py
+++ b/yardstick/benchmark/contexts/kubernetes.py
@@ -15,7 +15,7 @@ import pkg_resources
import paramiko
from yardstick.benchmark.contexts.base import Context
-from yardstick.orchestrator.kubernetes import KubernetesTemplate
+from yardstick.orchestrator import kubernetes
from yardstick.common import kubernetes_utils as k8s_utils
from yardstick.common import utils
@@ -33,17 +33,13 @@ class KubernetesContext(Context):
self.key_path = ''
self.public_key_path = ''
self.template = None
-
- super(KubernetesContext, self).__init__()
+ super(KubernetesContext, self).__init__(host_name_separator='-')
def init(self, attrs):
super(KubernetesContext, self).init(attrs)
- template_cfg = attrs.get('servers', {})
- self.template = KubernetesTemplate(self.name, template_cfg)
-
+ self.template = kubernetes.KubernetesTemplate(self.name, attrs)
self.ssh_key = '{}-key'.format(self.name)
-
self.key_path = self._get_key_path()
self.public_key_path = '{}.pub'.format(self.key_path)
diff --git a/yardstick/benchmark/contexts/node.py b/yardstick/benchmark/contexts/node.py
index fa619a9aa..93888ef41 100644
--- a/yardstick/benchmark/contexts/node.py
+++ b/yardstick/benchmark/contexts/node.py
@@ -139,7 +139,7 @@ class NodeContext(Context):
"""lookup server info by name from context
attr_name: a name for a server listed in nodes config file
"""
- node_name, name = self.split_name(attr_name)
+ node_name, name = self.split_host_name(attr_name)
if name is None or self.name != name:
return None
diff --git a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py
index b9e66a481..8a1482c07 100644
--- a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py
+++ b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py
@@ -304,7 +304,7 @@ class OvsDpdkContext(Context):
Keyword arguments:
attr_name -- A name for a server listed in nodes config file
"""
- node_name, name = self.split_name(attr_name)
+ node_name, name = self.split_host_name(attr_name)
if name is None or self.name != name:
return None
diff --git a/yardstick/benchmark/contexts/standalone/sriov.py b/yardstick/benchmark/contexts/standalone/sriov.py
index 2f93e530b..e9f83b217 100644
--- a/yardstick/benchmark/contexts/standalone/sriov.py
+++ b/yardstick/benchmark/contexts/standalone/sriov.py
@@ -112,7 +112,7 @@ class SriovContext(Context):
Keyword arguments:
attr_name -- A name for a server listed in nodes config file
"""
- node_name, name = self.split_name(attr_name)
+ node_name, name = self.split_host_name(attr_name)
if name is None or self.name != name:
return None
diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py
index 697cc007f..f050e8d0f 100644
--- a/yardstick/benchmark/core/task.py
+++ b/yardstick/benchmark/core/task.py
@@ -619,27 +619,22 @@ class TaskParser(object): # pragma: no cover
nodes:
tg__0: tg_0.yardstick
vnf__0: vnf_0.yardstick
+
+ NOTE: in Kubernetes context, the separator character between the server
+ name and the context name is "-":
+ scenario:
+ host: host-k8s
+ target: target-k8s
"""
def qualified_name(name):
- try:
- # for openstack
- node_name, context_name = name.split('.')
- sep = '.'
- except ValueError:
- # for kubernetes, some kubernetes resources don't support
- # name format like 'xxx.xxx', so we use '-' instead
- # need unified later
- node_name, context_name = name.split('-')
- sep = '-'
-
- try:
- ctx = next((context for context in contexts
- if context.assigned_name == context_name))
- except StopIteration:
- raise y_exc.ScenarioConfigContextNameNotFound(
- context_name=context_name)
-
- return '{}{}{}'.format(node_name, sep, ctx.name)
+ for context in contexts:
+ host_name, ctx_name = context.split_host_name(name)
+ if context.assigned_name == ctx_name:
+ return '{}{}{}'.format(host_name,
+ context.host_name_separator,
+ context.name)
+
+ raise y_exc.ScenarioConfigContextNameNotFound(host_name=name)
if 'host' in scenario:
scenario['host'] = qualified_name(scenario['host'])
diff --git a/yardstick/benchmark/runners/arithmetic.py b/yardstick/benchmark/runners/arithmetic.py
index 6aaaed888..ecb59f960 100755
--- a/yardstick/benchmark/runners/arithmetic.py
+++ b/yardstick/benchmark/runners/arithmetic.py
@@ -37,6 +37,7 @@ import six
from six.moves import range
from yardstick.benchmark.runners import base
+from yardstick.common import exceptions as y_exc
LOG = logging.getLogger(__name__)
@@ -86,7 +87,7 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
loop_iter = six.moves.zip(*param_iters)
else:
LOG.warning("iter_type unrecognized: %s", iter_type)
- raise TypeError("iter_type unrecognized: %s", iter_type)
+ raise TypeError("iter_type unrecognized: %s" % iter_type)
# Populate options and run the requested method for each value combination
for comb_values in loop_iter:
@@ -105,14 +106,14 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
try:
result = method(data)
- except AssertionError as assertion:
+ except y_exc.SLAValidationError as error:
# SLA validation failed in scenario, determine what to do now
if sla_action == "assert":
raise
elif sla_action == "monitor":
- LOG.warning("SLA validation failed: %s", assertion.args)
- errors = assertion.args
- except Exception as e:
+ LOG.warning("SLA validation failed: %s", error.args)
+ errors = error.args
+ except Exception as e: # pylint: disable=broad-except
errors = traceback.format_exc()
LOG.exception(e)
else:
diff --git a/yardstick/benchmark/runners/duration.py b/yardstick/benchmark/runners/duration.py
index 60b0348c3..60f1fa536 100644
--- a/yardstick/benchmark/runners/duration.py
+++ b/yardstick/benchmark/runners/duration.py
@@ -27,6 +27,7 @@ import traceback
import time
from yardstick.benchmark.runners import base
+from yardstick.common import exceptions as y_exc
LOG = logging.getLogger(__name__)
@@ -70,13 +71,13 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
try:
result = method(data)
- except AssertionError as assertion:
+ except y_exc.SLAValidationError as error:
# SLA validation failed in scenario, determine what to do now
if sla_action == "assert":
raise
elif sla_action == "monitor":
- LOG.warning("SLA validation failed: %s", assertion.args)
- errors = assertion.args
+ LOG.warning("SLA validation failed: %s", error.args)
+ errors = error.args
# catch all exceptions because with multiprocessing we can have un-picklable exception
# problems https://bugs.python.org/issue9400
except Exception: # pylint: disable=broad-except
diff --git a/yardstick/benchmark/runners/dynamictp.py b/yardstick/benchmark/runners/dynamictp.py
index 63bfc823a..88d3c5704 100755
--- a/yardstick/benchmark/runners/dynamictp.py
+++ b/yardstick/benchmark/runners/dynamictp.py
@@ -27,6 +27,7 @@ import traceback
import os
from yardstick.benchmark.runners import base
+from yardstick.common import exceptions as y_exc
LOG = logging.getLogger(__name__)
@@ -80,10 +81,10 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
try:
method(data)
- except AssertionError as assertion:
- LOG.warning("SLA validation failed: %s" % assertion.args)
+ except y_exc.SLAValidationError as error:
+ LOG.warning("SLA validation failed: %s", error.args)
too_high = True
- except Exception as e:
+ except Exception as e: # pylint: disable=broad-except
errors = traceback.format_exc()
LOG.exception(e)
diff --git a/yardstick/benchmark/runners/iteration.py b/yardstick/benchmark/runners/iteration.py
index 20d6da054..4c88f3671 100644
--- a/yardstick/benchmark/runners/iteration.py
+++ b/yardstick/benchmark/runners/iteration.py
@@ -29,6 +29,7 @@ import traceback
import os
from yardstick.benchmark.runners import base
+from yardstick.common import exceptions as y_exc
LOG = logging.getLogger(__name__)
@@ -75,13 +76,13 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
try:
result = method(data)
- except AssertionError as assertion:
+ except y_exc.SLAValidationError as error:
# SLA validation failed in scenario, determine what to do now
if sla_action == "assert":
raise
elif sla_action == "monitor":
- LOG.warning("SLA validation failed: %s", assertion.args)
- errors = assertion.args
+ LOG.warning("SLA validation failed: %s", error.args)
+ errors = error.args
elif sla_action == "rate-control":
try:
scenario_cfg['options']['rate']
diff --git a/yardstick/benchmark/runners/search.py b/yardstick/benchmark/runners/search.py
index 8037329b5..01a4292c7 100644
--- a/yardstick/benchmark/runners/search.py
+++ b/yardstick/benchmark/runners/search.py
@@ -33,6 +33,7 @@ from collections import Mapping
from six.moves import zip
from yardstick.benchmark.runners import base
+from yardstick.common import exceptions as y_exc
LOG = logging.getLogger(__name__)
@@ -119,14 +120,14 @@ If the scenario ends before the time has elapsed, it will be started again.
try:
self.worker_helper(data)
- except AssertionError as assertion:
+ except y_exc.SLAValidationError as error:
# SLA validation failed in scenario, determine what to do now
if self.sla_action == "assert":
raise
elif self.sla_action == "monitor":
- LOG.warning("SLA validation failed: %s", assertion.args)
- errors = assertion.args
- except Exception as e:
+ LOG.warning("SLA validation failed: %s", error.args)
+ errors = error.args
+ except Exception as e: # pylint: disable=broad-except
errors = traceback.format_exc()
LOG.exception(e)
diff --git a/yardstick/benchmark/runners/sequence.py b/yardstick/benchmark/runners/sequence.py
index d6e3f7109..0148a45b2 100644
--- a/yardstick/benchmark/runners/sequence.py
+++ b/yardstick/benchmark/runners/sequence.py
@@ -30,6 +30,7 @@ import traceback
import os
from yardstick.benchmark.runners import base
+from yardstick.common import exceptions as y_exc
LOG = logging.getLogger(__name__)
@@ -74,14 +75,14 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
try:
result = method(data)
- except AssertionError as assertion:
+ except y_exc.SLAValidationError as error:
# SLA validation failed in scenario, determine what to do now
if sla_action == "assert":
raise
elif sla_action == "monitor":
- LOG.warning("SLA validation failed: %s", assertion.args)
- errors = assertion.args
- except Exception as e:
+ LOG.warning("SLA validation failed: %s", error.args)
+ errors = error.args
+ except Exception as e: # pylint: disable=broad-except
errors = traceback.format_exc()
LOG.exception(e)
else:
diff --git a/yardstick/benchmark/scenarios/availability/scenario_general.py b/yardstick/benchmark/scenarios/availability/scenario_general.py
index 1fadd2532..e2db03a70 100644
--- a/yardstick/benchmark/scenarios/availability/scenario_general.py
+++ b/yardstick/benchmark/scenarios/availability/scenario_general.py
@@ -58,16 +58,20 @@ class ScenarioGeneral(base.Scenario):
self.director.stopMonitors()
verify_result = self.director.verify()
+ service_not_found = False
for k, v in self.director.data.items():
if v == 0:
- result['sla_pass'] = 0
verify_result = False
+ service_not_found = True
LOG.info("\033[92m The service process (%s) not found in the host environment", k)
result['sla_pass'] = 1 if verify_result else 0
self.director.store_result(result)
- assert verify_result is True, "The HA test case NOT passed"
+ self.verify_SLA(
+ verify_result, ("a service process was not found in the host "
+ "environment" if service_not_found
+ else "Director.verify() failed"))
def teardown(self):
self.director.knockoff()
diff --git a/yardstick/benchmark/scenarios/availability/serviceha.py b/yardstick/benchmark/scenarios/availability/serviceha.py
index 42941c6e7..76721e38c 100755
--- a/yardstick/benchmark/scenarios/availability/serviceha.py
+++ b/yardstick/benchmark/scenarios/availability/serviceha.py
@@ -70,17 +70,20 @@ class ServiceHA(base.Scenario):
LOG.info("Monitor '%s' stop!", self.__scenario_type__)
sla_pass = self.monitorMgr.verify_SLA()
+ service_not_found = False
for k, v in self.data.items():
if v == 0:
sla_pass = False
+ service_not_found = True
LOG.info("The service process (%s) not found in the host envrioment", k)
result['sla_pass'] = 1 if sla_pass else 0
self.monitorMgr.store_result(result)
- assert sla_pass is True, "The HA test case NOT pass the SLA"
-
- return
+ self.verify_SLA(
+ sla_pass, ("a service process was not found in the host "
+ "environment" if service_not_found
+ else "MonitorMgr.verify_SLA() failed"))
def teardown(self):
"""scenario teardown"""
diff --git a/yardstick/benchmark/scenarios/base.py b/yardstick/benchmark/scenarios/base.py
index 58a02805c..30ac1bea9 100644
--- a/yardstick/benchmark/scenarios/base.py
+++ b/yardstick/benchmark/scenarios/base.py
@@ -20,6 +20,7 @@ import six
from stevedore import extension
import yardstick.common.utils as utils
+from yardstick.common import exceptions as y_exc
def _iter_scenario_classes(scenario_type=None):
@@ -61,6 +62,11 @@ class Scenario(object):
"""Time waited after executing the run method"""
time.sleep(time_seconds)
+ def verify_SLA(self, condition, error_msg):
+ if not condition:
+ raise y_exc.SLAValidationError(
+ case_name=self.__scenario_type__, error_msg=error_msg)
+
@staticmethod
def get_types():
"""return a list of known runner type (class) names"""
diff --git a/yardstick/benchmark/scenarios/compute/cyclictest.py b/yardstick/benchmark/scenarios/compute/cyclictest.py
index 998463ef6..413709f3b 100644
--- a/yardstick/benchmark/scenarios/compute/cyclictest.py
+++ b/yardstick/benchmark/scenarios/compute/cyclictest.py
@@ -100,7 +100,7 @@ class Cyclictest(base.Scenario):
def _run_setup_cmd(self, client, cmd):
LOG.debug("Run cmd: %s", cmd)
- status, stdout, stderr = client.execute(cmd)
+ status, _, stderr = client.execute(cmd)
if status:
if re.search(self.REBOOT_CMD_PATTERN, cmd):
LOG.debug("Error on reboot")
@@ -195,7 +195,7 @@ class Cyclictest(base.Scenario):
if latency > sla_latency:
sla_error += "%s latency %d > sla:max_%s_latency(%d); " % \
(t, latency, t, sla_latency)
- assert sla_error == "", sla_error
+ self.verify_SLA(sla_error == "", sla_error)
def _test(): # pragma: no cover
diff --git a/yardstick/benchmark/scenarios/compute/lmbench.py b/yardstick/benchmark/scenarios/compute/lmbench.py
index 801f7fa80..2237e49e0 100644
--- a/yardstick/benchmark/scenarios/compute/lmbench.py
+++ b/yardstick/benchmark/scenarios/compute/lmbench.py
@@ -119,8 +119,8 @@ class Lmbench(base.Scenario):
cmd = "sudo bash lmbench_latency_for_cache.sh %d %d" % \
(repetition, warmup)
else:
- raise RuntimeError("No such test_type: %s for Lmbench scenario",
- test_type)
+ raise RuntimeError("No such test_type: %s for Lmbench scenario"
+ % test_type)
LOG.debug("Executing command: %s", cmd)
status, stdout, stderr = self.client.execute(cmd)
@@ -157,7 +157,7 @@ class Lmbench(base.Scenario):
if sla_latency < cache_latency:
sla_error += "latency %f > sla:max_latency(%f); " \
% (cache_latency, sla_latency)
- assert sla_error == "", sla_error
+ self.verify_SLA(sla_error == "", sla_error)
def _test():
diff --git a/yardstick/benchmark/scenarios/compute/perf.py b/yardstick/benchmark/scenarios/compute/perf.py
index 0b8ed9b28..b973211f1 100644
--- a/yardstick/benchmark/scenarios/compute/perf.py
+++ b/yardstick/benchmark/scenarios/compute/perf.py
@@ -93,7 +93,7 @@ class Perf(base.Scenario):
% (load, duration, events_string)
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.client.execute(cmd)
+ status, stdout, _ = self.client.execute(cmd)
if status:
raise RuntimeError(stdout)
@@ -105,16 +105,14 @@ class Perf(base.Scenario):
exp_val = self.scenario_cfg['sla']['expected_value']
smaller_than_exp = 'smaller_than_expected' \
in self.scenario_cfg['sla']
-
- if metric not in result:
- assert False, "Metric (%s) not found." % metric
- else:
- if smaller_than_exp:
- assert result[metric] < exp_val, "%s %d >= %d (sla); " \
- % (metric, result[metric], exp_val)
- else:
- assert result[metric] >= exp_val, "%s %d < %d (sla); " \
- % (metric, result[metric], exp_val)
+ self.verify_SLA(metric in result,
+ "Metric (%s) not found." % metric)
+ self.verify_SLA(
+ not smaller_than_exp,
+ "%s %d >= %d (sla); " % (metric, result[metric], exp_val))
+ self.verify_SLA(
+ result[metric] >= exp_val,
+ "%s %d < %d (sla); " % (metric, result[metric], exp_val))
def _test():
diff --git a/yardstick/benchmark/scenarios/compute/qemu_migrate.py b/yardstick/benchmark/scenarios/compute/qemu_migrate.py
index 2de1270ef..975c90b22 100644
--- a/yardstick/benchmark/scenarios/compute/qemu_migrate.py
+++ b/yardstick/benchmark/scenarios/compute/qemu_migrate.py
@@ -56,7 +56,7 @@ class QemuMigrate(base.Scenario):
def _run_setup_cmd(self, client, cmd):
LOG.debug("Run cmd: %s", cmd)
- status, stdout, stderr = client.execute(cmd)
+ status, _, stderr = client.execute(cmd)
if status:
if re.search(self.REBOOT_CMD_PATTERN, cmd):
LOG.debug("Error on reboot")
@@ -127,7 +127,7 @@ class QemuMigrate(base.Scenario):
if timevalue > sla_time:
sla_error += "%s timevalue %d > sla:max_%s(%d); " % \
(t, timevalue, t, sla_time)
- assert sla_error == "", sla_error
+ self.verify_SLA(sla_error == "", sla_error)
def _test(): # pragma: no cover
diff --git a/yardstick/benchmark/scenarios/compute/ramspeed.py b/yardstick/benchmark/scenarios/compute/ramspeed.py
index ca64935dd..4daf776ff 100644
--- a/yardstick/benchmark/scenarios/compute/ramspeed.py
+++ b/yardstick/benchmark/scenarios/compute/ramspeed.py
@@ -121,8 +121,8 @@ class Ramspeed(base.Scenario):
(test_id, load, block_size)
# only the test_id 1-6 will be used in this scenario
else:
- raise RuntimeError("No such type_id: %s for Ramspeed scenario",
- test_id)
+ raise RuntimeError("No such type_id: %s for Ramspeed scenario"
+ % test_id)
LOG.debug("Executing command: %s", cmd)
status, stdout, stderr = self.client.execute(cmd)
@@ -140,4 +140,4 @@ class Ramspeed(base.Scenario):
if bw < sla_min_bw:
sla_error += "Bandwidth %f < " \
"sla:min_bandwidth(%f)" % (bw, sla_min_bw)
- assert sla_error == "", sla_error
+ self.verify_SLA(sla_error == "", sla_error)
diff --git a/yardstick/benchmark/scenarios/compute/unixbench.py b/yardstick/benchmark/scenarios/compute/unixbench.py
index cdb345717..3cea31694 100644
--- a/yardstick/benchmark/scenarios/compute/unixbench.py
+++ b/yardstick/benchmark/scenarios/compute/unixbench.py
@@ -125,7 +125,7 @@ class Unixbench(base.Scenario):
if score < sla_score:
sla_error += "%s score %f < sla:%s_score(%f); " % \
(t, score, t, sla_score)
- assert sla_error == "", sla_error
+ self.verify_SLA(sla_error == "", sla_error)
def _test(): # pragma: no cover
diff --git a/yardstick/benchmark/scenarios/networking/iperf3.py b/yardstick/benchmark/scenarios/networking/iperf3.py
index 98c45990e..51e044e7b 100644
--- a/yardstick/benchmark/scenarios/networking/iperf3.py
+++ b/yardstick/benchmark/scenarios/networking/iperf3.py
@@ -92,7 +92,7 @@ For more info see http://software.es.net/iperf
def teardown(self):
LOG.debug("teardown")
self.host.close()
- status, stdout, stderr = self.target.execute("pkill iperf3")
+ status, _, stderr = self.target.execute("pkill iperf3")
if status:
LOG.warning(stderr)
self.target.close()
@@ -145,7 +145,7 @@ For more info see http://software.es.net/iperf
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.host.execute(cmd)
+ status, stdout, _ = self.host.execute(cmd)
if status:
# error cause in json dict on stdout
raise RuntimeError(stdout)
@@ -165,16 +165,17 @@ For more info see http://software.es.net/iperf
bit_per_second = \
int(iperf_result["end"]["sum_received"]["bits_per_second"])
bytes_per_second = bit_per_second / 8
- assert bytes_per_second >= sla_bytes_per_second, \
- "bytes_per_second %d < sla:bytes_per_second (%d); " % \
- (bytes_per_second, sla_bytes_per_second)
+ self.verify_SLA(
+ bytes_per_second >= sla_bytes_per_second,
+ "bytes_per_second %d < sla:bytes_per_second (%d); "
+ % (bytes_per_second, sla_bytes_per_second))
else:
sla_jitter = float(sla_iperf["jitter"])
jitter_ms = float(iperf_result["end"]["sum"]["jitter_ms"])
- assert jitter_ms <= sla_jitter, \
- "jitter_ms %f > sla:jitter %f; " % \
- (jitter_ms, sla_jitter)
+ self.verify_SLA(jitter_ms <= sla_jitter,
+ "jitter_ms %f > sla:jitter %f; "
+ % (jitter_ms, sla_jitter))
def _test():
diff --git a/yardstick/benchmark/scenarios/networking/moongen_testpmd.py b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py
index 86173c9da..e3bd7af46 100644
--- a/yardstick/benchmark/scenarios/networking/moongen_testpmd.py
+++ b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py
@@ -367,9 +367,10 @@ ports = {0,1},
throughput_rx_mpps = int(
self.scenario_cfg["sla"]["throughput_rx_mpps"])
- assert throughput_rx_mpps <= moongen_result["tx_mpps"], \
- "sla_throughput_rx_mpps %f > throughput_rx_mpps(%f); " % \
- (throughput_rx_mpps, moongen_result["tx_mpps"])
+ self.verify_SLA(
+ throughput_rx_mpps <= moongen_result["tx_mpps"],
+ "sla_throughput_rx_mpps %f > throughput_rx_mpps(%f); "
+ % (throughput_rx_mpps, moongen_result["tx_mpps"]))
def teardown(self):
"""cleanup after the test execution"""
diff --git a/yardstick/benchmark/scenarios/networking/netperf.py b/yardstick/benchmark/scenarios/networking/netperf.py
index 33c02d409..9f1a81413 100755
--- a/yardstick/benchmark/scenarios/networking/netperf.py
+++ b/yardstick/benchmark/scenarios/networking/netperf.py
@@ -138,9 +138,9 @@ class Netperf(base.Scenario):
sla_max_mean_latency = int(
self.scenario_cfg["sla"]["mean_latency"])
- assert mean_latency <= sla_max_mean_latency, \
- "mean_latency %f > sla_max_mean_latency(%f); " % \
- (mean_latency, sla_max_mean_latency)
+ self.verify_SLA(mean_latency <= sla_max_mean_latency,
+ "mean_latency %f > sla_max_mean_latency(%f); "
+ % (mean_latency, sla_max_mean_latency))
def _test():
diff --git a/yardstick/benchmark/scenarios/networking/netperf_node.py b/yardstick/benchmark/scenarios/networking/netperf_node.py
index d52e6b9e1..0ad2ecff5 100755
--- a/yardstick/benchmark/scenarios/networking/netperf_node.py
+++ b/yardstick/benchmark/scenarios/networking/netperf_node.py
@@ -156,9 +156,10 @@ class NetperfNode(base.Scenario):
sla_max_mean_latency = int(
self.scenario_cfg["sla"]["mean_latency"])
- assert mean_latency <= sla_max_mean_latency, \
- "mean_latency %f > sla_max_mean_latency(%f); " % \
- (mean_latency, sla_max_mean_latency)
+ self.verify_SLA(
+ mean_latency <= sla_max_mean_latency,
+ "mean_latency %f > sla_max_mean_latency(%f); "
+ % (mean_latency, sla_max_mean_latency))
def teardown(self):
"""remove netperf from nodes after test"""
diff --git a/yardstick/benchmark/scenarios/networking/nstat.py b/yardstick/benchmark/scenarios/networking/nstat.py
index 10c560769..ea067f8ab 100644
--- a/yardstick/benchmark/scenarios/networking/nstat.py
+++ b/yardstick/benchmark/scenarios/networking/nstat.py
@@ -121,4 +121,4 @@ class Nstat(base.Scenario):
if rate > sla_rate:
sla_error += "%s rate %f > sla:%s_rate(%f); " % \
(i, rate, i, sla_rate)
- assert sla_error == "", sla_error
+ self.verify_SLA(sla_error == "", sla_error)
diff --git a/yardstick/benchmark/scenarios/networking/ping.py b/yardstick/benchmark/scenarios/networking/ping.py
index e7d9beea8..6caeab5ef 100644
--- a/yardstick/benchmark/scenarios/networking/ping.py
+++ b/yardstick/benchmark/scenarios/networking/ping.py
@@ -91,9 +91,10 @@ class Ping(base.Scenario):
result.update(utils.flatten_dict_key(ping_result))
if sla_max_rtt is not None:
sla_max_rtt = float(sla_max_rtt)
- assert rtt_result[target_vm_name] <= sla_max_rtt,\
- "rtt %f > sla: max_rtt(%f); " % \
- (rtt_result[target_vm_name], sla_max_rtt)
+ self.verify_SLA(
+ rtt_result[target_vm_name] <= sla_max_rtt,
+ "rtt %f > sla: max_rtt(%f); "
+ % (rtt_result[target_vm_name], sla_max_rtt))
else:
LOG.error("ping '%s' '%s' timeout", options, target_vm)
# we need to specify a result to satisfy influxdb schema
@@ -102,13 +103,12 @@ class Ping(base.Scenario):
rtt_result[target_vm_name] = float(self.PING_ERROR_RTT)
# store result before potential AssertionError
result.update(utils.flatten_dict_key(ping_result))
- if sla_max_rtt is not None:
- raise AssertionError("packet dropped rtt {:f} > sla: max_rtt({:f})".format(
- rtt_result[target_vm_name], sla_max_rtt))
-
- else:
- raise AssertionError(
- "packet dropped rtt {:f}".format(rtt_result[target_vm_name]))
+ self.verify_SLA(sla_max_rtt is None,
+ "packet dropped rtt %f > sla: max_rtt(%f)"
+ % (rtt_result[target_vm_name], sla_max_rtt))
+ self.verify_SLA(False,
+ "packet dropped rtt %f"
+ % (rtt_result[target_vm_name]))
def _test(): # pragma: no cover
diff --git a/yardstick/benchmark/scenarios/networking/ping6.py b/yardstick/benchmark/scenarios/networking/ping6.py
index 74855a10f..377278004 100644
--- a/yardstick/benchmark/scenarios/networking/ping6.py
+++ b/yardstick/benchmark/scenarios/networking/ping6.py
@@ -59,8 +59,7 @@ class Ping6(base.Scenario): # pragma: no cover
self._ssh_host(node_name)
self.client._put_file_shell(
self.pre_setup_script, '~/pre_setup.sh')
- status, stdout, stderr = self.client.execute(
- "sudo bash pre_setup.sh")
+ self.client.execute("sudo bash pre_setup.sh")
def _get_controller_node(self, host_list):
for host_name in host_list:
@@ -122,7 +121,7 @@ class Ping6(base.Scenario): # pragma: no cover
cmd = "sudo bash %s %s %s" % \
(setup_bash_file, self.openrc, self.external_network)
LOG.debug("Executing setup command: %s", cmd)
- status, stdout, stderr = self.client.execute(cmd)
+ self.client.execute(cmd)
self.setup_done = True
@@ -171,8 +170,9 @@ class Ping6(base.Scenario): # pragma: no cover
result["rtt"] = float(stdout)
if "sla" in self.scenario_cfg:
sla_max_rtt = int(self.scenario_cfg["sla"]["max_rtt"])
- assert result["rtt"] <= sla_max_rtt, \
- "rtt %f > sla:max_rtt(%f); " % (result["rtt"], sla_max_rtt)
+ self.verify_SLA(result["rtt"] <= sla_max_rtt,
+ "rtt %f > sla:max_rtt(%f); "
+ % (result["rtt"], sla_max_rtt))
else:
LOG.error("ping6 timeout!!!")
self.run_done = True
@@ -216,5 +216,4 @@ class Ping6(base.Scenario): # pragma: no cover
self._ssh_host(node_name)
self.client._put_file_shell(
self.post_teardown_script, '~/post_teardown.sh')
- status, stdout, stderr = self.client.execute(
- "sudo bash post_teardown.sh")
+ self.client.execute("sudo bash post_teardown.sh")
diff --git a/yardstick/benchmark/scenarios/networking/pktgen.py b/yardstick/benchmark/scenarios/networking/pktgen.py
index b79b91539..c78108adb 100644
--- a/yardstick/benchmark/scenarios/networking/pktgen.py
+++ b/yardstick/benchmark/scenarios/networking/pktgen.py
@@ -87,7 +87,7 @@ class Pktgen(base.Scenario):
self.server.send_command(cmd)
self.client.send_command(cmd)
- """multiqueue setup"""
+ # multiqueue setup
if not self._is_irqbalance_disabled():
self._disable_irqbalance()
@@ -112,18 +112,14 @@ class Pktgen(base.Scenario):
def _get_vnic_driver_name(self):
cmd = "readlink /sys/class/net/%s/device/driver" % self.vnic_name
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
return os.path.basename(stdout.strip())
def _is_irqbalance_disabled(self):
"""Did we disable irqbalance already in the guest?"""
is_disabled = False
cmd = "grep ENABLED /etc/default/irqbalance"
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
if "0" in stdout:
is_disabled = True
@@ -132,49 +128,35 @@ class Pktgen(base.Scenario):
def _disable_irqbalance(self):
cmd = "sudo sed -i -e 's/ENABLED=\"1\"/ENABLED=\"0\"/g' " \
"/etc/default/irqbalance"
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
cmd = "sudo service irqbalance stop"
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
cmd = "sudo service irqbalance disable"
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
def _setup_irqmapping_ovs(self, queue_number):
cmd = "grep 'virtio0-input.0' /proc/interrupts |" \
"awk '{match($0,/ +[0-9]+/)} " \
"{print substr($1,RSTART,RLENGTH-1)}'"
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
cmd = "echo 1 | sudo tee /proc/irq/%s/smp_affinity" % (int(stdout))
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
cmd = "grep 'virtio0-output.0' /proc/interrupts |" \
"awk '{match($0,/ +[0-9]+/)} " \
"{print substr($1,RSTART,RLENGTH-1)}'"
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
cmd = "echo 1 | sudo tee /proc/irq/%s/smp_affinity" % (int(stdout))
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
if queue_number == 1:
return
@@ -186,44 +168,32 @@ class Pktgen(base.Scenario):
cmd = "grep 'virtio0-input.%s' /proc/interrupts |" \
"awk '{match($0,/ +[0-9]+/)} " \
"{print substr($1,RSTART,RLENGTH-1)}'" % (i)
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
cmd = "echo %s | sudo tee /proc/irq/%s/smp_affinity" \
% (smp_affinity_mask, int(stdout))
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
cmd = "grep 'virtio0-output.%s' /proc/interrupts |" \
"awk '{match($0,/ +[0-9]+/)} " \
"{print substr($1,RSTART,RLENGTH-1)}'" % (i)
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
cmd = "echo %s | sudo tee /proc/irq/%s/smp_affinity" \
% (smp_affinity_mask, int(stdout))
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
def _setup_irqmapping_sriov(self, queue_number):
cmd = "grep '%s-TxRx-0' /proc/interrupts |" \
"awk '{match($0,/ +[0-9]+/)} " \
"{print substr($1,RSTART,RLENGTH-1)}'" % self.vnic_name
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
cmd = "echo 1 | sudo tee /proc/irq/%s/smp_affinity" % (int(stdout))
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
if queue_number == 1:
return
@@ -234,24 +204,18 @@ class Pktgen(base.Scenario):
cmd = "grep '%s-TxRx-%s' /proc/interrupts |" \
"awk '{match($0,/ +[0-9]+/)} " \
"{print substr($1,RSTART,RLENGTH-1)}'" % (self.vnic_name, i)
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
cmd = "echo %s | sudo tee /proc/irq/%s/smp_affinity" \
% (smp_affinity_mask, int(stdout))
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
def _get_sriov_queue_number(self):
"""Get queue number from server as both VMs are the same"""
cmd = "grep %s-TxRx- /proc/interrupts | wc -l" % self.vnic_name
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
return int(stdout)
def _get_available_queue_number(self):
@@ -259,9 +223,7 @@ class Pktgen(base.Scenario):
cmd = "sudo ethtool -l %s | grep Combined | head -1 |" \
"awk '{printf $2}'" % self.vnic_name
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
return int(stdout)
def _get_usable_queue_number(self):
@@ -269,9 +231,7 @@ class Pktgen(base.Scenario):
cmd = "sudo ethtool -l %s | grep Combined | tail -1 |" \
"awk '{printf $2}'" % self.vnic_name
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
return int(stdout)
def _enable_ovs_multiqueue(self):
@@ -282,10 +242,8 @@ class Pktgen(base.Scenario):
cmd = "sudo ethtool -L %s combined %s" % \
(self.vnic_name, available_queue_number)
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.server.execute(cmd)
- status, stdout, stderr = self.client.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd)
+ self.client.run(cmd)
return available_queue_number
def _iptables_setup(self):
@@ -294,9 +252,7 @@ class Pktgen(base.Scenario):
"sudo iptables -A INPUT -p udp --dport 1000:%s -j DROP" \
% (1000 + self.number_of_ports)
LOG.debug("Executing command: %s", cmd)
- status, _, stderr = self.server.execute(cmd, timeout=SSH_TIMEOUT)
- if status:
- raise RuntimeError(stderr)
+ self.server.run(cmd, timeout=SSH_TIMEOUT)
def _iptables_get_result(self):
"""Get packet statistics from server"""
@@ -304,9 +260,7 @@ class Pktgen(base.Scenario):
"awk '/dpts:1000:%s/ {{printf \"%%s\", $1}}'" \
% (1000 + self.number_of_ports)
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.server.execute(cmd)
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.server.execute(cmd, raise_on_error=True)
return int(stdout)
def run(self, result):
@@ -356,10 +310,8 @@ class Pktgen(base.Scenario):
duration, queue_number, pps)
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.client.execute(cmd, timeout=SSH_TIMEOUT)
-
- if status:
- raise RuntimeError(stderr)
+ _, stdout, _ = self.client.execute(cmd, raise_on_error=True,
+ timeout=SSH_TIMEOUT)
result.update(jsonutils.loads(stdout))
@@ -374,8 +326,8 @@ class Pktgen(base.Scenario):
if "sla" in self.scenario_cfg:
LOG.debug("Lost packets %d - Lost ppm %d", (sent - received), ppm)
sla_max_ppm = int(self.scenario_cfg["sla"]["max_ppm"])
- assert ppm <= sla_max_ppm, "ppm %d > sla_max_ppm %d; " \
- % (ppm, sla_max_ppm)
+ self.verify_SLA(ppm <= sla_max_ppm,
+ "ppm %d > sla_max_ppm %d; " % (ppm, sla_max_ppm))
def _test(): # pragma: no cover
diff --git a/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py b/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py
index 9a7b975a2..efb7d8b5d 100644
--- a/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py
+++ b/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py
@@ -113,10 +113,7 @@ cat ~/result.log -vT \
{print substr($0,RSTART,RLENGTH)}' \
|grep -v ^$ |awk '{if ($2 != 0) print $2}'\
"""
- client_status, client_stdout, client_stderr = self.client.execute(cmd)
-
- if client_status:
- raise RuntimeError(client_stderr)
+ _, client_stdout, _ = self.client.execute(cmd, raise_on_error=True)
avg_latency = 0
if client_stdout:
@@ -135,4 +132,4 @@ cat ~/result.log -vT \
LOG.info("sla_max_latency: %d", sla_max_latency)
debug_info = "avg_latency %d > sla_max_latency %d" \
% (avg_latency, sla_max_latency)
- assert avg_latency <= sla_max_latency, debug_info
+ self.verify_SLA(avg_latency <= sla_max_latency, debug_info)
diff --git a/yardstick/benchmark/scenarios/networking/pktgen_dpdk_throughput.py b/yardstick/benchmark/scenarios/networking/pktgen_dpdk_throughput.py
index 497e59ee8..97b9cf73f 100644
--- a/yardstick/benchmark/scenarios/networking/pktgen_dpdk_throughput.py
+++ b/yardstick/benchmark/scenarios/networking/pktgen_dpdk_throughput.py
@@ -143,11 +143,11 @@ class PktgenDPDK(base.Scenario):
cmd = "ip a | grep eth1 2>/dev/null"
LOG.debug("Executing command: %s in %s", cmd, host)
if "server" in host:
- status, stdout, stderr = self.server.execute(cmd)
+ _, stdout, _ = self.server.execute(cmd)
if stdout:
is_run = False
else:
- status, stdout, stderr = self.client.execute(cmd)
+ _, stdout, _ = self.client.execute(cmd)
if stdout:
is_run = False
@@ -222,5 +222,5 @@ class PktgenDPDK(base.Scenario):
ppm += (sent - received) % sent > 0
LOG.debug("Lost packets %d - Lost ppm %d", (sent - received), ppm)
sla_max_ppm = int(self.scenario_cfg["sla"]["max_ppm"])
- assert ppm <= sla_max_ppm, "ppm %d > sla_max_ppm %d; " \
- % (ppm, sla_max_ppm)
+ self.verify_SLA(ppm <= sla_max_ppm, "ppm %d > sla_max_ppm %d; "
+ % (ppm, sla_max_ppm))
diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py
index 78f866e25..4d7c4f9be 100644
--- a/yardstick/benchmark/scenarios/networking/vnf_generic.py
+++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py
@@ -13,20 +13,19 @@
# limitations under the License.
import copy
-import logging
-import time
-
import ipaddress
from itertools import chain
+import logging
import os
import sys
+import time
import six
import yaml
from yardstick.benchmark.scenarios import base as scenario_base
-from yardstick.error import IncorrectConfig
from yardstick.common.constants import LOG_DIR
+from yardstick.common import exceptions
from yardstick.common.process import terminate_children
from yardstick.common import utils
from yardstick.network_services.collector.subscriber import Collector
@@ -134,11 +133,10 @@ class NetworkServiceTestCase(scenario_base.Scenario):
with utils.open_relative_file(profile, path) as infile:
return infile.read()
- def _get_topology(self):
- topology = self.scenario_cfg["topology"]
- path = self.scenario_cfg["task_path"]
- with utils.open_relative_file(topology, path) as infile:
- return infile.read()
+ def _get_duration(self):
+ options = self.scenario_cfg.get('options', {})
+ return options.get('duration',
+ tprofile_base.TrafficProfileConfig.DEFAULT_DURATION)
def _fill_traffic_profile(self):
tprofile = self._get_traffic_profile()
@@ -148,12 +146,17 @@ class NetworkServiceTestCase(scenario_base.Scenario):
'imix': self._get_traffic_imix(),
tprofile_base.TrafficProfile.UPLINK: {},
tprofile_base.TrafficProfile.DOWNLINK: {},
- 'extra_args': extra_args
- }
-
+ 'extra_args': extra_args,
+ 'duration': self._get_duration()}
traffic_vnfd = vnfdgen.generate_vnfd(tprofile, tprofile_data)
self.traffic_profile = tprofile_base.TrafficProfile.get(traffic_vnfd)
+ def _get_topology(self):
+ topology = self.scenario_cfg["topology"]
+ path = self.scenario_cfg["task_path"]
+ with utils.open_relative_file(topology, path) as infile:
+ return infile.read()
+
def _render_topology(self):
topology = self._get_topology()
topology_args = self.scenario_cfg.get('extra_args', {})
@@ -190,8 +193,9 @@ class NetworkServiceTestCase(scenario_base.Scenario):
try:
node0_data, node1_data = vld["vnfd-connection-point-ref"]
except (ValueError, TypeError):
- raise IncorrectConfig("Topology file corrupted, "
- "wrong endpoint count for connection")
+ raise exceptions.IncorrectConfig(
+ error_msg='Topology file corrupted, wrong endpoint count '
+ 'for connection')
node0_name = self._find_vnf_name_from_id(node0_data["member-vnf-index-ref"])
node1_name = self._find_vnf_name_from_id(node1_data["member-vnf-index-ref"])
@@ -237,15 +241,17 @@ class NetworkServiceTestCase(scenario_base.Scenario):
except KeyError:
LOG.exception("")
- raise IncorrectConfig("Required interface not found, "
- "topology file corrupted")
+ raise exceptions.IncorrectConfig(
+ error_msg='Required interface not found, topology file '
+ 'corrupted')
for vld in self.topology['vld']:
try:
node0_data, node1_data = vld["vnfd-connection-point-ref"]
except (ValueError, TypeError):
- raise IncorrectConfig("Topology file corrupted, "
- "wrong endpoint count for connection")
+ raise exceptions.IncorrectConfig(
+ error_msg='Topology file corrupted, wrong endpoint count '
+ 'for connection')
node0_name = self._find_vnf_name_from_id(node0_data["member-vnf-index-ref"])
node1_name = self._find_vnf_name_from_id(node1_data["member-vnf-index-ref"])
@@ -330,8 +336,9 @@ class NetworkServiceTestCase(scenario_base.Scenario):
except StopIteration:
pass
- raise IncorrectConfig("No implementation for %s found in %s" %
- (expected_name, classes_found))
+ message = ('No implementation for %s found in %s'
+ % (expected_name, classes_found))
+ raise exceptions.IncorrectConfig(error_msg=message)
@staticmethod
def create_interfaces_from_node(vnfd, node):
diff --git a/yardstick/benchmark/scenarios/networking/vsperf.py b/yardstick/benchmark/scenarios/networking/vsperf.py
index 705544c41..2b3474070 100644
--- a/yardstick/benchmark/scenarios/networking/vsperf.py
+++ b/yardstick/benchmark/scenarios/networking/vsperf.py
@@ -215,15 +215,15 @@ class Vsperf(base.Scenario):
if 'sla' in self.scenario_cfg and \
'metrics' in self.scenario_cfg['sla']:
for metric in self.scenario_cfg['sla']['metrics'].split(','):
- assert metric in result, \
- '%s is not collected by VSPERF' % (metric)
- assert metric in self.scenario_cfg['sla'], \
- '%s is not defined in SLA' % (metric)
+ self.verify_SLA(metric in result,
+ '%s was not collected by VSPERF' % metric)
+ self.verify_SLA(metric in self.scenario_cfg['sla'],
+ '%s is not defined in SLA' % metric)
vs_res = float(result[metric])
sla_res = float(self.scenario_cfg['sla'][metric])
- assert vs_res >= sla_res, \
- 'VSPERF_%s(%f) < SLA_%s(%f)' % \
- (metric, vs_res, metric, sla_res)
+ self.verify_SLA(vs_res >= sla_res,
+ 'VSPERF_%s(%f) < SLA_%s(%f)'
+ % (metric, vs_res, metric, sla_res))
def teardown(self):
"""cleanup after the test execution"""
diff --git a/yardstick/benchmark/scenarios/networking/vsperf_dpdk.py b/yardstick/benchmark/scenarios/networking/vsperf_dpdk.py
index 454587829..27bf40dcb 100644
--- a/yardstick/benchmark/scenarios/networking/vsperf_dpdk.py
+++ b/yardstick/benchmark/scenarios/networking/vsperf_dpdk.py
@@ -231,7 +231,7 @@ class VsperfDPDK(base.Scenario):
is_run = True
cmd = "ip a | grep %s 2>/dev/null" % (self.tg_port1)
LOG.debug("Executing command: %s", cmd)
- status, stdout, stderr = self.client.execute(cmd)
+ _, stdout, _ = self.client.execute(cmd)
if stdout:
is_run = False
return is_run
@@ -325,15 +325,15 @@ class VsperfDPDK(base.Scenario):
if 'sla' in self.scenario_cfg and \
'metrics' in self.scenario_cfg['sla']:
for metric in self.scenario_cfg['sla']['metrics'].split(','):
- assert metric in result, \
- '%s is not collected by VSPERF' % (metric)
- assert metric in self.scenario_cfg['sla'], \
- '%s is not defined in SLA' % (metric)
+ self.verify_SLA(metric in result,
+ '%s was not collected by VSPERF' % metric)
+ self.verify_SLA(metric in self.scenario_cfg['sla'],
+ '%s is not defined in SLA' % metric)
vs_res = float(result[metric])
sla_res = float(self.scenario_cfg['sla'][metric])
- assert vs_res >= sla_res, \
- 'VSPERF_%s(%f) < SLA_%s(%f)' % \
- (metric, vs_res, metric, sla_res)
+ self.verify_SLA(vs_res >= sla_res,
+ 'VSPERF_%s(%f) < SLA_%s(%f)'
+ % (metric, vs_res, metric, sla_res))
def teardown(self):
"""cleanup after the test execution"""
diff --git a/yardstick/benchmark/scenarios/storage/fio.py b/yardstick/benchmark/scenarios/storage/fio.py
index d3ed840d8..c57c6edf2 100644
--- a/yardstick/benchmark/scenarios/storage/fio.py
+++ b/yardstick/benchmark/scenarios/storage/fio.py
@@ -223,7 +223,7 @@ class Fio(base.Scenario):
sla_error += "%s %d < " \
"sla:%s(%d); " % (k, v, k, min_v)
- assert sla_error == "", sla_error
+ self.verify_SLA(sla_error == "", sla_error)
def _test():
diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py
index e6a1f1fa1..650c09edb 100644
--- a/yardstick/common/exceptions.py
+++ b/yardstick/common/exceptions.py
@@ -21,6 +21,16 @@ class ProcessExecutionError(RuntimeError):
self.returncode = returncode
+class ErrorClass(object):
+
+ def __init__(self, *args, **kwargs):
+ if 'test' not in kwargs:
+ raise RuntimeError
+
+ def __getattr__(self, item):
+ raise AttributeError
+
+
class YardstickException(Exception):
"""Base Yardstick Exception.
@@ -137,8 +147,28 @@ class LibvirtQemuImageCreateError(YardstickException):
'%(base_image)s. Error: %(error)s.')
+class SSHError(YardstickException):
+ message = '%(error_msg)s'
+
+
+class SSHTimeout(SSHError):
+ pass
+
+
+class IncorrectConfig(YardstickException):
+ message = '%(error_msg)s'
+
+
+class IncorrectSetup(YardstickException):
+ message = '%(error_msg)s'
+
+
+class IncorrectNodeSetup(IncorrectSetup):
+ pass
+
+
class ScenarioConfigContextNameNotFound(YardstickException):
- message = 'Context name "%(context_name)s" not found'
+ message = 'Context for host name "%(host_name)s" not found'
class StackCreationInterrupt(YardstickException):
@@ -165,6 +195,10 @@ class WaitTimeout(YardstickException):
message = 'Wait timeout while waiting for condition'
+class KubernetesTemplateInvalidVolumeType(YardstickException):
+ message = 'No valid "volume" types present in %(volume)s'
+
+
class ScenarioCreateNetworkError(YardstickException):
message = 'Create Neutron Network Scenario failed'
@@ -267,3 +301,28 @@ class ScenarioCreateImageError(YardstickException):
class ScenarioDeleteImageError(YardstickException):
message = 'Glance Delete Image Scenario failed'
+
+
+class IxNetworkClientNotConnected(YardstickException):
+ message = 'IxNetwork client not connected to a TCL server'
+
+
+class IxNetworkFlowNotPresent(YardstickException):
+ message = 'Flow Group "%(flow_group)s" is not present'
+
+
+class IxNetworkFieldNotPresentInStackItem(YardstickException):
+ message = 'Field "%(field_name)s" not present in stack item %(stack_item)s'
+
+
+class SLAValidationError(YardstickException):
+ message = '%(case_name)s SLA validation failed. Error: %(error_msg)s'
+
+
+class AclMissingActionArguments(YardstickException):
+ message = ('Missing ACL action parameter '
+ '[action=%(action_name)s parameter=%(action_param)s]')
+
+
+class AclUknownActionTemplate(YardstickException):
+ message = 'No ACL CLI template found for "%(action_name)s" action'
diff --git a/yardstick/common/kubernetes_utils.py b/yardstick/common/kubernetes_utils.py
index d60c9b23a..ee8e8edcd 100644
--- a/yardstick/common/kubernetes_utils.py
+++ b/yardstick/common/kubernetes_utils.py
@@ -199,3 +199,9 @@ def get_pod_list(namespace='default'): # pragma: no cover
def get_pod_by_name(name): # pragma: no cover
pod_list = get_pod_list()
return next((n for n in pod_list.items if n.metadata.name.startswith(name)), None)
+
+
+def get_volume_types():
+ """Return the "volume" types supported by the current API"""
+ return [vtype for vtype in client.V1Volume.attribute_map.values()
+ if vtype != 'name']
diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py
index 108ee17bc..f9fe0e336 100644
--- a/yardstick/common/utils.py
+++ b/yardstick/common/utils.py
@@ -306,6 +306,19 @@ def get_ip_version(ip_addr):
return address.version
+def make_ip_addr(ip, mask):
+ """
+ :param ip[str]: ip adddress
+ :param mask[str]: /24 prefix of 255.255.255.0 netmask
+ :return: IPv4Interface object
+ """
+ try:
+ return ipaddress.ip_interface(six.text_type('/'.join([ip, mask])))
+ except (TypeError, ValueError):
+ # None so we can skip later
+ return None
+
+
def ip_to_hex(ip_addr, separator=''):
try:
address = ipaddress.ip_address(six.text_type(ip_addr))
@@ -409,13 +422,18 @@ class ErrorClass(object):
class Timer(object):
- def __init__(self, timeout=None):
+ def __init__(self, timeout=None, raise_exception=True):
super(Timer, self).__init__()
self.start = self.delta = None
self._timeout = int(timeout) if timeout else None
+ self._timeout_flag = False
+ self._raise_exception = raise_exception
def _timeout_handler(self, *args):
- raise exceptions.TimerTimeout(timeout=self._timeout)
+ self._timeout_flag = True
+ if self._raise_exception:
+ raise exceptions.TimerTimeout(timeout=self._timeout)
+ self.__exit__()
def __enter__(self):
self.start = datetime.datetime.now()
@@ -432,6 +450,23 @@ class Timer(object):
def __getattr__(self, item):
return getattr(self.delta, item)
+ def __iter__(self):
+ self._raise_exception = False
+ return self.__enter__()
+
+ def next(self): # pragma: no cover
+ # NOTE(ralonsoh): Python 2 support.
+ if not self._timeout_flag:
+ return datetime.datetime.now()
+ raise StopIteration()
+
+ def __next__(self): # pragma: no cover
+ # NOTE(ralonsoh): Python 3 support.
+ return self.next()
+
+ def __del__(self): # pragma: no cover
+ signal.alarm(0)
+
def read_meminfo(ssh_client):
"""Read "/proc/meminfo" file and parse all keys and values"""
diff --git a/yardstick/error.py b/yardstick/error.py
deleted file mode 100644
index 9b84de1af..000000000
--- a/yardstick/error.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# 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.
-
-
-class SSHError(Exception):
- """Class handles ssh connection error exception"""
- pass
-
-
-class SSHTimeout(SSHError):
- """Class handles ssh connection timeout exception"""
- pass
-
-
-class IncorrectConfig(Exception):
- """Class handles incorrect configuration during setup"""
- pass
-
-
-class IncorrectSetup(Exception):
- """Class handles incorrect setup during setup"""
- pass
-
-
-class IncorrectNodeSetup(IncorrectSetup):
- """Class handles incorrect setup during setup"""
- pass
-
-
-class ErrorClass(object):
-
- def __init__(self, *args, **kwargs):
- if 'test' not in kwargs:
- raise RuntimeError
-
- def __getattr__(self, item):
- raise AttributeError
diff --git a/yardstick/network_services/helpers/dpdkbindnic_helper.py b/yardstick/network_services/helpers/dpdkbindnic_helper.py
index 05b822c2e..1c74355ef 100644
--- a/yardstick/network_services/helpers/dpdkbindnic_helper.py
+++ b/yardstick/network_services/helpers/dpdkbindnic_helper.py
@@ -18,12 +18,9 @@ import re
from collections import defaultdict
from itertools import chain
+from yardstick.common import exceptions
from yardstick.common.utils import validate_non_string_sequence
-from yardstick.error import IncorrectConfig
-from yardstick.error import IncorrectSetup
-from yardstick.error import IncorrectNodeSetup
-from yardstick.error import SSHTimeout
-from yardstick.error import SSHError
+
NETWORK_KERNEL = 'network_kernel'
NETWORK_DPDK = 'network_dpdk'
@@ -51,7 +48,7 @@ class DpdkInterface(object):
try:
assert self.local_mac
except (AssertionError, KeyError):
- raise IncorrectConfig
+ raise exceptions.IncorrectConfig(error_msg='')
@property
def local_mac(self):
@@ -98,10 +95,12 @@ class DpdkInterface(object):
# if we don't find all the keys then don't update
pass
- except (IncorrectNodeSetup, SSHError, SSHTimeout):
- raise IncorrectConfig(
- "Unable to probe missing interface fields '%s', on node %s "
- "SSH Error" % (', '.join(self.missing_fields), self.dpdk_node.node_key))
+ except (exceptions.IncorrectNodeSetup, exceptions.SSHError,
+ exceptions.SSHTimeout):
+ message = ('Unable to probe missing interface fields "%s", on '
+ 'node %s SSH Error' % (', '.join(self.missing_fields),
+ self.dpdk_node.node_key))
+ raise exceptions.IncorrectConfig(error_msg=message)
class DpdkNode(object):
@@ -118,11 +117,12 @@ class DpdkNode(object):
try:
self.dpdk_interfaces = {intf['name']: DpdkInterface(self, intf['virtual-interface'])
for intf in self.interfaces}
- except IncorrectConfig:
+ except exceptions.IncorrectConfig:
template = "MAC address is required for all interfaces, missing on: {}"
errors = (intf['name'] for intf in self.interfaces if
'local_mac' not in intf['virtual-interface'])
- raise IncorrectSetup(template.format(", ".join(errors)))
+ raise exceptions.IncorrectSetup(
+ error_msg=template.format(", ".join(errors)))
@property
def dpdk_helper(self):
@@ -176,7 +176,7 @@ class DpdkNode(object):
self._probe_netdevs()
try:
self._probe_missing_values()
- except IncorrectConfig:
+ except exceptions.IncorrectConfig:
# ignore for now
pass
@@ -193,7 +193,7 @@ class DpdkNode(object):
missing_fields)
errors = "\n".join(errors)
if errors:
- raise IncorrectSetup(errors)
+ raise exceptions.IncorrectSetup(error_msg=errors)
finally:
self._dpdk_helper = None
diff --git a/yardstick/network_services/helpers/samplevnf_helper.py b/yardstick/network_services/helpers/samplevnf_helper.py
index 0ab10d7b7..8e6a3a3ea 100644
--- a/yardstick/network_services/helpers/samplevnf_helper.py
+++ b/yardstick/network_services/helpers/samplevnf_helper.py
@@ -23,8 +23,7 @@ from itertools import chain, repeat
import six
from six.moves.configparser import ConfigParser
-
-from yardstick.common.utils import ip_to_hex
+from yardstick.common import utils
LOG = logging.getLogger(__name__)
@@ -34,19 +33,6 @@ link {0} config {1} {2}
link {0} up
"""
-ACTION_TEMPLATE = """\
-p action add {0} accept
-p action add {0} fwd {0}
-p action add {0} count
-"""
-
-FW_ACTION_TEMPLATE = """\
-p action add {0} accept
-p action add {0} fwd {0}
-p action add {0} count
-p action add {0} conntrack
-"""
-
# This sets up a basic passthrough with no rules
SCRIPT_TPL = """
{link_config}
@@ -59,9 +45,7 @@ SCRIPT_TPL = """
{arp_route_tbl6}
-{actions}
-
-{rules}
+{flows}
"""
@@ -182,26 +166,9 @@ class MultiPortConfig(object):
return parser.get(section, key)
return default
- @staticmethod
- def make_ip_addr(ip, mask):
- """
- :param ip: ip adddress
- :type ip: str
- :param mask: /24 prefix of 255.255.255.0 netmask
- :type mask: str
- :return: interface
- :rtype: IPv4Interface
- """
-
- try:
- return ipaddress.ip_interface(six.text_type('/'.join([ip, mask])))
- except (TypeError, ValueError):
- # None so we can skip later
- return None
-
@classmethod
def validate_ip_and_prefixlen(cls, ip_addr, prefixlen):
- ip_addr = cls.make_ip_addr(ip_addr, prefixlen)
+ ip_addr = utils.make_ip_addr(ip_addr, prefixlen)
return ip_addr.ip.exploded, ip_addr.network.prefixlen
def __init__(self, topology_file, config_tpl, tmp_file, vnfd_helper,
@@ -245,7 +212,7 @@ class MultiPortConfig(object):
self.ports_len = 0
self.prv_que_handler = None
self.vnfd = None
- self.rules = None
+ self.flows = None
self.pktq_out = []
@staticmethod
@@ -360,7 +327,7 @@ class MultiPortConfig(object):
"%s/%s" % (interface["dst_ip"], interface["netmask"])))
arp_vars = {
- "port_netmask_hex": ip_to_hex(dst_port_ip.network.netmask.exploded),
+ "port_netmask_hex": utils.ip_to_hex(dst_port_ip.network.netmask.exploded),
# this is the port num that contains port0 subnet and next_hop_ip_hex
# this is LINKID which should be based on DPDK port number
"port_num": dpdk_port_num,
@@ -542,7 +509,7 @@ class MultiPortConfig(object):
self.update_write_parser(self.loadb_tpl)
self.start_core += 1
- for i in range(self.worker_threads):
+ for _ in range(self.worker_threads):
vnf_data = self.generate_vnf_data()
if not self.vnf_tpl:
self.vnf_tpl = {}
@@ -637,65 +604,8 @@ class MultiPortConfig(object):
return '\n'.join(('p {3} arpadd {0} {1} {2}'.format(*values) for values in arp_config6))
- def generate_action_config(self):
- port_list = (self.vnfd_helper.port_num(p) for p in self.all_ports)
- if self.vnf_type == "VFW":
- template = FW_ACTION_TEMPLATE
- else:
- template = ACTION_TEMPLATE
-
- return ''.join((template.format(port) for port in port_list))
-
- def get_ip_from_port(self, port):
- # we can't use gateway because in OpenStack gateways interfer with floating ip routing
- # return self.make_ip_addr(self.get_ports_gateway(port), self.get_netmask_gateway(port))
- vintf = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
- ip = vintf["local_ip"]
- netmask = vintf["netmask"]
- return self.make_ip_addr(ip, netmask)
-
- def get_network_and_prefixlen_from_ip_of_port(self, port):
- ip_addr = self.get_ip_from_port(port)
- # handle cases with no gateway
- if ip_addr:
- return ip_addr.network.network_address.exploded, ip_addr.network.prefixlen
- else:
- return None, None
-
- def generate_rule_config(self):
- cmd = 'acl' if self.vnf_type == "ACL" else "vfw"
- rules_config = self.rules if self.rules else ''
- new_rules = []
- new_ipv6_rules = []
- pattern = 'p {0} add {1} {2} {3} {4} {5} 0 65535 0 65535 0 0 {6}'
- for src_intf, dst_intf in self.port_pair_list:
- src_port = self.vnfd_helper.port_num(src_intf)
- dst_port = self.vnfd_helper.port_num(dst_intf)
-
- src_net, src_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(src_intf)
- dst_net, dst_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(dst_intf)
- # ignore entires with empty values
- if all((src_net, src_prefix_len, dst_net, dst_prefix_len)):
- new_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len,
- dst_net, dst_prefix_len, dst_port))
- new_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len,
- src_net, src_prefix_len, src_port))
-
- # src_net = self.get_ports_gateway6(port_pair[0])
- # src_prefix_len = self.get_netmask_gateway6(port_pair[0])
- # dst_net = self.get_ports_gateway6(port_pair[1])
- # dst_prefix_len = self.get_netmask_gateway6(port_pair[0])
- # # ignore entires with empty values
- # if all((src_net, src_prefix_len, dst_net, dst_prefix_len)):
- # new_ipv6_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len,
- # dst_net, dst_prefix_len, dst_port))
- # new_ipv6_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len,
- # src_net, src_prefix_len, src_port))
-
- acl_apply = "\np %s applyruleset" % cmd
- new_rules_config = '\n'.join(pattern.format(*values) for values
- in chain(new_rules, new_ipv6_rules))
- return ''.join([rules_config, new_rules_config, acl_apply])
+ def get_flows_config(self):
+ return self.flows if self.flows else ''
def generate_script_data(self):
self._port_pairs = PortPairs(self.vnfd_helper.interfaces)
@@ -707,24 +617,15 @@ class MultiPortConfig(object):
# disable IPv6 for now
# 'arp_config6': self.generate_arp_config6(),
'arp_config6': "",
- 'arp_config': self.generate_arp_config(),
'arp_route_tbl': self.generate_arp_route_tbl(),
'arp_route_tbl6': "",
- 'actions': '',
- 'rules': '',
+ 'flows': self.get_flows_config()
}
-
- if self.vnf_type in ('ACL', 'VFW'):
- script_data.update({
- 'actions': self.generate_action_config(),
- 'rules': self.generate_rule_config(),
- })
-
return script_data
- def generate_script(self, vnfd, rules=None):
+ def generate_script(self, vnfd, flows=None):
self.vnfd = vnfd
- self.rules = rules
+ self.flows = flows
script_data = self.generate_script_data()
script = SCRIPT_TPL.format(**script_data)
if self.lb_config == self.HW_LB:
diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py
deleted file mode 100644
index c538ceeba..000000000
--- a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py
+++ /dev/null
@@ -1,334 +0,0 @@
-# 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 logging
-
-import re
-from itertools import product
-import IxNetwork
-
-
-log = logging.getLogger(__name__)
-
-IP_VERSION_4 = 4
-IP_VERSION_6 = 6
-
-
-class TrafficStreamHelper(object):
-
- TEMPLATE = '{0.traffic_item}/{0.stream}:{0.param_id}/{1}'
-
- def __init__(self, traffic_item, stream, param_id):
- super(TrafficStreamHelper, self).__init__()
- self.traffic_item = traffic_item
- self.stream = stream
- self.param_id = param_id
-
- def __getattr__(self, item):
- return self.TEMPLATE.format(self, item)
-
-
-class FramesizeHelper(object):
-
- def __init__(self):
- super(FramesizeHelper, self).__init__()
- self.weighted_pairs = []
- self.weighted_range_pairs = []
-
- @property
- def weighted_pairs_arg(self):
- return '-weightedPairs', self.weighted_pairs
-
- @property
- def weighted_range_pairs_arg(self):
- return '-weightedRangePairs', self.weighted_range_pairs
-
- def make_args(self, *args):
- return self.weighted_pairs_arg + self.weighted_range_pairs_arg + args
-
- def populate_data(self, framesize_data):
- for key, value in framesize_data.items():
- if value == '0':
- continue
-
- replaced = re.sub('[Bb]', '', key)
- self.weighted_pairs.extend([
- replaced,
- value,
- ])
- pairs = [
- replaced,
- replaced,
- value,
- ]
- self.weighted_range_pairs.append(pairs)
-
-
-class IxNextgen(object):
-
- STATS_NAME_MAP = {
- "traffic_item": 'Traffic Item',
- "Tx_Frames": 'Tx Frames',
- "Rx_Frames": 'Rx Frames',
- "Tx_Frame_Rate": 'Tx Frame Rate',
- "Rx_Frame_Rate": 'Tx Frame Rate',
- "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)',
- "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)',
- "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)',
- }
-
- PORT_STATS_NAME_MAP = {
- "stat_name": 'Stat Name',
- "Frames_Tx": 'Frames Tx.',
- "Valid_Frames_Rx": 'Valid Frames Rx.',
- "Frames_Tx_Rate": 'Frames Tx. Rate',
- "Valid_Frames_Rx_Rate": 'Valid Frames Rx. Rate',
- "Tx_Rate_Kbps": 'Tx. Rate (Kbps)',
- "Rx_Rate_Kbps": 'Rx. Rate (Kbps)',
- "Tx_Rate_Mbps": 'Tx. Rate (Mbps)',
- "Rx_Rate_Mbps": 'Rx. Rate (Mbps)',
- }
-
- LATENCY_NAME_MAP = {
- "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)',
- "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)',
- "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)',
- }
-
- RANDOM_MASK_MAP = {
- IP_VERSION_4: '0.0.0.255',
- IP_VERSION_6: '0:0:0:0:0:0:0:ff',
- }
-
- MODE_SEEDS_MAP = {
- 0: ('uplink', ['256', '2048']),
- }
-
- MODE_SEEDS_DEFAULT = 'downlink', ['2048', '256']
-
- @staticmethod
- def find_view_obj(view_name, views):
- edited_view_name = '::ixNet::OBJ-/statistics/view:"{}"'.format(view_name)
- return next((view for view in views if edited_view_name == view), '')
-
- @staticmethod
- def get_config(tg_cfg):
- card = []
- port = []
- external_interface = tg_cfg["vdu"][0]["external-interface"]
- for intf in external_interface:
- card_port0 = intf["virtual-interface"]["vpci"]
- card0, port0 = card_port0.split(':')[:2]
- card.append(card0)
- port.append(port0)
-
- cfg = {
- 'machine': tg_cfg["mgmt-interface"]["ip"],
- 'port': tg_cfg["mgmt-interface"]["tg-config"]["tcl_port"],
- 'chassis': tg_cfg["mgmt-interface"]["tg-config"]["ixchassis"],
- 'cards': card,
- 'ports': port,
- 'output_dir': tg_cfg["mgmt-interface"]["tg-config"]["dut_result_dir"],
- 'version': tg_cfg["mgmt-interface"]["tg-config"]["version"],
- 'bidir': True,
- }
-
- return cfg
-
- def __init__(self, ixnet=None):
- self.ixnet = ixnet
- self._objRefs = dict()
- self._cfg = None
- self._logger = logging.getLogger(__name__)
- self._params = None
- self._bidir = None
-
- def iter_over_get_lists(self, x1, x2, y2, offset=0):
- for x in self.ixnet.getList(x1, x2):
- y_list = self.ixnet.getList(x, y2)
- for i, y in enumerate(y_list, offset):
- yield x, y, i
-
- def set_random_ip_multi_attribute(self, ipv4, seed, fixed_bits, random_mask, l3_count):
- self.ixnet.setMultiAttribute(
- ipv4,
- '-seed', str(seed),
- '-fixedBits', str(fixed_bits),
- '-randomMask', str(random_mask),
- '-valueType', 'random',
- '-countValue', str(l3_count))
-
- def set_random_ip_multi_attributes(self, ip, version, seeds, l3):
- try:
- random_mask = self.RANDOM_MASK_MAP[version]
- except KeyError:
- raise ValueError('Unknown version %s' % version)
-
- l3_count = l3['count']
- if "srcIp" in ip:
- fixed_bits = l3['srcip4']
- self.set_random_ip_multi_attribute(ip, seeds[0], fixed_bits, random_mask, l3_count)
- if "dstIp" in ip:
- fixed_bits = l3['dstip4']
- self.set_random_ip_multi_attribute(ip, seeds[1], fixed_bits, random_mask, l3_count)
-
- def add_ip_header(self, params, version):
- for _, ep, i in self.iter_over_get_lists('/traffic', 'trafficItem', "configElement", 1):
- iter1 = (v['outer_l3'] for v in params.values() if str(v['id']) == str(i))
- try:
- l3 = next(iter1, {})
- seeds = self.MODE_SEEDS_MAP.get(i, self.MODE_SEEDS_DEFAULT)[1]
- except (KeyError, IndexError):
- continue
-
- for _, ip_bits, _ in self.iter_over_get_lists(ep, 'stack', 'field'):
- self.set_random_ip_multi_attributes(ip_bits, version, seeds, l3)
-
- self.ixnet.commit()
-
- def _connect(self, tg_cfg):
- self._cfg = self.get_config(tg_cfg)
- self.ixnet = IxNetwork.IxNet()
-
- machine = self._cfg['machine']
- port = str(self._cfg['port'])
- version = str(self._cfg['version'])
- result = self.ixnet.connect(machine, '-port', port, '-version', version)
- return result
-
- def clear_ixia_config(self):
- self.ixnet.execute('newConfig')
-
- def load_ixia_profile(self, profile):
- self.ixnet.execute('loadConfig', self.ixnet.readFrom(profile))
-
- def ix_load_config(self, profile):
- self.clear_ixia_config()
- self.load_ixia_profile(profile)
-
- def ix_assign_ports(self):
- vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport')
- ports = []
-
- chassis = self._cfg['chassis']
- ports = [(chassis, card, port) for card, port in
- zip(self._cfg['cards'], self._cfg['ports'])]
-
- vport_list = self.ixnet.getList("/", "vport")
- self.ixnet.execute('assignPorts', ports, [], vport_list, True)
- self.ixnet.commit()
-
- for vport in vports:
- if self.ixnet.getAttribute(vport, '-state') != 'up':
- log.error("Both thr ports are down...")
-
- def ix_update_frame(self, params):
- streams = ["configElement"]
-
- for param in params.values():
- framesize_data = FramesizeHelper()
- traffic_items = self.ixnet.getList('/traffic', 'trafficItem')
- param_id = param['id']
- for traffic_item, stream in product(traffic_items, streams):
- helper = TrafficStreamHelper(traffic_item, stream, param_id)
-
- self.ixnet.setMultiAttribute(helper.transmissionControl,
- '-type', '{0}'.format(param.get('traffic_type',
- 'continuous')),
- '-duration', '{0}'.format(param.get('duration',
- "30")))
-
- stream_frame_rate_path = helper.frameRate
- self.ixnet.setMultiAttribute(stream_frame_rate_path, '-rate', param['iload'])
- if param['outer_l2']['framesPerSecond']:
- self.ixnet.setMultiAttribute(stream_frame_rate_path,
- '-type', 'framesPerSecond')
-
- framesize_data.populate_data(param['outer_l2']['framesize'])
-
- make_attr_args = framesize_data.make_args('-incrementFrom', '66',
- '-randomMin', '66',
- '-quadGaussian', [],
- '-type', 'weightedPairs',
- '-presetDistribution', 'cisco',
- '-incrementTo', '1518')
-
- self.ixnet.setMultiAttribute(helper.frameSize, *make_attr_args)
-
- self.ixnet.commit()
-
- def update_ether_multi_attribute(self, ether, mac_addr):
- self.ixnet.setMultiAttribute(ether,
- '-singleValue', mac_addr,
- '-fieldValue', mac_addr,
- '-valueType', 'singleValue')
-
- def update_ether_multi_attributes(self, ether, l2):
- if "ethernet.header.destinationAddress" in ether:
- self.update_ether_multi_attribute(ether, str(l2.get('dstmac', "00:00:00:00:00:02")))
-
- if "ethernet.header.sourceAddress" in ether:
- self.update_ether_multi_attribute(ether, str(l2.get('srcmac', "00:00:00:00:00:01")))
-
- def ix_update_ether(self, params):
- for _, ep, index in self.iter_over_get_lists('/traffic', 'trafficItem',
- "configElement", 1):
- iter1 = (v['outer_l2'] for v in params.values() if str(v['id']) == str(index))
- try:
- l2 = next(iter1, {})
- except KeyError:
- continue
-
- for _, ether, _ in self.iter_over_get_lists(ep, 'stack', 'field'):
- self.update_ether_multi_attributes(ether, l2)
-
- self.ixnet.commit()
-
- def ix_update_udp(self, params):
- pass
-
- def ix_update_tcp(self, params):
- pass
-
- def ix_start_traffic(self):
- tis = self.ixnet.getList('/traffic', 'trafficItem')
- for ti in tis:
- self.ixnet.execute('generate', [ti])
- self.ixnet.execute('apply', '/traffic')
- self.ixnet.execute('start', '/traffic')
-
- def ix_stop_traffic(self):
- tis = self.ixnet.getList('/traffic', 'trafficItem')
- for _ in tis:
- self.ixnet.execute('stop', '/traffic')
-
- def build_stats_map(self, view_obj, name_map):
- return {kl: self.execute_get_column_values(view_obj, kr) for kl, kr in name_map.items()}
-
- def execute_get_column_values(self, view_obj, name):
- return self.ixnet.execute('getColumnValues', view_obj, name)
-
- def ix_get_statistics(self):
- views = self.ixnet.getList('/statistics', 'view')
- stats = {}
- view_obj = self.find_view_obj("Traffic Item Statistics", views)
- stats = self.build_stats_map(view_obj, self.STATS_NAME_MAP)
-
- view_obj = self.find_view_obj("Port Statistics", views)
- ports_stats = self.build_stats_map(view_obj, self.PORT_STATS_NAME_MAP)
-
- view_obj = self.find_view_obj("Flow Statistics", views)
- stats["latency"] = self.build_stats_map(view_obj, self.LATENCY_NAME_MAP)
-
- return stats, ports_stats
diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py b/yardstick/network_services/libs/ixia_libs/ixnet/__init__.py
index e69de29bb..e69de29bb 100644
--- a/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py
+++ b/yardstick/network_services/libs/ixia_libs/ixnet/__init__.py
diff --git a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
new file mode 100644
index 000000000..393f60f7c
--- /dev/null
+++ b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
@@ -0,0 +1,470 @@
+# 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 logging
+
+import IxNetwork
+
+from yardstick.common import exceptions
+from yardstick.common import utils
+
+
+log = logging.getLogger(__name__)
+
+IP_VERSION_4 = 4
+IP_VERSION_6 = 6
+
+PROTO_ETHERNET = 'ethernet'
+PROTO_IPV4 = 'ipv4'
+PROTO_IPV6 = 'ipv6'
+PROTO_UDP = 'udp'
+PROTO_TCP = 'tcp'
+PROTO_VLAN = 'vlan'
+
+IP_VERSION_4_MASK = '0.0.0.255'
+IP_VERSION_6_MASK = '0:0:0:0:0:0:0:ff'
+
+TRAFFIC_STATUS_STARTED = 'started'
+TRAFFIC_STATUS_STOPPED = 'stopped'
+
+
+# NOTE(ralonsoh): this pragma will be removed in the last patch of this series
+class IxNextgen(object): # pragma: no cover
+
+ PORT_STATS_NAME_MAP = {
+ "stat_name": 'Stat Name',
+ "Frames_Tx": 'Frames Tx.',
+ "Valid_Frames_Rx": 'Valid Frames Rx.',
+ "Frames_Tx_Rate": 'Frames Tx. Rate',
+ "Valid_Frames_Rx_Rate": 'Valid Frames Rx. Rate',
+ "Tx_Rate_Kbps": 'Tx. Rate (Kbps)',
+ "Rx_Rate_Kbps": 'Rx. Rate (Kbps)',
+ "Tx_Rate_Mbps": 'Tx. Rate (Mbps)',
+ "Rx_Rate_Mbps": 'Rx. Rate (Mbps)',
+ }
+
+ LATENCY_NAME_MAP = {
+ "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)',
+ "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)',
+ "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)',
+ }
+
+ @staticmethod
+ def get_config(tg_cfg):
+ card = []
+ port = []
+ external_interface = tg_cfg["vdu"][0]["external-interface"]
+ for intf in external_interface:
+ card_port0 = intf["virtual-interface"]["vpci"]
+ card0, port0 = card_port0.split(':')[:2]
+ card.append(card0)
+ port.append(port0)
+
+ cfg = {
+ 'machine': tg_cfg["mgmt-interface"]["ip"],
+ 'port': tg_cfg["mgmt-interface"]["tg-config"]["tcl_port"],
+ 'chassis': tg_cfg["mgmt-interface"]["tg-config"]["ixchassis"],
+ 'cards': card,
+ 'ports': port,
+ 'output_dir': tg_cfg["mgmt-interface"]["tg-config"]["dut_result_dir"],
+ 'version': tg_cfg["mgmt-interface"]["tg-config"]["version"],
+ 'bidir': True,
+ }
+
+ return cfg
+
+ def __init__(self): # pragma: no cover
+ self._ixnet = None
+ self._cfg = None
+ self._params = None
+ self._bidir = None
+
+ @property
+ def ixnet(self): # pragma: no cover
+ if self._ixnet:
+ return self._ixnet
+ raise exceptions.IxNetworkClientNotConnected()
+
+ def _get_config_element_by_flow_group_name(self, flow_group_name):
+ """Get a config element using the flow group name
+
+ Each named flow group contains one config element (by configuration).
+ According to the documentation, "configElements" is a list and "each
+ item in this list is aligned to the sequential order of your endpoint
+ list".
+
+ :param flow_group_name: (str) flow group name; this parameter is
+ always a number (converted to string) starting
+ from "1".
+ :return: (str) config element reference ID or None.
+ """
+ traffic_item = self.ixnet.getList(self.ixnet.getRoot() + '/traffic',
+ 'trafficItem')[0]
+ flow_groups = self.ixnet.getList(traffic_item, 'endpointSet')
+ for flow_group in flow_groups:
+ if (str(self.ixnet.getAttribute(flow_group, '-name')) ==
+ flow_group_name):
+ return traffic_item + '/configElement:' + flow_group_name
+
+ def _get_stack_item(self, flow_group_name, protocol_name):
+ """Return the stack item given the flow group name and the proto name
+
+ :param flow_group_name: (str) flow group name
+ :param protocol_name: (str) protocol name, referred to PROTO_*
+ constants
+ :return: list of stack item descriptors
+ """
+ celement = self._get_config_element_by_flow_group_name(flow_group_name)
+ if not celement:
+ raise exceptions.IxNetworkFlowNotPresent(
+ flow_group=flow_group_name)
+ stack_items = self.ixnet.getList(celement, 'stack')
+ return [s_i for s_i in stack_items if protocol_name in s_i]
+
+ def _get_field_in_stack_item(self, stack_item, field_name):
+ """Return the field in a stack item given the name
+
+ :param stack_item: (str) stack item descriptor
+ :param field_name: (str) field name
+ :return: (str) field descriptor
+ """
+ fields = self.ixnet.getList(stack_item, 'field')
+ for field in (field for field in fields if field_name in field):
+ return field
+ raise exceptions.IxNetworkFieldNotPresentInStackItem(
+ field_name=field_name, stack_item=stack_item)
+
+ def _get_traffic_state(self):
+ """Get traffic state"""
+ return self.ixnet.getAttribute(self.ixnet.getRoot() + 'traffic',
+ '-state')
+
+ def is_traffic_running(self):
+ """Returns true if traffic state == TRAFFIC_STATUS_STARTED"""
+ return self._get_traffic_state() == TRAFFIC_STATUS_STARTED
+
+ def is_traffic_stopped(self):
+ """Returns true if traffic state == TRAFFIC_STATUS_STOPPED"""
+ return self._get_traffic_state() == TRAFFIC_STATUS_STOPPED
+
+ @staticmethod
+ def _parse_framesize(framesize):
+ """Parse "framesize" config param. to return a list of weighted pairs
+
+ :param framesize: dictionary of frame sizes and weights
+ :return: list of paired frame sizes and weights
+ """
+ weighted_range_pairs = []
+ for size, weight in framesize.items():
+ weighted_range_pairs.append(int(size.upper().replace('B', '')))
+ weighted_range_pairs.append(int(weight))
+ return weighted_range_pairs
+
+ def iter_over_get_lists(self, x1, x2, y2, offset=0):
+ for x in self.ixnet.getList(x1, x2):
+ y_list = self.ixnet.getList(x, y2)
+ for i, y in enumerate(y_list, offset):
+ yield x, y, i
+
+ def connect(self, tg_cfg):
+ self._cfg = self.get_config(tg_cfg)
+ self._ixnet = IxNetwork.IxNet()
+
+ machine = self._cfg['machine']
+ port = str(self._cfg['port'])
+ version = str(self._cfg['version'])
+ return self.ixnet.connect(machine, '-port', port,
+ '-version', version)
+
+ def clear_config(self):
+ """Wipe out any possible configuration present in the client"""
+ self.ixnet.execute('newConfig')
+
+ def assign_ports(self):
+ """Create and assign vports for each physical port defined in config
+
+ This configuration is present in the IXIA profile file. E.g.:
+ name: trafficgen_1
+ role: IxNet
+ interfaces:
+ xe0:
+ vpci: "2:15" # Card:port
+ driver: "none"
+ dpdk_port_num: 0
+ local_ip: "152.16.100.20"
+ netmask: "255.255.0.0"
+ local_mac: "00:98:10:64:14:00"
+ xe1:
+ ...
+ """
+ chassis_ip = self._cfg['chassis']
+ ports = [(chassis_ip, card, port) for card, port in
+ zip(self._cfg['cards'], self._cfg['ports'])]
+
+ log.info('Create and assign vports: %s', ports)
+ for port in ports:
+ vport = self.ixnet.add(self.ixnet.getRoot(), 'vport')
+ self.ixnet.commit()
+ self.ixnet.execute('assignPorts', [port], [], [vport], True)
+ self.ixnet.commit()
+ if self.ixnet.getAttribute(vport, '-state') != 'up':
+ log.warning('Port %s is down', vport)
+
+ def _create_traffic_item(self):
+ """Create the traffic item to hold the flow groups
+
+ The traffic item tracking by "Traffic Item" is enabled to retrieve the
+ latency statistics.
+ """
+ log.info('Create the traffic item "RFC2544"')
+ traffic_item = self.ixnet.add(self.ixnet.getRoot() + '/traffic',
+ 'trafficItem')
+ self.ixnet.setMultiAttribute(traffic_item, '-name', 'RFC2544',
+ '-trafficType', 'raw')
+ self.ixnet.commit()
+
+ traffic_item_id = self.ixnet.remapIds(traffic_item)[0]
+ self.ixnet.setAttribute(traffic_item_id + '/tracking',
+ '-trackBy', 'trafficGroupId0')
+ self.ixnet.commit()
+
+ def _create_flow_groups(self):
+ """Create the flow groups between the assigned ports"""
+ traffic_item_id = self.ixnet.getList(self.ixnet.getRoot() + 'traffic',
+ 'trafficItem')[0]
+ log.info('Create the flow groups')
+ vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport')
+ uplink_ports = vports[::2]
+ downlink_ports = vports[1::2]
+ index = 0
+ for up, down in zip(uplink_ports, downlink_ports):
+ log.info('FGs: %s <--> %s', up, down)
+ endpoint_set_1 = self.ixnet.add(traffic_item_id, 'endpointSet')
+ endpoint_set_2 = self.ixnet.add(traffic_item_id, 'endpointSet')
+ self.ixnet.setMultiAttribute(
+ endpoint_set_1, '-name', str(index + 1),
+ '-sources', [up + '/protocols'],
+ '-destinations', [down + '/protocols'])
+ self.ixnet.setMultiAttribute(
+ endpoint_set_2, '-name', str(index + 2),
+ '-sources', [down + '/protocols'],
+ '-destinations', [up + '/protocols'])
+ self.ixnet.commit()
+ index += 2
+
+ def _append_procotol_to_stack(self, protocol_name, previous_element):
+ """Append a new element in the packet definition stack"""
+ protocol = (self.ixnet.getRoot() +
+ '/traffic/protocolTemplate:"{}"'.format(protocol_name))
+ self.ixnet.execute('append', previous_element, protocol)
+
+ def _setup_config_elements(self):
+ """Setup the config elements
+
+ The traffic item is configured to allow individual configurations per
+ config element. The default frame configuration is applied:
+ Ethernet II: added by default
+ IPv4: element to add
+ UDP: element to add
+ Payload: added by default
+ Ethernet II (Trailer): added by default
+ :return:
+ """
+ traffic_item_id = self.ixnet.getList(self.ixnet.getRoot() + 'traffic',
+ 'trafficItem')[0]
+ log.info('Split the frame rate distribution per config element')
+ config_elements = self.ixnet.getList(traffic_item_id, 'configElement')
+ for config_element in config_elements:
+ self.ixnet.setAttribute(config_element + '/frameRateDistribution',
+ '-portDistribution', 'splitRateEvenly')
+ self.ixnet.setAttribute(config_element + '/frameRateDistribution',
+ '-streamDistribution', 'splitRateEvenly')
+ self.ixnet.commit()
+ self._append_procotol_to_stack(
+ PROTO_UDP, config_element + '/stack:"ethernet-1"')
+ self._append_procotol_to_stack(
+ PROTO_IPV4, config_element + '/stack:"ethernet-1"')
+
+ def create_traffic_model(self):
+ """Create a traffic item and the needed flow groups
+
+ Each flow group inside the traffic item (only one is present)
+ represents the traffic between two ports:
+ (uplink) (downlink)
+ FlowGroup1: port1 -> port2
+ FlowGroup2: port1 <- port2
+ FlowGroup3: port3 -> port4
+ FlowGroup4: port3 <- port4
+ """
+ self._create_traffic_item()
+ self._create_flow_groups()
+ self._setup_config_elements()
+
+ def _update_frame_mac(self, ethernet_descriptor, field, mac_address):
+ """Set the MAC address in a config element stack Ethernet field
+
+ :param ethernet_descriptor: (str) ethernet descriptor, e.g.:
+ /traffic/trafficItem:1/configElement:1/stack:"ethernet-1"
+ :param field: (str) field name, e.g.: destinationAddress
+ :param mac_address: (str) MAC address
+ """
+ field_descriptor = self._get_field_in_stack_item(ethernet_descriptor,
+ field)
+ self.ixnet.setMultiAttribute(field_descriptor,
+ '-singleValue', mac_address,
+ '-fieldValue', mac_address,
+ '-valueType', 'singleValue')
+ self.ixnet.commit()
+
+ def update_frame(self, traffic):
+ """Update the L2 frame
+
+ This function updates the L2 frame options:
+ - Traffic type: "continuous", "fixedDuration".
+ - Duration: in case of traffic_type="fixedDuration", amount of seconds
+ to inject traffic.
+ - Rate: in frames per seconds or percentage.
+ - Type of rate: "framesPerSecond" ("bitsPerSecond" and
+ "percentLineRate" no used)
+ - Frame size: custom IMIX [1] definition; a list of packet size in
+ bytes and the weight. E.g.:
+ [64, 10, 128, 15, 512, 5]
+
+ [1] https://en.wikipedia.org/wiki/Internet_Mix
+
+ :param traffic: list of traffic elements; each traffic element contains
+ the injection parameter for each flow group.
+ """
+ for traffic_param in traffic.values():
+ fg_id = str(traffic_param['id'])
+ config_element = self._get_config_element_by_flow_group_name(fg_id)
+ if not config_element:
+ raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id)
+
+ type = traffic_param.get('traffic_type', 'fixedDuration')
+ duration = traffic_param.get('duration', 30)
+ rate = traffic_param['iload']
+ weighted_range_pairs = self._parse_framesize(
+ traffic_param['outer_l2']['framesize'])
+ srcmac = str(traffic_param.get('srcmac', '00:00:00:00:00:01'))
+ dstmac = str(traffic_param.get('dstmac', '00:00:00:00:00:02'))
+ # NOTE(ralonsoh): add QinQ tagging when
+ # traffic_param['outer_l2']['QinQ'] exists.
+ # s_vlan = traffic_param['outer_l2']['QinQ']['S-VLAN']
+ # c_vlan = traffic_param['outer_l2']['QinQ']['C-VLAN']
+
+ self.ixnet.setMultiAttribute(
+ config_element + '/transmissionControl',
+ '-type', type, '-duration', duration)
+ self.ixnet.setMultiAttribute(
+ config_element + '/frameRate',
+ '-rate', rate, '-type', 'framesPerSecond')
+ self.ixnet.setMultiAttribute(
+ config_element + '/frameSize',
+ '-type', 'weightedPairs',
+ '-weightedRangePairs', weighted_range_pairs)
+ self.ixnet.commit()
+
+ self._update_frame_mac(
+ self._get_stack_item(fg_id, PROTO_ETHERNET)[0],
+ 'destinationAddress', dstmac)
+ self._update_frame_mac(
+ self._get_stack_item(fg_id, PROTO_ETHERNET)[0],
+ 'sourceAddress', srcmac)
+
+ def _update_ipv4_address(self, ip_descriptor, field, ip_address, seed,
+ mask, count):
+ """Set the IPv4 address in a config element stack IP field
+
+ :param ip_descriptor: (str) IP descriptor, e.g.:
+ /traffic/trafficItem:1/configElement:1/stack:"ipv4-2"
+ :param field: (str) field name, e.g.: scrIp, dstIp
+ :param ip_address: (str) IP address
+ :param seed: (int) seed length
+ :param mask: (str) IP address mask
+ :param count: (int) number of random IPs to generate
+ """
+ field_descriptor = self._get_field_in_stack_item(ip_descriptor,
+ field)
+ self.ixnet.setMultiAttribute(field_descriptor,
+ '-seed', seed,
+ '-fixedBits', ip_address,
+ '-randomMask', mask,
+ '-valueType', 'random',
+ '-countValue', count)
+ self.ixnet.commit()
+
+ def update_ip_packet(self, traffic):
+ """Update the IP packet
+
+ NOTE: Only IPv4 is currently supported.
+ :param traffic: list of traffic elements; each traffic element contains
+ the injection parameter for each flow group.
+ """
+ # NOTE(ralonsoh): L4 configuration is not set.
+ for traffic_param in traffic.values():
+ fg_id = str(traffic_param['id'])
+ if not self._get_config_element_by_flow_group_name(fg_id):
+ raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id)
+
+ count = traffic_param['outer_l3']['count']
+ srcip4 = str(traffic_param['outer_l3']['srcip4'])
+ dstip4 = str(traffic_param['outer_l3']['dstip4'])
+
+ self._update_ipv4_address(
+ self._get_stack_item(fg_id, PROTO_IPV4)[0],
+ 'srcIp', srcip4, 1, IP_VERSION_4_MASK, count)
+ self._update_ipv4_address(
+ self._get_stack_item(fg_id, PROTO_IPV4)[0],
+ 'dstIp', dstip4, 1, IP_VERSION_4_MASK, count)
+
+ def _build_stats_map(self, view_obj, name_map):
+ return {data_yardstick: self.ixnet.execute(
+ 'getColumnValues', view_obj, data_ixia)
+ for data_yardstick, data_ixia in name_map.items()}
+
+ def get_statistics(self):
+ """Retrieve port and flow statistics
+
+ "Port Statistics" parameters are stored in self.PORT_STATS_NAME_MAP.
+ "Flow Statistics" parameters are stored in self.LATENCY_NAME_MAP.
+
+ :return: dictionary with the statistics; the keys of this dictionary
+ are PORT_STATS_NAME_MAP and LATENCY_NAME_MAP keys.
+ """
+ port_statistics = '::ixNet::OBJ-/statistics/view:"Port Statistics"'
+ flow_statistics = '::ixNet::OBJ-/statistics/view:"Flow Statistics"'
+ stats = self._build_stats_map(port_statistics,
+ self.PORT_STATS_NAME_MAP)
+ stats.update(self._build_stats_map(flow_statistics,
+ self.LATENCY_NAME_MAP))
+ return stats
+
+ def start_traffic(self):
+ """Start the traffic injection in the traffic item
+
+ By configuration, there is only one traffic item. This function returns
+ when the traffic state is TRAFFIC_STATUS_STARTED.
+ """
+ traffic_items = self.ixnet.getList('/traffic', 'trafficItem')
+ if self.is_traffic_running():
+ self.ixnet.execute('stop', '/traffic')
+ # pylint: disable=unnecessary-lambda
+ utils.wait_until_true(lambda: self.is_traffic_stopped())
+
+ self.ixnet.execute('generate', traffic_items)
+ self.ixnet.execute('apply', '/traffic')
+ self.ixnet.execute('start', '/traffic')
+ # pylint: disable=unnecessary-lambda
+ utils.wait_until_true(lambda: self.is_traffic_running())
diff --git a/yardstick/network_services/traffic_profile/base.py b/yardstick/network_services/traffic_profile/base.py
index 162bab2bc..f4b5b178c 100644
--- a/yardstick/network_services/traffic_profile/base.py
+++ b/yardstick/network_services/traffic_profile/base.py
@@ -16,6 +16,31 @@ from yardstick.common import exceptions
from yardstick.common import utils
+class TrafficProfileConfig(object):
+ """Class to contain the TrafficProfile class information
+
+ This object will parse and validate the traffic profile information.
+ """
+
+ DEFAULT_SCHEMA = 'nsb:traffic_profile:0.1'
+ DEFAULT_FRAME_RATE = 100
+ DEFAULT_DURATION = 30
+
+ def __init__(self, tp_config):
+ self.schema = tp_config.get('schema', self.DEFAULT_SCHEMA)
+ self.name = tp_config.get('name')
+ self.description = tp_config.get('description')
+ tprofile = tp_config['traffic_profile']
+ self.traffic_type = tprofile.get('traffic_type')
+ self.frame_rate = tprofile.get('frame_rate', self.DEFAULT_FRAME_RATE)
+ self.test_precision = tprofile.get('test_precision')
+ self.packet_sizes = tprofile.get('packet_sizes')
+ self.duration = tprofile.get('duration', self.DEFAULT_DURATION)
+ self.lower_bound = tprofile.get('lower_bound')
+ self.upper_bound = tprofile.get('upper_bound')
+ self.step_interval = tprofile.get('step_interval')
+
+
class TrafficProfile(object):
"""
This class defines the behavior
@@ -43,8 +68,9 @@ class TrafficProfile(object):
# e.g. RFC2544 start_ip, stop_ip, drop_rate,
# IMIX = {"10K": 0.1, "100M": 0.5}
self.params = tp_config
+ self.config = TrafficProfileConfig(tp_config)
- def execute_traffic(self, traffic_generator):
+ def execute_traffic(self, traffic_generator, **kawrgs):
""" This methods defines the behavior of the traffic generator.
It will be called in a loop until the traffic generator exits.
diff --git a/yardstick/network_services/traffic_profile/http_ixload.py b/yardstick/network_services/traffic_profile/http_ixload.py
index 348056551..6cbdb8ab2 100644
--- a/yardstick/network_services/traffic_profile/http_ixload.py
+++ b/yardstick/network_services/traffic_profile/http_ixload.py
@@ -12,9 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import absolute_import
-from __future__ import print_function
-
import sys
import os
import logging
@@ -27,22 +24,14 @@ try:
except ImportError:
import json as jsonutils
-
-class ErrorClass(object):
-
- def __init__(self, *args, **kwargs):
- if 'test' not in kwargs:
- raise RuntimeError
-
- def __getattr__(self, item):
- raise AttributeError
-
+from yardstick.common import exceptions
try:
from IxLoad import IxLoad, StatCollectorUtils
except ImportError:
- IxLoad = ErrorClass
- StatCollectorUtils = ErrorClass
+ IxLoad = exceptions.ErrorClass
+ StatCollectorUtils = exceptions.ErrorClass
+
LOG = logging.getLogger(__name__)
CSV_FILEPATH_NAME = 'IxL_statResults.csv'
@@ -93,7 +82,7 @@ def validate_non_string_sequence(value, default=None, raise_exc=None):
if isinstance(value, collections.Sequence) and not isinstance(value, str):
return value
if raise_exc:
- raise raise_exc
+ raise raise_exc # pylint: disable=raising-bad-type
return default
@@ -218,7 +207,7 @@ class IXLOADHttpTest(object):
# ---- Remap ports ----
try:
self.reassign_ports(test, repository, self.ports_to_reassign)
- except Exception:
+ except Exception: # pylint: disable=broad-except
LOG.exception("Exception occurred during reassign_ports")
# -----------------------------------------------------------------------
diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py
index 7f047226b..e105c2f55 100644
--- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py
+++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import absolute_import
import logging
from yardstick.network_services.traffic_profile.trex_traffic_profile import \
@@ -82,13 +81,10 @@ class IXIARFC2544Profile(TrexProfile):
def _ixia_traffic_generate(self, traffic, ixia_obj):
for key, value in traffic.items():
if key.startswith((self.UPLINK, self.DOWNLINK)):
- value["iload"] = str(self.rate)
- ixia_obj.ix_update_frame(traffic)
- ixia_obj.ix_update_ether(traffic)
- ixia_obj.add_ip_header(traffic, 4)
- ixia_obj.ix_start_traffic()
- self.tmp_drop = 0
- self.tmp_throughput = 0
+ value['iload'] = str(self.rate)
+ ixia_obj.update_frame(traffic)
+ ixia_obj.update_ip_packet(traffic)
+ ixia_obj.start_traffic()
def update_traffic_profile(self, traffic_generator):
def port_generator():
@@ -99,85 +95,65 @@ class IXIARFC2544Profile(TrexProfile):
if not profile_data:
continue
self.profile_data = profile_data
- self.get_streams(self.profile_data)
self.full_profile.update({vld_id: self.profile_data})
for intf in intfs:
yield traffic_generator.vnfd_helper.port_num(intf)
self.ports = [port for port in port_generator()]
- def execute_traffic(self, traffic_generator, ixia_obj, mac=None):
- if mac is None:
- mac = {}
+ def execute_traffic(self, traffic_generator, ixia_obj=None, mac=None):
+ mac = {} if mac is None else mac
+ first_run = self.first_run
if self.first_run:
+ self.first_run = False
self.full_profile = {}
self.pg_id = 0
self.update_traffic_profile(traffic_generator)
- traffic = \
- self._get_ixia_traffic_profile(self.full_profile, mac)
self.max_rate = self.rate
self.min_rate = 0
- self.get_multiplier()
- self._ixia_traffic_generate(traffic, ixia_obj)
-
- def get_multiplier(self):
- self.rate = round((self.max_rate + self.min_rate) / 2.0, 2)
- multiplier = round(self.rate / self.pps, 2)
- return str(multiplier)
+ else:
+ self.rate = round(float(self.max_rate + self.min_rate) / 2.0, 2)
- def start_ixia_latency(self, traffic_generator, ixia_obj, mac=None):
- if mac is None:
- mac = {}
- self.update_traffic_profile(traffic_generator)
- traffic = \
- self._get_ixia_traffic_profile(self.full_profile, mac)
+ traffic = self._get_ixia_traffic_profile(self.full_profile, mac)
self._ixia_traffic_generate(traffic, ixia_obj)
+ return first_run
- def get_drop_percentage(self, samples, tol_min, tolerance, ixia_obj,
- mac=None):
- if mac is None:
- mac = {}
- status = 'Running'
+ def get_drop_percentage(self, samples, tol_min, tolerance, duration=30.0,
+ first_run=False):
+ completed = False
drop_percent = 100
- in_packets = sum([samples[iface]['in_packets'] for iface in samples])
- out_packets = sum([samples[iface]['out_packets'] for iface in samples])
- rx_throughput = \
- sum([samples[iface]['RxThroughput'] for iface in samples])
- tx_throughput = \
- sum([samples[iface]['TxThroughput'] for iface in samples])
- packet_drop = abs(out_packets - in_packets)
+ num_ifaces = len(samples)
+ in_packets_sum = sum(
+ [samples[iface]['in_packets'] for iface in samples])
+ out_packets_sum = sum(
+ [samples[iface]['out_packets'] for iface in samples])
+ rx_throughput = sum(
+ [samples[iface]['RxThroughput'] for iface in samples])
+ rx_throughput = round(float(rx_throughput), 2)
+ tx_throughput = sum(
+ [samples[iface]['TxThroughput'] for iface in samples])
+ tx_throughput = round(float(tx_throughput), 2)
+ packet_drop = abs(out_packets_sum - in_packets_sum)
+
try:
- drop_percent = round((packet_drop / float(out_packets)) * 100, 2)
+ drop_percent = round(
+ (packet_drop / float(out_packets_sum)) * 100, 2)
except ZeroDivisionError:
LOG.info('No traffic is flowing')
- samples['TxThroughput'] = round(tx_throughput / 1.0, 2)
- samples['RxThroughput'] = round(rx_throughput / 1.0, 2)
- samples['CurrentDropPercentage'] = drop_percent
- samples['Throughput'] = self.tmp_throughput
- samples['DropPercentage'] = self.tmp_drop
- if drop_percent > tolerance and self.tmp_throughput == 0:
- samples['Throughput'] = round(rx_throughput / 1.0, 2)
- samples['DropPercentage'] = drop_percent
- if self.first_run:
- max_supported_rate = out_packets / 30.0
- self.rate = max_supported_rate
- self.first_run = False
- if drop_percent <= tolerance:
- status = 'Completed'
+
+ samples['TxThroughput'] = tx_throughput
+ samples['RxThroughput'] = rx_throughput
+ samples['DropPercentage'] = drop_percent
+
+ if first_run:
+ self.rate = out_packets_sum / duration / num_ifaces
+ completed = True if drop_percent <= tolerance else False
+
if drop_percent > tolerance:
self.max_rate = self.rate
elif drop_percent < tol_min:
self.min_rate = self.rate
- if drop_percent >= self.tmp_drop:
- self.tmp_drop = drop_percent
- self.tmp_throughput = round((rx_throughput / 1.0), 2)
- samples['Throughput'] = round(rx_throughput / 1.0, 2)
- samples['DropPercentage'] = drop_percent
else:
- samples['Throughput'] = round(rx_throughput / 1.0, 2)
- samples['DropPercentage'] = drop_percent
- return status, samples
- self.get_multiplier()
- traffic = self._get_ixia_traffic_profile(self.full_profile, mac)
- self._ixia_traffic_generate(traffic, ixia_obj)
- return status, samples
+ completed = True
+
+ return completed, samples
diff --git a/yardstick/network_services/traffic_profile/rfc2544.py b/yardstick/network_services/traffic_profile/rfc2544.py
index 83020c85c..c24e2f65a 100644
--- a/yardstick/network_services/traffic_profile/rfc2544.py
+++ b/yardstick/network_services/traffic_profile/rfc2544.py
@@ -11,190 +11,288 @@
# 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.
-""" RFC2544 Throughput implemenation """
-from __future__ import absolute_import
-from __future__ import division
import logging
-from trex_stl_lib.trex_stl_client import STLStream
-from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats
-from trex_stl_lib.trex_stl_streams import STLTXCont
+from trex_stl_lib import api as Pkt
+from trex_stl_lib import trex_stl_client
+from trex_stl_lib import trex_stl_packet_builder_scapy
+from trex_stl_lib import trex_stl_streams
+
+from yardstick.network_services.traffic_profile import trex_traffic_profile
-from yardstick.network_services.traffic_profile.trex_traffic_profile \
- import TrexProfile
LOGGING = logging.getLogger(__name__)
+SRC_PORT = 'sport'
+DST_PORT = 'dport'
+
+
+class PortPgIDMap(object):
+ """Port and pg_id mapping class
+
+ "pg_id" is the identification STL library gives to each stream. In the
+ RFC2544Profile class, the traffic has a STLProfile per port, which contains
+ one or several streams, one per packet size defined in the IMIX test case
+ description.
+
+ Example of port <-> pg_id map:
+ self._port_pg_id_map = {
+ 0: [1, 2, 3, 4],
+ 1: [5, 6, 7, 8]
+ }
+ """
+
+ def __init__(self):
+ self._pg_id = 0
+ self._last_port = None
+ self._port_pg_id_map = {}
+
+ def add_port(self, port):
+ self._last_port = port
+ self._port_pg_id_map[port] = []
+
+ def get_pg_ids(self, port):
+ return self._port_pg_id_map.get(port)
+
+ def increase_pg_id(self, port=None):
+ port = self._last_port if not port else port
+ if port is None:
+ return
+ pg_id_list = self._port_pg_id_map.get(port)
+ if not pg_id_list:
+ self.add_port(port)
+ pg_id_list = self._port_pg_id_map[port]
+ self._pg_id += 1
+ pg_id_list.append(self._pg_id)
+ return self._pg_id
-class RFC2544Profile(TrexProfile):
- """ This class handles rfc2544 implemenation. """
+class RFC2544Profile(trex_traffic_profile.TrexProfile):
+ """TRex RFC2544 traffic profile"""
+
+ TOLERANCE_LIMIT = 0.05
def __init__(self, traffic_generator):
super(RFC2544Profile, self).__init__(traffic_generator)
self.generator = None
- self.max_rate = None
- self.min_rate = None
- self.ports = None
- self.rate = 100
- self.drop_percent_at_max_tx = None
- self.throughput_max = None
+ self.rate = self.config.frame_rate
+ self.max_rate = self.config.frame_rate
+ self.min_rate = 0
+ self.drop_percent_max = 0
def register_generator(self, generator):
self.generator = generator
- def execute_traffic(self, traffic_generator=None):
- """ Generate the stream and run traffic on the given ports """
+ def stop_traffic(self, traffic_generator=None):
+ """"Stop traffic injection, reset counters and remove streams"""
if traffic_generator is not None and self.generator is None:
self.generator = traffic_generator
- if self.ports is not None:
- return
+ self.generator.client.stop()
+ self.generator.client.reset()
+ self.generator.client.remove_all_streams()
+
+ def execute_traffic(self, traffic_generator=None):
+ """Generate the stream and run traffic on the given ports
+
+ :param traffic_generator: (TrexTrafficGenRFC) traffic generator
+ :return ports: (list of int) indexes of ports
+ port_pg_id: (dict) port indexes and pg_id [1] map
+ [1] https://trex-tgn.cisco.com/trex/doc/cp_stl_docs/api/
+ profile_code.html#stlstream-modes
+ """
+ if traffic_generator is not None and self.generator is None:
+ self.generator = traffic_generator
- self.ports = []
+ port_pg_id = PortPgIDMap()
+ ports = []
for vld_id, intfs in sorted(self.generator.networks.items()):
profile_data = self.params.get(vld_id)
- # no profile for this port
if not profile_data:
continue
- # correlated traffic doesn't use public traffic?
- if vld_id.startswith(self.DOWNLINK) and \
- self.generator.rfc2544_helper.correlated_traffic:
+ if (vld_id.startswith(self.DOWNLINK) and
+ self.generator.rfc2544_helper.correlated_traffic):
continue
for intf in intfs:
- port = self.generator.port_num(intf)
- self.ports.append(port)
- self.generator.client.add_streams(self.get_streams(profile_data), ports=port)
-
- self.max_rate = self.rate
- self.min_rate = 0
- self.generator.client.start(ports=self.ports, mult=self.get_multiplier(),
- duration=30, force=True)
- self.drop_percent_at_max_tx = 0
- self.throughput_max = 0
-
- def get_multiplier(self):
- """ Get the rate at which next iteration to run """
- self.rate = round((self.max_rate + self.min_rate) / 2.0, 2)
- multiplier = round(self.rate / self.pps, 2)
- return str(multiplier)
-
- def get_drop_percentage(self, generator=None):
- """ Calculate the drop percentage and run the traffic """
- if generator is None:
- generator = self.generator
- run_duration = self.generator.RUN_DURATION
- samples = self.generator.generate_samples(self.ports)
-
- in_packets = sum([value['in_packets'] for value in samples.values()])
- out_packets = sum([value['out_packets'] for value in samples.values()])
-
- packet_drop = abs(out_packets - in_packets)
- drop_percent = 100.0
- try:
- drop_percent = round((packet_drop / float(out_packets)) * 100, 5)
- except ZeroDivisionError:
- LOGGING.info('No traffic is flowing')
+ port_num = int(self.generator.port_num(intf))
+ ports.append(port_num)
+ port_pg_id.add_port(port_num)
+ profile = self._create_profile(profile_data,
+ self.rate, port_pg_id)
+ self.generator.client.add_streams(profile, ports=[port_num])
+
+ self.generator.client.start(ports=ports,
+ duration=self.config.duration,
+ force=True)
+ return ports, port_pg_id
+
+ def _create_profile(self, profile_data, rate, port_pg_id):
+ """Create a STL profile (list of streams) for a port"""
+ streams = []
+ for packet_name in profile_data:
+ imix = (profile_data[packet_name].
+ get('outer_l2', {}).get('framesize'))
+ imix_data = self._create_imix_data(imix)
+ self._create_vm(profile_data[packet_name])
+ _streams = self._create_streams(imix_data, rate, port_pg_id)
+ streams.extend(_streams)
+ return trex_stl_streams.STLProfile(streams)
+
+ def _create_imix_data(self, imix):
+ """Generate the IMIX distribution for a STL profile
+
+ The input information is the framesize dictionary in a test case
+ traffic profile definition. E.g.:
+ downlink_0:
+ ipv4:
+ id: 2
+ outer_l2:
+ framesize:
+ 64B: 10
+ 128B: 20
+ ...
+
+ This function normalizes the sum of framesize weights to 100 and
+ returns a dictionary of frame sizes in bytes and weight in percentage.
+ E.g.:
+ imix_count = {64: 25, 128: 75}
+
+ :param imix: (dict) IMIX size and weight
+ """
+ imix_count = {}
+ if not imix:
+ return imix_count
+
+ imix_count = {size.upper().replace('B', ''): int(weight)
+ for size, weight in imix.items()}
+ imix_sum = sum(imix_count.values())
+ if imix_sum <= 0:
+ imix_count = {64: 100}
+ imix_sum = 100
+
+ weight_normalize = float(imix_sum) / 100
+ return {size: float(weight) / weight_normalize
+ for size, weight in imix_count.items()}
+
+ def _create_vm(self, packet_definition):
+ """Create the STL Raw instructions"""
+ self.ether_packet = Pkt.Ether()
+ self.ip_packet = Pkt.IP()
+ self.ip6_packet = None
+ self.udp_packet = Pkt.UDP()
+ self.udp[DST_PORT] = 'UDP.dport'
+ self.udp[SRC_PORT] = 'UDP.sport'
+ self.qinq = False
+ self.vm_flow_vars = []
+ outer_l2 = packet_definition.get('outer_l2')
+ outer_l3v4 = packet_definition.get('outer_l3v4')
+ outer_l3v6 = packet_definition.get('outer_l3v6')
+ outer_l4 = packet_definition.get('outer_l4')
+ if outer_l2:
+ self._set_outer_l2_fields(outer_l2)
+ if outer_l3v4:
+ self._set_outer_l3v4_fields(outer_l3v4)
+ if outer_l3v6:
+ self._set_outer_l3v6_fields(outer_l3v6)
+ if outer_l4:
+ self._set_outer_l4_fields(outer_l4)
+ self.trex_vm = trex_stl_packet_builder_scapy.STLScVmRaw(
+ self.vm_flow_vars)
+
+ def _create_single_packet(self, size=64):
+ size -= 4
+ ether_packet = self.ether_packet
+ ip_packet = self.ip6_packet if self.ip6_packet else self.ip_packet
+ udp_packet = self.udp_packet
+ if self.qinq:
+ qinq_packet = self.qinq_packet
+ base_pkt = ether_packet / qinq_packet / ip_packet / udp_packet
+ else:
+ base_pkt = ether_packet / ip_packet / udp_packet
+ pad = max(0, size - len(base_pkt)) * 'x'
+ return trex_stl_packet_builder_scapy.STLPktBuilder(
+ pkt=base_pkt / pad, vm=self.trex_vm)
+
+ def _create_streams(self, imix_data, rate, port_pg_id):
+ """Create a list of streams per packet size
+
+ The STL TX mode speed of the generated streams will depend on the frame
+ weight and the frame rate. Both the frame weight and the total frame
+ rate are normalized to 100. The STL TX mode speed, defined in
+ percentage, is the combitation of both percentages. E.g.:
+ frame weight = 100
+ rate = 90
+ --> STLTXmode percentage = 10 (%)
+
+ frame weight = 80
+ rate = 50
+ --> STLTXmode percentage = 40 (%)
+
+ :param imix_data: (dict) IMIX size and weight
+ :param rate: (float) normalized [0..100] total weight
+ :param pg_id: (PortPgIDMap) port / pg_id (list) map
+ """
+ streams = []
+ for size, weight in ((int(size), float(weight)) for (size, weight)
+ in imix_data.items() if float(weight) > 0):
+ packet = self._create_single_packet(size)
+ pg_id = port_pg_id.increase_pg_id()
+ stl_flow = trex_stl_streams.STLFlowLatencyStats(pg_id=pg_id)
+ mode = trex_stl_streams.STLTXCont(percentage=weight * rate / 100)
+ streams.append(trex_stl_client.STLStream(
+ packet=packet, flow_stats=stl_flow, mode=mode))
+ return streams
+
+ def get_drop_percentage(self, samples, tol_low, tol_high,
+ correlated_traffic):
+ """Calculate the drop percentage and run the traffic"""
+ tx_rate_fps = 0
+ rx_rate_fps = 0
+ for sample in samples:
+ tx_rate_fps += sum(
+ port['tx_throughput_fps'] for port in sample.values())
+ rx_rate_fps += sum(
+ port['rx_throughput_fps'] for port in sample.values())
+ tx_rate_fps = round(float(tx_rate_fps) / len(samples), 2)
+ rx_rate_fps = round(float(rx_rate_fps) / len(samples), 2)
# TODO(esm): RFC2544 doesn't tolerate packet loss, why do we?
- tolerance_low = generator.rfc2544_helper.tolerance_low
- tolerance_high = generator.rfc2544_helper.tolerance_high
-
- tx_rate = out_packets / run_duration
- rx_rate = in_packets / run_duration
-
- throughput_max = self.throughput_max
- drop_percent_at_max_tx = self.drop_percent_at_max_tx
+ out_packets = sum(port['out_packets'] for port in samples[-1].values())
+ in_packets = sum(port['in_packets'] for port in samples[-1].values())
+ drop_percent = 100.0
- if self.drop_percent_at_max_tx is None:
- self.rate = tx_rate
- self.first_run = False
+ # https://tools.ietf.org/html/rfc2544#section-26.3
+ if out_packets:
+ drop_percent = round(
+ (float(abs(out_packets - in_packets)) / out_packets) * 100, 5)
- if drop_percent > tolerance_high:
- # TODO(esm): why don't we discard results that are out of tolerance?
+ tol_high = tol_high if tol_high > self.TOLERANCE_LIMIT else tol_high
+ tol_low = tol_low if tol_low > self.TOLERANCE_LIMIT else tol_low
+ if drop_percent > tol_high:
self.max_rate = self.rate
- if throughput_max == 0:
- throughput_max = rx_rate
- drop_percent_at_max_tx = drop_percent
-
- elif drop_percent >= tolerance_low:
- # TODO(esm): why do we update the samples dict in this case
- # and not update our tracking values?
- throughput_max = rx_rate
- drop_percent_at_max_tx = drop_percent
-
- elif drop_percent >= self.drop_percent_at_max_tx:
- # TODO(esm): why don't we discard results that are out of tolerance?
+ elif drop_percent < tol_low:
self.min_rate = self.rate
- self.drop_percent_at_max_tx = drop_percent_at_max_tx = drop_percent
- self.throughput_max = throughput_max = rx_rate
+ # else:
+ # NOTE(ralonsoh): the test should finish here
+ # pass
+ last_rate = self.rate
+ self.rate = round(float(self.max_rate + self.min_rate) / 2.0, 5)
- else:
- # TODO(esm): why don't we discard results that are out of tolerance?
- self.min_rate = self.rate
+ throughput = rx_rate_fps * 2 if correlated_traffic else rx_rate_fps
- generator.clear_client_stats(self.ports)
- generator.start_client(self.ports, mult=self.get_multiplier(),
- duration=run_duration, force=True)
+ if drop_percent > self.drop_percent_max:
+ self.drop_percent_max = drop_percent
- # if correlated traffic update the Throughput
- if generator.rfc2544_helper.correlated_traffic:
- throughput_max *= 2
+ latency = {port_num: value['latency']
+ for port_num, value in samples[-1].items()}
- samples.update({
- 'TxThroughput': tx_rate,
- 'RxThroughput': rx_rate,
+ output = {
+ 'TxThroughput': tx_rate_fps,
+ 'RxThroughput': rx_rate_fps,
'CurrentDropPercentage': drop_percent,
- 'Throughput': throughput_max,
- 'DropPercentage': drop_percent_at_max_tx,
- })
-
- return samples
-
- def execute_latency(self, generator=None, samples=None):
- if generator is not None and self.generator is None:
- self.generator = generator
-
- if samples is None:
- samples = self.generator.generate_samples()
-
- self.pps, multiplier = self.calculate_pps(samples)
- self.ports = []
- self.pg_id = self.params['traffic_profile'].get('pg_id', 1)
- for vld_id, intfs in sorted(self.generator.networks.items()):
- profile_data = self.params.get(vld_id)
- if not profile_data:
- continue
- # correlated traffic doesn't use public traffic?
- if vld_id.startswith(self.DOWNLINK) and \
- self.generator.rfc2544_helper.correlated_traffic:
- continue
- for intf in intfs:
- port = self.generator.port_num(intf)
- self.ports.append(port)
- self.generator.client.add_streams(self.get_streams(profile_data), ports=port)
-
- self.generator.start_client(ports=self.ports, mult=str(multiplier),
- duration=120, force=True)
- self.first_run = False
-
- def calculate_pps(self, samples):
- pps = round(samples['Throughput'] / 2, 2)
- multiplier = round(self.rate / self.pps, 2)
- return pps, multiplier
-
- def create_single_stream(self, packet_size, pps, isg=0):
- packet = self._create_single_packet(packet_size)
- if pps:
- stl_mode = STLTXCont(pps=pps)
- else:
- stl_mode = STLTXCont(pps=self.pps)
- if self.pg_id:
- LOGGING.debug("pg_id: %s", self.pg_id)
- stl_flow_stats = STLFlowLatencyStats(pg_id=self.pg_id)
- stream = STLStream(isg=isg, packet=packet, mode=stl_mode,
- flow_stats=stl_flow_stats)
- self.pg_id += 1
- else:
- stream = STLStream(isg=isg, packet=packet, mode=stl_mode)
- return stream
+ 'Throughput': throughput,
+ 'DropPercentage': self.drop_percent_max,
+ 'Rate': last_rate,
+ 'Latency': latency
+ }
+ return output
diff --git a/yardstick/network_services/traffic_profile/trex_traffic_profile.py b/yardstick/network_services/traffic_profile/trex_traffic_profile.py
index f5e3923d5..ed0355fa5 100644
--- a/yardstick/network_services/traffic_profile/trex_traffic_profile.py
+++ b/yardstick/network_services/traffic_profile/trex_traffic_profile.py
@@ -19,21 +19,16 @@ from random import SystemRandom
import ipaddress
import six
-
-from yardstick.common import exceptions as y_exc
-from yardstick.network_services.traffic_profile import base
-from trex_stl_lib.trex_stl_client import STLStream
-from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats
-from trex_stl_lib.trex_stl_streams import STLTXCont
-from trex_stl_lib.trex_stl_streams import STLProfile
from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmWrFlowVar
from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFlowVarRepeatableRandom
from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFlowVar
-from trex_stl_lib.trex_stl_packet_builder_scapy import STLPktBuilder
-from trex_stl_lib.trex_stl_packet_builder_scapy import STLScVmRaw
from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFixIpv4
from trex_stl_lib import api as Pkt
+from yardstick.common import exceptions as y_exc
+from yardstick.network_services.traffic_profile import base
+
+
SRC = 'src'
DST = 'dst'
ETHERNET = 'Ethernet'
@@ -342,115 +337,6 @@ class TrexProfile(base.TrafficProfile):
if 'dstport' in outer_l4:
self._set_proto_addr(UDP, DST_PORT, outer_l4['dstport'], outer_l4['count'])
- def generate_imix_data(self, packet_definition):
- """ generate packet size for a given traffic profile """
- imix_count = {}
- imix_data = {}
- if not packet_definition:
- return imix_count
- imix = packet_definition.get('framesize')
- if imix:
- for size in imix:
- data = imix[size]
- imix_data[int(size[:-1])] = int(data)
- imix_sum = sum(imix_data.values())
- if imix_sum > 100:
- raise SystemExit("Error in IMIX data")
- elif imix_sum < 100:
- imix_data[64] = imix_data.get(64, 0) + (100 - imix_sum)
-
- avg_size = 0.0
- for size in imix_data:
- count = int(imix_data[size])
- if count:
- avg_size += round(size * count / 100, 2)
- pps = round(self.pps * count / 100, 0)
- imix_count[size] = pps
- self.rate = round(1342177280 / avg_size, 0) * 2
- logging.debug("Imax: %s rate: %s", imix_count, self.rate)
- return imix_count
-
- def get_streams(self, profile_data):
- """ generate trex stream
- :param profile_data:
- :type profile_data:
- """
- self.streams = []
- self.pps = self.params['traffic_profile'].get('frame_rate', 100)
- for packet_name in profile_data:
- outer_l2 = profile_data[packet_name].get('outer_l2')
- imix_data = self.generate_imix_data(outer_l2)
- if not imix_data:
- imix_data = {64: self.pps}
- self.generate_vm(profile_data[packet_name])
- for size in imix_data:
- self._generate_streams(size, imix_data[size])
- self._generate_profile()
- return self.profile
-
- def generate_vm(self, packet_definition):
- """ generate trex vm with flows setup """
- self.ether_packet = Pkt.Ether()
- self.ip_packet = Pkt.IP()
- self.ip6_packet = None
- self.udp_packet = Pkt.UDP()
- self.udp[DST_PORT] = 'UDP.dport'
- self.udp[SRC_PORT] = 'UDP.sport'
- self.qinq = False
- self.vm_flow_vars = []
- outer_l2 = packet_definition.get('outer_l2', None)
- outer_l3v4 = packet_definition.get('outer_l3v4', None)
- outer_l3v6 = packet_definition.get('outer_l3v6', None)
- outer_l4 = packet_definition.get('outer_l4', None)
- if outer_l2:
- self._set_outer_l2_fields(outer_l2)
- if outer_l3v4:
- self._set_outer_l3v4_fields(outer_l3v4)
- if outer_l3v6:
- self._set_outer_l3v6_fields(outer_l3v6)
- if outer_l4:
- self._set_outer_l4_fields(outer_l4)
- self.trex_vm = STLScVmRaw(self.vm_flow_vars)
-
- def generate_packets(self):
- """ generate packets from trex TG """
- base_pkt = self.base_pkt
- size = self.fsize - 4
- pad = max(0, size - len(base_pkt)) * 'x'
- self.packets = [STLPktBuilder(pkt=base_pkt / pad,
- vm=vm) for vm in self.vms]
-
- def _create_single_packet(self, size=64):
- size = size - 4
- ether_packet = self.ether_packet
- ip_packet = self.ip6_packet if self.ip6_packet else self.ip_packet
- udp_packet = self.udp_packet
- if self.qinq:
- qinq_packet = self.qinq_packet
- base_pkt = ether_packet / qinq_packet / ip_packet / udp_packet
- else:
- base_pkt = ether_packet / ip_packet / udp_packet
- pad = max(0, size - len(base_pkt)) * 'x'
- packet = STLPktBuilder(pkt=base_pkt / pad, vm=self.trex_vm)
- return packet
-
- def _create_single_stream(self, packet_size, pps, isg=0):
- packet = self._create_single_packet(packet_size)
- if self.pg_id:
- self.pg_id += 1
- stl_flow = STLFlowLatencyStats(pg_id=self.pg_id)
- stream = STLStream(isg=isg, packet=packet, mode=STLTXCont(pps=pps),
- flow_stats=stl_flow)
- else:
- stream = STLStream(isg=isg, packet=packet, mode=STLTXCont(pps=pps))
- return stream
-
- def _generate_streams(self, packet_size, pps):
- self.streams.append(self._create_single_stream(packet_size, pps))
-
- def _generate_profile(self):
- self.profile = STLProfile(self.streams)
-
@classmethod
def _count_ip(cls, start_ip, end_ip):
start = ipaddress.ip_address(six.u(start_ip))
diff --git a/yardstick/network_services/vnf_generic/vnf/acl_vnf.py b/yardstick/network_services/vnf_generic/vnf/acl_vnf.py
index d9719eb4e..1357f6b26 100644
--- a/yardstick/network_services/vnf_generic/vnf/acl_vnf.py
+++ b/yardstick/network_services/vnf_generic/vnf/acl_vnf.py
@@ -13,10 +13,14 @@
# limitations under the License.
import logging
-
+import ipaddress
+import six
from yardstick.common import utils
+from yardstick.common import exceptions
+
from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, DpdkVnfSetupEnvHelper
-from yardstick.network_services.yang_model import YangModel
+from yardstick.network_services.helpers.samplevnf_helper import PortPairs
+from itertools import chain
LOG = logging.getLogger(__name__)
@@ -38,6 +42,196 @@ class AclApproxSetupEnvSetupEnvHelper(DpdkVnfSetupEnvHelper):
SW_DEFAULT_CORE = 5
DEFAULT_CONFIG_TPL_CFG = "acl.cfg"
VNF_TYPE = "ACL"
+ RULE_CMD = "acl"
+
+ DEFAULT_PRIORITY = 1
+ DEFAULT_PROTOCOL = 0
+ DEFAULT_PROTOCOL_MASK = 0
+ # Default actions to be applied to SampleVNF. Please note,
+ # that this list is extended with `fwd` action when default
+ # actions are generated.
+ DEFAULT_FWD_ACTIONS = ["accept", "count"]
+
+ def __init__(self, vnfd_helper, ssh_helper, scenario_helper):
+ super(AclApproxSetupEnvSetupEnvHelper, self).__init__(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self._action_id = 0
+
+ def get_ip_from_port(self, port):
+ # we can't use gateway because in OpenStack gateways interfere with floating ip routing
+ # return self.make_ip_addr(self.get_ports_gateway(port), self.get_netmask_gateway(port))
+ vintf = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
+ return utils.make_ip_addr(vintf["local_ip"], vintf["netmask"])
+
+ def get_network_and_prefixlen_from_ip_of_port(self, port):
+ ip_addr = self.get_ip_from_port(port)
+ # handle cases with no gateway
+ if ip_addr:
+ return ip_addr.network.network_address.exploded, ip_addr.network.prefixlen
+ else:
+ return None, None
+
+ @property
+ def new_action_id(self):
+ """Get new action id"""
+ self._action_id += 1
+ return self._action_id
+
+ def get_default_flows(self):
+ """Get default actions/rules
+ Returns: (<actions>, <rules>)
+ <actions>:
+ { <action_id>: [ <list of actions> ]}
+ Example:
+ { 0 : [ "accept", "count", {"fwd" : "port": 0} ], ... }
+ <rules>:
+ [ {"src_ip": "x.x.x.x", "src_ip_mask", 24, ...}, ... ]
+ Note:
+ See `generate_rule_cmds()` to get list of possible map keys.
+ """
+ actions, rules = {}, []
+ _port_pairs = PortPairs(self.vnfd_helper.interfaces)
+ port_pair_list = _port_pairs.port_pair_list
+ for src_intf, dst_intf in port_pair_list:
+ # get port numbers of the interfaces
+ src_port = self.vnfd_helper.port_num(src_intf)
+ dst_port = self.vnfd_helper.port_num(dst_intf)
+ # get interface addresses and prefixes
+ src_net, src_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(src_intf)
+ dst_net, dst_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(dst_intf)
+ # ignore entries with empty values
+ if all((src_net, src_prefix_len, dst_net, dst_prefix_len)):
+ # flow: src_net:dst_net -> dst_port
+ action_id = self.new_action_id
+ actions[action_id] = self.DEFAULT_FWD_ACTIONS[:]
+ actions[action_id].append({"fwd": {"port": dst_port}})
+ rules.append({"priority": 1, 'cmd': self.RULE_CMD,
+ "src_ip": src_net, "src_ip_mask": src_prefix_len,
+ "dst_ip": dst_net, "dst_ip_mask": dst_prefix_len,
+ "src_port_from": 0, "src_port_to": 65535,
+ "dst_port_from": 0, "dst_port_to": 65535,
+ "protocol": 0, "protocol_mask": 0,
+ "action_id": action_id})
+ # flow: dst_net:src_net -> src_port
+ action_id = self.new_action_id
+ actions[action_id] = self.DEFAULT_FWD_ACTIONS[:]
+ actions[action_id].append({"fwd": {"port": src_port}})
+ rules.append({"cmd":self.RULE_CMD, "priority": 1,
+ "src_ip": dst_net, "src_ip_mask": dst_prefix_len,
+ "dst_ip": src_net, "dst_ip_mask": src_prefix_len,
+ "src_port_from": 0, "src_port_to": 65535,
+ "dst_port_from": 0, "dst_port_to": 65535,
+ "protocol": 0, "protocol_mask": 0,
+ "action_id": action_id})
+ return actions, rules
+
+ def get_flows(self, options):
+ """Get actions/rules based on provided options.
+ The `options` is a dict representing the ACL rules configuration
+ file. Result is the same as described in `get_default_flows()`.
+ """
+ actions, rules = {}, []
+ for ace in options['access-list-entries']:
+ # Generate list of actions
+ action_id = self.new_action_id
+ actions[action_id] = ace['actions']
+ # Destination nestwork
+ matches = ace['matches']
+ dst_ipv4_net = matches['destination-ipv4-network']
+ dst_ipv4_net_ip = ipaddress.ip_interface(six.text_type(dst_ipv4_net))
+ # Source network
+ src_ipv4_net = matches['source-ipv4-network']
+ src_ipv4_net_ip = ipaddress.ip_interface(six.text_type(src_ipv4_net))
+ # Append the rule
+ rules.append({'action_id': action_id, 'cmd': self.RULE_CMD,
+ 'dst_ip': dst_ipv4_net_ip.network.network_address.exploded,
+ 'dst_ip_mask': dst_ipv4_net_ip.network.prefixlen,
+ 'src_ip': src_ipv4_net_ip.network.network_address.exploded,
+ 'src_ip_mask': src_ipv4_net_ip.network.prefixlen,
+ 'dst_port_from': matches['destination-port-range']['lower-port'],
+ 'dst_port_to': matches['destination-port-range']['upper-port'],
+ 'src_port_from': matches['source-port-range']['lower-port'],
+ 'src_port_to': matches['source-port-range']['upper-port'],
+ 'priority': matches.get('priority', self.DEFAULT_PRIORITY),
+ 'protocol': matches.get('protocol', self.DEFAULT_PROTOCOL),
+ 'protocol_mask': matches.get('protocol_mask',
+ self.DEFAULT_PROTOCOL_MASK)
+ })
+ return actions, rules
+
+ def generate_rule_cmds(self, rules, apply_rules=False):
+ """Convert rules into list of SampleVNF CLI commands"""
+ rule_template = ("p {cmd} add {priority} {src_ip} {src_ip_mask} "
+ "{dst_ip} {dst_ip_mask} {src_port_from} {src_port_to} "
+ "{dst_port_from} {dst_port_to} {protocol} "
+ "{protocol_mask} {action_id}")
+ rule_cmd_list = []
+ for rule in rules:
+ rule_cmd_list.append(rule_template.format(**rule))
+ if apply_rules:
+ # add command to apply all rules at the end
+ rule_cmd_list.append("p {cmd} applyruleset".format(cmd=self.RULE_CMD))
+ return rule_cmd_list
+
+ def generate_action_cmds(self, actions):
+ """Convert actions into list of SampleVNF CLI commands.
+ These method doesn't validate the provided list of actions. Supported
+ list of actions are limited by SampleVNF. Thus, the user should be
+ responsible to specify correct action name(s). Yardstick should take
+ the provided action by user and apply it to SampleVNF.
+ Anyway, some of the actions require addition parameters to be
+ specified. In case of `fwd` & `nat` action used have to specify
+ the port attribute.
+ """
+ _action_template_map = {
+ "fwd": "p action add {action_id} fwd {port}",
+ "nat": "p action add {action_id} nat {port}"
+ }
+ action_cmd_list = []
+ for action_id, actions in actions.items():
+ for action in actions:
+ if isinstance(action, dict):
+ for action_name in action.keys():
+ # user provided an action name with addition options
+ # e.g.: {"fwd": {"port": 0}}
+ # format action CLI command and add it to the list
+ if action_name not in _action_template_map.keys():
+ raise exceptions.AclUknownActionTemplate(
+ action_name=action_name)
+ template = _action_template_map[action_name]
+ try:
+ action_cmd_list.append(template.format(
+ action_id=action_id, **action[action_name]))
+ except KeyError as exp:
+ raise exceptions.AclMissingActionArguments(
+ action_name=action_name,
+ action_param=exp.args[0])
+ else:
+ # user provided an action name w/o addition options
+ # e.g.: "accept", "count"
+ action_cmd_list.append(
+ "p action add {action_id} {action}".format(
+ action_id=action_id, action=action))
+ return action_cmd_list
+
+ def get_flows_config(self, options=None):
+ """Get action/rules configuration commands (string) to be
+ applied to SampleVNF to configure ACL rules (flows).
+ """
+ action_cmd_list, rule_cmd_list = [], []
+ if options:
+ # if file name is set, read actions/rules from the file
+ actions, rules = self.get_flows(options)
+ action_cmd_list = self.generate_action_cmds(actions)
+ rule_cmd_list = self.generate_rule_cmds(rules)
+ # default actions/rules
+ dft_actions, dft_rules = self.get_default_flows()
+ dft_action_cmd_list = self.generate_action_cmds(dft_actions)
+ dft_rule_cmd_list = self.generate_rule_cmds(dft_rules, apply_rules=True)
+ # generate multi-line commands to add actions/rules
+ return '\n'.join(chain(action_cmd_list, dft_action_cmd_list,
+ rule_cmd_list, dft_rule_cmd_list))
class AclApproxVnf(SampleVNF):
@@ -57,12 +251,3 @@ class AclApproxVnf(SampleVNF):
setup_env_helper_type = AclApproxSetupEnvSetupEnvHelper
super(AclApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type)
- self.acl_rules = None
-
- def _start_vnf(self):
- yang_model_path = utils.find_relative_file(
- self.scenario_helper.options['rules'],
- self.scenario_helper.task_path)
- yang_model = YangModel(yang_model_path)
- self.acl_rules = yang_model.get_rules()
- super(AclApproxVnf, self)._start_vnf()
diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py
index ef8b3f126..3976acb76 100644
--- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py
+++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py
@@ -11,20 +11,17 @@
# 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.
-""" Base class implementation for generic vnf implementation """
-from collections import Mapping
import logging
from multiprocessing import Queue, Value, Process
import os
import posixpath
import re
+import six
import subprocess
import time
-import six
-
from trex_stl_lib.trex_stl_client import LoggerApi
from trex_stl_lib.trex_stl_client import STLClient
from trex_stl_lib.trex_stl_exceptions import STLError
@@ -32,6 +29,7 @@ from yardstick.benchmark.contexts.base import Context
from yardstick.common import exceptions as y_exceptions
from yardstick.common.process import check_if_process_failed
from yardstick.common import utils
+from yardstick.common import yaml_loader
from yardstick.network_services import constants
from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper, DpdkNode
from yardstick.network_services.helpers.samplevnf_helper import MultiPortConfig
@@ -144,6 +142,13 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper):
'vnf_type': self.VNF_TYPE,
}
+ # read actions/rules from file
+ acl_options = None
+ acl_file_name = self.scenario_helper.options.get('rules')
+ if acl_file_name:
+ with utils.open_relative_file(acl_file_name, task_path) as infile:
+ acl_options = yaml_loader.yaml_load(infile)
+
config_tpl_cfg = utils.find_relative_file(self.DEFAULT_CONFIG_TPL_CFG,
task_path)
config_basename = posixpath.basename(self.CFG_CONFIG)
@@ -176,12 +181,17 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper):
new_config = self._update_packet_type(new_config, traffic_options)
self.ssh_helper.upload_config_file(config_basename, new_config)
self.ssh_helper.upload_config_file(script_basename,
- multiport.generate_script(self.vnfd_helper))
+ multiport.generate_script(self.vnfd_helper,
+ self.get_flows_config(acl_options)))
LOG.info("Provision and start the %s", self.APP_NAME)
self._build_pipeline_kwargs()
return self.PIPELINE_COMMAND.format(**self.pipeline_kwargs)
+ def get_flows_config(self, options=None): # pylint: disable=unused-argument
+ """No actions/rules (flows) by default"""
+ return None
+
def _build_pipeline_kwargs(self):
tool_path = self.ssh_helper.provision_tool(tool_file=self.APP_NAME)
# count the number of actual ports in the list of pairs
@@ -375,39 +385,14 @@ class ClientResourceHelper(ResourceHelper):
LOG.error('TRex client not connected')
return {}
- def generate_samples(self, ports, key=None, default=None):
- # needs to be used ports
- last_result = self.get_stats(ports)
- key_value = last_result.get(key, default)
-
- if not isinstance(last_result, Mapping): # added for mock unit test
- self._terminated.value = 1
- return {}
-
- samples = {}
- # recalculate port for interface and see if it matches ports provided
- for intf in self.vnfd_helper.interfaces:
- name = intf["name"]
- port = self.vnfd_helper.port_num(name)
- if port in ports:
- xe_value = last_result.get(port, {})
- samples[name] = {
- "rx_throughput_fps": float(xe_value.get("rx_pps", 0.0)),
- "tx_throughput_fps": float(xe_value.get("tx_pps", 0.0)),
- "rx_throughput_mbps": float(xe_value.get("rx_bps", 0.0)),
- "tx_throughput_mbps": float(xe_value.get("tx_bps", 0.0)),
- "in_packets": int(xe_value.get("ipackets", 0)),
- "out_packets": int(xe_value.get("opackets", 0)),
- }
- if key:
- samples[name][key] = key_value
- return samples
+ def _get_samples(self, ports, port_pg_id=False):
+ raise NotImplementedError()
def _run_traffic_once(self, traffic_profile):
traffic_profile.execute_traffic(self)
self.client_started.value = 1
time.sleep(self.RUN_DURATION)
- samples = self.generate_samples(traffic_profile.ports)
+ samples = self._get_samples(traffic_profile.ports)
time.sleep(self.QUEUE_WAIT_TIME)
self._queue.put(samples)
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
index 265d0b7a9..a1f9fbeb4 100644
--- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
+++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
@@ -12,31 +12,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import absolute_import
-
-import time
-import os
import logging
-import sys
from yardstick.common import utils
-from yardstick import error
+from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api
from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen
from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper
from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper
+
LOG = logging.getLogger(__name__)
WAIT_AFTER_CFG_LOAD = 10
WAIT_FOR_TRAFFIC = 30
-IXIA_LIB = os.path.dirname(os.path.realpath(__file__))
-IXNET_LIB = os.path.join(IXIA_LIB, "../../libs/ixia_libs/IxNet")
-sys.path.append(IXNET_LIB)
-
-try:
- from IxNet import IxNextgen
-except ImportError:
- IxNextgen = error.ErrorClass
class IxiaRfc2544Helper(Rfc2544ResourceHelper):
@@ -53,7 +41,7 @@ class IxiaResourceHelper(ClientResourceHelper):
super(IxiaResourceHelper, self).__init__(setup_helper)
self.scenario_helper = setup_helper.scenario_helper
- self.client = IxNextgen()
+ self.client = ixnet_api.IxNextgen()
if rfc_helper_type is None:
rfc_helper_type = IxiaRfc2544Helper
@@ -64,20 +52,16 @@ class IxiaResourceHelper(ClientResourceHelper):
self._connect()
def _connect(self, client=None):
- self.client._connect(self.vnfd_helper)
+ self.client.connect(self.vnfd_helper)
def get_stats(self, *args, **kwargs):
- return self.client.ix_get_statistics()
+ return self.client.get_statistics()
def stop_collect(self):
self._terminated.value = 1
- if self.client:
- self.client.ix_stop_traffic()
- def generate_samples(self, ports, key=None, default=None):
+ def generate_samples(self, ports, key=None):
stats = self.get_stats()
- last_result = stats[1]
- latency = stats[0]
samples = {}
# this is not DPDK port num, but this is whatever number we gave
@@ -88,19 +72,21 @@ class IxiaResourceHelper(ClientResourceHelper):
intf = self.vnfd_helper.find_interface_by_port(port_num)
port_name = intf["name"]
samples[port_name] = {
- "rx_throughput_kps": float(last_result["Rx_Rate_Kbps"][port_num]),
- "tx_throughput_kps": float(last_result["Tx_Rate_Kbps"][port_num]),
- "rx_throughput_mbps": float(last_result["Rx_Rate_Mbps"][port_num]),
- "tx_throughput_mbps": float(last_result["Tx_Rate_Mbps"][port_num]),
- "in_packets": int(last_result["Valid_Frames_Rx"][port_num]),
- "out_packets": int(last_result["Frames_Tx"][port_num]),
- "RxThroughput": int(last_result["Valid_Frames_Rx"][port_num]) / 30,
- "TxThroughput": int(last_result["Frames_Tx"][port_num]) / 30,
+ "rx_throughput_kps": float(stats["Rx_Rate_Kbps"][port_num]),
+ "tx_throughput_kps": float(stats["Tx_Rate_Kbps"][port_num]),
+ "rx_throughput_mbps": float(stats["Rx_Rate_Mbps"][port_num]),
+ "tx_throughput_mbps": float(stats["Tx_Rate_Mbps"][port_num]),
+ "in_packets": int(stats["Valid_Frames_Rx"][port_num]),
+ "out_packets": int(stats["Frames_Tx"][port_num]),
+ # NOTE(ralonsoh): we need to make the traffic injection
+ # time variable.
+ "RxThroughput": int(stats["Valid_Frames_Rx"][port_num]) / 30,
+ "TxThroughput": int(stats["Frames_Tx"][port_num]) / 30,
}
if key:
- avg_latency = latency["Store-Forward_Avg_latency_ns"][port_num]
- min_latency = latency["Store-Forward_Min_latency_ns"][port_num]
- max_latency = latency["Store-Forward_Max_latency_ns"][port_num]
+ avg_latency = stats["Store-Forward_Avg_latency_ns"][port_num]
+ min_latency = stats["Store-Forward_Min_latency_ns"][port_num]
+ max_latency = stats["Store-Forward_Max_latency_ns"][port_num]
samples[port_name][key] = \
{"Store-Forward_Avg_latency_ns": avg_latency,
"Store-Forward_Min_latency_ns": min_latency,
@@ -110,6 +96,12 @@ class IxiaResourceHelper(ClientResourceHelper):
return samples
+ def _initialize_client(self):
+ """Initialize the IXIA IxNetwork client and configure the server"""
+ self.client.clear_config()
+ self.client.assign_ports()
+ self.client.create_traffic_model()
+
def run_traffic(self, traffic_profile):
if self._terminated.value:
return
@@ -119,16 +111,7 @@ class IxiaResourceHelper(ClientResourceHelper):
default = "00:00:00:00:00:00"
self._build_ports()
-
- # we don't know client_file_name until runtime as instantiate
- client_file_name = \
- utils.find_relative_file(
- self.scenario_helper.scenario_cfg['ixia_profile'],
- self.scenario_helper.scenario_cfg["task_path"])
- self.client.ix_load_config(client_file_name)
- time.sleep(WAIT_AFTER_CFG_LOAD)
-
- self.client.ix_assign_ports()
+ self._initialize_client()
mac = {}
for port_name in self.vnfd_helper.port_pairs.all_ports:
@@ -140,43 +123,28 @@ class IxiaResourceHelper(ClientResourceHelper):
mac["src_mac_{}".format(port_num)] = virt_intf.get("local_mac", default)
mac["dst_mac_{}".format(port_num)] = virt_intf.get("dst_mac", default)
- samples = {}
- # Generate ixia traffic config...
try:
while not self._terminated.value:
- traffic_profile.execute_traffic(self, self.client, mac)
+ first_run = traffic_profile.execute_traffic(
+ self, self.client, mac)
self.client_started.value = 1
- time.sleep(WAIT_FOR_TRAFFIC)
- self.client.ix_stop_traffic()
+ # pylint: disable=unnecessary-lambda
+ utils.wait_until_true(lambda: self.client.is_traffic_stopped())
samples = self.generate_samples(traffic_profile.ports)
+
+ # NOTE(ralonsoh): the traffic injection duration is fixed to 30
+ # seconds. This parameter is configurable and must be retrieved
+ # from the traffic_profile.full_profile information.
+ # Every flow must have the same duration.
+ completed, samples = traffic_profile.get_drop_percentage(
+ samples, min_tol, max_tol, first_run=first_run)
self._queue.put(samples)
- status, samples = traffic_profile.get_drop_percentage(samples, min_tol,
- max_tol, self.client, mac)
- current = samples['CurrentDropPercentage']
- if min_tol <= current <= max_tol or status == 'Completed':
+ if completed:
self._terminated.value = 1
- self.client.ix_stop_traffic()
- self._queue.put(samples)
-
- if not self.rfc_helper.is_done():
- self._terminated.value = 1
- return
-
- traffic_profile.execute_traffic(self, self.client, mac)
- for _ in range(5):
- time.sleep(self.LATENCY_TIME_SLEEP)
- self.client.ix_stop_traffic()
- samples = self.generate_samples(traffic_profile.ports, 'latency', {})
- self._queue.put(samples)
- traffic_profile.start_ixia_latency(self, self.client, mac)
- if self._terminated.value:
- break
-
- self.client.ix_stop_traffic()
except Exception: # pylint: disable=broad-except
- LOG.exception("Run Traffic terminated")
+ LOG.exception('Run Traffic terminated')
self._terminated.value = 1
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py
index 4e9f4bdc1..07cec6745 100644
--- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py
+++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py
@@ -11,74 +11,45 @@
# 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.
-""" Trex traffic generation definitions which implements rfc2544 """
-from __future__ import absolute_import
-from __future__ import print_function
-import time
import logging
-from collections import Mapping
-
-from yardstick.network_services.vnf_generic.vnf.tg_trex import TrexTrafficGen
-from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper
-from yardstick.network_services.vnf_generic.vnf.tg_trex import TrexResourceHelper
-
-LOGGING = logging.getLogger(__name__)
+import time
+from yardstick.common import utils
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+from yardstick.network_services.vnf_generic.vnf import tg_trex
-class TrexRfc2544ResourceHelper(Rfc2544ResourceHelper):
- def is_done(self):
- return self.latency and self.iteration.value > 10
+LOGGING = logging.getLogger(__name__)
-class TrexRfcResourceHelper(TrexResourceHelper):
+class TrexRfcResourceHelper(tg_trex.TrexResourceHelper):
- LATENCY_TIME_SLEEP = 120
- RUN_DURATION = 30
- WAIT_TIME = 3
+ SAMPLING_PERIOD = 2
+ TRANSIENT_PERIOD = 10
- def __init__(self, setup_helper, rfc_helper_type=None):
+ def __init__(self, setup_helper):
super(TrexRfcResourceHelper, self).__init__(setup_helper)
-
- if rfc_helper_type is None:
- rfc_helper_type = TrexRfc2544ResourceHelper
-
- self.rfc2544_helper = rfc_helper_type(self.scenario_helper)
+ self.rfc2544_helper = sample_vnf.Rfc2544ResourceHelper(
+ self.scenario_helper)
def _run_traffic_once(self, traffic_profile):
- if self._terminated.value:
- return
-
- traffic_profile.execute_traffic(self)
self.client_started.value = 1
- time.sleep(self.RUN_DURATION)
- self.client.stop(traffic_profile.ports)
- time.sleep(self.WAIT_TIME)
- samples = traffic_profile.get_drop_percentage(self)
- self._queue.put(samples)
-
- if not self.rfc2544_helper.is_done():
- return
-
- self.client.stop(traffic_profile.ports)
- self.client.reset(ports=traffic_profile.ports)
- self.client.remove_all_streams(traffic_profile.ports)
- traffic_profile.execute_traffic_latency(samples=samples)
- multiplier = traffic_profile.calculate_pps(samples)[1]
- for _ in range(5):
- time.sleep(self.LATENCY_TIME_SLEEP)
- self.client.stop(traffic_profile.ports)
- time.sleep(self.WAIT_TIME)
- last_res = self.client.get_stats(traffic_profile.ports)
- if not isinstance(last_res, Mapping):
- self._terminated.value = 1
- continue
- self.generate_samples(traffic_profile.ports, 'latency', {})
- self._queue.put(samples)
- self.client.start(mult=str(multiplier),
- ports=traffic_profile.ports,
- duration=120, force=True)
+ ports, port_pg_id = traffic_profile.execute_traffic(self)
+
+ samples = []
+ timeout = int(traffic_profile.config.duration) - self.TRANSIENT_PERIOD
+ time.sleep(self.TRANSIENT_PERIOD)
+ for _ in utils.Timer(timeout=timeout):
+ samples.append(self._get_samples(ports, port_pg_id=port_pg_id))
+ time.sleep(self.SAMPLING_PERIOD)
+
+ traffic_profile.stop_traffic(self)
+ output = traffic_profile.get_drop_percentage(
+ samples, self.rfc2544_helper.tolerance_low,
+ self.rfc2544_helper.tolerance_high,
+ self.rfc2544_helper.correlated_traffic)
+ self._queue.put(output)
def start_client(self, ports, mult=None, duration=None, force=True):
self.client.start(ports=ports, mult=mult, duration=duration, force=force)
@@ -86,12 +57,8 @@ class TrexRfcResourceHelper(TrexResourceHelper):
def clear_client_stats(self, ports):
self.client.clear_stats(ports=ports)
- def collect_kpi(self):
- self.rfc2544_helper.iteration.value += 1
- return super(TrexRfcResourceHelper, self).collect_kpi()
-
-class TrexTrafficGenRFC(TrexTrafficGen):
+class TrexTrafficGenRFC(tg_trex.TrexTrafficGen):
"""
This class handles mapping traffic profile and generating
traffic for rfc2544 testcase.
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_trex.py b/yardstick/network_services/vnf_generic/vnf/tg_trex.py
index 0084a124c..80b42e22d 100644
--- a/yardstick/network_services/vnf_generic/vnf/tg_trex.py
+++ b/yardstick/network_services/vnf_generic/vnf/tg_trex.py
@@ -13,7 +13,6 @@
# limitations under the License.
""" Trex acts as traffic generation and vnf definitions based on IETS Spec """
-from __future__ import absolute_import
import logging
import os
@@ -25,6 +24,7 @@ from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTraff
from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper
from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper
+
LOG = logging.getLogger(__name__)
@@ -165,6 +165,30 @@ class TrexResourceHelper(ClientResourceHelper):
cmd = "sudo fuser -n tcp %s %s -k > /dev/null 2>&1"
self.ssh_helper.execute(cmd % (self.SYNC_PORT, self.ASYNC_PORT))
+ def _get_samples(self, ports, port_pg_id=None):
+ stats = self.get_stats(ports)
+ samples = {}
+ for pname in (intf['name'] for intf in self.vnfd_helper.interfaces):
+ port_num = self.vnfd_helper.port_num(pname)
+ port_stats = stats.get(port_num, {})
+ samples[pname] = {
+ 'rx_throughput_fps': float(port_stats.get('rx_pps', 0.0)),
+ 'tx_throughput_fps': float(port_stats.get('tx_pps', 0.0)),
+ 'rx_throughput_bps': float(port_stats.get('rx_bps', 0.0)),
+ 'tx_throughput_bps': float(port_stats.get('tx_bps', 0.0)),
+ 'in_packets': int(port_stats.get('ipackets', 0)),
+ 'out_packets': int(port_stats.get('opackets', 0)),
+ }
+
+ pg_id_list = port_pg_id.get_pg_ids(port_num)
+ samples[pname]['latency'] = {}
+ for pg_id in pg_id_list:
+ latency_global = stats.get('latency', {})
+ pg_latency = latency_global.get(pg_id, {}).get('latency')
+ samples[pname]['latency'][pg_id] = pg_latency
+
+ return samples
+
class TrexTrafficGen(SampleVNFTrafficGen):
"""
diff --git a/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py b/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py
index 3ba1f91b7..432f30a0c 100644
--- a/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py
+++ b/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py
@@ -14,9 +14,8 @@
import logging
-from yardstick.common import utils
-from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, DpdkVnfSetupEnvHelper
-from yardstick.network_services.yang_model import YangModel
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF
+from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxSetupEnvSetupEnvHelper
LOG = logging.getLogger(__name__)
@@ -27,7 +26,7 @@ FW_COLLECT_KPI = (r"""VFW TOTAL:[^p]+pkts_received"?:\s(\d+),[^p]+pkts_fw_forwar
r"""[^p]+pkts_drop_fw"?:\s(\d+),\s""")
-class FWApproxSetupEnvHelper(DpdkVnfSetupEnvHelper):
+class FWApproxSetupEnvHelper(AclApproxSetupEnvSetupEnvHelper):
APP_NAME = "vFW"
CFG_CONFIG = "/tmp/vfw_config"
@@ -37,6 +36,8 @@ class FWApproxSetupEnvHelper(DpdkVnfSetupEnvHelper):
SW_DEFAULT_CORE = 5
HW_DEFAULT_CORE = 2
VNF_TYPE = "VFW"
+ RULE_CMD = "vfw"
+ DEFAULT_FWD_ACTIONS = ["accept", "count", "conntrack"]
class FWApproxVnf(SampleVNF):
@@ -56,12 +57,3 @@ class FWApproxVnf(SampleVNF):
setup_env_helper_type = FWApproxSetupEnvHelper
super(FWApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type)
- self.vfw_rules = None
-
- def _start_vnf(self):
- yang_model_path = utils.find_relative_file(
- self.scenario_helper.options['rules'],
- self.scenario_helper.task_path)
- yang_model = YangModel(yang_model_path)
- self.vfw_rules = yang_model.get_rules()
- super(FWApproxVnf, self)._start_vnf()
diff --git a/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py b/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py
index de6fd9329..6c5c6c833 100644
--- a/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py
+++ b/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py
@@ -47,6 +47,7 @@ class VnfSshHelper(AutoConnectSSH):
def upload_config_file(self, prefix, content):
cfg_file = os.path.join(constants.REMOTE_TMP, prefix)
+ LOG.debug('Config file name: %s', cfg_file)
LOG.debug(content)
file_obj = StringIO(content)
self.put_file_obj(file_obj, cfg_file)
diff --git a/yardstick/network_services/vnf_generic/vnf/vpe_vnf.py b/yardstick/network_services/vnf_generic/vnf/vpe_vnf.py
index 0067f6bf9..9deef5cfa 100644
--- a/yardstick/network_services/vnf_generic/vnf/vpe_vnf.py
+++ b/yardstick/network_services/vnf_generic/vnf/vpe_vnf.py
@@ -115,7 +115,8 @@ class ConfigCreate(object):
pktq = "SWQ{0}{1}".format(self.sw_q, sink)
return pktq
- def vpe_upstream(self, vnf_cfg, index=0):
+ def vpe_upstream(self, vnf_cfg, index=0): # pragma: no cover
+ # NOTE(ralonsoh): this function must be covered in UTs.
parser = configparser.ConfigParser()
parser.read(os.path.join(vnf_cfg, 'vpe_upstream'))
@@ -147,7 +148,8 @@ class ConfigCreate(object):
self.n_pipeline += 1
return parser
- def vpe_downstream(self, vnf_cfg, index):
+ def vpe_downstream(self, vnf_cfg, index): # pragma: no cover
+ # NOTE(ralonsoh): this function must be covered in UTs.
parser = configparser.ConfigParser()
parser.read(os.path.join(vnf_cfg, 'vpe_downstream'))
for pipeline in parser.sections():
diff --git a/yardstick/network_services/yang_model.py b/yardstick/network_services/yang_model.py
deleted file mode 100644
index ec00c4513..000000000
--- a/yardstick/network_services/yang_model.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# 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.
-
-from __future__ import absolute_import
-from __future__ import print_function
-import logging
-import ipaddress
-import six
-
-from yardstick.common.yaml_loader import yaml_load
-
-LOG = logging.getLogger(__name__)
-
-
-class YangModel(object):
-
- RULE_TEMPLATE = "p acl add 1 {0} {1} {2} {3} {4} {5} {6} {7} 0 0 {8}"
-
- def __init__(self, config_file):
- super(YangModel, self).__init__()
- self._config_file = config_file
- self._options = {}
- self._rules = ''
-
- @property
- def config_file(self):
- return self._config_file
-
- @config_file.setter
- def config_file(self, value):
- self._config_file = value
- self._options = {}
- self._rules = ''
-
- def _read_config(self):
- # TODO: add some error handling in case of empty or non-existing file
- try:
- with open(self._config_file) as f:
- self._options = yaml_load(f)
- except Exception as e:
- LOG.exception("Failed to load the yaml %s", e)
- raise
-
- def _get_entries(self):
- if not self._options:
- return ''
-
- rule_list = []
- for ace in self._options['access-list1']['acl']['access-list-entries']:
- # TODO: resolve ports using topology file and nodes'
- # ids: public or private.
- matches = ace['ace']['matches']
- dst_ipv4_net = matches['destination-ipv4-network']
- dst_ipv4_net_ip = ipaddress.ip_interface(six.text_type(dst_ipv4_net))
- port0_local_network = dst_ipv4_net_ip.network.network_address.exploded
- port0_prefix = dst_ipv4_net_ip.network.prefixlen
-
- src_ipv4_net = matches['source-ipv4-network']
- src_ipv4_net_ip = ipaddress.ip_interface(six.text_type(src_ipv4_net))
- port1_local_network = src_ipv4_net_ip.network.network_address.exploded
- port1_prefix = src_ipv4_net_ip.network.prefixlen
-
- lower_dport = matches['destination-port-range']['lower-port']
- upper_dport = matches['destination-port-range']['upper-port']
-
- lower_sport = matches['source-port-range']['lower-port']
- upper_sport = matches['source-port-range']['upper-port']
-
- # TODO: proto should be read from file also.
- # Now all rules in sample ACL file are TCP.
- rule_list.append('') # get an extra new line
- rule_list.append(self.RULE_TEMPLATE.format(port0_local_network,
- port0_prefix,
- port1_local_network,
- port1_prefix,
- lower_dport,
- upper_dport,
- lower_sport,
- upper_sport,
- 0))
- rule_list.append(self.RULE_TEMPLATE.format(port1_local_network,
- port1_prefix,
- port0_local_network,
- port0_prefix,
- lower_sport,
- upper_sport,
- lower_dport,
- upper_dport,
- 1))
-
- self._rules = '\n'.join(rule_list)
-
- def get_rules(self):
- if not self._rules:
- self._read_config()
- self._get_entries()
- return self._rules
diff --git a/yardstick/orchestrator/kubernetes.py b/yardstick/orchestrator/kubernetes.py
index ac3a09ed1..e05c971ac 100644
--- a/yardstick/orchestrator/kubernetes.py
+++ b/yardstick/orchestrator/kubernetes.py
@@ -7,25 +7,30 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-from __future__ import absolute_import
-from __future__ import print_function
+import copy
+from yardstick.common import exceptions
from yardstick.common import utils
from yardstick.common import kubernetes_utils as k8s_utils
class KubernetesObject(object):
+ SSH_MOUNT_PATH = '/tmp/.ssh/'
+ IMAGE_DEFAULT = 'openretriever/yardstick'
+ COMMAND_DEFAULT = '/bin/bash'
+ SSHKEY_DEFAULT = 'yardstick_key'
+
def __init__(self, name, **kwargs):
super(KubernetesObject, self).__init__()
self.name = name
- self.image = kwargs.get('image', 'openretriever/yardstick')
- self.command = [kwargs.get('command', '/bin/bash')]
+ self.image = kwargs.get('image', self.IMAGE_DEFAULT)
+ self.command = [kwargs.get('command', self.COMMAND_DEFAULT)]
self.args = kwargs.get('args', [])
- self.ssh_key = kwargs.get('ssh_key', 'yardstick_key')
+ self.ssh_key = kwargs.get('ssh_key', self.SSHKEY_DEFAULT)
self.node_selector = kwargs.get('nodeSelector', {})
-
- self.volumes = []
+ self._volumes = kwargs.get('volumes', [])
+ self._volume_mounts = kwargs.get('volumeMounts', [])
self.template = {
"apiVersion": "v1",
@@ -53,7 +58,6 @@ class KubernetesObject(object):
self._change_value_according_name(name)
self._add_containers()
self._add_node_selector()
- self._add_ssh_key_volume()
self._add_volumes()
def get_template(self):
@@ -67,29 +71,19 @@ class KubernetesObject(object):
name)
def _add_containers(self):
- containers = [self._add_container()]
+ containers = [self._create_container_item()]
utils.set_dict_value(self.template,
'spec.template.spec.containers',
containers)
- def _add_container(self):
+ def _create_container_item(self):
+ """Create a "container" item"""
container_name = '{}-container'.format(self.name)
- ssh_key_mount_path = '/tmp/.ssh/'
-
- container = {
- "args": self.args,
- "command": self.command,
- "image": self.image,
- "name": container_name,
- "volumeMounts": [
- {
- "mountPath": ssh_key_mount_path,
- "name": self.ssh_key
- }
- ]
- }
-
- return container
+ return {'args': self.args,
+ 'command': self.command,
+ 'image': self.image,
+ 'name': container_name,
+ 'volumeMounts': self._create_volume_mounts()}
def _add_node_selector(self):
utils.set_dict_value(self.template,
@@ -97,21 +91,48 @@ class KubernetesObject(object):
self.node_selector)
def _add_volumes(self):
+ """Add "volume" items to container specs, including the SSH one"""
+ volume_items = [self._create_volume_item(vol) for vol in self._volumes]
+ volume_items.append(self._create_ssh_key_volume())
utils.set_dict_value(self.template,
'spec.template.spec.volumes',
- self.volumes)
-
- def _add_volume(self, volume):
- self.volumes.append(volume)
-
- def _add_ssh_key_volume(self):
- key_volume = {
- "configMap": {
- "name": self.ssh_key
- },
- "name": self.ssh_key
- }
- self._add_volume(key_volume)
+ volume_items)
+
+ def _create_ssh_key_volume(self):
+ """Create a "volume" item of type "configMap" for the SSH key"""
+ return {'name': self.ssh_key,
+ 'configMap': {'name': self.ssh_key}}
+
+ @staticmethod
+ def _create_volume_item(volume):
+ """Create a "volume" item"""
+ volume = copy.deepcopy(volume)
+ name = volume.pop('name')
+ for key in (k for k in volume if k in k8s_utils.get_volume_types()):
+ type_name = key
+ type_data = volume[key]
+ break
+ else:
+ raise exceptions.KubernetesTemplateInvalidVolumeType(volume=volume)
+
+ return {'name': name,
+ type_name: type_data}
+
+ def _create_volume_mounts(self):
+ """Return all "volumeMounts" items per container"""
+ volume_mounts_items = [self._create_volume_mounts_item(vol)
+ for vol in self._volume_mounts]
+ ssh_vol = {'name': self.ssh_key,
+ 'mountPath': self.SSH_MOUNT_PATH}
+ volume_mounts_items.append(self._create_volume_mounts_item(ssh_vol))
+ return volume_mounts_items
+
+ @staticmethod
+ def _create_volume_mounts_item(volume_mount):
+ """Create a "volumeMounts" item"""
+ return {'name': volume_mount['name'],
+ 'mountPath': volume_mount['mountPath'],
+ 'readOnly': volume_mount.get('readOnly', False)}
class ServiceObject(object):
@@ -145,15 +166,22 @@ class ServiceObject(object):
class KubernetesTemplate(object):
- def __init__(self, name, template_cfg):
+ def __init__(self, name, context_cfg):
+ """KubernetesTemplate object initialization
+
+ :param name: (str) name of the Kubernetes context
+ :param context_cfg: (dict) context definition
+ """
+ context_cfg = copy.deepcopy(context_cfg)
+ servers_cfg = context_cfg.pop('servers', {})
self.name = name
self.ssh_key = '{}-key'.format(name)
- self.rcs = [self._get_rc_name(rc) for rc in template_cfg]
+ self.rcs = [self._get_rc_name(rc) for rc in servers_cfg]
self.k8s_objs = [KubernetesObject(self._get_rc_name(rc),
ssh_key=self.ssh_key,
**cfg)
- for rc, cfg in template_cfg.items()]
+ for rc, cfg in servers_cfg.items()]
self.service_objs = [ServiceObject(s) for s in self.rcs]
self.pods = []
diff --git a/yardstick/ssh.py b/yardstick/ssh.py
index d7adc0d05..e6a26ab6b 100644
--- a/yardstick/ssh.py
+++ b/yardstick/ssh.py
@@ -62,15 +62,13 @@ Eventlet:
sshclient = eventlet.import_patched("yardstick.ssh")
"""
-from __future__ import absolute_import
-import os
import io
+import logging
+import os
+import re
import select
import socket
import time
-import re
-
-import logging
import paramiko
from chainmap import ChainMap
@@ -78,6 +76,7 @@ from oslo_utils import encodeutils
from scp import SCPClient
import six
+from yardstick.common import exceptions
from yardstick.common.utils import try_int, NON_NONE_DEFAULT, make_dict_from_map
from yardstick.network_services.utils import provision_tool
@@ -90,12 +89,12 @@ def convert_key_to_str(key):
return k.getvalue()
-class SSHError(Exception):
- pass
-
-
-class SSHTimeout(SSHError):
- pass
+# class SSHError(Exception):
+# pass
+#
+#
+# class SSHTimeout(SSHError):
+# pass
class SSH(object):
@@ -193,7 +192,7 @@ class SSH(object):
return key_class.from_private_key(key)
except paramiko.SSHException as e:
errors.append(e)
- raise SSHError("Invalid pkey: %s" % errors)
+ raise exceptions.SSHError(error_msg='Invalid pkey: %s' % errors)
@property
def is_connected(self):
@@ -214,10 +213,10 @@ class SSH(object):
return self._client
except Exception as e:
message = ("Exception %(exception_type)s was raised "
- "during connect. Exception value is: %(exception)r")
+ "during connect. Exception value is: %(exception)r" %
+ {"exception": e, "exception_type": type(e)})
self._client = False
- raise SSHError(message % {"exception": e,
- "exception_type": type(e)})
+ raise exceptions.SSHError(error_msg=message)
def _make_dict(self):
return {
@@ -334,11 +333,11 @@ class SSH(object):
break
if timeout and (time.time() - timeout) > start_time:
- args = {"cmd": cmd, "host": self.host}
- raise SSHTimeout("Timeout executing command "
- "'%(cmd)s' on host %(host)s" % args)
+ message = ('Timeout executing command %(cmd)s on host %(host)s'
+ % {"cmd": cmd, "host": self.host})
+ raise exceptions.SSHTimeout(error_msg=message)
if e:
- raise SSHError("Socket error.")
+ raise exceptions.SSHError(error_msg='Socket error')
exit_status = session.recv_exit_status()
if exit_status != 0 and raise_on_error:
@@ -346,15 +345,17 @@ class SSH(object):
details = fmt % {"cmd": cmd, "status": exit_status}
if stderr_data:
details += " Last stderr data: '%s'." % stderr_data
- raise SSHError(details)
+ raise exceptions.SSHError(error_msg=details)
return exit_status
- def execute(self, cmd, stdin=None, timeout=3600):
+ def execute(self, cmd, stdin=None, timeout=3600, raise_on_error=False):
"""Execute the specified command on the server.
- :param cmd: Command to be executed.
- :param stdin: Open file to be sent on process stdin.
- :param timeout: Timeout for execution of the command.
+ :param cmd: (str) Command to be executed.
+ :param stdin: (StringIO) Open file to be sent on process stdin.
+ :param timeout: (int) Timeout for execution of the command.
+ :param raise_on_error: (bool) If True, then an SSHError will be raised
+ when non-zero exit code.
:returns: tuple (exit_status, stdout, stderr)
"""
@@ -363,7 +364,7 @@ class SSH(object):
exit_status = self.run(cmd, stderr=stderr,
stdout=stdout, stdin=stdin,
- timeout=timeout, raise_on_error=False)
+ timeout=timeout, raise_on_error=raise_on_error)
stdout.seek(0)
stderr.seek(0)
return exit_status, stdout.read(), stderr.read()
@@ -377,11 +378,12 @@ class SSH(object):
while True:
try:
return self.execute("uname")
- except (socket.error, SSHError) as e:
+ except (socket.error, exceptions.SSHError) as e:
self.log.debug("Ssh is still unavailable: %r", e)
time.sleep(interval)
if time.time() > end_time:
- raise SSHTimeout("Timeout waiting for '%s'" % self.host)
+ raise exceptions.SSHTimeout(
+ error_msg='Timeout waiting for "%s"' % self.host)
def put(self, files, remote_path=b'.', recursive=False):
client = self._get_client()
@@ -486,11 +488,12 @@ class AutoConnectSSH(SSH):
while True:
try:
return self._get_client()
- except (socket.error, SSHError) as e:
+ except (socket.error, exceptions.SSHError) as e:
self.log.debug("Ssh is still unavailable: %r", e)
time.sleep(interval)
if time.time() > end_time:
- raise SSHTimeout("Timeout waiting for '%s'" % self.host)
+ raise exceptions.SSHTimeout(
+ error_msg='Timeout waiting for "%s"' % self.host)
def drop_connection(self):
""" Don't close anything, just force creation of a new client """
diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py
index 72e684a68..246a5b2b9 100644
--- a/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py
+++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py
@@ -550,4 +550,4 @@ class OvsDeployTestCase(unittest.TestCase):
'dpdk_version': dpdk_version,
'proxy': 'test_proxy'})
mock_execute.assert_called_once_with(cmd)
- mock_env_get.assert_called_once_with('http_proxy', '')
+ mock_env_get.assert_has_calls([mock.call('http_proxy', '')])
diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py
index bc3bb73cd..6eb438cb1 100644
--- a/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py
+++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py
@@ -19,6 +19,7 @@ import mock
import six
import unittest
+from yardstick.benchmark.contexts import base
from yardstick.benchmark.contexts.standalone import model
from yardstick.benchmark.contexts.standalone import ovs_dpdk
from yardstick.common import exceptions
@@ -59,9 +60,11 @@ class OvsDpdkContextTestCase(unittest.TestCase):
self.ovs_dpdk = ovs_dpdk.OvsDpdkContext()
self.addCleanup(self._remove_contexts)
- def _remove_contexts(self):
- if self.ovs_dpdk in self.ovs_dpdk.list:
- self.ovs_dpdk._delete_context()
+ @staticmethod
+ def _remove_contexts():
+ for context in base.Context.list:
+ context._delete_context()
+ base.Context.list = []
@mock.patch('yardstick.benchmark.contexts.standalone.model.Server')
@mock.patch('yardstick.benchmark.contexts.standalone.model.StandaloneContextHelper')
diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py
index b426985be..de748e285 100644
--- a/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py
+++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py
@@ -18,6 +18,7 @@ import mock
import unittest
from yardstick import ssh
+from yardstick.benchmark.contexts import base
from yardstick.benchmark.contexts.standalone import model
from yardstick.benchmark.contexts.standalone import sriov
@@ -66,9 +67,11 @@ class SriovContextTestCase(unittest.TestCase):
self.sriov = sriov.SriovContext()
self.addCleanup(self._remove_contexts)
- def _remove_contexts(self):
- if self.sriov in self.sriov.list:
- self.sriov._delete_context()
+ @staticmethod
+ def _remove_contexts():
+ for context in base.Context.list:
+ context._delete_context()
+ base.Context.list = []
@mock.patch.object(model, 'StandaloneContextHelper')
@mock.patch.object(model, 'Libvirt')
diff --git a/yardstick/tests/unit/benchmark/contexts/test_base.py b/yardstick/tests/unit/benchmark/contexts/test_base.py
index b19883479..81267cf98 100644
--- a/yardstick/tests/unit/benchmark/contexts/test_base.py
+++ b/yardstick/tests/unit/benchmark/contexts/test_base.py
@@ -12,12 +12,26 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import unittest
-
from yardstick.benchmark.contexts import base
+from yardstick.tests.unit import base as ut_base
+
+
+class DummyContextClass(base.Context):
+
+ def _get_network(self, *args):
+ pass
+
+ def _get_server(self, *args):
+ pass
+
+ def deploy(self):
+ pass
+
+ def undeploy(self):
+ pass
-class FlagsTestCase(unittest.TestCase):
+class FlagsTestCase(ut_base.BaseUnitTestCase):
def setUp(self):
self.flags = base.Flags()
@@ -44,3 +58,32 @@ class FlagsTestCase(unittest.TestCase):
self.flags.parse(foo=42)
with self.assertRaises(AttributeError):
_ = self.flags.foo
+
+
+class ContextTestCase(ut_base.BaseUnitTestCase):
+
+ @staticmethod
+ def _remove_ctx(ctx_obj):
+ if ctx_obj in base.Context.list:
+ base.Context.list.remove(ctx_obj)
+
+ def test_split_host_name(self):
+ ctx_obj = DummyContextClass()
+ self.addCleanup(self._remove_ctx, ctx_obj)
+ config_name = 'host_name.ctx_name'
+ self.assertEqual(('host_name', 'ctx_name'),
+ ctx_obj.split_host_name(config_name))
+
+ def test_split_host_name_wrong_separator(self):
+ ctx_obj = DummyContextClass()
+ self.addCleanup(self._remove_ctx, ctx_obj)
+ config_name = 'host_name-ctx_name'
+ self.assertEqual((None, None),
+ ctx_obj.split_host_name(config_name))
+
+ def test_split_host_name_other_separator(self):
+ ctx_obj = DummyContextClass(host_name_separator='-')
+ self.addCleanup(self._remove_ctx, ctx_obj)
+ config_name = 'host_name-ctx_name'
+ self.assertEqual(('host_name', 'ctx_name'),
+ ctx_obj.split_host_name(config_name))
diff --git a/yardstick/tests/unit/benchmark/contexts/test_dummy.py b/yardstick/tests/unit/benchmark/contexts/test_dummy.py
index e393001a1..c4113be41 100644
--- a/yardstick/tests/unit/benchmark/contexts/test_dummy.py
+++ b/yardstick/tests/unit/benchmark/contexts/test_dummy.py
@@ -9,6 +9,7 @@
import unittest
+from yardstick.benchmark.contexts import base
from yardstick.benchmark.contexts import dummy
@@ -20,7 +21,12 @@ class DummyContextTestCase(unittest.TestCase):
'task_id': '1234567890',
}
self.test_context = dummy.DummyContext()
- self.addCleanup(self.test_context._delete_context)
+ self.addCleanup(self._delete_contexts)
+
+ @staticmethod
+ def _delete_contexts():
+ for context in base.Context.list:
+ context._delete_context()
def test___init__(self):
self.assertFalse(self.test_context._flags.no_setup)
diff --git a/yardstick/tests/unit/benchmark/contexts/test_heat.py b/yardstick/tests/unit/benchmark/contexts/test_heat.py
index 947e6fe22..9c822b3a7 100644
--- a/yardstick/tests/unit/benchmark/contexts/test_heat.py
+++ b/yardstick/tests/unit/benchmark/contexts/test_heat.py
@@ -8,7 +8,6 @@
##############################################################################
from collections import OrderedDict
-from itertools import count
import logging
import os
@@ -31,12 +30,12 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase):
def setUp(self):
self.test_context = heat.HeatContext()
self.addCleanup(self._remove_contexts)
- self.mock_context = mock.Mock(spec=heat.HeatContext())
- self.name_iter = ('vnf{:03}'.format(x) for x in count(0, step=3))
- def _remove_contexts(self):
- if self.test_context in self.test_context.list:
- self.test_context._delete_context()
+ @staticmethod
+ def _remove_contexts():
+ for context in base.Context.list:
+ context._delete_context()
+ base.Context.list = []
def test___init__(self):
self.assertIsNone(self.test_context._name)
@@ -655,6 +654,7 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase):
baz3_server.public_ip = None
baz3_server.context.user = 'zab'
+ self.mock_context = mock.Mock(spec=heat.HeatContext())
self.mock_context._name = 'bar1'
self.test_context.stack = mock.Mock()
self.mock_context.stack.outputs = {
diff --git a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py
index 4dd9d40d1..0d698c5bd 100644
--- a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py
+++ b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py
@@ -10,10 +10,12 @@
import mock
import unittest
+from yardstick.benchmark.contexts import base
from yardstick.benchmark.contexts import kubernetes
+from yardstick.orchestrator import kubernetes as orchestrator_kubernetes
-context_cfg = {
+CONTEXT_CFG = {
'type': 'Kubernetes',
'name': 'k8s',
'task_id': '1234567890',
@@ -21,14 +23,14 @@ context_cfg = {
'host': {
'image': 'openretriever/yardstick',
'command': '/bin/bash',
- 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
-service ssh restart;while true ; do sleep 10000; done']
+ 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; '
+ 'service ssh restart;while true ; do sleep 10000; done']
},
'target': {
'image': 'openretriever/yardstick',
'command': '/bin/bash',
- 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
-service ssh restart;while true ; do sleep 10000; done']
+ 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; '
+ 'service ssh restart;while true ; do sleep 10000; done']
}
}
}
@@ -41,11 +43,13 @@ class KubernetesTestCase(unittest.TestCase):
def setUp(self):
self.k8s_context = kubernetes.KubernetesContext()
self.addCleanup(self._remove_contexts)
- self.k8s_context.init(context_cfg)
+ self.k8s_context.init(CONTEXT_CFG)
- def _remove_contexts(self):
- if self.k8s_context in self.k8s_context.list:
- self.k8s_context._delete_context()
+ @staticmethod
+ def _remove_contexts():
+ for context in base.Context.list:
+ context._delete_context()
+ base.Context.list = []
@mock.patch.object(kubernetes.KubernetesContext, '_delete_services')
@mock.patch.object(kubernetes.KubernetesContext, '_delete_ssh_key')
@@ -65,7 +69,8 @@ class KubernetesTestCase(unittest.TestCase):
@mock.patch.object(kubernetes.KubernetesContext, '_create_services')
@mock.patch.object(kubernetes.KubernetesContext, '_wait_until_running')
- @mock.patch.object(kubernetes.KubernetesTemplate, 'get_rc_pods')
+ @mock.patch.object(orchestrator_kubernetes.KubernetesTemplate,
+ 'get_rc_pods')
@mock.patch.object(kubernetes.KubernetesContext, '_create_rcs')
@mock.patch.object(kubernetes.KubernetesContext, '_set_ssh_key')
def test_deploy(self,
@@ -167,3 +172,13 @@ class KubernetesTestCase(unittest.TestCase):
def test_delete_services(self, mock_delete):
self.k8s_context._delete_services()
mock_delete.assert_called()
+
+ def test_init(self):
+ self.k8s_context._delete_context()
+ with mock.patch.object(orchestrator_kubernetes, 'KubernetesTemplate',
+ return_value='fake_template') as mock_k8stemplate:
+ self.k8s_context = kubernetes.KubernetesContext()
+ self.k8s_context.init(CONTEXT_CFG)
+ mock_k8stemplate.assert_called_once_with(self.k8s_context.name,
+ CONTEXT_CFG)
+ self.assertEqual('fake_template', self.k8s_context.template)
diff --git a/yardstick/tests/unit/benchmark/contexts/test_node.py b/yardstick/tests/unit/benchmark/contexts/test_node.py
index 8b232481b..b67be3758 100644
--- a/yardstick/tests/unit/benchmark/contexts/test_node.py
+++ b/yardstick/tests/unit/benchmark/contexts/test_node.py
@@ -13,6 +13,7 @@ import errno
import mock
from yardstick.common import constants as consts
+from yardstick.benchmark.contexts import base
from yardstick.benchmark.contexts import node
@@ -33,9 +34,11 @@ class NodeContextTestCase(unittest.TestCase):
'file': self._get_file_abspath(self.NODES_SAMPLE)
}
- def _remove_contexts(self):
- if self.test_context in self.test_context.list:
- self.test_context._delete_context()
+ @staticmethod
+ def _remove_contexts():
+ for context in base.Context.list:
+ context._delete_context()
+ base.Context.list = []
def _get_file_abspath(self, filename):
curr_path = os.path.dirname(os.path.abspath(__file__))
diff --git a/yardstick/tests/unit/benchmark/core/test_report.py b/yardstick/tests/unit/benchmark/core/test_report.py
index a684ad750..524302f92 100644
--- a/yardstick/tests/unit/benchmark/core/test_report.py
+++ b/yardstick/tests/unit/benchmark/core/test_report.py
@@ -42,16 +42,16 @@ class ReportTestCase(unittest.TestCase):
self.param.task_id = [FAKE_TASK_ID]
self.rep = report.Report()
- @mock.patch('yardstick.benchmark.core.report.Report._get_tasks')
- @mock.patch('yardstick.benchmark.core.report.Report._get_fieldkeys')
- @mock.patch('yardstick.benchmark.core.report.Report._validate')
+ @mock.patch.object(report.Report, '_get_tasks')
+ @mock.patch.object(report.Report, '_get_fieldkeys')
+ @mock.patch.object(report.Report, '_validate')
def test_generate_success(self, mock_valid, mock_keys, mock_tasks):
mock_tasks.return_value = FAKE_DB_TASK
mock_keys.return_value = FAKE_DB_FIELDKEYS
self.rep.generate(self.param)
mock_valid.assert_called_once_with(FAKE_YAML_NAME, FAKE_TASK_ID)
- self.assertEqual(1, mock_tasks.call_count)
- self.assertEqual(1, mock_keys.call_count)
+ mock_tasks.assert_called_once_with()
+ mock_keys.assert_called_once_with()
# pylint: disable=deprecated-method
def test_invalid_yaml_name(self):
diff --git a/yardstick/tests/unit/benchmark/core/test_task.py b/yardstick/tests/unit/benchmark/core/test_task.py
index e7d2c70b7..7468368df 100644
--- a/yardstick/tests/unit/benchmark/core/test_task.py
+++ b/yardstick/tests/unit/benchmark/core/test_task.py
@@ -17,6 +17,7 @@ import six
import unittest
import uuid
+from yardstick.benchmark.contexts import base
from yardstick.benchmark.contexts import dummy
from yardstick.benchmark.core import task
from yardstick.common import constants as consts
@@ -358,9 +359,10 @@ key2:
}
@staticmethod
- def _remove_context(context):
- if context:
+ def _remove_contexts():
+ for context in base.Context.list:
context._delete_context()
+ base.Context.list = []
def test__change_node_names(self):
@@ -376,7 +378,7 @@ key2:
}
my_context = dummy.DummyContext()
- self.addCleanup(self._remove_context, my_context)
+ self.addCleanup(self._remove_contexts)
my_context.init(ctx_attrs)
expected_scenario = {
@@ -419,7 +421,7 @@ key2:
}
my_context = dummy.DummyContext()
- self.addCleanup(self._remove_context, my_context)
+ self.addCleanup(self._remove_contexts)
my_context.init(ctx_attrs)
scenario = copy.deepcopy(self.scenario)
@@ -435,7 +437,7 @@ key2:
}
my_context = dummy.DummyContext()
- self.addCleanup(self._remove_context, my_context)
+ self.addCleanup(self._remove_contexts)
my_context.init(ctx_attrs)
scenario = copy.deepcopy(self.scenario)
scenario['options'] = None
@@ -450,7 +452,7 @@ key2:
}
my_context = dummy.DummyContext()
- self.addCleanup(self._remove_context, my_context)
+ self.addCleanup(self._remove_contexts)
my_context.init(ctx_attrs)
scenario = copy.deepcopy(self.scenario)
scenario['options']['server_name'] = None
diff --git a/yardstick/tests/unit/benchmark/runner/test_duration.py b/yardstick/tests/unit/benchmark/runner/test_duration.py
new file mode 100644
index 000000000..21e3874b8
--- /dev/null
+++ b/yardstick/tests/unit/benchmark/runner/test_duration.py
@@ -0,0 +1,39 @@
+##############################################################################
+# Copyright (c) 2018 Nokia and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import mock
+import unittest
+import multiprocessing
+import os
+
+from yardstick.benchmark.runners import duration
+
+
+class DurationRunnerTest(unittest.TestCase):
+ def setUp(self):
+ self.scenario_cfg = {
+ 'runner': {'interval': 0, "duration": 0},
+ 'type': 'some_type'
+ }
+
+ @mock.patch.object(os, 'getpid')
+ @mock.patch.object(multiprocessing, 'Process')
+ def test__run_benchmark_called_with(self, mock_multiprocessing_process,
+ mock_os_getpid):
+ mock_os_getpid.return_value = 101
+
+ runner = duration.DurationRunner({})
+ benchmark_cls = mock.Mock()
+ runner._run_benchmark(benchmark_cls, 'my_method', self.scenario_cfg,
+ {})
+ mock_multiprocessing_process.assert_called_once_with(
+ name='Duration-some_type-101',
+ target=duration._worker_process,
+ args=(runner.result_queue, benchmark_cls, 'my_method',
+ self.scenario_cfg, {}, runner.aborted, runner.output_queue))
diff --git a/yardstick/tests/unit/benchmark/runner/test_search.py b/yardstick/tests/unit/benchmark/runner/test_search.py
index 4e5b4fe77..d5d1b8ded 100644
--- a/yardstick/tests/unit/benchmark/runner/test_search.py
+++ b/yardstick/tests/unit/benchmark/runner/test_search.py
@@ -19,36 +19,33 @@ import unittest
from yardstick.benchmark.runners.search import SearchRunner
from yardstick.benchmark.runners.search import SearchRunnerHelper
+from yardstick.common import exceptions as y_exc
class TestSearchRunnerHelper(unittest.TestCase):
def test___call__(self):
- cls = mock.MagicMock()
- aborted = mock.MagicMock()
scenario_cfg = {
'runner': {},
}
- benchmark = cls()
- method = getattr(benchmark, 'my_method')
+ benchmark = mock.Mock()
+ method = getattr(benchmark(), 'my_method')
helper = SearchRunnerHelper(
- cls, 'my_method', scenario_cfg, {}, aborted)
+ benchmark, 'my_method', scenario_cfg, {}, mock.Mock())
with helper.get_benchmark_instance():
helper()
- self.assertEqual(method.call_count, 1)
+ method.assert_called_once()
def test___call___error(self):
- cls = mock.MagicMock()
- aborted = mock.MagicMock()
scenario_cfg = {
'runner': {},
}
helper = SearchRunnerHelper(
- cls, 'my_method', scenario_cfg, {}, aborted)
+ mock.Mock(), 'my_method', scenario_cfg, {}, mock.Mock())
with self.assertRaises(RuntimeError):
helper()
@@ -56,8 +53,6 @@ class TestSearchRunnerHelper(unittest.TestCase):
@mock.patch.object(time, 'sleep')
@mock.patch.object(time, 'time')
def test_is_not_done(self, mock_time, *args):
- cls = mock.MagicMock()
- aborted = mock.MagicMock()
scenario_cfg = {
'runner': {},
}
@@ -65,7 +60,7 @@ class TestSearchRunnerHelper(unittest.TestCase):
mock_time.side_effect = range(1000)
helper = SearchRunnerHelper(
- cls, 'my_method', scenario_cfg, {}, aborted)
+ mock.Mock(), 'my_method', scenario_cfg, {}, mock.Mock())
index = -1
for index in helper.is_not_done():
@@ -76,8 +71,6 @@ class TestSearchRunnerHelper(unittest.TestCase):
@mock.patch.object(time, 'sleep')
def test_is_not_done_immediate_stop(self, *args):
- cls = mock.MagicMock()
- aborted = mock.MagicMock()
scenario_cfg = {
'runner': {
'run_step': '',
@@ -85,7 +78,7 @@ class TestSearchRunnerHelper(unittest.TestCase):
}
helper = SearchRunnerHelper(
- cls, 'my_method', scenario_cfg, {}, aborted)
+ mock.Mock(), 'my_method', scenario_cfg, {}, mock.Mock())
index = -1
for index in helper.is_not_done():
@@ -112,7 +105,7 @@ class TestSearchRunner(unittest.TestCase):
}
runner = SearchRunner({})
- runner.worker_helper = mock.MagicMock(side_effect=update)
+ runner.worker_helper = mock.Mock(side_effect=update)
self.assertFalse(runner._worker_run_once('sequence 1'))
@@ -136,51 +129,49 @@ class TestSearchRunner(unittest.TestCase):
}
runner = SearchRunner({})
- runner.worker_helper = mock.MagicMock(side_effect=update)
+ runner.worker_helper = mock.Mock(side_effect=update)
self.assertTrue(runner._worker_run_once('sequence 1'))
def test__worker_run_once_assertion_error_assert(self):
runner = SearchRunner({})
runner.sla_action = 'assert'
- runner.worker_helper = mock.MagicMock(side_effect=AssertionError)
+ runner.worker_helper = mock.Mock(side_effect=y_exc.SLAValidationError)
- with self.assertRaises(AssertionError):
+ with self.assertRaises(y_exc.SLAValidationError):
runner._worker_run_once('sequence 1')
def test__worker_run_once_assertion_error_monitor(self):
runner = SearchRunner({})
runner.sla_action = 'monitor'
- runner.worker_helper = mock.MagicMock(side_effect=AssertionError)
+ runner.worker_helper = mock.Mock(side_effect=y_exc.SLAValidationError)
self.assertFalse(runner._worker_run_once('sequence 1'))
def test__worker_run_once_non_assertion_error_none(self):
runner = SearchRunner({})
- runner.worker_helper = mock.MagicMock(side_effect=RuntimeError)
+ runner.worker_helper = mock.Mock(side_effect=RuntimeError)
self.assertTrue(runner._worker_run_once('sequence 1'))
def test__worker_run_once_non_assertion_error(self):
runner = SearchRunner({})
runner.sla_action = 'monitor'
- runner.worker_helper = mock.MagicMock(side_effect=RuntimeError)
+ runner.worker_helper = mock.Mock(side_effect=RuntimeError)
self.assertFalse(runner._worker_run_once('sequence 1'))
def test__worker_run(self):
- cls = mock.MagicMock()
scenario_cfg = {
'runner': {'interval': 0, 'timeout': 1},
}
runner = SearchRunner({})
- runner._worker_run_once = mock.MagicMock(side_effect=[0, 0, 1])
+ runner._worker_run_once = mock.Mock(side_effect=[0, 0, 1])
- runner._worker_run(cls, 'my_method', scenario_cfg, {})
+ runner._worker_run(mock.Mock(), 'my_method', scenario_cfg, {})
def test__worker_run_immediate_stop(self):
- cls = mock.MagicMock()
scenario_cfg = {
'runner': {
'run_step': '',
@@ -188,15 +179,14 @@ class TestSearchRunner(unittest.TestCase):
}
runner = SearchRunner({})
- runner._worker_run(cls, 'my_method', scenario_cfg, {})
+ runner._worker_run(mock.Mock(), 'my_method', scenario_cfg, {})
@mock.patch('yardstick.benchmark.runners.search.multiprocessing')
def test__run_benchmark(self, mock_multi_process):
- cls = mock.MagicMock()
scenario_cfg = {
'runner': {},
}
runner = SearchRunner({})
- runner._run_benchmark(cls, 'my_method', scenario_cfg, {})
- self.assertEqual(mock_multi_process.Process.call_count, 1)
+ runner._run_benchmark(mock.Mock(), 'my_method', scenario_cfg, {})
+ mock_multi_process.Process.assert_called_once()
diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py
index ce972779d..8d042c406 100644
--- a/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py
+++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py
@@ -7,6 +7,8 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
+import time
+
import mock
import unittest
@@ -86,13 +88,19 @@ class BaseMonitorTestCase(unittest.TestCase):
'sla': {'max_outage_time': 5}
}
+ def _close_queue(self, instace):
+ time.sleep(0.1)
+ instace._queue.close()
+
def test__basemonitor_start_wait_successful(self):
ins = basemonitor.BaseMonitor(self.monitor_cfg, None, {"nova-api": 10})
+ self.addCleanup(self._close_queue, ins)
ins.start_monitor()
ins.wait_monitor()
def test__basemonitor_all_successful(self):
ins = self.MonitorSimple(self.monitor_cfg, None, {"nova-api": 10})
+ self.addCleanup(self._close_queue, ins)
ins.setup()
ins.run()
ins.verify_SLA()
@@ -100,16 +108,12 @@ class BaseMonitorTestCase(unittest.TestCase):
@mock.patch.object(basemonitor, 'multiprocessing')
def test__basemonitor_func_false(self, mock_multiprocess):
ins = self.MonitorSimple(self.monitor_cfg, None, {"nova-api": 10})
+ self.addCleanup(self._close_queue, ins)
ins.setup()
mock_multiprocess.Event().is_set.return_value = False
ins.run()
ins.verify_SLA()
- # TODO(elfoley): fix this test to not throw an error
def test__basemonitor_getmonitorcls_successfule(self):
- cls = None
- try:
- cls = basemonitor.BaseMonitor.get_monitor_cls(self.monitor_cfg)
- except Exception: # pylint: disable=broad-except
- pass
- self.assertIsNone(cls)
+ with self.assertRaises(RuntimeError):
+ basemonitor.BaseMonitor.get_monitor_cls(self.monitor_cfg)
diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_scenario_general.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_scenario_general.py
index d1172d5a6..cd065c961 100644
--- a/yardstick/tests/unit/benchmark/scenarios/availability/test_scenario_general.py
+++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_scenario_general.py
@@ -11,6 +11,7 @@ import mock
import unittest
from yardstick.benchmark.scenarios.availability import scenario_general
+from yardstick.common import exceptions as y_exc
class ScenarioGeneralTestCase(unittest.TestCase):
@@ -59,6 +60,14 @@ class ScenarioGeneralTestCase(unittest.TestCase):
self.instance.director.verify.return_value = False
self.instance.director.data = {}
ret = {}
- self.assertRaises(AssertionError, self.instance.run, ret)
+ self.assertRaises(y_exc.SLAValidationError, self.instance.run, ret)
+ self.instance.teardown()
+ self.assertEqual(ret['sla_pass'], 0)
+
+ def test_scenario_general_case_service_not_found_fail(self):
+ self.instance.director.verify.return_value = True
+ self.instance.director.data = {"general-attacker": 0}
+ ret = {}
+ self.assertRaises(y_exc.SLAValidationError, self.instance.run, ret)
self.instance.teardown()
self.assertEqual(ret['sla_pass'], 0)
diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_serviceha.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_serviceha.py
index dd656fbd5..cf1e76d7a 100644
--- a/yardstick/tests/unit/benchmark/scenarios/availability/test_serviceha.py
+++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_serviceha.py
@@ -11,6 +11,7 @@ import mock
import unittest
from yardstick.benchmark.scenarios.availability import serviceha
+from yardstick.common import exceptions as y_exc
class ServicehaTestCase(unittest.TestCase):
@@ -71,5 +72,21 @@ class ServicehaTestCase(unittest.TestCase):
mock_monitor.MonitorMgr().verify_SLA.return_value = False
ret = {}
- self.assertRaises(AssertionError, p.run, ret)
+ self.assertRaises(y_exc.SLAValidationError, p.run, ret)
+ self.assertEqual(ret['sla_pass'], 0)
+
+ @mock.patch.object(serviceha, 'baseattacker')
+ @mock.patch.object(serviceha, 'basemonitor')
+ def test__serviceha_run_service_not_found_sla_error(self, mock_monitor,
+ *args):
+ p = serviceha.ServiceHA(self.args, self.ctx)
+
+ p.setup()
+ self.assertTrue(p.setup_done)
+ p.data["kill-process"] = 0
+
+ mock_monitor.MonitorMgr().verify_SLA.return_value = True
+
+ ret = {}
+ self.assertRaises(y_exc.SLAValidationError, p.run, ret)
self.assertEqual(ret['sla_pass'], 0)
diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py
index f24ec24ec..4fadde4dc 100644
--- a/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py
+++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py
@@ -17,6 +17,7 @@ import mock
from oslo_serialization import jsonutils
from yardstick.benchmark.scenarios.compute import cyclictest
+from yardstick.common import exceptions as y_exc
@mock.patch('yardstick.benchmark.scenarios.compute.cyclictest.ssh')
@@ -122,7 +123,7 @@ class CyclictestTestCase(unittest.TestCase):
sample_output = '{"min": 100, "avg": 500, "max": 1000}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, c.run, result)
+ self.assertRaises(y_exc.SLAValidationError, c.run, result)
def test_cyclictest_unsuccessful_sla_avg_latency(self, mock_ssh):
@@ -136,7 +137,7 @@ class CyclictestTestCase(unittest.TestCase):
sample_output = '{"min": 100, "avg": 500, "max": 1000}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, c.run, result)
+ self.assertRaises(y_exc.SLAValidationError, c.run, result)
def test_cyclictest_unsuccessful_sla_max_latency(self, mock_ssh):
@@ -150,7 +151,7 @@ class CyclictestTestCase(unittest.TestCase):
sample_output = '{"min": 100, "avg": 500, "max": 1000}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, c.run, result)
+ self.assertRaises(y_exc.SLAValidationError, c.run, result)
def test_cyclictest_unsuccessful_script_error(self, mock_ssh):
diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py
index 9640ce000..c4ac347f4 100644
--- a/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py
+++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py
@@ -17,6 +17,7 @@ import mock
from oslo_serialization import jsonutils
from yardstick.benchmark.scenarios.compute import lmbench
+from yardstick.common import exceptions as y_exc
# pylint: disable=unused-argument
@@ -144,7 +145,7 @@ class LmbenchTestCase(unittest.TestCase):
sample_output = '[{"latency": 37.5, "size": 0.00049}]'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, l.run, self.result)
+ self.assertRaises(y_exc.SLAValidationError, l.run, self.result)
def test_unsuccessful_bandwidth_run_sla(self, mock_ssh):
@@ -162,7 +163,7 @@ class LmbenchTestCase(unittest.TestCase):
sample_output = '{"size(MB)": 0.262144, "bandwidth(MBps)": 9925.5}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, l.run, self.result)
+ self.assertRaises(y_exc.SLAValidationError, l.run, self.result)
def test_successful_latency_for_cache_run_sla(self, mock_ssh):
diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py
index 03003d01f..02040ca01 100644
--- a/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py
+++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py
@@ -17,6 +17,7 @@ import mock
from oslo_serialization import jsonutils
from yardstick.benchmark.scenarios.compute import qemu_migrate
+from yardstick.common import exceptions as y_exc
@mock.patch('yardstick.benchmark.scenarios.compute.qemu_migrate.ssh')
@@ -116,7 +117,7 @@ class QemuMigrateTestCase(unittest.TestCase):
sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, q.run, result)
+ self.assertRaises(y_exc.SLAValidationError, q.run, result)
def test_qemu_migrate_unsuccessful_sla_downtime(self, mock_ssh):
@@ -129,7 +130,7 @@ class QemuMigrateTestCase(unittest.TestCase):
sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, q.run, result)
+ self.assertRaises(y_exc.SLAValidationError, q.run, result)
def test_qemu_migrate_unsuccessful_sla_setuptime(self, mock_ssh):
@@ -142,7 +143,7 @@ class QemuMigrateTestCase(unittest.TestCase):
sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, q.run, result)
+ self.assertRaises(y_exc.SLAValidationError, q.run, result)
def test_qemu_migrate_unsuccessful_script_error(self, mock_ssh):
diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py
index dcc0e810d..9e055befe 100644
--- a/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py
+++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py
@@ -18,6 +18,7 @@ from oslo_serialization import jsonutils
from yardstick.common import utils
from yardstick.benchmark.scenarios.compute import ramspeed
+from yardstick.common import exceptions as y_exc
@mock.patch('yardstick.benchmark.scenarios.compute.ramspeed.ssh')
@@ -146,7 +147,7 @@ class RamspeedTestCase(unittest.TestCase):
"Block_size(kb)": 16384, "Bandwidth(MBps)": 14128.94}, {"Test_type":\
"INTEGER & WRITING", "Block_size(kb)": 32768, "Bandwidth(MBps)": 8340.85}]}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, r.run, self.result)
+ self.assertRaises(y_exc.SLAValidationError, r.run, self.result)
def test_ramspeed_unsuccessful_script_error(self, mock_ssh):
options = {
@@ -219,7 +220,7 @@ class RamspeedTestCase(unittest.TestCase):
"Bandwidth(MBps)": 1300.27}, {"Test_type": "INTEGER AVERAGE:",\
"Bandwidth(MBps)": 2401.58}]}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, r.run, self.result)
+ self.assertRaises(y_exc.SLAValidationError, r.run, self.result)
def test_ramspeed_unsuccessful_unknown_type_run(self, mock_ssh):
options = {
diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py
index 6339a2dcd..e4a8d6e26 100644
--- a/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py
+++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py
@@ -17,6 +17,7 @@ import mock
from oslo_serialization import jsonutils
from yardstick.benchmark.scenarios.compute import unixbench
+from yardstick.common import exceptions as y_exc
@mock.patch('yardstick.benchmark.scenarios.compute.unixbench.ssh')
@@ -122,7 +123,7 @@ class UnixbenchTestCase(unittest.TestCase):
sample_output = '{"single_score":"200.7","parallel_score":"4395.9"}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, u.run, result)
+ self.assertRaises(y_exc.SLAValidationError, u.run, result)
def test_unixbench_unsuccessful_sla_parallel_score(self, mock_ssh):
@@ -137,7 +138,7 @@ class UnixbenchTestCase(unittest.TestCase):
sample_output = '{"signle_score":"2251.7","parallel_score":"3395.9"}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, u.run, result)
+ self.assertRaises(y_exc.SLAValidationError, u.run, result)
def test_unixbench_unsuccessful_script_error(self, mock_ssh):
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py
index 74144afd5..2190e9337 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py
@@ -19,6 +19,7 @@ from oslo_serialization import jsonutils
from yardstick.common import utils
from yardstick.benchmark.scenarios.networking import iperf3
+from yardstick.common import exceptions as y_exc
@mock.patch('yardstick.benchmark.scenarios.networking.iperf3.ssh')
@@ -118,7 +119,7 @@ class IperfTestCase(unittest.TestCase):
sample_output = self._read_sample_output(self.output_name_tcp)
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
def test_iperf_successful_sla_jitter(self, mock_ssh):
options = {"protocol": "udp", "bandwidth": "20m"}
@@ -152,7 +153,7 @@ class IperfTestCase(unittest.TestCase):
sample_output = self._read_sample_output(self.output_name_udp)
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
def test_iperf_successful_tcp_protocal(self, mock_ssh):
options = {"protocol": "tcp", "nodelay": "yes"}
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py
index 5907562c2..a7abcd98a 100755
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py
@@ -18,6 +18,7 @@ import mock
from oslo_serialization import jsonutils
from yardstick.benchmark.scenarios.networking import netperf
+from yardstick.common import exceptions as y_exc
@mock.patch('yardstick.benchmark.scenarios.networking.netperf.ssh')
@@ -98,7 +99,7 @@ class NetperfTestCase(unittest.TestCase):
sample_output = self._read_sample_output()
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
def test_netperf_unsuccessful_script_error(self, mock_ssh):
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py
index 956a9c078..a577dba59 100755
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py
@@ -19,6 +19,7 @@ import mock
from oslo_serialization import jsonutils
from yardstick.benchmark.scenarios.networking import netperf_node
+from yardstick.common import exceptions as y_exc
@mock.patch('yardstick.benchmark.scenarios.networking.netperf_node.ssh')
@@ -98,7 +99,7 @@ class NetperfNodeTestCase(unittest.TestCase):
sample_output = self._read_sample_output()
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
def test_netperf_node_unsuccessful_script_error(self, mock_ssh):
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py
index 4adfab120..559e0599e 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py
@@ -14,6 +14,7 @@ import mock
import unittest
from yardstick.benchmark.scenarios.networking import ping
+from yardstick.common import exceptions as y_exc
class PingTestCase(unittest.TestCase):
@@ -74,7 +75,7 @@ class PingTestCase(unittest.TestCase):
p = ping.Ping(args, self.ctx)
mock_ssh.SSH.from_node().execute.return_value = (0, '100', '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
@mock.patch('yardstick.benchmark.scenarios.networking.ping.ssh')
def test_ping_unsuccessful_script_error(self, mock_ssh):
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py
index 4662c8537..ad5217a14 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py
@@ -14,6 +14,7 @@ import mock
import unittest
from yardstick.benchmark.scenarios.networking import ping6
+from yardstick.common import exceptions as y_exc
class PingTestCase(unittest.TestCase):
@@ -98,7 +99,7 @@ class PingTestCase(unittest.TestCase):
p = ping6.Ping6(args, self.ctx)
p.client = mock_ssh.SSH.from_node()
mock_ssh.SSH.from_node().execute.side_effect = [(0, 'host1', ''), (0, 100, '')]
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
@mock.patch('yardstick.benchmark.scenarios.networking.ping6.ssh')
def test_ping_unsuccessful_script_error(self, mock_ssh):
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py
index 6aea03aee..4016f5055 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py
@@ -13,6 +13,7 @@ import unittest
from oslo_serialization import jsonutils
from yardstick.benchmark.scenarios.networking import pktgen
+from yardstick.common import exceptions as y_exc
@mock.patch('yardstick.benchmark.scenarios.networking.pktgen.ssh')
@@ -55,11 +56,9 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.number_of_ports = args['options']['number_of_ports']
- mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
-
p._iptables_setup()
- mock_ssh.SSH.from_node().execute.assert_called_with(
+ mock_ssh.SSH.from_node().run.assert_called_with(
"sudo iptables -F; "
"sudo iptables -A INPUT -p udp --dport 1000:%s -j DROP"
% 1010, timeout=60)
@@ -74,8 +73,8 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.number_of_ports = args['options']['number_of_ports']
- mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR')
- self.assertRaises(RuntimeError, p._iptables_setup)
+ mock_ssh.SSH.from_node().run.side_effect = y_exc.SSHError
+ self.assertRaises(y_exc.SSHError, p._iptables_setup)
def test_pktgen_successful_iptables_get_result(self, mock_ssh):
@@ -88,12 +87,14 @@ class PktgenTestCase(unittest.TestCase):
p.number_of_ports = args['options']['number_of_ports']
mock_ssh.SSH.from_node().execute.return_value = (0, '150000', '')
- p._iptables_get_result()
+ result = p._iptables_get_result()
+ expected_result = 150000
+ self.assertEqual(result, expected_result)
mock_ssh.SSH.from_node().execute.assert_called_with(
"sudo iptables -L INPUT -vnx |"
"awk '/dpts:1000:%s/ {{printf \"%%s\", $1}}'"
- % 1010)
+ % 1010, raise_on_error=True)
def test_pktgen_unsuccessful_iptables_get_result(self, mock_ssh):
@@ -106,8 +107,8 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.number_of_ports = args['options']['number_of_ports']
- mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR')
- self.assertRaises(RuntimeError, p._iptables_get_result)
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
+ self.assertRaises(y_exc.SSHError, p._iptables_get_result)
def test_pktgen_successful_no_sla(self, mock_ssh):
@@ -176,7 +177,7 @@ class PktgenTestCase(unittest.TestCase):
sample_output = '{"packets_per_second": 9753, "errors": 0, \
"packets_sent": 149776, "packetsize": 60, "flows": 110}'
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
def test_pktgen_unsuccessful_script_error(self, mock_ssh):
@@ -191,8 +192,8 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.client = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR')
- self.assertRaises(RuntimeError, p.run, result)
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
+ self.assertRaises(y_exc.SSHError, p.run, result)
def test_pktgen_get_vnic_driver_name(self, mock_ssh):
args = {
@@ -213,9 +214,9 @@ class PktgenTestCase(unittest.TestCase):
p = pktgen.Pktgen(args, self.ctx)
p.server = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._get_vnic_driver_name)
+ self.assertRaises(y_exc.SSHError, p._get_vnic_driver_name)
def test_pktgen_get_sriov_queue_number(self, mock_ssh):
args = {
@@ -236,9 +237,9 @@ class PktgenTestCase(unittest.TestCase):
p = pktgen.Pktgen(args, self.ctx)
p.server = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._get_sriov_queue_number)
+ self.assertRaises(y_exc.SSHError, p._get_sriov_queue_number)
def test_pktgen_get_available_queue_number(self, mock_ssh):
args = {
@@ -249,11 +250,11 @@ class PktgenTestCase(unittest.TestCase):
mock_ssh.SSH.from_node().execute.return_value = (0, '4', '')
- p._get_available_queue_number()
+ self.assertEqual(p._get_available_queue_number(), 4)
mock_ssh.SSH.from_node().execute.assert_called_with(
"sudo ethtool -l eth0 | grep Combined | head -1 |"
- "awk '{printf $2}'")
+ "awk '{printf $2}'", raise_on_error=True)
def test_pktgen_unsuccessful_get_available_queue_number(self, mock_ssh):
args = {
@@ -262,9 +263,9 @@ class PktgenTestCase(unittest.TestCase):
p = pktgen.Pktgen(args, self.ctx)
p.server = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._get_available_queue_number)
+ self.assertRaises(y_exc.SSHError, p._get_available_queue_number)
def test_pktgen_get_usable_queue_number(self, mock_ssh):
args = {
@@ -275,11 +276,11 @@ class PktgenTestCase(unittest.TestCase):
mock_ssh.SSH.from_node().execute.return_value = (0, '1', '')
- p._get_usable_queue_number()
+ self.assertEqual(p._get_usable_queue_number(), 1)
mock_ssh.SSH.from_node().execute.assert_called_with(
"sudo ethtool -l eth0 | grep Combined | tail -1 |"
- "awk '{printf $2}'")
+ "awk '{printf $2}'", raise_on_error=True)
def test_pktgen_unsuccessful_get_usable_queue_number(self, mock_ssh):
args = {
@@ -288,9 +289,9 @@ class PktgenTestCase(unittest.TestCase):
p = pktgen.Pktgen(args, self.ctx)
p.server = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._get_usable_queue_number)
+ self.assertRaises(y_exc.SSHError, p._get_usable_queue_number)
def test_pktgen_enable_ovs_multiqueue(self, mock_ssh):
args = {
@@ -332,12 +333,12 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.client = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().run.side_effect = y_exc.SSHError
p._get_usable_queue_number = mock.Mock(return_value=1)
p._get_available_queue_number = mock.Mock(return_value=4)
- self.assertRaises(RuntimeError, p._enable_ovs_multiqueue)
+ self.assertRaises(y_exc.SSHError, p._enable_ovs_multiqueue)
def test_pktgen_setup_irqmapping_ovs(self, mock_ssh):
args = {
@@ -351,7 +352,7 @@ class PktgenTestCase(unittest.TestCase):
p._setup_irqmapping_ovs(4)
- mock_ssh.SSH.from_node().execute.assert_called_with(
+ mock_ssh.SSH.from_node().run.assert_called_with(
"echo 8 | sudo tee /proc/irq/10/smp_affinity")
def test_pktgen_setup_irqmapping_ovs_1q(self, mock_ssh):
@@ -366,7 +367,7 @@ class PktgenTestCase(unittest.TestCase):
p._setup_irqmapping_ovs(1)
- mock_ssh.SSH.from_node().execute.assert_called_with(
+ mock_ssh.SSH.from_node().run.assert_called_with(
"echo 1 | sudo tee /proc/irq/10/smp_affinity")
def test_pktgen_unsuccessful_setup_irqmapping_ovs(self, mock_ssh):
@@ -377,9 +378,9 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.client = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._setup_irqmapping_ovs, 4)
+ self.assertRaises(y_exc.SSHError, p._setup_irqmapping_ovs, 4)
def test_pktgen_unsuccessful_setup_irqmapping_ovs_1q(self, mock_ssh):
args = {
@@ -389,9 +390,9 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.client = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._setup_irqmapping_ovs, 1)
+ self.assertRaises(y_exc.SSHError, p._setup_irqmapping_ovs, 1)
def test_pktgen_setup_irqmapping_sriov(self, mock_ssh):
args = {
@@ -405,7 +406,7 @@ class PktgenTestCase(unittest.TestCase):
p._setup_irqmapping_sriov(2)
- mock_ssh.SSH.from_node().execute.assert_called_with(
+ mock_ssh.SSH.from_node().run.assert_called_with(
"echo 2 | sudo tee /proc/irq/10/smp_affinity")
def test_pktgen_setup_irqmapping_sriov_1q(self, mock_ssh):
@@ -420,7 +421,7 @@ class PktgenTestCase(unittest.TestCase):
p._setup_irqmapping_sriov(1)
- mock_ssh.SSH.from_node().execute.assert_called_with(
+ mock_ssh.SSH.from_node().run.assert_called_with(
"echo 1 | sudo tee /proc/irq/10/smp_affinity")
def test_pktgen_unsuccessful_setup_irqmapping_sriov(self, mock_ssh):
@@ -431,9 +432,9 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.client = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._setup_irqmapping_sriov, 2)
+ self.assertRaises(y_exc.SSHError, p._setup_irqmapping_sriov, 2)
def test_pktgen_unsuccessful_setup_irqmapping_sriov_1q(self, mock_ssh):
args = {
@@ -443,9 +444,9 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.client = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._setup_irqmapping_sriov, 1)
+ self.assertRaises(y_exc.SSHError, p._setup_irqmapping_sriov, 1)
def test_pktgen_is_irqbalance_disabled(self, mock_ssh):
args = {
@@ -456,10 +457,11 @@ class PktgenTestCase(unittest.TestCase):
mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- p._is_irqbalance_disabled()
+ result = p._is_irqbalance_disabled()
+ self.assertFalse(result)
mock_ssh.SSH.from_node().execute.assert_called_with(
- "grep ENABLED /etc/default/irqbalance")
+ "grep ENABLED /etc/default/irqbalance", raise_on_error=True)
def test_pktgen_unsuccessful_is_irqbalance_disabled(self, mock_ssh):
args = {
@@ -468,9 +470,9 @@ class PktgenTestCase(unittest.TestCase):
p = pktgen.Pktgen(args, self.ctx)
p.server = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().execute.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._is_irqbalance_disabled)
+ self.assertRaises(y_exc.SSHError, p._is_irqbalance_disabled)
def test_pktgen_disable_irqbalance(self, mock_ssh):
args = {
@@ -480,11 +482,11 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.client = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
+ mock_ssh.SSH.from_node().run.return_value = (0, '', '')
p._disable_irqbalance()
- mock_ssh.SSH.from_node().execute.assert_called_with(
+ mock_ssh.SSH.from_node().run.assert_called_with(
"sudo service irqbalance disable")
def test_pktgen_unsuccessful_disable_irqbalance(self, mock_ssh):
@@ -495,9 +497,9 @@ class PktgenTestCase(unittest.TestCase):
p.server = mock_ssh.SSH.from_node()
p.client = mock_ssh.SSH.from_node()
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ mock_ssh.SSH.from_node().run.side_effect = y_exc.SSHError
- self.assertRaises(RuntimeError, p._disable_irqbalance)
+ self.assertRaises(y_exc.SSHError, p._disable_irqbalance)
def test_pktgen_multiqueue_setup_ovs(self, mock_ssh):
args = {
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py
index 976087148..bcd417830 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py
@@ -12,6 +12,7 @@ import unittest
import yardstick.common.utils as utils
from yardstick.benchmark.scenarios.networking import pktgen_dpdk
+from yardstick.common import exceptions as y_exc
class PktgenDPDKLatencyTestCase(unittest.TestCase):
@@ -162,9 +163,9 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
sample_output = '100\n110\n112\n130\n149\n150\n90\n150\n200\n162\n'
self.mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
- def test_pktgen_dpdk_unsuccessful_script_error(self):
+ def test_pktgen_dpdk_run_unsuccessful_get_port_mac(self):
args = {
'options': {'packetsize': 60},
@@ -176,3 +177,19 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
self.mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR')
self.assertRaises(RuntimeError, p.run, result)
+
+ def test_pktgen_dpdk_run_unsuccessful_script_error(self):
+ args = {
+ 'options': {'packetsize': 60}
+ }
+
+ p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx)
+
+ self.mock_ssh.SSH.from_node().execute.side_effect = ((0, '', ''),
+ (0, '', ''),
+ (0, '', ''),
+ (0, '', ''),
+ (0, '', ''),
+ y_exc.SSHError)
+ self.assertRaises(y_exc.SSHError, p.run, {})
+ self.assertEqual(self.mock_ssh.SSH.from_node().execute.call_count, 6)
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py
index e90fb07c7..39392e4bb 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py
@@ -16,6 +16,7 @@ from oslo_serialization import jsonutils
import mock
from yardstick.benchmark.scenarios.networking import pktgen_dpdk_throughput
+from yardstick.common import exceptions as y_exc
# pylint: disable=unused-argument
@@ -131,7 +132,7 @@ class PktgenDPDKTestCase(unittest.TestCase):
sample_output = '{"packets_per_second": 9753, "errors": 0, \
"packets_sent": 149776, "flows": 110}'
mock_ssh.SSH().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
def test_pktgen_dpdk_throughput_unsuccessful_script_error(
self, mock_ssh):
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py
index 9bfbf0752..bb1a7aaca 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py
@@ -20,11 +20,11 @@ import mock
import unittest
from yardstick import tests
+from yardstick.common import exceptions
from yardstick.common import utils
from yardstick.network_services.collector.subscriber import Collector
from yardstick.network_services.traffic_profile import base
from yardstick.network_services.vnf_generic import vnfdgen
-from yardstick.error import IncorrectConfig
from yardstick.network_services.vnf_generic.vnf.base import GenericTrafficGen
from yardstick.network_services.vnf_generic.vnf.base import GenericVNF
@@ -423,7 +423,7 @@ class TestNetworkServiceTestCase(unittest.TestCase):
with mock.patch.dict(sys.modules, tests.STL_MOCKS):
self.assertIsNotNone(self.s.get_vnf_impl(vnfd))
- with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
+ with self.assertRaises(exceptions.IncorrectConfig) as raised:
self.s.get_vnf_impl('NonExistentClass')
exc_str = str(raised.exception)
@@ -465,7 +465,7 @@ class TestNetworkServiceTestCase(unittest.TestCase):
cfg_patch = mock.patch.object(self.s, 'context_cfg', cfg)
with cfg_patch:
- with self.assertRaises(IncorrectConfig):
+ with self.assertRaises(exceptions.IncorrectConfig):
self.s.map_topology_to_infrastructure()
def test_map_topology_to_infrastructure_config_invalid(self):
@@ -482,7 +482,7 @@ class TestNetworkServiceTestCase(unittest.TestCase):
config_patch = mock.patch.object(self.s, 'context_cfg', cfg)
with config_patch:
- with self.assertRaises(IncorrectConfig):
+ with self.assertRaises(exceptions.IncorrectConfig):
self.s.map_topology_to_infrastructure()
def test__resolve_topology_invalid_config(self):
@@ -496,7 +496,7 @@ class TestNetworkServiceTestCase(unittest.TestCase):
for interface in self.tg__1['interfaces'].values():
del interface['local_mac']
- with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
+ with self.assertRaises(exceptions.IncorrectConfig) as raised:
self.s._resolve_topology()
self.assertIn('not found', str(raised.exception))
@@ -509,7 +509,7 @@ class TestNetworkServiceTestCase(unittest.TestCase):
self.s.topology["vld"][0]['vnfd-connection-point-ref'].append(
self.s.topology["vld"][0]['vnfd-connection-point-ref'][0])
- with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
+ with self.assertRaises(exceptions.IncorrectConfig) as raised:
self.s._resolve_topology()
self.assertIn('wrong endpoint count', str(raised.exception))
@@ -518,7 +518,7 @@ class TestNetworkServiceTestCase(unittest.TestCase):
self.s.topology["vld"][0]['vnfd-connection-point-ref'] = \
self.s.topology["vld"][0]['vnfd-connection-point-ref'][:1]
- with self.assertRaises(vnf_generic.IncorrectConfig) as raised:
+ with self.assertRaises(exceptions.IncorrectConfig) as raised:
self.s._resolve_topology()
self.assertIn('wrong endpoint count', str(raised.exception))
@@ -628,7 +628,8 @@ class TestNetworkServiceTestCase(unittest.TestCase):
'extra_args': {'arg1': 'value1', 'arg2': 'value2'},
'flow': {'flow': {}},
'imix': {'imix': {'64B': 100}},
- 'uplink': {}}
+ 'uplink': {},
+ 'duration': 30}
)
mock_tprofile_get.assert_called_once_with(fake_vnfd)
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py
index 419605b26..a606543e5 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py
@@ -12,31 +12,26 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Unittest for yardstick.benchmark.scenarios.networking.vsperf.Vsperf
-
-from __future__ import absolute_import
-try:
- from unittest import mock
-except ImportError:
- import mock
+import mock
import unittest
+import subprocess
+import yardstick.ssh as ssh
from yardstick.benchmark.scenarios.networking import vsperf
+from yardstick import exceptions as y_exc
-@mock.patch('yardstick.benchmark.scenarios.networking.vsperf.subprocess')
-@mock.patch('yardstick.benchmark.scenarios.networking.vsperf.ssh')
class VsperfTestCase(unittest.TestCase):
def setUp(self):
- self.ctx = {
+ self.context_cfg = {
"host": {
"ip": "10.229.47.137",
"user": "ubuntu",
"password": "ubuntu",
},
}
- self.args = {
+ self.scenario_cfg = {
'options': {
'testname': 'p2p_rfc2544_continuous',
'traffic_type': 'continuous',
@@ -57,70 +52,154 @@ class VsperfTestCase(unittest.TestCase):
}
}
- def test_vsperf_setup(self, mock_ssh, mock_subprocess):
- p = vsperf.Vsperf(self.args, self.ctx)
- mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- mock_subprocess.call().execute.return_value = None
+ self._mock_SSH = mock.patch.object(ssh, 'SSH')
+ self.mock_SSH = self._mock_SSH.start()
+ self.mock_SSH.from_node().execute.return_value = (0, '', '')
+
+ self._mock_subprocess_call = mock.patch.object(subprocess, 'call')
+ self.mock_subprocess_call = self._mock_subprocess_call.start()
+ self.mock_subprocess_call.return_value = None
+
+ self.addCleanup(self._stop_mock)
+
+ self.scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg)
+
+ def _stop_mock(self):
+ self._mock_SSH.stop()
+ self._mock_subprocess_call.stop()
+
+ def test_setup(self):
+ self.scenario.setup()
+ self.assertIsNotNone(self.scenario.client)
+ self.assertTrue(self.scenario.setup_done)
+
+ def test_setup_tg_port_not_set(self):
+ del self.scenario_cfg['options']['trafficgen_port1']
+ del self.scenario_cfg['options']['trafficgen_port2']
+ scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg)
+ scenario.setup()
+
+ self.mock_subprocess_call.assert_called_once_with(
+ 'setup_yardstick.sh setup', shell=True)
+ self.assertIsNone(scenario.tg_port1)
+ self.assertIsNone(scenario.tg_port2)
+ self.assertIsNotNone(scenario.client)
+ self.assertTrue(scenario.setup_done)
+
+ def test_setup_no_setup_script(self):
+ del self.scenario_cfg['options']['setup_script']
+ scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg)
+ scenario.setup()
+
+ self.mock_subprocess_call.assert_has_calls(
+ (mock.call('sudo bash -c "ovs-vsctl add-port br-ex eth1"',
+ shell=True),
+ mock.call('sudo bash -c "ovs-vsctl add-port br-ex eth3"',
+ shell=True)))
+ self.assertEqual(2, self.mock_subprocess_call.call_count)
+ self.assertIsNone(scenario.setup_script)
+ self.assertIsNotNone(scenario.client)
+ self.assertTrue(scenario.setup_done)
+
+ def test_run_ok(self):
+ self.scenario.setup()
+
+ self.mock_SSH.from_node().execute.return_value = (
+ 0, 'throughput_rx_fps\r\n14797660.000\r\n', '')
- p.setup()
- self.assertIsNotNone(p.client)
- self.assertTrue(p.setup_done)
+ result = {}
+ self.scenario.run(result)
- def test_vsperf_teardown(self, mock_ssh, mock_subprocess):
- p = vsperf.Vsperf(self.args, self.ctx)
+ self.assertEqual(result['throughput_rx_fps'], '14797660.000')
- # setup() specific mocks
- mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- mock_subprocess.call().execute.return_value = None
+ def test_run_ok_setup_not_done(self):
+ self.mock_SSH.from_node().execute.return_value = (
+ 0, 'throughput_rx_fps\r\n14797660.000\r\n', '')
- p.setup()
- self.assertIsNotNone(p.client)
- self.assertTrue(p.setup_done)
+ result = {}
+ self.scenario.run(result)
- p.teardown()
- self.assertFalse(p.setup_done)
+ self.assertTrue(self.scenario.setup_done)
+ self.assertEqual(result['throughput_rx_fps'], '14797660.000')
- def test_vsperf_run_ok(self, mock_ssh, mock_subprocess):
- p = vsperf.Vsperf(self.args, self.ctx)
+ def test_run_failed_vsperf_execution(self):
+ self.mock_SSH.from_node().execute.side_effect = ((0, '', ''),
+ (1, '', ''))
- # setup() specific mocks
- mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- mock_subprocess.call().execute.return_value = None
+ with self.assertRaises(RuntimeError):
+ self.scenario.run({})
+ self.assertEqual(self.mock_SSH.from_node().execute.call_count, 2)
- # run() specific mocks
- mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- mock_ssh.SSH.from_node().execute.return_value = (
- 0, 'throughput_rx_fps\r\n14797660.000\r\n', '')
+ def test_run_failed_csv_report(self):
+ self.mock_SSH.from_node().execute.side_effect = ((0, '', ''),
+ (0, '', ''),
+ (1, '', ''))
- result = {}
- p.run(result)
+ with self.assertRaises(RuntimeError):
+ self.scenario.run({})
+ self.assertEqual(self.mock_SSH.from_node().execute.call_count, 3)
- self.assertEqual(result['throughput_rx_fps'], '14797660.000')
+ def test_run_sla_fail(self):
+ self.mock_SSH.from_node().execute.return_value = (
+ 0, 'throughput_rx_fps\r\n123456.000\r\n', '')
- def test_vsperf_run_falied_vsperf_execution(self, mock_ssh,
- mock_subprocess):
- p = vsperf.Vsperf(self.args, self.ctx)
+ with self.assertRaises(y_exc.SLAValidationError) as raised:
+ self.scenario.run({})
- # setup() specific mocks
- mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- mock_subprocess.call().execute.return_value = None
+ self.assertTrue('VSPERF_throughput_rx_fps(123456.000000) < '
+ 'SLA_throughput_rx_fps(500000.000000)'
+ in str(raised.exception))
- # run() specific mocks
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ def test_run_sla_fail_metric_not_collected(self):
+ self.mock_SSH.from_node().execute.return_value = (
+ 0, 'nonexisting_metric\r\n14797660.000\r\n', '')
- result = {}
- self.assertRaises(RuntimeError, p.run, result)
+ with self.assertRaises(y_exc.SLAValidationError) as raised:
+ self.scenario.run({})
- def test_vsperf_run_falied_csv_report(self, mock_ssh, mock_subprocess):
- p = vsperf.Vsperf(self.args, self.ctx)
+ self.assertTrue('throughput_rx_fps was not collected by VSPERF'
+ in str(raised.exception))
- # setup() specific mocks
- mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- mock_subprocess.call().execute.return_value = None
+ def test_run_sla_fail_metric_not_defined_in_sla(self):
+ del self.scenario_cfg['sla']['throughput_rx_fps']
+ scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg)
+ scenario.setup()
- # run() specific mocks
- mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ self.mock_SSH.from_node().execute.return_value = (
+ 0, 'throughput_rx_fps\r\n14797660.000\r\n', '')
- result = {}
- self.assertRaises(RuntimeError, p.run, result)
+ with self.assertRaises(y_exc.SLAValidationError) as raised:
+ scenario.run({})
+ self.assertTrue('throughput_rx_fps is not defined in SLA'
+ in str(raised.exception))
+
+ def test_teardown(self):
+ self.scenario.setup()
+ self.assertIsNotNone(self.scenario.client)
+ self.assertTrue(self.scenario.setup_done)
+
+ self.scenario.teardown()
+ self.assertFalse(self.scenario.setup_done)
+
+ def test_teardown_tg_port_not_set(self):
+ del self.scenario_cfg['options']['trafficgen_port1']
+ del self.scenario_cfg['options']['trafficgen_port2']
+ scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg)
+ scenario.teardown()
+
+ self.mock_subprocess_call.assert_called_once_with(
+ 'setup_yardstick.sh teardown', shell=True)
+ self.assertFalse(scenario.setup_done)
+
+ def test_teardown_no_setup_script(self):
+ del self.scenario_cfg['options']['setup_script']
+ scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg)
+ scenario.teardown()
+
+ self.mock_subprocess_call.assert_has_calls(
+ (mock.call('sudo bash -c "ovs-vsctl del-port br-ex eth1"',
+ shell=True),
+ mock.call('sudo bash -c "ovs-vsctl del-port br-ex eth3"',
+ shell=True)))
+ self.assertEqual(2, self.mock_subprocess_call.call_count)
+ self.assertFalse(scenario.setup_done)
diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py
index 1d2278e21..c05d2ced2 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py
@@ -19,6 +19,7 @@ import mock
import unittest
from yardstick.benchmark.scenarios.networking import vsperf_dpdk
+from yardstick import exceptions as y_exc
class VsperfDPDKTestCase(unittest.TestCase):
@@ -211,3 +212,47 @@ class VsperfDPDKTestCase(unittest.TestCase):
result = {}
self.assertRaises(RuntimeError, self.scenario.run, result)
+
+ @mock.patch.object(time, 'sleep')
+ @mock.patch.object(subprocess, 'check_output')
+ def test_vsperf_run_sla_fail(self, *args):
+ self.scenario.setup()
+
+ self.mock_ssh.SSH.from_node().execute.return_value = (
+ 0, 'throughput_rx_fps\r\n123456.000\r\n', '')
+
+ with self.assertRaises(y_exc.SLAValidationError) as raised:
+ self.scenario.run({})
+
+ self.assertIn('VSPERF_throughput_rx_fps(123456.000000) < '
+ 'SLA_throughput_rx_fps(500000.000000)',
+ str(raised.exception))
+
+ @mock.patch.object(time, 'sleep')
+ @mock.patch.object(subprocess, 'check_output')
+ def test_vsperf_run_sla_fail_metric_not_collected(self, *args):
+ self.scenario.setup()
+
+ self.mock_ssh.SSH.from_node().execute.return_value = (
+ 0, 'nonexisting_metric\r\n123456.000\r\n', '')
+
+ with self.assertRaises(y_exc.SLAValidationError) as raised:
+ self.scenario.run({})
+
+ self.assertIn('throughput_rx_fps was not collected by VSPERF',
+ str(raised.exception))
+
+ @mock.patch.object(time, 'sleep')
+ @mock.patch.object(subprocess, 'check_output')
+ def test_vsperf_run_sla_fail_sla_not_defined(self, *args):
+ del self.scenario.scenario_cfg['sla']['throughput_rx_fps']
+ self.scenario.setup()
+
+ self.mock_ssh.SSH.from_node().execute.return_value = (
+ 0, 'throughput_rx_fps\r\n14797660.000\r\n', '')
+
+ with self.assertRaises(y_exc.SLAValidationError) as raised:
+ self.scenario.run({})
+
+ self.assertIn('throughput_rx_fps is not defined in SLA',
+ str(raised.exception))
diff --git a/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py b/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py
index f149cee69..6e69ddc6d 100644
--- a/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py
+++ b/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py
@@ -18,6 +18,7 @@ import mock
from oslo_serialization import jsonutils
from yardstick.benchmark.scenarios.storage import fio
+from yardstick.common import exceptions as y_exc
@mock.patch('yardstick.benchmark.scenarios.storage.fio.ssh')
@@ -203,7 +204,7 @@ class FioTestCase(unittest.TestCase):
sample_output = self._read_sample_output(self.sample_output['rw'])
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
def test_fio_successful_bw_iops_sla(self, mock_ssh):
@@ -252,7 +253,7 @@ class FioTestCase(unittest.TestCase):
sample_output = self._read_sample_output(self.sample_output['rw'])
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
- self.assertRaises(AssertionError, p.run, result)
+ self.assertRaises(y_exc.SLAValidationError, p.run, result)
def test_fio_unsuccessful_script_error(self, mock_ssh):
diff --git a/yardstick/tests/unit/common/test_exceptions.py b/yardstick/tests/unit/common/test_exceptions.py
new file mode 100644
index 000000000..884015536
--- /dev/null
+++ b/yardstick/tests/unit/common/test_exceptions.py
@@ -0,0 +1,28 @@
+# Copyright 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 yardstick.common import exceptions
+from yardstick.tests.unit import base as ut_base
+
+
+class ErrorClassTestCase(ut_base.BaseUnitTestCase):
+
+ def test_init(self):
+ with self.assertRaises(RuntimeError):
+ exceptions.ErrorClass()
+
+ def test_getattr(self):
+ error_instance = exceptions.ErrorClass(test='')
+ with self.assertRaises(AttributeError):
+ error_instance.get_name()
diff --git a/yardstick/tests/unit/common/test_utils.py b/yardstick/tests/unit/common/test_utils.py
index 826c55e7a..6e7a0bfc4 100644
--- a/yardstick/tests/unit/common/test_utils.py
+++ b/yardstick/tests/unit/common/test_utils.py
@@ -20,7 +20,6 @@ import time
import unittest
from yardstick import ssh
-import yardstick.error
from yardstick.common import constants
from yardstick.common import utils
from yardstick.common import exceptions
@@ -1068,14 +1067,6 @@ class TestUtils(ut_base.BaseUnitTestCase):
with self.assertRaises(RuntimeError):
utils.validate_non_string_sequence(1, raise_exc=RuntimeError)
- def test_error_class(self):
- with self.assertRaises(RuntimeError):
- yardstick.error.ErrorClass()
-
- error_instance = yardstick.error.ErrorClass(test='')
- with self.assertRaises(AttributeError):
- error_instance.get_name()
-
class TestUtilsIpAddrMethods(ut_base.BaseUnitTestCase):
@@ -1259,6 +1250,17 @@ class TimerTestCase(ut_base.BaseUnitTestCase):
with utils.Timer(timeout=1):
time.sleep(2)
+ def test__enter_with_timeout_no_exception(self):
+ with utils.Timer(timeout=1, raise_exception=False):
+ time.sleep(2)
+
+ def test__iter(self):
+ iterations = []
+ for i in utils.Timer(timeout=2):
+ iterations.append(i)
+ time.sleep(1.1)
+ self.assertEqual(2, len(iterations))
+
class WaitUntilTrueTestCase(ut_base.BaseUnitTestCase):
diff --git a/yardstick/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py b/yardstick/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py
index 367072e84..e19311613 100644
--- a/yardstick/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py
+++ b/yardstick/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py
@@ -17,9 +17,7 @@ import unittest
import os
-from yardstick.error import IncorrectConfig, SSHError
-from yardstick.error import IncorrectNodeSetup
-from yardstick.error import IncorrectSetup
+from yardstick.common import exceptions
from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkInterface
from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkNode
from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper
@@ -142,12 +140,13 @@ class TestDpdkInterface(unittest.TestCase):
def test_probe_missing_values_negative(self):
mock_dpdk_node = mock.Mock()
- mock_dpdk_node.netdevs.values.side_effect = IncorrectNodeSetup
+ mock_dpdk_node.netdevs.values.side_effect = (
+ exceptions.IncorrectNodeSetup(error_msg=''))
interface = {'local_mac': '0a:de:ad:be:ef:f5'}
dpdk_intf = DpdkInterface(mock_dpdk_node, interface)
- with self.assertRaises(IncorrectConfig):
+ with self.assertRaises(exceptions.IncorrectConfig):
dpdk_intf.probe_missing_values()
@@ -213,7 +212,7 @@ class TestDpdkNode(unittest.TestCase):
def test_check(self):
def update():
if not mock_force_rebind.called:
- raise IncorrectConfig
+ raise exceptions.IncorrectConfig(error_msg='')
interfaces[0]['virtual-interface'].update({
'vpci': '0000:01:02.1',
@@ -244,11 +243,11 @@ class TestDpdkNode(unittest.TestCase):
mock_ssh_helper = mock.Mock()
mock_ssh_helper.execute.return_value = 0, '', ''
- mock_intf_type().check.side_effect = SSHError
+ mock_intf_type().check.side_effect = exceptions.SSHError
dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper)
- with self.assertRaises(IncorrectSetup):
+ with self.assertRaises(exceptions.IncorrectSetup):
dpdk_node.check()
def test_probe_netdevs(self):
@@ -290,7 +289,7 @@ class TestDpdkNode(unittest.TestCase):
dpdk_helper.force_dpdk_rebind = mock_helper_func = mock.Mock()
dpdk_node._force_rebind()
- self.assertEqual(mock_helper_func.call_count, 1)
+ mock_helper_func.assert_called_once()
class TestDpdkBindHelper(unittest.TestCase):
diff --git a/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py b/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py
index 6d5e1da60..e66e7fbb8 100644
--- a/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py
+++ b/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py
@@ -223,7 +223,7 @@ class TestMultiPortConfig(unittest.TestCase):
mock.Mock(return_value={'link_config': 0, 'arp_config': '',
'arp_config6': '', 'actions': '',
'arp_route_tbl': '', 'arp_route_tbl6': '',
- 'rules': ''})
+ 'flows': ''})
opnfv_vnf.port_pair_list = [("xe0", "xe1")]
self.assertIsNotNone(opnfv_vnf.generate_script(self.VNFD))
opnfv_vnf.lb_config = 'HW'
@@ -249,66 +249,6 @@ class TestMultiPortConfig(unittest.TestCase):
opnfv_vnf.generate_rule_config = mock.Mock()
self.assertIsNotNone(opnfv_vnf.generate_script_data())
- def test_generate_rule_config(self):
- topology_file = mock.Mock()
- config_tpl = mock.Mock()
- tmp_file = mock.Mock()
- vnfd_mock = mock.MagicMock()
- opnfv_vnf = samplevnf_helper.MultiPortConfig(
- topology_file, config_tpl, tmp_file, vnfd_mock)
- opnfv_vnf.get_config_tpl_data = mock.MagicMock()
- opnfv_vnf.socket = 0
- opnfv_vnf.start_core = 0
- opnfv_vnf.update_write_parser = mock.MagicMock()
- opnfv_vnf.generate_script_data = \
- mock.Mock(return_value={'link_config': 0, 'arp_config': '',
- 'arp_config6': '', 'actions': '',
- 'rules': ''})
- opnfv_vnf.port_pair_list = [("xe0", "xe1")]
- opnfv_vnf.get_port_pairs = mock.Mock()
- opnfv_vnf.vnf_type = 'ACL'
- opnfv_vnf.get_ports_gateway = mock.Mock(return_value=u'1.1.1.1')
- opnfv_vnf.get_netmask_gateway = mock.Mock(
- return_value=u'255.255.255.0')
- opnfv_vnf.get_ports_gateway6 = mock.Mock(return_value=u'1.1.1.1')
- opnfv_vnf.get_netmask_gateway6 = mock.Mock(
- return_value=u'255.255.255.0')
- opnfv_vnf.txrx_pipeline = ''
- opnfv_vnf.vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
- opnfv_vnf.interfaces = opnfv_vnf.vnfd['vdu'][0]['external-interface']
- opnfv_vnf.rules = ''
- self.assertIsNotNone(opnfv_vnf.generate_rule_config())
- opnfv_vnf.rules = 'new'
- self.assertIsNotNone(opnfv_vnf.generate_rule_config())
-
- def test_generate_action_config(self):
- topology_file = mock.Mock()
- config_tpl = mock.Mock()
- tmp_file = mock.Mock()
- vnfd_mock = mock.MagicMock()
- opnfv_vnf = samplevnf_helper.MultiPortConfig(
- topology_file, config_tpl, tmp_file, vnfd_mock)
- opnfv_vnf.get_config_tpl_data = mock.MagicMock()
- opnfv_vnf.socket = 0
- opnfv_vnf.start_core = 0
- opnfv_vnf.update_write_parser = mock.MagicMock()
- opnfv_vnf.generate_script_data = \
- mock.Mock(return_value={'link_config': 0, 'arp_config': '',
- 'arp_config6': '', 'actions': '',
- 'rules': ''})
- opnfv_vnf.port_pair_list = [("xe0", "xe1")]
- opnfv_vnf.get_port_pairs = mock.Mock()
- opnfv_vnf.vnf_type = 'VFW'
- opnfv_vnf.get_ports_gateway = mock.Mock(return_value=u'1.1.1.1')
- opnfv_vnf.get_netmask_gateway = mock.Mock(
- return_value=u'255.255.255.0')
- opnfv_vnf.get_ports_gateway6 = mock.Mock(return_value=u'1.1.1.1')
- opnfv_vnf.get_netmask_gateway6 = mock.Mock(
- return_value=u'255.255.255.0')
- opnfv_vnf.txrx_pipeline = ''
- opnfv_vnf.rules = ''
- self.assertIsNotNone(opnfv_vnf.generate_action_config())
-
def test_generate_arp_config6(self):
topology_file = mock.Mock()
config_tpl = mock.Mock()
diff --git a/yardstick/tests/unit/network_services/libs/ixia_libs/test_IxNet.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_IxNet.py
deleted file mode 100644
index 7ca2f0f19..000000000
--- a/yardstick/tests/unit/network_services/libs/ixia_libs/test_IxNet.py
+++ /dev/null
@@ -1,874 +0,0 @@
-# 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 IxNetwork
-import unittest
-
-from yardstick.network_services.libs.ixia_libs.IxNet.IxNet import IxNextgen
-from yardstick.network_services.libs.ixia_libs.IxNet.IxNet import IP_VERSION_4
-from yardstick.network_services.libs.ixia_libs.IxNet.IxNet import IP_VERSION_6
-
-UPLINK = "uplink"
-DOWNLINK = "downlink"
-
-
-class TestIxNextgen(unittest.TestCase):
-
- def test___init__(self):
- ixnet_gen = IxNextgen()
- self.assertIsNone(ixnet_gen._bidir)
-
- @mock.patch.object(IxNetwork, 'IxNet')
- def test_connect(self, mock_ixnet):
- ixnet_instance = mock.Mock()
- mock_ixnet.return_value = ixnet_instance
- ixnet_gen = IxNextgen()
- with mock.patch.object(ixnet_gen, 'get_config') as mock_config:
- mock_config.return_value = {'machine': 'machine_fake',
- 'port': 'port_fake',
- 'version': 12345}
- ixnet_gen._connect(mock.ANY)
-
- ixnet_instance.connect.assert_called_once_with(
- 'machine_fake', '-port', 'port_fake', '-version', '12345')
- mock_config.assert_called_once()
-
- def test_clear_ixia_config(self):
- ixnet = mock.MagicMock()
- ixnet.execute = mock.Mock()
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.clear_ixia_config()
- self.assertIsNone(result)
- self.assertEqual(ixnet.execute.call_count, 1)
-
- def test_load_ixia_profile(self):
- ixnet = mock.MagicMock()
- ixnet.execute = mock.Mock()
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.load_ixia_profile({})
- self.assertIsNone(result)
- self.assertEqual(ixnet.execute.call_count, 1)
-
- def test_load_ixia_config(self):
- ixnet = mock.MagicMock()
- ixnet.execute = mock.Mock()
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.ix_load_config({})
- self.assertIsNone(result)
- self.assertEqual(ixnet.execute.call_count, 2)
-
- @mock.patch('yardstick.network_services.libs.ixia_libs.IxNet.IxNet.log')
- def test_ix_assign_ports(self, mock_logger):
- ixnet = mock.MagicMock()
- ixnet.getList.return_value = [0, 1]
- ixnet.getAttribute.side_effect = ['up', 'down']
-
- config = {
- 'chassis': '1.1.1.1',
- 'cards': ['1', '2'],
- 'ports': ['2', '2'],
- }
-
- ixnet_gen = IxNextgen(ixnet)
- ixnet_gen._cfg = config
-
- result = ixnet_gen.ix_assign_ports()
- self.assertIsNone(result)
- self.assertEqual(ixnet.execute.call_count, 1)
- self.assertEqual(ixnet.commit.call_count, 1)
- self.assertEqual(ixnet.getAttribute.call_count, 2)
- self.assertEqual(mock_logger.error.call_count, 1)
-
- def test_ix_update_frame(self):
- static_traffic_params = {
- UPLINK: {
- "id": 1,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:03",
- "framesPerSecond": True,
- "framesize": {
- "64B": "100",
- "1KB": "0",
- },
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l3v4": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "2001",
- "srcport": "1234"
- },
- "traffic_type": "continuous"
- },
- DOWNLINK: {
- "id": 2,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:04",
- "framesPerSecond": False,
- "framesize": {"64B": "100"},
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v4": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "1234",
- "srcport": "2001"
- },
- "traffic_type": "continuous"
- }
- }
-
- ixnet = mock.MagicMock()
- ixnet.remapIds.return_value = ["0"]
- ixnet.setMultiAttribute.return_value = [1]
- ixnet.commit.return_value = [1]
- ixnet.getList.side_effect = [
- [1],
- [1],
- [1],
- [
- "ethernet.header.destinationAddress",
- "ethernet.header.sourceAddress",
- ],
- ]
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.ix_update_frame(static_traffic_params)
- self.assertIsNone(result)
- self.assertEqual(ixnet.setMultiAttribute.call_count, 7)
- self.assertEqual(ixnet.commit.call_count, 2)
-
- def test_ix_update_udp(self):
- ixnet = mock.MagicMock()
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.ix_update_udp({})
- self.assertIsNone(result)
-
- def test_ix_update_tcp(self):
- ixnet = mock.MagicMock()
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.ix_update_tcp({})
- self.assertIsNone(result)
-
- def test_ix_start_traffic(self):
- ixnet = mock.MagicMock()
- ixnet.getList.return_value = [0]
- ixnet.getAttribute.return_value = 'down'
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.ix_start_traffic()
- self.assertIsNone(result)
- self.assertEqual(ixnet.getList.call_count, 1)
- self.assertEqual(ixnet.execute.call_count, 3)
-
- def test_ix_stop_traffic(self):
- ixnet = mock.MagicMock()
- ixnet.getList.return_value = [0]
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.ix_stop_traffic()
- self.assertIsNone(result)
- self.assertEqual(ixnet.getList.call_count, 1)
- self.assertEqual(ixnet.execute.call_count, 1)
-
- def test_ix_get_statistics(self):
- ixnet = mock.MagicMock()
- ixnet.execute.return_value = ""
- ixnet.getList.side_effect = [
- [
- '::ixNet::OBJ-/statistics/view:"Traffic Item Statistics"',
- '::ixNet::OBJ-/statistics/view:"Port Statistics"',
- ],
- [
- '::ixNet::OBJ-/statistics/view:"Flow Statistics"',
- ],
- ]
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.ix_get_statistics()
- self.assertIsNotNone(result)
- self.assertEqual(ixnet.getList.call_count, 1)
- self.assertEqual(ixnet.execute.call_count, 20)
-
- def test_find_view_obj_no_where(self):
- views = ['here', 'there', 'everywhere']
- result = IxNextgen.find_view_obj('no_where', views)
- self.assertEqual(result, '')
-
- def test_add_ip_header_v4(self):
- static_traffic_params = {
- "uplink_0": {
- "id": 1,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:03",
- "framesPerSecond": True,
- "framesize": {"64B": "100"},
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "count": 1024,
- "ttl": 32
- },
- "outer_l3v4": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "2001",
- "srcport": "1234"
- },
- "traffic_type": "continuous"
- },
- "downlink_0": {
- "id": 2,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:04",
- "framesPerSecond": True,
- "framesize": {"64B": "100"},
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v4": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "1234",
- "srcport": "2001"
- },
- "traffic_type": "continuous"
- }
- }
-
- ixnet = mock.MagicMock()
- ixnet.remapIds.return_value = ["0"]
- ixnet.setMultiAttribute.return_value = [1]
- ixnet.commit.return_value = [1]
- ixnet.getList.side_effect = [[1], [0], [0], ["srcIp", "dstIp"]]
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.add_ip_header(static_traffic_params, IP_VERSION_4)
- self.assertIsNone(result)
- self.assertGreater(ixnet.setMultiAttribute.call_count, 0)
- self.assertEqual(ixnet.commit.call_count, 1)
-
- def test_add_ip_header_v4_nothing_to_do(self):
- static_traffic_params = {
- "uplink_0": {
- "id": 1,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:03",
- "framesPerSecond": True,
- "framesize": {"64B": "100"},
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "count": 1024,
- "ttl": 32
- },
- "outer_l3v4": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "2001",
- "srcport": "1234"
- },
- "traffic_type": "continuous"
- },
- "downlink_0": {
- "id": 2,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:04",
- "framesPerSecond": True,
- "framesize": {"64B": "100"},
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v4": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "1234",
- "srcport": "2001"
- },
- "traffic_type": "continuous"
- }
- }
-
- ixnet = mock.MagicMock()
- ixnet.remapIds.return_value = ["0"]
- ixnet.setMultiAttribute.return_value = [1]
- ixnet.commit.return_value = [1]
- ixnet.getList.side_effect = [[1], [0, 1], [0], ["srcIp", "dstIp"]]
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.add_ip_header(static_traffic_params, IP_VERSION_4)
- self.assertIsNone(result)
- self.assertGreater(ixnet.setMultiAttribute.call_count, 0)
- self.assertEqual(ixnet.commit.call_count, 1)
-
- def test_add_ip_header_v6(self):
- static_traffic_profile = {
- "uplink_0": {
- "id": 1,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:03",
- "framesPerSecond": True,
- "framesize": {"64B": "100"},
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "2001",
- "srcport": "1234"
- },
- "traffic_type": "continuous"
- },
- "downlink_0": {
- "id": 2,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:04",
- "framesPerSecond": True,
- "framesize": {"64B": "100"},
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "1234",
- "srcport": "2001"
- },
- "traffic_type": "continuous"
- }
- }
-
- ixnet = mock.MagicMock()
- ixnet.getList.side_effect = [[1], [1], [1], ["srcIp", "dstIp"]]
- ixnet.remapIds.return_value = ["0"]
- ixnet.setMultiAttribute.return_value = [1]
- ixnet.commit.return_value = [1]
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.add_ip_header(static_traffic_profile, IP_VERSION_6)
- self.assertIsNone(result)
- self.assertGreater(ixnet.setMultiAttribute.call_count, 0)
- self.assertEqual(ixnet.commit.call_count, 1)
-
- def test_add_ip_header_v6_nothing_to_do(self):
- static_traffic_params = {
- "uplink_0": {
- "id": 1,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:03",
- "framesPerSecond": True,
- "framesize": {"64B": "100"},
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "count": 1024,
- "ttl": 32
- },
- "outer_l3v6": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "2001",
- "srcport": "1234"
- },
- "traffic_type": "continuous"
- },
- "downlink_0": {
- "id": 2,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:04",
- "framesPerSecond": True,
- "framesize": {"64B": "100"},
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "1234",
- "srcport": "2001"
- },
- "traffic_type": "continuous"
- }
- }
-
- ixnet = mock.MagicMock()
- ixnet.getList.side_effect = [[1], [0, 1], [1], ["srcIP", "dstIP"]]
- ixnet.remapIds.return_value = ["0"]
- ixnet.setMultiAttribute.return_value = [1]
- ixnet.commit.return_value = [1]
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.add_ip_header(static_traffic_params, IP_VERSION_6)
- self.assertIsNone(result)
- self.assertEqual(ixnet.setMultiAttribute.call_count, 0)
-
- def test_set_random_ip_multi_attributes_bad_ip_version(self):
- bad_ip_version = object()
- ixnet_gen = IxNextgen(mock.Mock())
- with self.assertRaises(ValueError):
- ixnet_gen.set_random_ip_multi_attributes(
- mock.Mock(), bad_ip_version, mock.Mock(), mock.Mock())
-
- def test_get_config(self):
- tg_cfg = {
- "vdu": [
- {
- "external-interface": [
- {
- "virtual-interface": {
- "vpci": "0000:07:00.1",
- },
- },
- {
- "virtual-interface": {
- "vpci": "0001:08:01.2",
- },
- },
- ],
- },
- ],
- "mgmt-interface": {
- "ip": "test1",
- "tg-config": {
- "dut_result_dir": "test2",
- "version": "test3",
- "ixchassis": "test4",
- "tcl_port": "test5",
- },
- }
- }
-
- expected = {
- 'machine': 'test1',
- 'port': 'test5',
- 'chassis': 'test4',
- 'cards': ['0000', '0001'],
- 'ports': ['07', '08'],
- 'output_dir': 'test2',
- 'version': 'test3',
- 'bidir': True,
- }
-
- result = IxNextgen.get_config(tg_cfg)
- self.assertDictEqual(result, expected)
-
- def test_ix_update_ether(self):
- static_traffic_params = {
- "uplink_0": {
- "id": 1,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:03",
- "framesPerSecond": True,
- "framesize": 64,
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l3v4": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "2001",
- "srcport": "1234"
- },
- "traffic_type": "continuous"
- },
- "downlink_0": {
- "id": 2,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l2": {
- "dstmac": "00:00:00:00:00:04",
- "framesPerSecond": True,
- "framesize": 64,
- "srcmac": "00:00:00:00:00:01"
- },
- "outer_l3": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v4": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "1234",
- "srcport": "2001"
- },
- "traffic_type": "continuous"
- }
- }
-
- ixnet = mock.MagicMock()
- ixnet.setMultiAttribute.return_value = [1]
- ixnet.commit.return_value = [1]
- ixnet.getList.side_effect = [
- [1],
- [1],
- [1],
- [
- "ethernet.header.destinationAddress",
- "ethernet.header.sourceAddress",
- ],
- ]
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.ix_update_ether(static_traffic_params)
- self.assertIsNone(result)
- self.assertGreater(ixnet.setMultiAttribute.call_count, 0)
-
- def test_ix_update_ether_nothing_to_do(self):
- static_traffic_params = {
- "uplink_0": {
- "id": 1,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l3": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l3v4": {
- "dscp": 0,
- "dstip4": "152.16.40.20",
- "proto": "udp",
- "srcip4": "152.16.100.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "2001",
- "srcport": "1234"
- },
- "traffic_type": "continuous"
- },
- "downlink_0": {
- "id": 2,
- "bidir": "False",
- "duration": 60,
- "iload": "100",
- "outer_l3": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v4": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l3v6": {
- "count": 1024,
- "dscp": 0,
- "dstip4": "152.16.100.20",
- "proto": "udp",
- "srcip4": "152.16.40.20",
- "ttl": 32
- },
- "outer_l4": {
- "dstport": "1234",
- "srcport": "2001"
- },
- "traffic_type": "continuous"
- }
- }
-
- ixnet = mock.MagicMock()
- ixnet.setMultiAttribute.return_value = [1]
- ixnet.commit.return_value = [1]
- ixnet.getList.side_effect = [
- [1],
- [1],
- [1],
- [
- "ethernet.header.destinationAddress",
- "ethernet.header.sourceAddress",
- ],
- ]
-
- ixnet_gen = IxNextgen(ixnet)
-
- result = ixnet_gen.ix_update_ether(static_traffic_params)
- self.assertIsNone(result)
- self.assertEqual(ixnet.setMultiAttribute.call_count, 0)
diff --git a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py
new file mode 100644
index 000000000..34afa3d5b
--- /dev/null
+++ b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py
@@ -0,0 +1,512 @@
+# Copyright (c) 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.
+
+import mock
+import IxNetwork
+import unittest
+
+from yardstick.common import exceptions
+from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api
+
+
+UPLINK = 'uplink'
+DOWNLINK = 'downlink'
+
+TRAFFIC_PARAMETERS = {
+ UPLINK: {
+ 'id': 1,
+ 'bidir': 'False',
+ 'duration': 60,
+ 'iload': '100',
+ 'outer_l2': {
+ 'framesize': {'64B': '25', '256B': '75'}
+ },
+ 'outer_l3': {
+ 'count': 512,
+ 'dscp': 0,
+ 'dstip4': '152.16.40.20',
+ 'proto': 'udp',
+ 'srcip4': '152.16.100.20',
+ 'ttl': 32
+ },
+ 'outer_l3v4': {
+ 'dscp': 0,
+ 'dstip4': '152.16.40.20',
+ 'proto': 'udp',
+ 'srcip4': '152.16.100.20',
+ 'ttl': 32
+ },
+ 'outer_l3v6': {
+ 'count': 1024,
+ 'dscp': 0,
+ 'dstip4': '152.16.100.20',
+ 'proto': 'udp',
+ 'srcip4': '152.16.40.20',
+ 'ttl': 32
+ },
+ 'outer_l4': {
+ 'dstport': '2001',
+ 'srcport': '1234'
+ },
+ 'traffic_type': 'continuous'
+ },
+ DOWNLINK: {
+ 'id': 2,
+ 'bidir': 'False',
+ 'duration': 60,
+ 'iload': '100',
+ 'outer_l2': {
+ 'framesize': {'128B': '35', '1024B': '65'}
+ },
+ 'outer_l3': {
+ 'count': 1024,
+ 'dscp': 0,
+ 'dstip4': '152.16.100.20',
+ 'proto': 'udp',
+ 'srcip4': '152.16.40.20',
+ 'ttl': 32
+ },
+ 'outer_l3v4': {
+ 'count': 1024,
+ 'dscp': 0,
+ 'dstip4': '152.16.100.20',
+ 'proto': 'udp',
+ 'srcip4': '152.16.40.20',
+ 'ttl': 32
+ },
+ 'outer_l3v6': {
+ 'count': 1024,
+ 'dscp': 0,
+ 'dstip4': '152.16.100.20',
+ 'proto': 'udp',
+ 'srcip4': '152.16.40.20',
+ 'ttl': 32
+ },
+ 'outer_l4': {
+ 'dstport': '1234',
+ 'srcport': '2001'
+ },
+ 'traffic_type': 'continuous'
+ }
+}
+
+
+class TestIxNextgen(unittest.TestCase):
+
+ def setUp(self):
+ self.ixnet = mock.Mock()
+ self.ixnet.execute = mock.Mock()
+ self.ixnet.getRoot.return_value = 'my_root'
+
+ def test_get_config(self):
+ tg_cfg = {
+ 'vdu': [
+ {
+ 'external-interface': [
+ {'virtual-interface': {'vpci': '0000:07:00.1'}},
+ {'virtual-interface': {'vpci': '0001:08:01.2'}}
+ ]
+ },
+ ],
+ 'mgmt-interface': {
+ 'ip': 'test1',
+ 'tg-config': {
+ 'dut_result_dir': 'test2',
+ 'version': 'test3',
+ 'ixchassis': 'test4',
+ 'tcl_port': 'test5',
+ },
+ }
+ }
+
+ expected = {
+ 'machine': 'test1',
+ 'port': 'test5',
+ 'chassis': 'test4',
+ 'cards': ['0000', '0001'],
+ 'ports': ['07', '08'],
+ 'output_dir': 'test2',
+ 'version': 'test3',
+ 'bidir': True,
+ }
+
+ result = ixnet_api.IxNextgen.get_config(tg_cfg)
+ self.assertEqual(result, expected)
+
+ def test__get_config_element_by_flow_group_name(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._ixnet.getList.side_effect = [['traffic_item'],
+ ['fg_01']]
+ ixnet_gen._ixnet.getAttribute.return_value = 'flow_group_01'
+ output = ixnet_gen._get_config_element_by_flow_group_name(
+ 'flow_group_01')
+ self.assertEqual('traffic_item/configElement:flow_group_01', output)
+
+ def test__get_config_element_by_flow_group_name_no_match(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._ixnet.getList.side_effect = [['traffic_item'],
+ ['fg_01']]
+ ixnet_gen._ixnet.getAttribute.return_value = 'flow_group_02'
+ output = ixnet_gen._get_config_element_by_flow_group_name(
+ 'flow_group_01')
+ self.assertIsNone(output)
+
+ def test__get_stack_item(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._ixnet.getList.return_value = ['tcp1', 'tcp2', 'udp']
+ with mock.patch.object(
+ ixnet_gen, '_get_config_element_by_flow_group_name') as \
+ mock_get_cfg_element:
+ mock_get_cfg_element.return_value = 'cfg_element'
+ output = ixnet_gen._get_stack_item(mock.ANY, ixnet_api.PROTO_TCP)
+ self.assertEqual(['tcp1', 'tcp2'], output)
+
+ def test__get_stack_item_no_config_element(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ with mock.patch.object(
+ ixnet_gen, '_get_config_element_by_flow_group_name',
+ return_value=None):
+ with self.assertRaises(exceptions.IxNetworkFlowNotPresent):
+ ixnet_gen._get_stack_item(mock.ANY, mock.ANY)
+
+ def test__get_field_in_stack_item(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._ixnet.getList.return_value = ['field1', 'field2']
+ output = ixnet_gen._get_field_in_stack_item(mock.ANY, 'field2')
+ self.assertEqual('field2', output)
+
+ def test__get_field_in_stack_item_no_field_present(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._ixnet.getList.return_value = ['field1', 'field2']
+ with self.assertRaises(exceptions.IxNetworkFieldNotPresentInStackItem):
+ ixnet_gen._get_field_in_stack_item(mock.ANY, 'field3')
+
+ def test__parse_framesize(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ framesize = {'64B': '75', '512b': '25'}
+ output = ixnet_gen._parse_framesize(framesize)
+ for idx in range(len(framesize)):
+ if output[idx * 2] == 64:
+ self.assertEqual(75, output[idx * 2 + 1])
+ elif output[idx * 2] == 512:
+ self.assertEqual(25, output[idx * 2 + 1])
+ else:
+ raise self.failureException('Framesize (64, 512) not present')
+
+ @mock.patch.object(IxNetwork, 'IxNet')
+ def test_connect(self, mock_ixnet):
+ mock_ixnet.return_value = self.ixnet
+ ixnet_gen = ixnet_api.IxNextgen()
+ with mock.patch.object(ixnet_gen, 'get_config') as mock_config:
+ mock_config.return_value = {'machine': 'machine_fake',
+ 'port': 'port_fake',
+ 'version': 12345}
+ ixnet_gen.connect(mock.ANY)
+
+ self.ixnet.connect.assert_called_once_with(
+ 'machine_fake', '-port', 'port_fake', '-version', '12345')
+ mock_config.assert_called_once()
+
+ def test_connect_invalid_config_no_machine(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen.get_config = mock.Mock(return_value={
+ 'port': 'port_fake',
+ 'version': '12345'})
+ self.assertRaises(KeyError, ixnet_gen.connect, mock.ANY)
+ self.ixnet.connect.assert_not_called()
+
+ def test_connect_invalid_config_no_port(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen.get_config = mock.Mock(return_value={
+ 'machine': 'machine_fake',
+ 'version': '12345'})
+ self.assertRaises(KeyError, ixnet_gen.connect, mock.ANY)
+ self.ixnet.connect.assert_not_called()
+
+ def test_connect_invalid_config_no_version(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen.get_config = mock.Mock(return_value={
+ 'machine': 'machine_fake',
+ 'port': 'port_fake'})
+ self.assertRaises(KeyError, ixnet_gen.connect, mock.ANY)
+ self.ixnet.connect.assert_not_called()
+
+ def test_connect_no_config(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen.get_config = mock.Mock(return_value={})
+ self.assertRaises(KeyError, ixnet_gen.connect, mock.ANY)
+ self.ixnet.connect.assert_not_called()
+
+ def test_clear_config(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen.clear_config()
+ self.ixnet.execute.assert_called_once_with('newConfig')
+
+ @mock.patch.object(ixnet_api, 'log')
+ def test_assign_ports_2_ports(self, *args):
+ self.ixnet.getAttribute.side_effect = ['up', 'down']
+ config = {
+ 'chassis': '1.1.1.1',
+ 'cards': ['1', '2'],
+ 'ports': ['2', '2']}
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._cfg = config
+
+ self.assertIsNone(ixnet_gen.assign_ports())
+ self.assertEqual(self.ixnet.execute.call_count, 2)
+ self.assertEqual(self.ixnet.commit.call_count, 4)
+ self.assertEqual(self.ixnet.getAttribute.call_count, 2)
+
+ @mock.patch.object(ixnet_api, 'log')
+ def test_assign_ports_port_down(self, mock_log):
+ self.ixnet.getAttribute.return_value = 'down'
+ config = {
+ 'chassis': '1.1.1.1',
+ 'cards': ['1', '2'],
+ 'ports': ['3', '4']}
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._cfg = config
+ ixnet_gen.assign_ports()
+ mock_log.warning.assert_called()
+
+ def test_assign_ports_no_config(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._cfg = {}
+ self.assertRaises(KeyError, ixnet_gen.assign_ports)
+
+ def test__create_traffic_item(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ self.ixnet.add.return_value = 'my_new_traffic_item'
+ self.ixnet.remapIds.return_value = ['my_traffic_item_id']
+
+ ixnet_gen._create_traffic_item()
+ self.ixnet.add.assert_called_once_with(
+ 'my_root/traffic', 'trafficItem')
+ self.ixnet.setMultiAttribute.assert_called_once_with(
+ 'my_new_traffic_item', '-name', 'RFC2544', '-trafficType', 'raw')
+ self.assertEqual(2, self.ixnet.commit.call_count)
+ self.ixnet.remapIds.assert_called_once_with('my_new_traffic_item')
+ self.ixnet.setAttribute('my_traffic_item_id/tracking',
+ '-trackBy', 'trafficGroupId0')
+
+ def test__create_flow_groups(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen.ixnet.getList.side_effect = [['traffic_item'], ['1', '2']]
+ ixnet_gen.ixnet.add.side_effect = ['endp1', 'endp2']
+ ixnet_gen._create_flow_groups()
+ ixnet_gen.ixnet.add.assert_has_calls([
+ mock.call('traffic_item', 'endpointSet'),
+ mock.call('traffic_item', 'endpointSet')])
+ ixnet_gen.ixnet.setMultiAttribute.assert_has_calls([
+ mock.call('endp1', '-name', '1', '-sources', ['1/protocols'],
+ '-destinations', ['2/protocols']),
+ mock.call('endp2', '-name', '2', '-sources', ['2/protocols'],
+ '-destinations', ['1/protocols'])])
+
+ def test__append_protocol_to_stack(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+
+ ixnet_gen._append_procotol_to_stack('my_protocol', 'prev_element')
+ self.ixnet.execute.assert_called_with(
+ 'append', 'prev_element',
+ 'my_root/traffic/protocolTemplate:"my_protocol"')
+
+ def test__setup_config_elements(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen.ixnet.getList.side_effect = [['traffic_item'],
+ ['cfg_element']]
+ with mock.patch.object(ixnet_gen, '_append_procotol_to_stack') as \
+ mock_append_proto:
+ ixnet_gen._setup_config_elements()
+ mock_append_proto.assert_has_calls([
+ mock.call(ixnet_api.PROTO_UDP, 'cfg_element/stack:"ethernet-1"'),
+ mock.call(ixnet_api.PROTO_IPV4, 'cfg_element/stack:"ethernet-1"')])
+ ixnet_gen.ixnet.setAttribute.assert_has_calls([
+ mock.call('cfg_element/frameRateDistribution', '-portDistribution',
+ 'splitRateEvenly'),
+ mock.call('cfg_element/frameRateDistribution',
+ '-streamDistribution', 'splitRateEvenly')])
+
+ @mock.patch.object(ixnet_api.IxNextgen, '_create_traffic_item')
+ @mock.patch.object(ixnet_api.IxNextgen, '_create_flow_groups')
+ @mock.patch.object(ixnet_api.IxNextgen, '_setup_config_elements')
+ def test_create_traffic_model(self, mock__setup_config_elements,
+ mock__create_flow_groups,
+ mock__create_traffic_item):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+
+ ixnet_gen.create_traffic_model()
+ mock__create_traffic_item.assert_called_once()
+ mock__create_flow_groups.assert_called_once()
+ mock__setup_config_elements.assert_called_once()
+
+ def test__update_frame_mac(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ with mock.patch.object(ixnet_gen, '_get_field_in_stack_item') as \
+ mock_get_field:
+ mock_get_field.return_value = 'field_descriptor'
+ ixnet_gen._update_frame_mac('ethernet_descriptor', 'field', 'mac')
+ mock_get_field.assert_called_once_with('ethernet_descriptor', 'field')
+ ixnet_gen.ixnet.setMultiAttribute(
+ 'field_descriptor', '-singleValue', 'mac', '-fieldValue', 'mac',
+ '-valueType', 'singleValue')
+ ixnet_gen.ixnet.commit.assert_called_once()
+
+ def test_update_frame(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ with mock.patch.object(
+ ixnet_gen, '_get_config_element_by_flow_group_name',
+ return_value='cfg_element'), \
+ mock.patch.object(ixnet_gen, '_update_frame_mac') as \
+ mock_update_frame, \
+ mock.patch.object(ixnet_gen, '_get_stack_item') as \
+ mock_get_stack_item:
+ mock_get_stack_item.side_effect = [['item1'], ['item2'],
+ ['item3'], ['item4']]
+ ixnet_gen.update_frame(TRAFFIC_PARAMETERS)
+
+ self.assertEqual(6, len(ixnet_gen.ixnet.setMultiAttribute.mock_calls))
+ self.assertEqual(4, len(mock_update_frame.mock_calls))
+
+ def test_update_frame_flow_not_present(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ with mock.patch.object(
+ ixnet_gen, '_get_config_element_by_flow_group_name',
+ return_value=None):
+ with self.assertRaises(exceptions.IxNetworkFlowNotPresent):
+ ixnet_gen.update_frame(TRAFFIC_PARAMETERS)
+
+ def test_get_statistics(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ port_statistics = '::ixNet::OBJ-/statistics/view:"Port Statistics"'
+ flow_statistics = '::ixNet::OBJ-/statistics/view:"Flow Statistics"'
+ with mock.patch.object(ixnet_gen, '_build_stats_map') as \
+ mock_build_stats:
+ ixnet_gen.get_statistics()
+
+ mock_build_stats.assert_has_calls([
+ mock.call(port_statistics, ixnet_gen.PORT_STATS_NAME_MAP),
+ mock.call(flow_statistics, ixnet_gen.LATENCY_NAME_MAP)])
+
+ def test__update_ipv4_address(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ with mock.patch.object(ixnet_gen, '_get_field_in_stack_item',
+ return_value='field_desc'):
+ ixnet_gen._update_ipv4_address(mock.ANY, mock.ANY, '192.168.1.1',
+ 100, '255.255.255.0', 25)
+ ixnet_gen.ixnet.setMultiAttribute.assert_called_once_with(
+ 'field_desc', '-seed', 100, '-fixedBits', '192.168.1.1',
+ '-randomMask', '255.255.255.0', '-valueType', 'random',
+ '-countValue', 25)
+
+ def test_update_ip_packet(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ with mock.patch.object(ixnet_gen, '_update_ipv4_address') as \
+ mock_update_add, \
+ mock.patch.object(ixnet_gen, '_get_stack_item'), \
+ mock.patch.object(ixnet_gen,
+ '_get_config_element_by_flow_group_name', return_value='celm'):
+ ixnet_gen.update_ip_packet(TRAFFIC_PARAMETERS)
+
+ self.assertEqual(4, len(mock_update_add.mock_calls))
+
+ def test_update_ip_packet_exception_no_config_element(self):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ with mock.patch.object(ixnet_gen,
+ '_get_config_element_by_flow_group_name',
+ return_value=None):
+ with self.assertRaises(exceptions.IxNetworkFlowNotPresent):
+ ixnet_gen.update_ip_packet(TRAFFIC_PARAMETERS)
+
+ @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state')
+ def test_start_traffic(self, mock_ixnextgen_get_traffic_state):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._ixnet.getList.return_value = [0]
+
+ mock_ixnextgen_get_traffic_state.side_effect = [
+ 'stopped', 'started', 'started', 'started']
+
+ result = ixnet_gen.start_traffic()
+ self.assertIsNone(result)
+ self.ixnet.getList.assert_called_once()
+ self.assertEqual(3, ixnet_gen._ixnet.execute.call_count)
+
+ @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state')
+ def test_start_traffic_traffic_running(
+ self, mock_ixnextgen_get_traffic_state):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._ixnet.getList.return_value = [0]
+ mock_ixnextgen_get_traffic_state.side_effect = [
+ 'started', 'stopped', 'started']
+
+ result = ixnet_gen.start_traffic()
+ self.assertIsNone(result)
+ self.ixnet.getList.assert_called_once()
+ self.assertEqual(4, ixnet_gen._ixnet.execute.call_count)
+
+ @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state')
+ def test_start_traffic_wait_for_traffic_to_stop(
+ self, mock_ixnextgen_get_traffic_state):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._ixnet.getList.return_value = [0]
+ mock_ixnextgen_get_traffic_state.side_effect = [
+ 'started', 'started', 'started', 'stopped', 'started']
+
+ result = ixnet_gen.start_traffic()
+ self.assertIsNone(result)
+ self.ixnet.getList.assert_called_once()
+ self.assertEqual(4, ixnet_gen._ixnet.execute.call_count)
+
+ @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state')
+ def test_start_traffic_wait_for_traffic_start(
+ self, mock_ixnextgen_get_traffic_state):
+ ixnet_gen = ixnet_api.IxNextgen()
+ ixnet_gen._ixnet = self.ixnet
+ ixnet_gen._ixnet.getList.return_value = [0]
+ mock_ixnextgen_get_traffic_state.side_effect = [
+ 'stopped', 'stopped', 'stopped', 'started']
+
+ result = ixnet_gen.start_traffic()
+ self.assertIsNone(result)
+ self.ixnet.getList.assert_called_once()
+ self.assertEqual(3, ixnet_gen._ixnet.execute.call_count)
diff --git a/yardstick/tests/unit/network_services/nfvi/test_resource.py b/yardstick/tests/unit/network_services/nfvi/test_resource.py
index 9f337c673..de9679456 100644
--- a/yardstick/tests/unit/network_services/nfvi/test_resource.py
+++ b/yardstick/tests/unit/network_services/nfvi/test_resource.py
@@ -17,10 +17,10 @@ import errno
import mock
import unittest
+from yardstick.common import exceptions
from yardstick.network_services.nfvi.resource import ResourceProfile
from yardstick.network_services.nfvi import resource, collectd
-from yardstick.common.exceptions import ResourceCommandError
-from yardstick import ssh
+
class TestResourceProfile(unittest.TestCase):
VNFD = {'vnfd:vnfd-catalog':
@@ -134,8 +134,8 @@ class TestResourceProfile(unittest.TestCase):
self.assertIsNone(self.resource_profile._start_collectd(ssh_mock,
"/opt/nsb_bin"))
- ssh_mock.execute = mock.Mock(side_effect=ssh.SSHError)
- with self.assertRaises(ssh.SSHError):
+ ssh_mock.execute = mock.Mock(side_effect=exceptions.SSHError)
+ with self.assertRaises(exceptions.SSHError):
self.resource_profile._start_collectd(ssh_mock, "/opt/nsb_bin")
ssh_mock.execute = mock.Mock(return_value=(1, "", ""))
@@ -148,11 +148,11 @@ class TestResourceProfile(unittest.TestCase):
self.assertIsNone(self.resource_profile._start_rabbitmq(ssh_mock))
ssh_mock.execute = mock.Mock(return_value=(0, "", ""))
- with self.assertRaises(ResourceCommandError):
+ with self.assertRaises(exceptions.ResourceCommandError):
self.resource_profile._start_rabbitmq(ssh_mock)
ssh_mock.execute = mock.Mock(return_value=(1, "", ""))
- with self.assertRaises(ResourceCommandError):
+ with self.assertRaises(exceptions.ResourceCommandError):
self.resource_profile._start_rabbitmq(ssh_mock)
def test__prepare_collectd_conf(self):
diff --git a/yardstick/tests/unit/network_services/test_yang_model.py b/yardstick/tests/unit/network_services/test_yang_model.py
deleted file mode 100644
index a7eb36b8a..000000000
--- a/yardstick/tests/unit/network_services/test_yang_model.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# 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.network_services.yang_model import YangModel
-
-
-class YangModelTestCase(unittest.TestCase):
- """Test all Yang Model methods."""
-
- ENTRIES = {
- 'access-list1': {
- 'acl': {
- 'access-list-entries': [{
- 'ace': {
- 'ace-oper-data': {
- 'match-counter': 0},
- 'actions': 'drop,count',
- 'matches': {
- 'destination-ipv4-network':
- '152.16.40.20/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}},
- 'rule-name': 'rule1588'}},
- {
- 'ace': {
- 'ace-oper-data': {
- 'match-counter': 0},
- 'actions': 'drop,count',
- 'matches': {
- 'destination-ipv4-network':
- '0.0.0.0/0',
- 'destination-port-range': {
- 'lower-port': 0,
- 'upper-port': 65535},
- 'source-ipv4-network':
- '152.16.100.20/24',
- 'source-port-range': {
- 'lower-port': 0,
- 'upper-port': 65535}},
- 'rule-name': 'rule1589'}}],
- 'acl-name': 'sample-ipv4-acl',
- 'acl-type': 'ipv4-acl'}
- }
- }
-
- def test__init__(self):
- cfg = "yang.yaml"
- y = YangModel(cfg)
- self.assertEqual(y.config_file, cfg)
-
- def test_config_file_setter(self):
- cfg = "yang.yaml"
- y = YangModel(cfg)
- self.assertEqual(y.config_file, cfg)
- cfg2 = "yang2.yaml"
- y.config_file = cfg2
- self.assertEqual(y.config_file, cfg2)
-
- def test__get_entries(self):
- cfg = "yang.yaml"
- y = YangModel(cfg)
- y._options = self.ENTRIES
- y._get_entries()
- self.assertIn("p acl add", y._rules)
-
- def test__get_entries_no_options(self):
- cfg = "yang.yaml"
- y = YangModel(cfg)
- y._get_entries()
- self.assertEqual(y._rules, '')
-
- @mock.patch('yardstick.network_services.yang_model.open')
- @mock.patch('yardstick.network_services.yang_model.yaml_load')
- def test__read_config(self, mock_safe_load, *args):
- cfg = "yang.yaml"
- y = YangModel(cfg)
- mock_safe_load.return_value = expected = {'key1': 'value1', 'key2': 'value2'}
- y._read_config()
- self.assertDictEqual(y._options, expected)
-
- @mock.patch('yardstick.network_services.yang_model.open')
- def test__read_config_open_error(self, mock_open):
- cfg = "yang.yaml"
- y = YangModel(cfg)
- mock_open.side_effect = IOError('my error')
-
- self.assertEqual(y._options, {})
- with self.assertRaises(IOError) as raised:
- y._read_config()
-
- self.assertIn('my error', str(raised.exception))
- self.assertEqual(y._options, {})
-
- def test_get_rules(self):
- cfg = "yang.yaml"
- y = YangModel(cfg)
- y._read_config = read_mock = mock.Mock()
- y._get_entries = get_mock = mock.Mock()
-
- y._rules = None
- self.assertIsNone(y.get_rules())
- self.assertEqual(read_mock.call_count, 1)
- self.assertEqual(get_mock.call_count, 1)
-
- # True value should prevent calling read and get
- y._rules = 999
- self.assertEqual(y.get_rules(), 999)
- self.assertEqual(read_mock.call_count, 1)
- self.assertEqual(get_mock.call_count, 1)
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_base.py b/yardstick/tests/unit/network_services/traffic_profile/test_base.py
index 3b8804976..55276af58 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_base.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_base.py
@@ -44,7 +44,7 @@ class TestTrafficProfile(unittest.TestCase):
traffic_profile = base.TrafficProfile(self.TRAFFIC_PROFILE)
self.assertEqual(self.TRAFFIC_PROFILE, traffic_profile.params)
- def test_execute(self):
+ def test_execute_traffic(self):
traffic_profile = base.TrafficProfile(self.TRAFFIC_PROFILE)
self.assertRaises(NotImplementedError,
traffic_profile.execute_traffic, {})
@@ -69,5 +69,20 @@ class TestTrafficProfile(unittest.TestCase):
class TestDummyProfile(unittest.TestCase):
def test_execute(self):
- dummy_profile = base.DummyProfile(base.TrafficProfile)
+ tp_config = {'traffic_profile': {'duration': 15}}
+ dummy_profile = base.DummyProfile(tp_config)
self.assertIsNone(dummy_profile.execute({}))
+
+
+class TrafficProfileConfigTestCase(unittest.TestCase):
+
+ def test__init(self):
+ tp_config = {'traffic_profile': {'packet_sizes': {'64B': 100}}}
+ tp_config_obj = base.TrafficProfileConfig(tp_config)
+ self.assertEqual({'64B': 100}, tp_config_obj.packet_sizes)
+ self.assertEqual(base.TrafficProfileConfig.DEFAULT_SCHEMA,
+ tp_config_obj.schema)
+ self.assertEqual(base.TrafficProfileConfig.DEFAULT_FRAME_RATE,
+ tp_config_obj.frame_rate)
+ self.assertEqual(base.TrafficProfileConfig.DEFAULT_DURATION,
+ tp_config_obj.duration)
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_fixed.py b/yardstick/tests/unit/network_services/traffic_profile/test_fixed.py
index 39905e6b1..2f6713760 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_fixed.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_fixed.py
@@ -102,8 +102,7 @@ class TestFixedProfile(unittest.TestCase):
'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}}
def test___init__(self):
- fixed_profile = \
- FixedProfile(TrafficProfile)
+ fixed_profile = FixedProfile(self.TRAFFIC_PROFILE)
self.assertIsNotNone(fixed_profile)
def test_execute(self):
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_http.py b/yardstick/tests/unit/network_services/traffic_profile/test_http.py
index 0d1b916a7..d44fab2b5 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_http.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_http.py
@@ -11,30 +11,29 @@
# 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
-from yardstick.network_services.traffic_profile.base import TrafficProfile
-from yardstick.network_services.traffic_profile.http import \
- TrafficProfileGenericHTTP
+from yardstick.network_services.traffic_profile import http
class TestTrafficProfileGenericHTTP(unittest.TestCase):
+
+ TP_CONFIG = {'traffic_profile': {'duration': 10}}
+
def test___init__(self):
- traffic_profile_generic_htt_p = \
- TrafficProfileGenericHTTP(TrafficProfile)
- self.assertIsNotNone(traffic_profile_generic_htt_p)
+ tp_generic_http = http.TrafficProfileGenericHTTP(
+ self.TP_CONFIG)
+ self.assertIsNotNone(tp_generic_http)
def test_execute(self):
- traffic_profile_generic_htt_p = \
- TrafficProfileGenericHTTP(TrafficProfile)
+ tp_generic_http = http.TrafficProfileGenericHTTP(
+ self.TP_CONFIG)
traffic_generator = {}
- self.assertIsNone(
- traffic_profile_generic_htt_p.execute(traffic_generator))
+ self.assertIsNone(tp_generic_http.execute(traffic_generator))
def test__send_http_request(self):
- traffic_profile_generic_htt_p = \
- TrafficProfileGenericHTTP(TrafficProfile)
- self.assertIsNone(traffic_profile_generic_htt_p._send_http_request(
- "10.1.1.1", "250", "/req"))
+ tp_generic_http = http.TrafficProfileGenericHTTP(
+ self.TP_CONFIG)
+ self.assertIsNone(tp_generic_http._send_http_request(
+ '10.1.1.1', '250', '/req'))
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py
index a0abe2bbd..6b3532fa2 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py
@@ -11,25 +11,14 @@
# 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 copy import deepcopy
-from yardstick.tests import STL_MOCKS
-
-STLClient = mock.MagicMock()
-stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
-stl_patch.start()
+import mock
+import unittest
-if stl_patch:
- from yardstick.network_services.traffic_profile.trex_traffic_profile \
- import TrexProfile
- from yardstick.network_services.traffic_profile.ixia_rfc2544 import \
- IXIARFC2544Profile
- from yardstick.network_services.traffic_profile import ixia_rfc2544
+from yardstick.network_services.traffic_profile import ixia_rfc2544
+from yardstick.network_services.traffic_profile import trex_traffic_profile
class TestIXIARFC2544Profile(unittest.TestCase):
@@ -52,7 +41,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
'traffic_profile': {
'traffic_type': 'IXIARFC2544Profile',
'frame_rate': 100},
- IXIARFC2544Profile.DOWNLINK: {
+ ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: {
'ipv4': {
'outer_l2': {
'framesize': {
@@ -73,7 +62,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
'outer_l4': {
'srcport': '2001',
'dsrport': '1234'}}},
- IXIARFC2544Profile.UPLINK: {
+ ixia_rfc2544.IXIARFC2544Profile.UPLINK: {
'ipv4': {
'outer_l2': {
'framesize': {
@@ -97,14 +86,15 @@ class TestIXIARFC2544Profile(unittest.TestCase):
'schema': 'isb:traffic_profile:0.1'}
def test_get_ixia_traffic_profile_error(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator = mock.Mock(
+ autospec=trex_traffic_profile.TrexProfile)
traffic_generator.my_ports = [0, 1]
traffic_generator.uplink_ports = [-1]
traffic_generator.downlink_ports = [1]
traffic_generator.client = \
mock.Mock(return_value=True)
STATIC_TRAFFIC = {
- IXIARFC2544Profile.UPLINK: {
+ ixia_rfc2544.IXIARFC2544Profile.UPLINK: {
"id": 1,
"bidir": "False",
"duration": 60,
@@ -143,7 +133,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
},
"traffic_type": "continuous"
},
- IXIARFC2544Profile.DOWNLINK: {
+ ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: {
"id": 2,
"bidir": "False",
"duration": 60,
@@ -187,7 +177,8 @@ class TestIXIARFC2544Profile(unittest.TestCase):
}
ixia_rfc2544.STATIC_TRAFFIC = STATIC_TRAFFIC
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile(
+ self.TRAFFIC_PROFILE)
r_f_c2544_profile.rate = 100
mac = {"src_mac_0": "00:00:00:00:00:01",
"src_mac_1": "00:00:00:00:00:02",
@@ -199,14 +190,15 @@ class TestIXIARFC2544Profile(unittest.TestCase):
self.assertIsNotNone(result)
def test_get_ixia_traffic_profile(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator = mock.Mock(
+ autospec=trex_traffic_profile.TrexProfile)
traffic_generator.my_ports = [0, 1]
traffic_generator.uplink_ports = [-1]
traffic_generator.downlink_ports = [1]
traffic_generator.client = \
mock.Mock(return_value=True)
STATIC_TRAFFIC = {
- IXIARFC2544Profile.UPLINK: {
+ ixia_rfc2544.IXIARFC2544Profile.UPLINK: {
"id": 1,
"bidir": "False",
"duration": 60,
@@ -246,7 +238,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
},
"traffic_type": "continuous"
},
- IXIARFC2544Profile.DOWNLINK: {
+ ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: {
"id": 2,
"bidir": "False",
"duration": 60,
@@ -289,7 +281,8 @@ class TestIXIARFC2544Profile(unittest.TestCase):
}
ixia_rfc2544.STATIC_TRAFFIC = STATIC_TRAFFIC
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile(
+ self.TRAFFIC_PROFILE)
r_f_c2544_profile.rate = 100
mac = {"src_mac_0": "00:00:00:00:00:01",
"src_mac_1": "00:00:00:00:00:02",
@@ -302,14 +295,15 @@ class TestIXIARFC2544Profile(unittest.TestCase):
@mock.patch("yardstick.network_services.traffic_profile.ixia_rfc2544.open")
def test_get_ixia_traffic_profile_v6(self, *args):
- traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator = mock.Mock(
+ autospec=trex_traffic_profile.TrexProfile)
traffic_generator.my_ports = [0, 1]
traffic_generator.uplink_ports = [-1]
traffic_generator.downlink_ports = [1]
traffic_generator.client = \
mock.Mock(return_value=True)
STATIC_TRAFFIC = {
- IXIARFC2544Profile.UPLINK: {
+ ixia_rfc2544.IXIARFC2544Profile.UPLINK: {
"id": 1,
"bidir": "False",
"duration": 60,
@@ -348,7 +342,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
},
"traffic_type": "continuous"
},
- IXIARFC2544Profile.DOWNLINK: {
+ ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: {
"id": 2,
"bidir": "False",
"duration": 60,
@@ -392,7 +386,8 @@ class TestIXIARFC2544Profile(unittest.TestCase):
}
ixia_rfc2544.STATIC_TRAFFIC = STATIC_TRAFFIC
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile(
+ self.TRAFFIC_PROFILE)
r_f_c2544_profile.rate = 100
mac = {"src_mac_0": "00:00:00:00:00:01",
"src_mac_1": "00:00:00:00:00:02",
@@ -405,7 +400,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
'traffic_profile':
{'traffic_type': 'IXIARFC2544Profile',
'frame_rate': 100},
- IXIARFC2544Profile.DOWNLINK:
+ ixia_rfc2544.IXIARFC2544Profile.DOWNLINK:
{'ipv4':
{'outer_l2': {'framesize':
{'64B': '100', '1518B': '0',
@@ -422,7 +417,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
'dscp': 0, 'ttl': 32},
'outer_l4': {'srcport': '2001',
'dsrport': '1234'}}},
- IXIARFC2544Profile.UPLINK: {'ipv4':
+ ixia_rfc2544.IXIARFC2544Profile.UPLINK: {'ipv4':
{'outer_l2': {'framesize':
{'64B': '100', '1518B': '0',
'128B': '0', '1400B': '0',
@@ -446,51 +441,75 @@ class TestIXIARFC2544Profile(unittest.TestCase):
self.assertIsNotNone(result)
def test__get_ixia_traffic_profile_default_args(self):
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile(
+ self.TRAFFIC_PROFILE)
expected = {}
result = r_f_c2544_profile._get_ixia_traffic_profile({})
self.assertDictEqual(result, expected)
def test__ixia_traffic_generate(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator = mock.Mock(
+ autospec=trex_traffic_profile.TrexProfile)
traffic_generator.networks = {
"uplink_0": ["xe0"],
"downlink_0": ["xe1"],
}
traffic_generator.client = \
mock.Mock(return_value=True)
- traffic = {IXIARFC2544Profile.DOWNLINK: {'iload': 10},
- IXIARFC2544Profile.UPLINK: {'iload': 10}}
+ traffic = {ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: {'iload': 10},
+ ixia_rfc2544.IXIARFC2544Profile.UPLINK: {'iload': 10}}
ixia_obj = mock.MagicMock()
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile(
+ self.TRAFFIC_PROFILE)
r_f_c2544_profile.rate = 100
result = r_f_c2544_profile._ixia_traffic_generate(traffic, ixia_obj)
self.assertIsNone(result)
- def test_execute(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
- traffic_generator.networks = {
- "uplink_0": ["xe0"],
- "downlink_0": ["xe1"],
- }
- traffic_generator.client = \
- mock.Mock(return_value=True)
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.first_run = True
- r_f_c2544_profile.params = {IXIARFC2544Profile.DOWNLINK: {'iload': 10},
- IXIARFC2544Profile.UPLINK: {'iload': 10}}
+ def test_execute_traffic_first_run(self):
+ rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ rfc2544_profile.first_run = True
+ rfc2544_profile.rate = 50
+ with mock.patch.object(rfc2544_profile, '_get_ixia_traffic_profile') \
+ as mock_get_tp, \
+ mock.patch.object(rfc2544_profile, '_ixia_traffic_generate') \
+ as mock_tgenerate, \
+ mock.patch.object(rfc2544_profile, 'update_traffic_profile') \
+ as mock_update_tp:
+ mock_get_tp.return_value = 'fake_tprofile'
+ output = rfc2544_profile.execute_traffic(mock.ANY,
+ ixia_obj=mock.ANY)
- r_f_c2544_profile.get_streams = mock.Mock()
- r_f_c2544_profile.full_profile = {}
- r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock()
- r_f_c2544_profile.get_multiplier = mock.Mock()
- r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
- ixia_obj = mock.MagicMock()
- self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator, ixia_obj))
+ self.assertTrue(output)
+ self.assertFalse(rfc2544_profile.first_run)
+ self.assertEqual(50, rfc2544_profile.max_rate)
+ self.assertEqual(0, rfc2544_profile.min_rate)
+ mock_get_tp.assert_called_once()
+ mock_tgenerate.assert_called_once()
+ mock_update_tp.assert_called_once()
+
+ def test_execute_traffic_not_first_run(self):
+ rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ rfc2544_profile.first_run = False
+ rfc2544_profile.max_rate = 70
+ rfc2544_profile.min_rate = 0
+ with mock.patch.object(rfc2544_profile, '_get_ixia_traffic_profile') \
+ as mock_get_tp, \
+ mock.patch.object(rfc2544_profile, '_ixia_traffic_generate') \
+ as mock_tgenerate:
+ mock_get_tp.return_value = 'fake_tprofile'
+ rfc2544_profile.full_profile = mock.ANY
+ output = rfc2544_profile.execute_traffic(mock.ANY,
+ ixia_obj=mock.ANY)
+
+ self.assertFalse(output)
+ self.assertEqual(35.0, rfc2544_profile.rate)
+ mock_get_tp.assert_called_once()
+ mock_tgenerate.assert_called_once()
def test_update_traffic_profile(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator = mock.Mock(
+ autospec=trex_traffic_profile.TrexProfile)
traffic_generator.networks = {
"uplink_0": ["xe0"], # private, one value for intfs
"downlink_0": ["xe1", "xe2"], # public, two values for intfs
@@ -508,7 +527,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
"downlink_0": ["xe1", "xe2"],
})
- r_f_c2544_profile = IXIARFC2544Profile(traffic_profile)
+ r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile(traffic_profile)
r_f_c2544_profile.full_profile = {}
r_f_c2544_profile.get_streams = mock.Mock()
@@ -516,112 +535,89 @@ class TestIXIARFC2544Profile(unittest.TestCase):
r_f_c2544_profile.update_traffic_profile(traffic_generator))
self.assertEqual(r_f_c2544_profile.ports, ports_expected)
- def test_get_drop_percentage(self):
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.params = self.PROFILE
- ixia_obj = mock.MagicMock()
- r_f_c2544_profile.execute = mock.Mock()
- r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock()
- r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
- r_f_c2544_profile.get_multiplier = mock.Mock()
- r_f_c2544_profile.tmp_throughput = 0
- r_f_c2544_profile.tmp_drop = 0
- r_f_c2544_profile.full_profile = {}
- samples = {}
- for ifname in range(1):
- name = "xe{}".format(ifname)
- samples[name] = {"rx_throughput_fps": 20,
- "tx_throughput_fps": 20,
- "rx_throughput_mbps": 10,
- "tx_throughput_mbps": 10,
- "RxThroughput": 10,
- "TxThroughput": 10,
- "in_packets": 1000,
- "out_packets": 1000}
- tol_min = 100.0
- tolerance = 0.0
- self.assertIsNotNone(
- r_f_c2544_profile.get_drop_percentage(samples, tol_min, tolerance,
- ixia_obj))
+ def test_get_drop_percentage_completed(self):
+ samples = {'iface_name_1':
+ {'RxThroughput': 10, 'TxThroughput': 10,
+ 'in_packets': 1000, 'out_packets': 1000},
+ 'iface_name_2':
+ {'RxThroughput': 11, 'TxThroughput': 13,
+ 'in_packets': 1005, 'out_packets': 1007}
+ }
+ rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ completed, samples = rfc2544_profile.get_drop_percentage(samples, 0, 1)
+ self.assertTrue(completed)
+ self.assertEqual(23.0, samples['TxThroughput'])
+ self.assertEqual(21.0, samples['RxThroughput'])
+ self.assertEqual(0.1, samples['DropPercentage'])
- def test_get_drop_percentage_update(self):
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.params = self.PROFILE
- ixia_obj = mock.MagicMock()
- r_f_c2544_profile.execute = mock.Mock()
- r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock()
- r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
- r_f_c2544_profile.get_multiplier = mock.Mock()
- r_f_c2544_profile.tmp_throughput = 0
- r_f_c2544_profile.tmp_drop = 0
- r_f_c2544_profile.full_profile = {}
- samples = {}
- for ifname in range(1):
- name = "xe{}".format(ifname)
- samples[name] = {"rx_throughput_fps": 20,
- "tx_throughput_fps": 20,
- "rx_throughput_mbps": 10,
- "tx_throughput_mbps": 10,
- "RxThroughput": 10,
- "TxThroughput": 10,
- "in_packets": 1000,
- "out_packets": 1002}
- tol_min = 0.0
- tolerance = 1.0
- self.assertIsNotNone(
- r_f_c2544_profile.get_drop_percentage(samples, tol_min, tolerance,
- ixia_obj))
+ def test_get_drop_percentage_over_drop_percentage(self):
+ samples = {'iface_name_1':
+ {'RxThroughput': 10, 'TxThroughput': 10,
+ 'in_packets': 1000, 'out_packets': 1000},
+ 'iface_name_2':
+ {'RxThroughput': 11, 'TxThroughput': 13,
+ 'in_packets': 1005, 'out_packets': 1007}
+ }
+ rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ rfc2544_profile.rate = 1000
+ completed, samples = rfc2544_profile.get_drop_percentage(
+ samples, 0, 0.05)
+ self.assertFalse(completed)
+ self.assertEqual(23.0, samples['TxThroughput'])
+ self.assertEqual(21.0, samples['RxThroughput'])
+ self.assertEqual(0.1, samples['DropPercentage'])
+ self.assertEqual(rfc2544_profile.rate, rfc2544_profile.max_rate)
- def test_get_drop_percentage_div_zero(self):
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.params = self.PROFILE
- ixia_obj = mock.MagicMock()
- r_f_c2544_profile.execute = mock.Mock()
- r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock()
- r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
- r_f_c2544_profile.get_multiplier = mock.Mock()
- r_f_c2544_profile.tmp_throughput = 0
- r_f_c2544_profile.tmp_drop = 0
- r_f_c2544_profile.full_profile = {}
- samples = {}
- for ifname in range(1):
- name = "xe{}".format(ifname)
- samples[name] = {"rx_throughput_fps": 20,
- "tx_throughput_fps": 20,
- "rx_throughput_mbps": 10,
- "tx_throughput_mbps": 10,
- "RxThroughput": 10,
- "TxThroughput": 10,
- "in_packets": 1000,
- "out_packets": 0}
- tol_min = 0.0
- tolerance = 0.0
- r_f_c2544_profile.tmp_throughput = 0
- self.assertIsNotNone(
- r_f_c2544_profile.get_drop_percentage(samples, tol_min, tolerance,
- ixia_obj))
+ def test_get_drop_percentage_under_drop_percentage(self):
+ samples = {'iface_name_1':
+ {'RxThroughput': 10, 'TxThroughput': 10,
+ 'in_packets': 1000, 'out_packets': 1000},
+ 'iface_name_2':
+ {'RxThroughput': 11, 'TxThroughput': 13,
+ 'in_packets': 1005, 'out_packets': 1007}
+ }
+ rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ rfc2544_profile.rate = 1000
+ completed, samples = rfc2544_profile.get_drop_percentage(
+ samples, 0.2, 1)
+ self.assertFalse(completed)
+ self.assertEqual(23.0, samples['TxThroughput'])
+ self.assertEqual(21.0, samples['RxThroughput'])
+ self.assertEqual(0.1, samples['DropPercentage'])
+ self.assertEqual(rfc2544_profile.rate, rfc2544_profile.min_rate)
- def test_get_multiplier(self):
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.max_rate = 100
- r_f_c2544_profile.min_rate = 100
- self.assertEqual("1.0", r_f_c2544_profile.get_multiplier())
+ @mock.patch.object(ixia_rfc2544.LOG, 'info')
+ def test_get_drop_percentage_not_flow(self, *args):
+ samples = {'iface_name_1':
+ {'RxThroughput': 0, 'TxThroughput': 10,
+ 'in_packets': 1000, 'out_packets': 0},
+ 'iface_name_2':
+ {'RxThroughput': 0, 'TxThroughput': 13,
+ 'in_packets': 1005, 'out_packets': 0}
+ }
+ rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ rfc2544_profile.rate = 1000
+ completed, samples = rfc2544_profile.get_drop_percentage(
+ samples, 0.2, 1)
+ self.assertFalse(completed)
+ self.assertEqual(23.0, samples['TxThroughput'])
+ self.assertEqual(0, samples['RxThroughput'])
+ self.assertEqual(100, samples['DropPercentage'])
+ self.assertEqual(rfc2544_profile.rate, rfc2544_profile.max_rate)
- def test_start_ixia_latency(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
- traffic_generator.networks = {
- "uplink_0": ["xe0"],
- "downlink_0": ["xe1"],
- }
- traffic_generator.client = \
- mock.Mock(return_value=True)
- r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.max_rate = 100
- r_f_c2544_profile.min_rate = 100
- ixia_obj = mock.MagicMock()
- r_f_c2544_profile._get_ixia_traffic_profile = \
- mock.Mock(return_value={})
- r_f_c2544_profile.full_profile = {}
- r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
- self.assertIsNone(
- r_f_c2544_profile.start_ixia_latency(traffic_generator, ixia_obj))
+ def test_get_drop_percentage_first_run(self):
+ samples = {'iface_name_1':
+ {'RxThroughput': 10, 'TxThroughput': 10,
+ 'in_packets': 1000, 'out_packets': 1000},
+ 'iface_name_2':
+ {'RxThroughput': 11, 'TxThroughput': 13,
+ 'in_packets': 1005, 'out_packets': 1007}
+ }
+ rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ completed, samples = rfc2544_profile.get_drop_percentage(
+ samples, 0, 1, first_run=True)
+ self.assertTrue(completed)
+ self.assertEqual(23.0, samples['TxThroughput'])
+ self.assertEqual(21.0, samples['RxThroughput'])
+ self.assertEqual(0.1, samples['DropPercentage'])
+ self.assertEqual(33.45, rfc2544_profile.rate)
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py b/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py
index e466305ea..cf31cc27c 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py
@@ -124,5 +124,5 @@ class TestProxProfile(unittest.TestCase):
for _ in profile.bounds_iterator(mock_logger):
pass
- self.assertEqual(mock_logger.debug.call_count, 1)
+ mock_logger.debug.assert_called_once()
self.assertEqual(mock_logger.info.call_count, 10)
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py
index 2684e0ba1..0cf93f9ae 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py
@@ -11,33 +11,26 @@
# 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 import STL_MOCKS
-
+from trex_stl_lib import api as Pkt
+from trex_stl_lib import trex_stl_client
+from trex_stl_lib import trex_stl_packet_builder_scapy
+from trex_stl_lib import trex_stl_streams
-STLClient = mock.MagicMock()
-stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
-stl_patch.start()
+from yardstick.network_services.traffic_profile import rfc2544
+from yardstick.tests.unit import base
-if stl_patch:
- from yardstick.network_services.traffic_profile.trex_traffic_profile \
- import TrexProfile
- from yardstick.network_services.traffic_profile.rfc2544 import \
- RFC2544Profile
-
-class TestRFC2544Profile(unittest.TestCase):
+class TestRFC2544Profile(base.BaseUnitTestCase):
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
+ "frame_rate": 100,
"flow_number": 10,
"frame_size": 64}}
@@ -45,233 +38,251 @@ class TestRFC2544Profile(unittest.TestCase):
'name': 'rfc2544',
'traffic_profile': {'traffic_type': 'RFC2544Profile',
'frame_rate': 100},
- 'downlink_0': {'ipv4':
- {'outer_l2': {'framesize':
- {'64B': '100', '1518B': '0',
- '128B': '0', '1400B': '0',
- '256B': '0', '373b': '0',
- '570B': '0'}},
- 'outer_l3v4': {'dstip4': '1.1.1.1-1.15.255.255',
- 'proto': 'udp',
- 'srcip4': '90.90.1.1-90.105.255.255',
- 'dscp': 0, 'ttl': 32, 'count': 1},
- 'outer_l4': {'srcport': '2001',
- 'dsrport': '1234', 'count': 1}}},
- 'uplink_0': {'ipv4':
- {'outer_l2': {'framesize':
- {'64B': '100', '1518B': '0',
- '128B': '0', '1400B': '0',
- '256B': '0', '373b': '0',
- '570B': '0'}},
- 'outer_l3v4': {'dstip4': '9.9.1.1-90.105.255.255',
- 'proto': 'udp',
- 'srcip4': '1.1.1.1-1.15.255.255',
- 'dscp': 0, 'ttl': 32, 'count': 1},
- 'outer_l4': {'dstport': '2001',
- 'srcport': '1234', 'count': 1}}},
+ 'downlink_0':
+ {'ipv4':
+ {'outer_l2':
+ {'framesize':
+ {'64B': '100', '1518B': '0',
+ '128B': '0', '1400B': '0',
+ '256B': '0', '373b': '0',
+ '570B': '0'}},
+ 'outer_l3v4':
+ {'dstip4': '1.1.1.1-1.15.255.255',
+ 'proto': 'udp',
+ 'srcip4': '90.90.1.1-90.105.255.255',
+ 'dscp': 0, 'ttl': 32, 'count': 1},
+ 'outer_l4':
+ {'srcport': '2001',
+ 'dsrport': '1234', 'count': 1}}},
+ 'uplink_0':
+ {'ipv4':
+ {'outer_l2':
+ {'framesize':
+ {'64B': '100', '1518B': '0',
+ '128B': '0', '1400B': '0',
+ '256B': '0', '373b': '0',
+ '570B': '0'}},
+ 'outer_l3v4':
+ {'dstip4': '9.9.1.1-90.105.255.255',
+ 'proto': 'udp',
+ 'srcip4': '1.1.1.1-1.15.255.255',
+ 'dscp': 0, 'ttl': 32, 'count': 1},
+ 'outer_l4':
+ {'dstport': '2001',
+ 'srcport': '1234', 'count': 1}}},
'schema': 'isb:traffic_profile:0.1'}
def test___init__(self):
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- self.assertIsNotNone(r_f_c2544_profile.rate)
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ self.assertEqual(rfc2544_profile.max_rate, rfc2544_profile.rate)
+ self.assertEqual(0, rfc2544_profile.min_rate)
- def test_execute(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
- traffic_generator.networks = {
- "uplink_0": ["xe0"],
- "downlink_0": ["xe1"],
- }
- traffic_generator.client.return_value = True
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.params = self.PROFILE
- r_f_c2544_profile.first_run = True
- self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator))
+ def test_stop_traffic(self):
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ mock_generator = mock.Mock()
+ rfc2544_profile.stop_traffic(traffic_generator=mock_generator)
+ mock_generator.client.stop.assert_called_once()
+ mock_generator.client.reset.assert_called_once()
+ mock_generator.client.remove_all_streams.assert_called_once()
- def test_get_drop_percentage(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
- traffic_generator.networks = {
- "uplink_0": ["xe0"],
- "downlink_0": ["xe1"],
- }
- traffic_generator.client.return_value = True
+ def test_execute_traffic(self):
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ mock_generator = mock.Mock()
+ mock_generator.networks = {
+ 'downlink_0': ['xe0', 'xe1'],
+ 'uplink_0': ['xe2', 'xe3'],
+ 'downlink_1': []}
+ mock_generator.port_num.side_effect = [10, 20, 30, 40]
+ mock_generator.rfc2544_helper.correlated_traffic = False
+ rfc2544_profile.params = {
+ 'downlink_0': 'profile1',
+ 'uplink_0': 'profile2'}
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.params = self.PROFILE
- r_f_c2544_profile.register_generator(traffic_generator)
- self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator))
+ with mock.patch.object(rfc2544_profile, '_create_profile') as \
+ mock_create_profile:
+ rfc2544_profile.execute_traffic(traffic_generator=mock_generator)
+ mock_create_profile.assert_has_calls([
+ mock.call('profile1', rfc2544_profile.rate, mock.ANY),
+ mock.call('profile1', rfc2544_profile.rate, mock.ANY),
+ mock.call('profile2', rfc2544_profile.rate, mock.ANY),
+ mock.call('profile2', rfc2544_profile.rate, mock.ANY)])
+ mock_generator.client.add_streams.assert_has_calls([
+ mock.call(mock.ANY, ports=[10]),
+ mock.call(mock.ANY, ports=[20]),
+ mock.call(mock.ANY, ports=[30]),
+ mock.call(mock.ANY, ports=[40])])
+ mock_generator.client.start(ports=[10, 20, 30, 40],
+ duration=rfc2544_profile.config.duration,
+ force=True)
- samples = {}
- for ifname in range(1):
- name = "xe{}".format(ifname)
- samples[name] = {
- "rx_throughput_fps": 20,
- "tx_throughput_fps": 20,
- "rx_throughput_mbps": 10,
- "tx_throughput_mbps": 10,
- "in_packets": 1000,
- "out_packets": 1000,
- }
+ @mock.patch.object(trex_stl_streams, 'STLProfile')
+ def test__create_profile(self, mock_stl_profile):
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ port_pg_id = mock.ANY
+ profile_data = {'packetid_1': {'outer_l2': {'framesize': 'imix_info'}}}
+ rate = 100
+ with mock.patch.object(rfc2544_profile, '_create_imix_data') as \
+ mock_create_imix, \
+ mock.patch.object(rfc2544_profile, '_create_vm') as \
+ mock_create_vm, \
+ mock.patch.object(rfc2544_profile, '_create_streams') as \
+ mock_create_streams:
+ mock_create_imix.return_value = 'imix_data'
+ mock_create_streams.return_value = ['stream1']
+ rfc2544_profile._create_profile(profile_data, rate, port_pg_id)
- expected = {
- 'DropPercentage': 0.0,
- 'RxThroughput': 100 / 3.0,
- 'TxThroughput': 100 / 3.0,
- 'CurrentDropPercentage': 0.0,
- 'Throughput': 66.66666666666667,
- 'xe0': {
- 'tx_throughput_fps': 20,
- 'in_packets': 1000,
- 'out_packets': 1000,
- 'rx_throughput_mbps': 10,
- 'tx_throughput_mbps': 10,
- 'rx_throughput_fps': 20,
- },
- }
- traffic_generator.generate_samples.return_value = samples
- traffic_generator.RUN_DURATION = 30
- traffic_generator.rfc2544_helper.tolerance_low = 0.0001
- traffic_generator.rfc2544_helper.tolerance_high = 0.0001
- result = r_f_c2544_profile.get_drop_percentage(traffic_generator)
- self.assertDictEqual(result, expected)
+ mock_create_imix.assert_called_once_with('imix_info')
+ mock_create_vm.assert_called_once_with(
+ {'outer_l2': {'framesize': 'imix_info'}})
+ mock_create_streams.assert_called_once_with('imix_data', 100,
+ port_pg_id)
+ mock_stl_profile.assert_called_once_with(['stream1'])
- def test_get_drop_percentage_update(self):
- traffic_generator = mock.Mock(autospec=RFC2544Profile)
- traffic_generator.networks = {
- "uplink_0": ["xe0"],
- "downlink_0": ["xe1"],
- }
- traffic_generator.client = mock.Mock(return_value=True)
+ def test__create_imix_data(self):
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ data = {'64B': 50, '128B': 50}
+ self.assertEqual({'64': 50.0, '128': 50.0},
+ rfc2544_profile._create_imix_data(data))
+ data = {'64B': 1, '128b': 3}
+ self.assertEqual({'64': 25.0, '128': 75.0},
+ rfc2544_profile._create_imix_data(data))
+ data = {}
+ self.assertEqual({}, rfc2544_profile._create_imix_data(data))
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.params = self.PROFILE
- r_f_c2544_profile.register_generator(traffic_generator)
- self.assertIsNone(r_f_c2544_profile.execute_traffic())
+ def test__create_vm(self):
+ packet = {'outer_l2': 'l2_definition'}
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ with mock.patch.object(rfc2544_profile, '_set_outer_l2_fields') as \
+ mock_l2_fileds:
+ rfc2544_profile._create_vm(packet)
+ mock_l2_fileds.assert_called_once_with('l2_definition')
- samples = {}
- for ifname in range(1):
- name = "xe{}".format(ifname)
- samples[name] = {
- "rx_throughput_fps": 20,
- "tx_throughput_fps": 20,
- "rx_throughput_mbps": 10,
- "tx_throughput_mbps": 10,
- "in_packets": 1000,
- "out_packets": 1002,
- }
- expected = {
- 'DropPercentage': 0.1996,
- 'RxThroughput': 33.333333333333336,
- 'TxThroughput': 33.4,
- 'CurrentDropPercentage': 0.1996,
- 'Throughput': 66.66666666666667,
- 'xe0': {
- 'tx_throughput_fps': 20,
- 'in_packets': 1000,
- 'out_packets': 1002,
- 'rx_throughput_mbps': 10,
- 'tx_throughput_mbps': 10,
- 'rx_throughput_fps': 20,
- },
- }
- traffic_generator.generate_samples = mock.MagicMock(
- return_value=samples)
- traffic_generator.RUN_DURATION = 30
- traffic_generator.rfc2544_helper.tolerance_low = 0.0001
- traffic_generator.rfc2544_helper.tolerance_high = 0.0001
- result = r_f_c2544_profile.get_drop_percentage(traffic_generator)
- self.assertDictEqual(expected, result)
+ @mock.patch.object(trex_stl_packet_builder_scapy, 'STLPktBuilder',
+ return_value='packet')
+ def test__create_single_packet(self, mock_pktbuilder):
+ size = 128
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ rfc2544_profile.ether_packet = Pkt.Eth()
+ rfc2544_profile.ip_packet = Pkt.IP()
+ rfc2544_profile.udp_packet = Pkt.UDP()
+ rfc2544_profile.trex_vm = 'trex_vm'
+ base_pkt = (rfc2544_profile.ether_packet / rfc2544_profile.ip_packet /
+ rfc2544_profile.udp_packet)
+ pad = (size - len(base_pkt)) * 'x'
+ output = rfc2544_profile._create_single_packet(size=size)
+ mock_pktbuilder.assert_called_once_with(pkt=base_pkt / pad,
+ vm='trex_vm')
+ self.assertEqual(output, 'packet')
- def test_get_drop_percentage_div_zero(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
- traffic_generator.networks = {
- "uplink_0": ["xe0"],
- "downlink_0": ["xe1"],
- }
- traffic_generator.client = \
- mock.Mock(return_value=True)
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.params = self.PROFILE
- self.assertIsNone(
- r_f_c2544_profile.execute_traffic(traffic_generator))
- samples = {}
- for ifname in range(1):
- name = "xe{}".format(ifname)
- samples[name] = {"rx_throughput_fps": 20,
- "tx_throughput_fps": 20,
- "rx_throughput_mbps": 10,
- "tx_throughput_mbps": 10,
- "in_packets": 1000,
- "out_packets": 0}
- r_f_c2544_profile.throughput_max = 0
- expected = {
- 'DropPercentage': 100.0, 'RxThroughput': 100 / 3.0,
- 'TxThroughput': 0.0, 'CurrentDropPercentage': 100.0,
- 'Throughput': 66.66666666666667,
- 'xe0': {
- 'tx_throughput_fps': 20, 'in_packets': 1000,
- 'out_packets': 0, 'rx_throughput_mbps': 10,
- 'tx_throughput_mbps': 10, 'rx_throughput_fps': 20
- }
- }
- traffic_generator.generate_samples = mock.Mock(return_value=samples)
- traffic_generator.RUN_DURATION = 30
- traffic_generator.rfc2544_helper.tolerance_low = 0.0001
- traffic_generator.rfc2544_helper.tolerance_high = 0.0001
- self.assertDictEqual(expected,
- r_f_c2544_profile.get_drop_percentage(traffic_generator))
+ @mock.patch.object(trex_stl_packet_builder_scapy, 'STLPktBuilder',
+ return_value='packet')
+ def test__create_single_packet_qinq(self, mock_pktbuilder):
+ size = 128
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ rfc2544_profile.ether_packet = Pkt.Eth()
+ rfc2544_profile.ip_packet = Pkt.IP()
+ rfc2544_profile.udp_packet = Pkt.UDP()
+ rfc2544_profile.trex_vm = 'trex_vm'
+ rfc2544_profile.qinq = True
+ rfc2544_profile.qinq_packet = Pkt.Dot1Q(vlan=1) / Pkt.Dot1Q(vlan=2)
+ base_pkt = (rfc2544_profile.ether_packet /
+ rfc2544_profile.qinq_packet / rfc2544_profile.ip_packet /
+ rfc2544_profile.udp_packet)
+ pad = (size - len(base_pkt)) * 'x'
+ output = rfc2544_profile._create_single_packet(size=size)
+ mock_pktbuilder.assert_called_once_with(pkt=base_pkt / pad,
+ vm='trex_vm')
+ self.assertEqual(output, 'packet')
+
+ @mock.patch.object(trex_stl_streams, 'STLFlowLatencyStats')
+ @mock.patch.object(trex_stl_streams, 'STLTXCont')
+ @mock.patch.object(trex_stl_client, 'STLStream')
+ def test__create_streams(self, mock_stream, mock_txcont, mock_latency):
+ imix_data = {'64': 25, '512': 75}
+ rate = 35
+ port_pg_id = rfc2544.PortPgIDMap()
+ port_pg_id.add_port(10)
+ mock_stream.side_effect = ['stream1', 'stream2']
+ mock_txcont.side_effect = ['txcont1', 'txcont2']
+ mock_latency.side_effect = ['latency1', 'latency2']
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ with mock.patch.object(rfc2544_profile, '_create_single_packet'):
+ output = rfc2544_profile._create_streams(imix_data, rate,
+ port_pg_id)
+ self.assertEqual(['stream1', 'stream2'], output)
+ mock_latency.assert_has_calls([
+ mock.call(pg_id=1), mock.call(pg_id=2)])
+ mock_txcont.assert_has_calls([
+ mock.call(percentage=float(25 * 35) / 100),
+ mock.call(percentage=float(75 * 35) / 100)], any_order=True)
+
+ def test_get_drop_percentage(self):
+ rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE)
+ samples = [
+ {'xe1': {'tx_throughput_fps': 100,
+ 'rx_throughput_fps': 101,
+ 'out_packets': 2000,
+ 'in_packets': 2010},
+ 'xe2': {'tx_throughput_fps': 200,
+ 'rx_throughput_fps': 201,
+ 'out_packets': 4000,
+ 'in_packets': 4010}},
+ {'xe1': {'tx_throughput_fps': 106,
+ 'rx_throughput_fps': 108,
+ 'out_packets': 2031,
+ 'in_packets': 2040,
+ 'latency': 'Latency1'},
+ 'xe2': {'tx_throughput_fps': 203,
+ 'rx_throughput_fps': 215,
+ 'out_packets': 4025,
+ 'in_packets': 4040,
+ 'latency': 'Latency2'}}
+ ]
+ output = rfc2544_profile.get_drop_percentage(samples, 0, 0, False)
+ expected = {'DropPercentage': 0.3963,
+ 'Latency': {'xe1': 'Latency1', 'xe2': 'Latency2'},
+ 'RxThroughput': 312.5,
+ 'TxThroughput': 304.5,
+ 'CurrentDropPercentage': 0.3963,
+ 'Rate': 100,
+ 'Throughput': 312.5}
+ self.assertEqual(expected, output)
- def test_get_multiplier(self):
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.max_rate = 100
- r_f_c2544_profile.min_rate = 100
- self.assertEqual("1.0", r_f_c2544_profile.get_multiplier())
- def test_calculate_pps(self):
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.rate = 100
- r_f_c2544_profile.pps = 100
- samples = {'Throughput': 4549093.33}
- self.assertEqual((2274546.67, 1.0),
- r_f_c2544_profile.calculate_pps(samples))
+class PortPgIDMapTestCase(base.BaseUnitTestCase):
- def test_create_single_stream(self):
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile._create_single_packet = mock.MagicMock()
- r_f_c2544_profile.pg_id = 1
- self.assertIsNotNone(
- r_f_c2544_profile.create_single_stream(64, 2274546.67))
+ def test_add_port(self):
+ port_pg_id_map = rfc2544.PortPgIDMap()
+ port_pg_id_map.add_port(10)
+ self.assertEqual(10, port_pg_id_map._last_port)
+ self.assertEqual([], port_pg_id_map._port_pg_id_map[10])
- def test_create_single_stream_no_pg_id(self):
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile._create_single_packet = mock.MagicMock()
- r_f_c2544_profile.pg_id = 0
- self.assertIsNotNone(
- r_f_c2544_profile.create_single_stream(64, 2274546.67))
+ def test_get_pg_ids(self):
+ port_pg_id_map = rfc2544.PortPgIDMap()
+ port_pg_id_map.add_port(10)
+ port_pg_id_map.increase_pg_id()
+ port_pg_id_map.increase_pg_id()
+ port_pg_id_map.add_port(20)
+ port_pg_id_map.increase_pg_id()
+ self.assertEqual([1, 2], port_pg_id_map.get_pg_ids(10))
+ self.assertEqual([3], port_pg_id_map.get_pg_ids(20))
- def test_execute_latency(self):
- traffic_generator = mock.Mock(autospec=TrexProfile)
- traffic_generator.networks = {
- "private_0": ["xe0"],
- "public_0": ["xe1"],
- }
- traffic_generator.client = \
- mock.Mock(return_value=True)
- r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE)
- r_f_c2544_profile.params = self.PROFILE
- r_f_c2544_profile.first_run = True
- samples = {}
- for ifname in range(1):
- name = "xe{}".format(ifname)
- samples[name] = {"rx_throughput_fps": 20,
- "tx_throughput_fps": 20,
- "rx_throughput_mbps": 10,
- "tx_throughput_mbps": 10,
- "in_packets": 1000,
- "out_packets": 0}
+ def test_increase_pg_id_no_port(self):
+ port_pg_id_map = rfc2544.PortPgIDMap()
+ self.assertIsNone(port_pg_id_map.increase_pg_id())
- samples['Throughput'] = 4549093.33
- r_f_c2544_profile.calculate_pps = mock.Mock(return_value=[2274546.67,
- 1.0])
+ def test_increase_pg_id_last_port(self):
+ port_pg_id_map = rfc2544.PortPgIDMap()
+ port_pg_id_map.add_port(10)
+ self.assertEqual(1, port_pg_id_map.increase_pg_id())
+ self.assertEqual([1], port_pg_id_map.get_pg_ids(10))
+ self.assertEqual(10, port_pg_id_map._last_port)
- self.assertIsNone(r_f_c2544_profile.execute_latency(traffic_generator,
- samples))
+ def test_increase_pg_id(self):
+ port_pg_id_map = rfc2544.PortPgIDMap()
+ port_pg_id_map.add_port(10)
+ port_pg_id_map.increase_pg_id()
+ self.assertEqual(2, port_pg_id_map.increase_pg_id(port=20))
+ self.assertEqual([1], port_pg_id_map.get_pg_ids(10))
+ self.assertEqual([2], port_pg_id_map.get_pg_ids(20))
+ self.assertEqual(20, port_pg_id_map._last_port)
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py b/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py
index 5fe1b7326..628e85459 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py
@@ -14,29 +14,12 @@
import ipaddress
-import mock
import six
import unittest
-from yardstick.tests import STL_MOCKS
from yardstick.common import exceptions as y_exc
-
-STLClient = mock.MagicMock()
-stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
-stl_patch.start()
-
-if stl_patch:
- from yardstick.network_services.traffic_profile.base import TrafficProfile
- from yardstick.network_services.traffic_profile.trex_traffic_profile import TrexProfile
- from yardstick.network_services.traffic_profile.trex_traffic_profile import SRC
- from yardstick.network_services.traffic_profile.trex_traffic_profile import DST
- from yardstick.network_services.traffic_profile.trex_traffic_profile import ETHERNET
- from yardstick.network_services.traffic_profile.trex_traffic_profile import IP
- from yardstick.network_services.traffic_profile.trex_traffic_profile import IPv6
- from yardstick.network_services.traffic_profile.trex_traffic_profile import UDP
- from yardstick.network_services.traffic_profile.trex_traffic_profile import SRC_PORT
- from yardstick.network_services.traffic_profile.trex_traffic_profile import DST_PORT
- from yardstick.network_services.traffic_profile.trex_traffic_profile import TYPE_OF_SERVICE
+from yardstick.network_services.traffic_profile import base as tp_base
+from yardstick.network_services.traffic_profile import trex_traffic_profile
class TestTrexProfile(unittest.TestCase):
@@ -59,7 +42,7 @@ class TestTrexProfile(unittest.TestCase):
'name': 'rfc2544',
'traffic_profile': {'traffic_type': 'RFC2544Profile',
'frame_rate': 100},
- TrafficProfile.DOWNLINK: {
+ tp_base.TrafficProfile.DOWNLINK: {
'ipv4': {'outer_l2': {'framesize': {'64B': '100',
'1518B': '0',
'128B': '0',
@@ -77,7 +60,7 @@ class TestTrexProfile(unittest.TestCase):
'outer_l4': {'srcport': '2001',
'dsrport': '1234',
'count': 1}}},
- TrafficProfile.UPLINK: {
+ tp_base.TrafficProfile.UPLINK: {
'ipv4':
{'outer_l2': {'framesize':
{'64B': '100', '1518B': '0',
@@ -99,7 +82,7 @@ class TestTrexProfile(unittest.TestCase):
'name': 'rfc2544',
'traffic_profile': {'traffic_type': 'RFC2544Profile',
'frame_rate': 100},
- TrafficProfile.DOWNLINK: {
+ tp_base.TrafficProfile.DOWNLINK: {
'ipv6': {'outer_l2': {'framesize':
{'64B': '100', '1518B': '0',
'128B': '0', '1400B': '0',
@@ -118,7 +101,7 @@ class TestTrexProfile(unittest.TestCase):
'outer_l4': {'srcport': '2001',
'dsrport': '1234',
'count': 1}}},
- TrafficProfile.UPLINK: {
+ tp_base.TrafficProfile.UPLINK: {
'ipv6': {'outer_l2': {'framesize':
{'64B': '100', '1518B': '0',
'128B': '0', '1400B': '0',
@@ -140,17 +123,15 @@ class TestTrexProfile(unittest.TestCase):
'schema': 'isb:traffic_profile:0.1'}
def test___init__(self):
- TrafficProfile.params = self.PROFILE
- trex_profile = \
- TrexProfile(TrafficProfile)
+ trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
self.assertEqual(trex_profile.pps, 100)
def test_qinq(self):
+ trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
qinq = {"S-VLAN": {"id": 128, "priority": 0, "cfi": 0},
"C-VLAN": {"id": 512, "priority": 0, "cfi": 0}}
- trex_profile = \
- TrexProfile(TrafficProfile)
+ trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
self.assertIsNone(trex_profile.set_qinq(qinq))
qinq = {"S-VLAN": {"id": "128-130", "priority": 0, "cfi": 0},
@@ -158,64 +139,39 @@ class TestTrexProfile(unittest.TestCase):
self.assertIsNone(trex_profile.set_qinq(qinq))
def test__set_outer_l2_fields(self):
- trex_profile = \
- TrexProfile(TrafficProfile)
+ trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
qinq = {"S-VLAN": {"id": 128, "priority": 0, "cfi": 0},
"C-VLAN": {"id": 512, "priority": 0, "cfi": 0}}
- outer_l2 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l2']
+ outer_l2 = self.PROFILE[
+ tp_base.TrafficProfile.UPLINK]['ipv4']['outer_l2']
outer_l2['QinQ'] = qinq
self.assertIsNone(trex_profile._set_outer_l2_fields(outer_l2))
def test__set_outer_l3v4_fields(self):
- trex_profile = \
- TrexProfile(TrafficProfile)
- outer_l3v4 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l3v4']
+ trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
+ outer_l3v4 = self.PROFILE[
+ tp_base.TrafficProfile.UPLINK]['ipv4']['outer_l3v4']
outer_l3v4['proto'] = 'tcp'
self.assertIsNone(trex_profile._set_outer_l3v4_fields(outer_l3v4))
def test__set_outer_l3v6_fields(self):
- trex_profile = \
- TrexProfile(TrafficProfile)
- outer_l3v6 = self.PROFILE_v6[TrafficProfile.UPLINK]['ipv6']['outer_l3v4']
+ trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
+ outer_l3v6 = self.PROFILE_v6[
+ tp_base.TrafficProfile.UPLINK]['ipv6']['outer_l3v4']
outer_l3v6['proto'] = 'tcp'
outer_l3v6['tc'] = 1
outer_l3v6['hlim'] = 10
self.assertIsNone(trex_profile._set_outer_l3v6_fields(outer_l3v6))
def test__set_outer_l4_fields(self):
- trex_profile = \
- TrexProfile(TrafficProfile)
- outer_l4 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l4']
+ trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
+ outer_l4 = self.PROFILE[
+ tp_base.TrafficProfile.UPLINK]['ipv4']['outer_l4']
self.assertIsNone(trex_profile._set_outer_l4_fields(outer_l4))
- def test_get_streams(self):
- trex_profile = \
- TrexProfile(TrafficProfile)
- trex_profile.params = self.PROFILE
- profile_data = self.PROFILE[TrafficProfile.UPLINK]
- self.assertIsNotNone(trex_profile.get_streams(profile_data))
- trex_profile.pg_id = 1
- self.assertIsNotNone(trex_profile.get_streams(profile_data))
- trex_profile.params = self.PROFILE_v6
- trex_profile.profile_data = self.PROFILE_v6[TrafficProfile.UPLINK]
- self.assertIsNotNone(trex_profile.get_streams(profile_data))
- trex_profile.pg_id = 1
- self.assertIsNotNone(trex_profile.get_streams(profile_data))
-
- def test_generate_packets(self):
- trex_profile = \
- TrexProfile(TrafficProfile)
- trex_profile.fsize = 10
- trex_profile.base_pkt = [10]
- self.assertIsNone(trex_profile.generate_packets())
-
- def test_generate_imix_data_error(self):
- trex_profile = \
- TrexProfile(TrafficProfile)
- self.assertEqual({}, trex_profile.generate_imix_data(False))
-
def test__count_ip_ipv4(self):
- start, end, count = TrexProfile._count_ip('1.1.1.1', '1.2.3.4')
+ start, end, count = trex_traffic_profile.TrexProfile._count_ip(
+ '1.1.1.1', '1.2.3.4')
self.assertEqual('1.1.1.1', str(start))
self.assertEqual('1.2.3.4', str(end))
diff = (int(ipaddress.IPv4Address(six.u('1.2.3.4'))) -
@@ -225,7 +181,8 @@ class TestTrexProfile(unittest.TestCase):
def test__count_ip_ipv6(self):
start_ip = '0064:ff9b:0:0:0:0:9810:6414'
end_ip = '0064:ff9b:0:0:0:0:9810:6420'
- start, end, count = TrexProfile._count_ip(start_ip, end_ip)
+ start, end, count = trex_traffic_profile.TrexProfile._count_ip(
+ start_ip, end_ip)
self.assertEqual(0x98106414, start)
self.assertEqual(0x98106420, end)
self.assertEqual(0x98106420 - 0x98106414, count)
@@ -234,10 +191,10 @@ class TestTrexProfile(unittest.TestCase):
start_ip = '0064:ff9b:0:0:0:0:9810:6420'
end_ip = '0064:ff9b:0:0:0:0:9810:6414'
with self.assertRaises(y_exc.IPv6RangeError):
- TrexProfile._count_ip(start_ip, end_ip)
+ trex_traffic_profile.TrexProfile._count_ip(start_ip, end_ip)
def test__dscp_range_action_partial_actual_count_zero(self):
- traffic_profile = TrexProfile(TrafficProfile)
+ traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
dscp_partial = traffic_profile._dscp_range_action_partial()
flow_vars_initial_length = len(traffic_profile.vm_flow_vars)
@@ -245,7 +202,7 @@ class TestTrexProfile(unittest.TestCase):
self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2)
def test__dscp_range_action_partial_count_greater_than_actual(self):
- traffic_profile = TrexProfile(TrafficProfile)
+ traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
dscp_partial = traffic_profile._dscp_range_action_partial()
flow_vars_initial_length = len(traffic_profile.vm_flow_vars)
@@ -253,7 +210,7 @@ class TestTrexProfile(unittest.TestCase):
self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2)
def test__udp_range_action_partial_actual_count_zero(self):
- traffic_profile = TrexProfile(TrafficProfile)
+ traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
traffic_profile.udp['field1'] = 'value1'
udp_partial = traffic_profile._udp_range_action_partial('field1')
@@ -262,48 +219,59 @@ class TestTrexProfile(unittest.TestCase):
self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2)
def test__udp_range_action_partial_count_greater_than_actual(self):
- traffic_profile = TrexProfile(TrafficProfile)
+ traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
traffic_profile.udp['field1'] = 'value1'
- udp_partial = traffic_profile._udp_range_action_partial('field1', 'not_used_count')
-
+ udp_partial = traffic_profile._udp_range_action_partial(
+ 'field1', 'not_used_count')
flow_vars_initial_length = len(traffic_profile.vm_flow_vars)
udp_partial('1', '10', '100')
self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2)
def test__general_single_action_partial(self):
- trex_profile = TrexProfile(TrafficProfile)
-
- trex_profile._general_single_action_partial(ETHERNET)(SRC)(
+ trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
+ trex_profile._general_single_action_partial(
+ trex_traffic_profile.ETHERNET)(trex_traffic_profile.SRC)(
self.EXAMPLE_ETHERNET_ADDR)
self.assertEqual(self.EXAMPLE_ETHERNET_ADDR,
trex_profile.ether_packet.src)
- trex_profile._general_single_action_partial(IP)(DST)(
- self.EXAMPLE_IP_ADDR)
+ trex_profile._general_single_action_partial(trex_traffic_profile.IP)(
+ trex_traffic_profile.DST)(self.EXAMPLE_IP_ADDR)
self.assertEqual(self.EXAMPLE_IP_ADDR, trex_profile.ip_packet.dst)
- trex_profile._general_single_action_partial(IPv6)(DST)(
- self.EXAMPLE_IPv6_ADDR)
+ trex_profile._general_single_action_partial(trex_traffic_profile.IPv6)(
+ trex_traffic_profile.DST)(self.EXAMPLE_IPv6_ADDR)
self.assertEqual(self.EXAMPLE_IPv6_ADDR, trex_profile.ip6_packet.dst)
- trex_profile._general_single_action_partial(UDP)(SRC_PORT)(5060)
+ trex_profile._general_single_action_partial(trex_traffic_profile.UDP)(
+ trex_traffic_profile.SRC_PORT)(5060)
self.assertEqual(5060, trex_profile.udp_packet.sport)
- trex_profile._general_single_action_partial(IP)(TYPE_OF_SERVICE)(0)
+ trex_profile._general_single_action_partial(trex_traffic_profile.IP)(
+ trex_traffic_profile.TYPE_OF_SERVICE)(0)
self.assertEqual(0, trex_profile.ip_packet.tos)
def test__set_proto_addr(self):
- trex_profile = TrexProfile(TrafficProfile)
+ trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE)
ether_range = "00:00:00:00:00:01-00:00:00:00:00:02"
ip_range = "1.1.1.2-1.1.1.10"
ipv6_range = '0064:ff9b:0:0:0:0:9810:6414-0064:ff9b:0:0:0:0:9810:6420'
- trex_profile._set_proto_addr(ETHERNET, SRC, ether_range)
- trex_profile._set_proto_addr(ETHERNET, DST, ether_range)
- trex_profile._set_proto_addr(IP, SRC, ip_range)
- trex_profile._set_proto_addr(IP, DST, ip_range)
- trex_profile._set_proto_addr(IPv6, SRC, ipv6_range)
- trex_profile._set_proto_addr(IPv6, DST, ipv6_range)
- trex_profile._set_proto_addr(UDP, SRC_PORT, "5060-5090")
- trex_profile._set_proto_addr(UDP, DST_PORT, "5060")
+ trex_profile._set_proto_addr(trex_traffic_profile.ETHERNET,
+ trex_traffic_profile.SRC, ether_range)
+ trex_profile._set_proto_addr(trex_traffic_profile.ETHERNET,
+ trex_traffic_profile.DST, ether_range)
+ trex_profile._set_proto_addr(trex_traffic_profile.IP,
+ trex_traffic_profile.SRC, ip_range)
+ trex_profile._set_proto_addr(trex_traffic_profile.IP,
+ trex_traffic_profile.DST, ip_range)
+ trex_profile._set_proto_addr(trex_traffic_profile.IPv6,
+ trex_traffic_profile.SRC, ipv6_range)
+ trex_profile._set_proto_addr(trex_traffic_profile.IPv6,
+ trex_traffic_profile.DST, ipv6_range)
+ trex_profile._set_proto_addr(trex_traffic_profile.UDP,
+ trex_traffic_profile.SRC_PORT,
+ '5060-5090')
+ trex_profile._set_proto_addr(trex_traffic_profile.UDP,
+ trex_traffic_profile.DST_PORT, '5060')
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/acl_1rule.yaml b/yardstick/tests/unit/network_services/vnf_generic/vnf/acl_1rule.yaml
new file mode 100644
index 000000000..b184a29e2
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/acl_1rule.yaml
@@ -0,0 +1,47 @@
+# 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.
+
+access-list1:
+ acl:
+ access-list-entries:
+ - ace:
+ ace-oper-data:
+ match-counter: 0
+ actions: drop,count
+ matches:
+ destination-ipv4-network: 152.16.40.20/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
+ rule-name: rule1588
+ - ace:
+ ace-oper-data:
+ match-counter: 0
+ actions: drop,count
+ matches:
+ destination-ipv4-network: 0.0.0.0/0
+ destination-port-range:
+ lower-port: 0
+ upper-port: 65535
+ source-ipv4-network: 152.16.100.20/24
+ source-port-range:
+ lower-port: 0
+ upper-port: 65535
+ rule-name: rule1589
+ acl-name: sample-ipv4-acl
+ acl-type: ipv4-acl
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..ce32a31e2
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py
@@ -0,0 +1,517 @@
+# 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.tests import STL_MOCKS
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+from yardstick.common import utils
+from yardstick.common import exceptions
+
+
+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.acl_vnf import AclApproxVnf
+ 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
+
+
+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': 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': 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': 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': 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 = AclApproxVnf(name, vnfd)
+ self.assertIsNone(acl_approx_vnf._vnf_process)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @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 = AclApproxVnf(name, vnfd)
+ 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 = {'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 = AclApproxVnf(name, vnfd)
+ 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 = AclApproxVnf(name, vnfd)
+ 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 = AclApproxVnf(name, vnfd)
+ 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 = AclApproxVnf(name, vnfd)
+ 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 = AclApproxVnf(name, vnfd)
+ 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..ebedcb451
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_base.py
@@ -0,0 +1,236 @@
+# 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 mock
+import unittest
+
+from yardstick.network_services.vnf_generic.vnf import base
+from yardstick.ssh import SSH
+
+
+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 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(unittest.TestCase):
+
+ 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])
+
+ 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 TestGenericTrafficGen(unittest.TestCase):
+
+ 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)
+ msg = ("Can't instantiate abstract class GenericTrafficGen with "
+ "abstract methods collect_kpi, instantiate, run_traffic, "
+ "scale, terminate")
+ self.assertEqual(msg, str(exc.exception))
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..6b6f3ef34
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py
@@ -0,0 +1,403 @@
+# 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)
+ self.assertIsNone(cgnapt_approx_vnf._vnf_process)
+
+ @mock.patch.object(process, 'check_if_process_failed')
+ def test_collect_kpi(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd)
+ 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 = {'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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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..cc695a5bf
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py
@@ -0,0 +1,2335 @@
+
+# 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.tests import STL_MOCKS
+from yardstick.common import utils
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services import constants
+
+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.sample_vnf import ScenarioHelper
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxSocketHelper
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import PacketDump
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import CoreSocketTuple
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxTestDataTuple
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxDpdkVnfSetupEnvHelper
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import TotStatsTuple
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxDataHelper
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxResourceHelper
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxProfileHelper
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxMplsProfileHelper
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxBngProfileHelper
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxVpeProfileHelper
+ from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxlwAFTRProfileHelper
+
+class TestCoreTuple(unittest.TestCase):
+ def test___init__(self):
+ core_tuple = 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 = 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):
+ CoreSocketTuple(bad_input)
+
+ def test_find_in_topology(self):
+ topology_in = {
+ 6: {
+ 5: {
+ 'key1': ['a', 'b'],
+ 'key2': ['c', 'd'],
+ },
+ },
+ }
+
+ core_tuple = CoreSocketTuple('core 5s6')
+
+ expected = 'a'
+ result = core_tuple.find_in_topology(topology_in)
+ self.assertEqual(result, expected)
+
+ core_tuple = 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 = 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 = 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
+ TotStatsTuple()
+
+ with self.assertRaises(TypeError):
+ # one, non-integer value
+ TotStatsTuple('a')
+
+ with self.assertRaises(TypeError):
+ # too many values
+ TotStatsTuple(3, 4, 5, 6, 7)
+
+
+class TestProxTestDataTuple(unittest.TestCase):
+ def test___init__(self):
+ prox_test_data = 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 = 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 = 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 = 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 = 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 = 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):
+ PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD)
+
+ def test___str__(self):
+ expected = '<PacketDump port: port_id payload: {}>'.format(self.PAYLOAD)
+ dump1 = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD)
+ self.assertEqual(str(dump1), expected)
+
+ def test_port_id(self):
+ p = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD)
+ self.assertEqual(p.port_id, "port_id")
+
+ def test_data_len(self):
+ p = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD)
+ self.assertEqual(p.data_len, len(self.PAYLOAD))
+
+ def test_payload(self):
+ p = 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('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket')
+ def test___init__(self, mock_socket):
+ expected = mock_socket.socket()
+ prox = ProxSocketHelper()
+ result = prox._sock
+ self.assertEqual(result, expected)
+
+ def test_connect(self):
+ mock_sock = mock.MagicMock()
+ prox = 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 = ProxSocketHelper(mock_sock)
+ result = prox.get_socket()
+ self.assertIs(result, mock_sock)
+
+ # TODO(elfoley): Split this into three tests
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.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 = 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 = 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 = 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 = 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 = 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 = ProxSocketHelper(mock_socket)
+ prox.put_command("data")
+ mock_socket.sendall.assert_called_once()
+
+ def test_get_packet_dump(self):
+ mock_socket = mock.MagicMock()
+ prox = 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 = ProxSocketHelper(mock_socket)
+ prox.stop_all_reset()
+ mock_socket.sendall.assert_called()
+
+ def test_stop_all(self):
+ mock_socket = mock.MagicMock()
+ prox = ProxSocketHelper(mock_socket)
+ prox.stop_all()
+ mock_socket.sendall.assert_called()
+
+ def test_stop(self):
+ mock_socket = mock.MagicMock()
+ prox = ProxSocketHelper(mock_socket)
+ prox.stop([3, 4, 5], 16)
+ mock_socket.sendall.assert_called()
+
+ def test_start_all(self):
+ mock_socket = mock.MagicMock()
+ prox = ProxSocketHelper(mock_socket)
+ prox.start_all()
+ mock_socket.sendall.assert_called()
+
+ def test_start(self):
+ mock_socket = mock.MagicMock()
+ prox = ProxSocketHelper(mock_socket)
+ prox.start([3, 4, 5])
+ mock_socket.sendall.assert_called()
+
+ def test_reset_stats(self):
+ mock_socket = mock.MagicMock()
+ prox = ProxSocketHelper(mock_socket)
+ prox.reset_stats()
+ mock_socket.sendall.assert_called()
+
+ def test_set_pkt_size(self):
+ mock_socket = mock.MagicMock()
+ prox = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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)
+
+ 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 = 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 = 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 = 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 = 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 = 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 = ProxSocketHelper(mock_socket)
+ prox.dump_rx(3, 5, 8)
+ mock_socket.sendall.assert_called_once()
+
+ def test_quit(self):
+ mock_socket = mock.MagicMock()
+ prox = ProxSocketHelper(mock_socket)
+ prox.quit()
+ mock_socket.sendall.assert_called()
+
+ def test_force_quit(self):
+ mock_socket = mock.MagicMock()
+ prox = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = ProxDpdkVnfSetupEnvHelper.write_prox_config(input_data)
+ self.assertEqual(result, expected)
+
+ input_data = [
+ [
+ 'section1',
+ [],
+ ],
+ ]
+ expected = '[section1]'
+ result = 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 = ProxDpdkVnfSetupEnvHelper.write_prox_config(input_data)
+ self.assertEqual(result, expected)
+
+ def test_prox_config_data(self):
+ setup_helper = 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 = ScenarioHelper('vnf1')
+ scenario_helper.scenario_cfg = {
+ 'task_path': 'a/b',
+ 'options': {
+ 'vnf1': vnf1,
+ },
+ }
+
+ helper = 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 = ScenarioHelper('vnf1')
+ scenario_helper.scenario_cfg = {
+ 'task_path': 'a/b',
+ 'options': {
+ 'vnf1': vnf1,
+ },
+ }
+
+ vnfd_helper.port_pairs.all_ports = ['xe0', 'xe1', 'xe2', 'xe3']
+ helper = 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 = ScenarioHelper('vnf1')
+ scenario_helper.scenario_cfg = {
+ 'task_path': 'a/b',
+ 'options': {
+ 'vnf1': vnf1,
+ },
+ }
+
+ helper = 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 = 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 = 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 = 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 = VnfdHelper(self.VNFD0)
+ ssh_helper = mock.MagicMock()
+ scenario_helper = mock.MagicMock()
+
+ helper = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = ProxResourceHelper(setup_helper)
+ with self.assertRaises(NotImplementedError):
+ helper.terminate()
+
+ def test_up_post(self):
+ setup_helper = mock.MagicMock()
+ helper = 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 = 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.port_stats.return_value = list(range(10))
+
+ data_helper = ProxDataHelper(
+ vnfd_helper, sut, pkt_size, 25, None,
+ constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS)
+
+ self.assertEqual(data_helper.rx_total, 6)
+ self.assertEqual(data_helper.tx_total, 7)
+ self.assertEqual(data_helper.requested_pps, 6.25e6)
+
+ def test_samples(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 = ProxDataHelper(vnfd_helper, sut, None, None, None, None)
+
+ expected = {
+ 'xe1': {
+ 'in_packets': 6,
+ 'out_packets': 7,
+ },
+ 'xe2': {
+ 'in_packets': 6,
+ 'out_packets': 7,
+ },
+ }
+ 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 = 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': 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 = 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 = 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 = ProxSocketHelper(mock.MagicMock())
+ sut.get_all_tot_stats = mock.MagicMock(side_effect=[start, end])
+
+ data_helper = ProxDataHelper(vnfd_helper, sut, None, None, 5.4, None)
+
+ self.assertIsNone(data_helper.measured_stats)
+
+ expected = {
+ 'start_tot': start,
+ 'end_tot': end,
+ 'delta': 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 = 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(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 = []
+ 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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..f5f4b3907
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py
@@ -0,0 +1,455 @@
+# 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
+
+
+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.prox_vnf import ProxApproxVnf
+ 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': 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': 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': 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': 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 = ProxApproxVnf(NAME, self.VNFD0)
+ self.assertIsNone(prox_approx_vnf._vnf_process)
+
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi_no_client(self, ssh, *args):
+ mock_ssh(ssh)
+
+ prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0)
+ prox_approx_vnf.resource_helper = None
+ expected = {
+ 'packets_in': 0,
+ 'packets_dropped': 0,
+ 'packets_fwd': 0,
+ 'collect_stats': {'core': {}}
+ }
+ result = prox_approx_vnf.collect_kpi()
+ self.assertEqual(result, expected)
+
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, *args):
+ mock_ssh(ssh)
+
+ resource_helper = mock.MagicMock()
+ resource_helper.execute.return_value = list(range(12))
+ resource_helper.collect_collectd_kpi.return_value = {'core': {'result': 234}}
+
+ prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0)
+ prox_approx_vnf.resource_helper = resource_helper
+
+ expected = {
+ 'packets_in': 6,
+ 'packets_dropped': 1,
+ 'packets_fwd': 7,
+ '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(SSH_HELPER)
+ def test_collect_kpi_error(self, ssh, *args):
+ mock_ssh(ssh)
+
+ resource_helper = mock.MagicMock()
+
+ prox_approx_vnf = ProxApproxVnf(NAME, deepcopy(self.VNFD0))
+ 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 = ProxApproxVnf(NAME, self.VNFD0)
+ 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 = ProxApproxVnf(NAME, self.VNFD0)
+ 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 = ProxApproxVnf(NAME, self.VNFD0)
+ 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 = ProxApproxVnf(NAME, self.VNFD0)
+ 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 = ProxApproxVnf(NAME, self.VNFD0)
+ 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 = ProxApproxVnf(NAME, self.VNFD0)
+ 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..5574c6770
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py
@@ -0,0 +1,260 @@
+# 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 import STL_MOCKS
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+
+
+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.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)
+ 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("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, _):
+ m = mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ router_vnf = RouterVNF(name, vnfd)
+ router_vnf.ssh_helper = m
+ result = {'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)
+ router_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
+ router_vnf._run()
+ router_vnf.ssh_helper.drop_connection.assert_called_once()
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.router_vnf.Context")
+ @mock.patch(SSH_HELPER)
+ def test_instantiate(self, ssh, _):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ router_vnf = RouterVNF(name, vnfd)
+ 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)
+ 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..ce849d174
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py
@@ -0,0 +1,1951 @@
+# 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.benchmark.contexts.base import Context
+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
+
+
+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)
+
+
+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)
+
+ 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, 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)
+ 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("yardstick.ssh.SSH")
+ def test_instantiate(self, ssh):
+ test_base.mock_ssh(ssh)
+
+ nodes = {
+ 'vnf1': 'name1',
+ 'vnf2': 'name2',
+ }
+
+ context1 = mock.Mock()
+ context1._get_server.return_value = None
+ context2 = mock.Mock()
+ context2._get_server.return_value = context2
+
+ try:
+ Context.list.clear()
+ except AttributeError:
+ # clear() but works in Py2.7
+ Context.list[:] = []
+
+ Context.list.extend([
+ context1,
+ context2,
+ ])
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd)
+ 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, {}))
+ self.assertEqual(sample_vnf.nfvi_context, context2)
+
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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')
+
+ def test_collect_kpi(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd)
+ 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': {},
+ }
+ result = sample_vnf.collect_kpi()
+ self.assertDictEqual(result, expected)
+
+ def test_collect_kpi_default(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sample_vnf = SampleVNF('vnf1', vnfd)
+ 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 = {
+ '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)
+ 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)
+ 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)
+
+ with self.assertRaises(NotImplementedError):
+ sample_vnf_tg._check_status()
+
+ def test_listen_traffic(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+
+ sample_vnf_tg.listen_traffic(mock.Mock())
+
+ def test_verify_traffic(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+
+ sample_vnf_tg.verify_traffic(mock.Mock())
+
+ def test_terminate(self):
+ sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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..59594a3c3
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py
@@ -0,0 +1,321 @@
+# 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
+import unittest
+
+from yardstick import ssh
+from yardstick.common import utils
+from yardstick.tests import STL_MOCKS
+
+
+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.tg_ixload import IxLoadTrafficGen
+ from yardstick.network_services.vnf_generic.vnf.tg_ixload import IxLoadResourceHelper
+ from yardstick.network_services.traffic_profile.base import TrafficProfile
+
+
+NAME = "tg__1"
+
+
+class TestIxLoadTrafficGen(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}}
+
+ def setUp(self):
+ self._mock_call = mock.patch.object(subprocess, "call")
+ self.mock_call = self._mock_call.start()
+ self._mock_open = mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open")
+ self.mock_open = self._mock_open.start()
+
+ self.addCleanup(self._stop_mock)
+
+ def _stop_mock(self):
+ self._mock_call.stop()
+ self._mock_open.stop()
+
+ def test___init__(self):
+ 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]
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ self.assertIsNone(ixload_traffic_gen.resource_helper.data)
+
+ def test_collect_kpi(self):
+ 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]
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ ixload_traffic_gen.data = {}
+ restult = ixload_traffic_gen.collect_kpi()
+ self.assertEqual({}, restult)
+
+ def test_listen_traffic(self):
+ 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]
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ self.assertIsNone(ixload_traffic_gen.listen_traffic({}))
+
+ @mock.patch.object(utils, 'find_relative_file')
+ @mock.patch.object(utils, 'makedirs')
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil")
+ 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]
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ scenario_cfg = {'tc': "nsb_test_case",
+ 'ixia_profile': "ixload.cfg",
+ 'task_path': "/path/to/task"}
+ ixload_traffic_gen.RESULTS_MOUNT = "/tmp/result"
+ 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}}
+ }})
+ 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("yardstick.network_services.vnf_generic.vnf.tg_ixload.open")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil")
+ def test_run_traffic(self, *args):
+ mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+ 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]
+ 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 = IxLoadTrafficGen(NAME, vnfd)
+ sut.connection = mock.Mock()
+ sut.connection.run = mock.Mock()
+ sut._traffic_runner = mock.Mock(return_value=0)
+ result = sut.run_traffic(mock_traffic_profile)
+ self.assertIsNone(result)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil")
+ def test_run_traffic_csv(self, *args):
+ mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+ 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]
+ 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 = IxLoadTrafficGen(NAME, vnfd)
+ sut.connection = mock.Mock()
+ sut.connection.run = 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)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call")
+ @mock.patch.object(ssh, 'SSH')
+ def test_terminate(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ self.assertIsNone(ixload_traffic_gen.terminate())
+
+ @mock.patch("yardstick.ssh.SSH")
+ def test_parse_csv_read(self, mock_ssh):
+ 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]
+
+ mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH)
+ mock_ssh_type.execute.return_value = 0, "", ""
+ mock_ssh.from_node.return_value = mock_ssh_type
+
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ result = ixload_traffic_gen.resource_helper.result
+
+ ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
+ for key_left, key_right in IxLoadResourceHelper.KPI_LIST.items():
+ self.assertEqual(result[key_left][-1], int(kpi_data[key_right]))
+
+ @mock.patch("yardstick.ssh.SSH")
+ def test_parse_csv_read_value_error(self, mock_ssh):
+ 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,
+ }]
+
+ mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH)
+ mock_ssh_type.execute.return_value = 0, "", ""
+ mock_ssh.from_node.return_value = mock_ssh_type
+
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ 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)
+
+ @mock.patch.object(ssh, 'SSH')
+ def test_parse_csv_read_error(self, mock_ssh):
+ 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,
+ }]
+
+ mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH)
+ mock_ssh_type.execute.return_value = 0, "", ""
+ mock_ssh.from_node.return_value = mock_ssh_type
+
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+
+ 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..14e0db788
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py
@@ -0,0 +1,292 @@
+# 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.tests import STL_MOCKS
+
+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.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
+
+
+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)
+
+ 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)
+ 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("yardstick.ssh.SSH")
+ def test_collect_kpi(self, ssh):
+ mock_ssh(ssh, exec_result=(0, "success", ""))
+ ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0)
+ ping_traffic_gen._queue = Queue()
+ ping_traffic_gen._queue.put({})
+ ping_traffic_gen.collect_kpi()
+ self.assertEqual(ping_traffic_gen._result, {})
+
+ @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)
+ 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)
+ 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)
+ 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..f581ec8d9
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py
@@ -0,0 +1,426 @@
+# 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.tests import STL_MOCKS
+
+
+SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
+NAME = 'vnf__1'
+
+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.tg_prox import ProxTrafficGen
+ from yardstick.network_services.traffic_profile.base import TrafficProfile
+
+
+@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)
+ self.assertIsNone(prox_traffic_gen._tg_process)
+ self.assertIsNone(prox_traffic_gen._traffic_process)
+
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, *args):
+ mock_ssh(ssh)
+
+ prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0)
+ 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="")
+ self.assertEqual({}, prox_traffic_gen.collect_kpi())
+
+
+ @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)
+ 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)
+ 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=STLClient)
+ sut._connect_client.get_stats = mock.Mock(return_value="0")
+ sut._traffic_runner(mock_traffic_profile)
+
+ @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)
+ 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)
+ 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..dca8098fa
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.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 os
+
+import mock
+import six
+import unittest
+
+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': '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)
+
+ 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)
+ self.assertIsNone(ixnet_traffic_gen.listen_traffic({}))
+
+ 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)
+ 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}}}})
+ 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, {}))
+
+ 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)
+ ixnet_traffic_gen.data = {}
+ restult = ixnet_traffic_gen.collect_kpi()
+ self.assertEqual({}, 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)
+ 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)
+ 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)
+ 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):
+ result = sut._traffic_runner(mock_traffic_profile)
+ 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..9531b90c4
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py
@@ -0,0 +1,293 @@
+# 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.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': '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)
+ self.assertIsNotNone(trex_traffic_gen.resource_helper._terminated.value)
+
+ def test_instantiate(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
+
+ trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC('vnf1', self.VNFD_0)
+ 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", "vnf_1"]})
+ self.assertIsNone(trex_traffic_gen.instantiate(scenario_cfg, {}))
+
+ def test_instantiate_error(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
+
+ trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC('vnf1', self.VNFD_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",
+ "nodes": [
+ "tg_1",
+ "vnf_1",
+ ],
+ "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..4f8742477
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py
@@ -0,0 +1,505 @@
+# 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
+
+
+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)
+ self.assertIsInstance(trex_traffic_gen.resource_helper,
+ tg_trex.TrexResourceHelper)
+
+ def test_collect_kpi(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+ trex_traffic_gen.resource_helper._queue.put({})
+ result = trex_traffic_gen.collect_kpi()
+ self.assertEqual({}, result)
+
+ def test_listen_traffic(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+ self.assertIsNone(trex_traffic_gen.listen_traffic({}))
+
+ def test_instantiate(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+ 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))
+
+ def test_instantiate_error(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+ 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)
+ 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)
+ 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)
+ 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()
+ with mock.patch.object(self.sut.resource_helper, 'run_traffic'):
+ self.sut._traffic_runner(mock_traffic_profile)
+
+ def test__generate_trex_cfg(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+ 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)
+ 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)
+ 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
+ result = self.sut.run_traffic(mock_traffic_profile)
+ self.sut._traffic_process.terminate()
+ self.assertIsNotNone(result)
+
+ def test_terminate(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
+ 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)
+ 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..05a0ead71
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py
@@ -0,0 +1,464 @@
+# 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 import STL_MOCKS
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+
+
+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.udp_replay import UdpReplayApproxVnf
+ from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper
+
+
+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)
+ self.assertIsNone(udp_replay_approx_vnf._vnf_process)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @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)
+ 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 = {'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)
+ 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("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context")
+ @mock.patch(SSH_HELPER)
+ def test__build_config(self, ssh, mock_context, *args):
+ mock_ssh(ssh)
+
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+ udp_replay_approx_vnf.queue_wrapper = mock.MagicMock()
+ udp_replay_approx_vnf.nfvi_context = mock_context
+ 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("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context")
+ @mock.patch(SSH_HELPER)
+ def test__build_pipeline_kwargs(self, ssh, mock_context, *args):
+ mock_ssh(ssh)
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+ udp_replay_approx_vnf.nfvi_context = mock_context
+ udp_replay_approx_vnf.nfvi_context.attrs = {'nfvi_type': 'baremetal'}
+ 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)
+ 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("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context")
+ @mock.patch(SSH_HELPER)
+ def test_instantiate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+ 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("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context")
+ @mock.patch('yardstick.ssh.SSH')
+ @mock.patch(SSH_HELPER)
+ def test_instantiate_panic(self, *args):
+ udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0)
+ 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..a0a0794ea
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py
@@ -0,0 +1,376 @@
+# 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 import STL_MOCKS
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+
+from yardstick.common import utils
+
+
+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.vfw_vnf import FWApproxVnf
+ from yardstick.network_services.nfvi.resource import ResourceProfile
+ from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxSetupEnvHelper
+
+
+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)
+ 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(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)
+ 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 = {
+ '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)
+ 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)
+ 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)
+ 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("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]
+ vfw_approx_vnf = FWApproxVnf(name, vnfd)
+ 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..73f91d1b1
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py
@@ -0,0 +1,799 @@
+# 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 os
+import time
+
+import mock
+from six.moves import configparser
+import unittest
+
+from yardstick.tests import STL_MOCKS
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import FileAbsPath
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+from yardstick.network_services.vnf_generic.vnf.base import QueueFileWrapper
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+
+
+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.vpe_vnf import ConfigCreate
+ from yardstick.network_services.nfvi.resource import ResourceProfile
+ from yardstick.network_services.vnf_generic.vnf.vpe_vnf import \
+ VpeApproxVnf, VpeApproxSetupEnvHelper
+
+
+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 = 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 = VnfdHelper(self.VNFD_0)
+ config_create = 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 = VnfdHelper(self.VNFD_0)
+ config_create = 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 = VnfdHelper(self.VNFD_0)
+ config_create = 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 = VnfdHelper(self.VNFD_0)
+ config_create = 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 = VnfdHelper(self.VNFD_0)
+ config_create = 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 = VnfdHelper(self.VNFD_0)
+ vpe_config_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 = VnfdHelper(self.VNFD_0)
+ config_create = ConfigCreate(vnfd_helper, 23)
+ config_create.downlink_ports = ['xe1']
+ config_create.uplink_ports = ['xe1']
+ curr_path = os.path.dirname(os.path.abspath(__file__))
+ vpe_cfg = "samples/vnf_samples/nsut/vpe/vpe_config"
+ vnf_cfg = os.path.join(curr_path, "../../../../..", vpe_cfg)
+ config_create.create_vpe_config(vnf_cfg)
+ os.system("git checkout -- %s" % vnf_cfg)
+
+
+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': 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': 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': 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': 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 = VpeApproxVnf(NAME, self.VNFD_0)
+ self.assertIsNone(vpe_approx_vnf._vnf_process)
+
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi_sa_not_running(self, ssh):
+ 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 = VpeApproxVnf(NAME, self.VNFD_0)
+ 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 = {
+ '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(SSH_HELPER)
+ def test_collect_kpi_sa_running(self, ssh):
+ 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 = VpeApproxVnf(NAME, self.VNFD_0)
+ 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 = {
+ '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(SSH_HELPER)
+ def test_vnf_execute(self, ssh):
+ mock_ssh(ssh)
+ vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
+ 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(SSH_HELPER)
+ def test_run_vpe(self, ssh):
+ mock_ssh(ssh)
+
+ vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
+ 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.sample_vnf.Context")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.vpe_vnf.ConfigCreate")
+ @mock.patch("six.moves.builtins.open")
+ @mock.patch(SSH_HELPER)
+ def test_build_config(self, ssh, *args):
+ mock_ssh(ssh)
+ vpe_approx_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(SSH_HELPER)
+ def test_wait_for_instantiate(self, ssh):
+ 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 = VpeApproxVnf(NAME, self.VNFD_0)
+ vpe_approx_vnf._vnf_process = mock_process
+ vpe_approx_vnf.q_out = mock_q_out
+ vpe_approx_vnf.queue_wrapper = mock.Mock(autospec=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(SSH_HELPER)
+ def test_wait_for_instantiate_fragmented(self, ssh):
+ 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 = VpeApproxVnf(NAME, self.VNFD_0)
+ vpe_approx_vnf._vnf_process = mock_process
+ vpe_approx_vnf.q_out = mock_q_out
+ vpe_approx_vnf.queue_wrapper = mock.Mock(autospec=QueueFileWrapper)
+ vpe_approx_vnf.resource_helper.resource = mock_resource
+
+ self.assertEqual(vpe_approx_vnf.wait_for_instantiate(), 432)
+
+ @mock.patch(SSH_HELPER)
+ def test_wait_for_instantiate_crash(self, ssh):
+ 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 = VpeApproxVnf(NAME, self.VNFD_0)
+ 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(SSH_HELPER)
+ def test_wait_for_instantiate_panic(self, ssh):
+ 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 = VpeApproxVnf(NAME, self.VNFD_0)
+ 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(SSH_HELPER)
+ def test_wait_for_instantiate_panic_fragmented(self, ssh):
+ 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 = VpeApproxVnf(NAME, self.VNFD_0)
+ 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(SSH_HELPER)
+ def test_terminate(self, ssh):
+ mock_ssh(ssh)
+
+ vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0)
+ 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())
diff --git a/yardstick/tests/unit/orchestrator/test_kubernetes.py b/yardstick/tests/unit/orchestrator/test_kubernetes.py
index 58971f515..21a12a0d3 100644
--- a/yardstick/tests/unit/orchestrator/test_kubernetes.py
+++ b/yardstick/tests/unit/orchestrator/test_kubernetes.py
@@ -7,15 +7,17 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-# Unittest for yardstick.benchmark.orchestrator.heat
-import unittest
+import copy
+
import mock
-from yardstick.orchestrator.kubernetes import KubernetesObject
-from yardstick.orchestrator.kubernetes import KubernetesTemplate
+from yardstick.common import exceptions
+from yardstick.common import kubernetes_utils
+from yardstick.orchestrator import kubernetes
+from yardstick.tests.unit import base
-class GetTemplateTestCase(unittest.TestCase):
+class GetTemplateTestCase(base.BaseUnitTestCase):
def test_get_template(self):
output_t = {
@@ -48,7 +50,8 @@ service ssh restart;while true ; do sleep 10000; done"
"volumeMounts": [
{
"mountPath": "/tmp/.ssh/",
- "name": "k8s-86096c30-key"
+ "name": "k8s-86096c30-key",
+ "readOnly": False
}
]
}
@@ -73,14 +76,15 @@ service ssh restart;while true ; do sleep 10000; done"
'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
service ssh restart;while true ; do sleep 10000; done'],
'ssh_key': 'k8s-86096c30-key',
- 'nodeSelector': {'kubernetes.io/hostname': 'node-01'}
+ 'nodeSelector': {'kubernetes.io/hostname': 'node-01'},
+ 'volumes': []
}
name = 'host-k8s-86096c30'
- output_r = KubernetesObject(name, **input_s).get_template()
+ output_r = kubernetes.KubernetesObject(name, **input_s).get_template()
self.assertEqual(output_r, output_t)
-class GetRcPodsTestCase(unittest.TestCase):
+class GetRcPodsTestCase(base.BaseUnitTestCase):
@mock.patch('yardstick.orchestrator.kubernetes.k8s_utils.get_pod_list')
def test_get_rc_pods(self, mock_get_pod_list):
@@ -98,7 +102,95 @@ service ssh restart;while true ; do sleep 10000; done']
service ssh restart;while true ; do sleep 10000; done']
}
}
- k8s_template = KubernetesTemplate('k8s-86096c30', servers)
+ k8s_template = kubernetes.KubernetesTemplate('k8s-86096c30', servers)
mock_get_pod_list.return_value.items = []
pods = k8s_template.get_rc_pods()
self.assertEqual(pods, [])
+
+
+class KubernetesObjectTestCase(base.BaseUnitTestCase):
+
+ def test__add_volumes(self):
+ volume1 = {'name': 'fake_sshkey',
+ 'configMap': {'name': 'fake_sshkey'}}
+ volume2 = {'name': 'volume2',
+ 'configMap': 'data'}
+ k8s_obj = kubernetes.KubernetesObject('name', ssh_key='fake_sshkey',
+ volumes=[volume2])
+ k8s_obj._add_volumes()
+ volumes = k8s_obj.template['spec']['template']['spec']['volumes']
+ self.assertEqual(sorted([volume1, volume2], key=lambda k: k['name']),
+ sorted(volumes, key=lambda k: k['name']))
+
+ def test__add_volumes_no_volumes(self):
+ volume1 = {'name': 'fake_sshkey',
+ 'configMap': {'name': 'fake_sshkey'}}
+ k8s_obj = kubernetes.KubernetesObject('name', ssh_key='fake_sshkey')
+ k8s_obj._add_volumes()
+ volumes = k8s_obj.template['spec']['template']['spec']['volumes']
+ self.assertEqual([volume1], volumes)
+
+ def test__create_ssh_key_volume(self):
+ expected = {'name': 'fake_sshkey',
+ 'configMap': {'name': 'fake_sshkey'}}
+ k8s_obj = kubernetes.KubernetesObject('name', ssh_key='fake_sshkey')
+ self.assertEqual(expected, k8s_obj._create_ssh_key_volume())
+
+ def test__create_volume_item(self):
+ for vol_type in kubernetes_utils.get_volume_types():
+ volume = {'name': 'vol_name',
+ vol_type: 'data'}
+ self.assertEqual(
+ volume,
+ kubernetes.KubernetesObject._create_volume_item(volume))
+
+ def test__create_volume_item_invalid_type(self):
+ volume = {'name': 'vol_name',
+ 'invalid_type': 'data'}
+ with self.assertRaises(exceptions.KubernetesTemplateInvalidVolumeType):
+ kubernetes.KubernetesObject._create_volume_item(volume)
+
+ def test__create_volume_mounts(self):
+ volume_mount = {'name': 'fake_name',
+ 'mountPath': 'fake_path'}
+ ssh_vol = {'name': kubernetes.KubernetesObject.SSHKEY_DEFAULT,
+ 'mountPath': kubernetes.KubernetesObject.SSH_MOUNT_PATH,
+ 'readOnly': False}
+ expected = copy.deepcopy(volume_mount)
+ expected['readOnly'] = False
+ expected = [expected, ssh_vol]
+ k8s_obj = kubernetes.KubernetesObject('name',
+ volumeMounts=[volume_mount])
+ output = k8s_obj._create_volume_mounts()
+ self.assertEqual(expected, output)
+
+ def test__create_volume_mounts_no_volume_mounts(self):
+ ssh_vol = {'name': kubernetes.KubernetesObject.SSHKEY_DEFAULT,
+ 'mountPath': kubernetes.KubernetesObject.SSH_MOUNT_PATH,
+ 'readOnly': False}
+ k8s_obj = kubernetes.KubernetesObject('name')
+ output = k8s_obj._create_volume_mounts()
+ self.assertEqual([ssh_vol], output)
+
+ def test__create_volume_mounts_item(self):
+ volume_mount = {'name': 'fake_name',
+ 'mountPath': 'fake_path'}
+ expected = copy.deepcopy(volume_mount)
+ expected['readOnly'] = False
+ output = kubernetes.KubernetesObject._create_volume_mounts_item(
+ volume_mount)
+ self.assertEqual(expected, output)
+
+ def test__create_container_item(self):
+ volume_mount = {'name': 'fake_name',
+ 'mountPath': 'fake_path'}
+ args = ['arg1', 'arg2']
+ k8s_obj = kubernetes.KubernetesObject(
+ 'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
+ args=args)
+ expected = {'args': args,
+ 'command': [kubernetes.KubernetesObject.COMMAND_DEFAULT],
+ 'image': kubernetes.KubernetesObject.IMAGE_DEFAULT,
+ 'name': 'cname-container',
+ 'volumeMounts': k8s_obj._create_volume_mounts()}
+ self.assertEqual(expected, k8s_obj._create_container_item())
diff --git a/yardstick/tests/unit/service/test_environment.py b/yardstick/tests/unit/service/test_environment.py
index 4af9a3958..be4882e30 100644
--- a/yardstick/tests/unit/service/test_environment.py
+++ b/yardstick/tests/unit/service/test_environment.py
@@ -6,16 +6,16 @@
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-import unittest
import mock
+from yardstick.common.exceptions import UnsupportedPodFormatError
from yardstick.service.environment import Environment
from yardstick.service.environment import AnsibleCommon
-from yardstick.common.exceptions import UnsupportedPodFormatError
+from yardstick.tests.unit import base as ut_base
-class EnvironmentTestCase(unittest.TestCase):
+class EnvironmentTestCase(ut_base.BaseUnitTestCase):
def test_get_sut_info(self):
pod_info = {
@@ -31,11 +31,11 @@ class EnvironmentTestCase(unittest.TestCase):
]
}
- AnsibleCommon.gen_inventory_ini_dict = mock.MagicMock()
- AnsibleCommon.get_sut_info = mock.MagicMock(return_value={'node1': {}})
-
- env = Environment(pod=pod_info)
- env.get_sut_info()
+ with mock.patch.object(AnsibleCommon, 'gen_inventory_ini_dict'), \
+ mock.patch.object(AnsibleCommon, 'get_sut_info',
+ return_value={'node1': {}}):
+ env = Environment(pod=pod_info)
+ env.get_sut_info()
def test_get_sut_info_pod_str(self):
pod_info = 'nodes'
@@ -43,7 +43,3 @@ class EnvironmentTestCase(unittest.TestCase):
env = Environment(pod=pod_info)
with self.assertRaises(UnsupportedPodFormatError):
env.get_sut_info()
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/yardstick/tests/unit/test_cmd/commands/test_env.py b/yardstick/tests/unit/test_cmd/commands/test_env.py
index 57dacbcd3..5d3520986 100644
--- a/yardstick/tests/unit/test_cmd/commands/test_env.py
+++ b/yardstick/tests/unit/test_cmd/commands/test_env.py
@@ -6,60 +6,64 @@
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-from __future__ import absolute_import
-import unittest
+
+import os
+import sys
+
import mock
import uuid
-from yardstick.cmd.commands.env import EnvCommand
+from yardstick.cmd.commands import env
+from yardstick.tests.unit import base
-class EnvCommandTestCase(unittest.TestCase):
+class EnvCommandTestCase(base.BaseUnitTestCase):
- @mock.patch('yardstick.cmd.commands.env.EnvCommand._start_async_task')
- @mock.patch('yardstick.cmd.commands.env.EnvCommand._check_status')
+ @mock.patch.object(env.EnvCommand, '_start_async_task')
+ @mock.patch.object(env.EnvCommand, '_check_status')
def test_do_influxdb(self, check_status_mock, start_async_task_mock):
- env = EnvCommand()
- env.do_influxdb({})
+ _env = env.EnvCommand()
+ _env.do_influxdb({})
start_async_task_mock.assert_called_once()
check_status_mock.assert_called_once()
- @mock.patch('yardstick.cmd.commands.env.EnvCommand._start_async_task')
- @mock.patch('yardstick.cmd.commands.env.EnvCommand._check_status')
+ @mock.patch.object(env.EnvCommand, '_start_async_task')
+ @mock.patch.object(env.EnvCommand, '_check_status')
def test_do_grafana(self, check_status_mock, start_async_task_mock):
- env = EnvCommand()
- env.do_grafana({})
+ _env = env.EnvCommand()
+ _env.do_grafana({})
start_async_task_mock.assert_called_once()
check_status_mock.assert_called_once()
- @mock.patch('yardstick.cmd.commands.env.EnvCommand._start_async_task')
- @mock.patch('yardstick.cmd.commands.env.EnvCommand._check_status')
+ @mock.patch.object(env.EnvCommand, '_start_async_task')
+ @mock.patch.object(env.EnvCommand, '_check_status')
def test_do_prepare(self, check_status_mock, start_async_task_mock):
- env = EnvCommand()
- env.do_prepare({})
+ _env = env.EnvCommand()
+ _env.do_prepare({})
start_async_task_mock.assert_called_once()
check_status_mock.assert_called_once()
- @mock.patch('yardstick.cmd.commands.env.HttpClient.post')
+ @mock.patch.object(env.HttpClient, 'post')
def test_start_async_task(self, post_mock):
data = {'action': 'create_grafana'}
- EnvCommand()._start_async_task(data)
+ env.EnvCommand()._start_async_task(data)
post_mock.assert_called_once()
- @mock.patch('yardstick.cmd.commands.env.HttpClient.get')
- @mock.patch('yardstick.cmd.commands.env.EnvCommand._print_status')
- def test_check_status(self, print_mock, get_mock):
- # pylint: disable=unused-argument
- # NOTE(ralonsoh): the pylint exception must be removed. The mocked
- # command call must be tested.
+ @mock.patch.object(env.HttpClient, 'get')
+ @mock.patch.object(env.EnvCommand, '_print_status')
+ def test_check_status(self, mock_print, mock_get):
task_id = str(uuid.uuid4())
- get_mock.return_value = {'status': 2, 'result': 'error'}
- status = EnvCommand()._check_status(task_id, 'hello world')
- self.assertEqual(status, 2)
+ mock_get.return_value = {'status': 2, 'result': 'error'}
+ self.assertEqual(
+ 2, env.EnvCommand()._check_status(task_id, 'hello world'))
+ self.assertEqual(2, mock_print.call_count)
- def test_print_status(self):
- try:
- EnvCommand()._print_status('hello', 'word')
- except Exception as e: # pylint: disable=broad-except
- # NOTE(ralonsoh): try to reduce the scope of this exception.
- self.assertIsInstance(e, IndexError)
+ @mock.patch.object(sys, 'stdout')
+ @mock.patch.object(os, 'popen')
+ def test_print_status(self, mock_popen, mock_stdout):
+ mock_popen_obj = mock.Mock()
+ mock_popen_obj.read.return_value = ''
+ mock_popen.return_value = mock_popen_obj
+ env.EnvCommand()._print_status('hello', 'word')
+ mock_stdout.write.assert_not_called()
+ mock_stdout.flush.assert_not_called()
diff --git a/yardstick/tests/unit/test_ssh.py b/yardstick/tests/unit/test_ssh.py
index f92290070..b727e821d 100644
--- a/yardstick/tests/unit/test_ssh.py
+++ b/yardstick/tests/unit/test_ssh.py
@@ -13,10 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-# yardstick comment: this file is a modified copy of
-# rally/tests/unit/common/test_sshutils.py
-
-from __future__ import absolute_import
import os
import socket
import unittest
@@ -26,8 +22,8 @@ from itertools import count
import mock
from oslo_utils import encodeutils
+from yardstick.common import exceptions
from yardstick import ssh
-from yardstick.ssh import SSHError, SSHTimeout
from yardstick.ssh import SSH
from yardstick.ssh import AutoConnectSSH
@@ -127,7 +123,7 @@ class SSHTestCase(unittest.TestCase):
dss = mock_paramiko.dsskey.DSSKey
rsa.from_private_key.side_effect = mock_paramiko.SSHException
dss.from_private_key.side_effect = mock_paramiko.SSHException
- self.assertRaises(ssh.SSHError, self.test_client._get_pkey, "key")
+ self.assertRaises(exceptions.SSHError, self.test_client._get_pkey, "key")
@mock.patch("yardstick.ssh.six.moves.StringIO")
@mock.patch("yardstick.ssh.paramiko")
@@ -194,13 +190,13 @@ class SSHTestCase(unittest.TestCase):
test_ssh = ssh.SSH("admin", "example.net", pkey="key")
- with self.assertRaises(SSHError) as raised:
+ with self.assertRaises(exceptions.SSHError) as raised:
test_ssh._get_client()
- self.assertEqual(mock_paramiko.SSHClient.call_count, 1)
- self.assertEqual(mock_paramiko.AutoAddPolicy.call_count, 1)
- self.assertEqual(fake_client.set_missing_host_key_policy.call_count, 1)
- self.assertEqual(fake_client.connect.call_count, 1)
+ mock_paramiko.SSHClient.assert_called_once()
+ mock_paramiko.AutoAddPolicy.assert_called_once()
+ fake_client.set_missing_host_key_policy.assert_called_once()
+ fake_client.connect.assert_called_once()
exc_str = str(raised.exception)
self.assertIn('raised during connect', exc_str)
self.assertIn('MyError', exc_str)
@@ -242,21 +238,40 @@ class SSHTestCase(unittest.TestCase):
self.assertEqual("stdout fake data", stdout)
self.assertEqual("stderr fake data", stderr)
+ @mock.patch("yardstick.ssh.six.moves.StringIO")
+ def test_execute_raise_on_error_passed(self, mock_string_io):
+ mock_string_io.side_effect = stdio = [mock.Mock(), mock.Mock()]
+ stdio[0].read.return_value = "stdout fake data"
+ stdio[1].read.return_value = "stderr fake data"
+ with mock.patch.object(self.test_client, "run", return_value=0) \
+ as mock_run:
+ status, stdout, stderr = self.test_client.execute(
+ "cmd",
+ stdin="fake_stdin",
+ timeout=43,
+ raise_on_error=True)
+ mock_run.assert_called_once_with(
+ "cmd", stdin="fake_stdin", stdout=stdio[0],
+ stderr=stdio[1], timeout=43, raise_on_error=True)
+ self.assertEqual(0, status)
+ self.assertEqual("stdout fake data", stdout)
+ self.assertEqual("stderr fake data", stderr)
+
@mock.patch("yardstick.ssh.time")
def test_wait_timeout(self, mock_time):
mock_time.time.side_effect = [1, 50, 150]
- self.test_client.execute = mock.Mock(side_effect=[ssh.SSHError,
- ssh.SSHError,
+ self.test_client.execute = mock.Mock(side_effect=[exceptions.SSHError,
+ exceptions.SSHError,
0])
- self.assertRaises(ssh.SSHTimeout, self.test_client.wait)
+ self.assertRaises(exceptions.SSHTimeout, self.test_client.wait)
self.assertEqual([mock.call("uname")] * 2,
self.test_client.execute.mock_calls)
@mock.patch("yardstick.ssh.time")
def test_wait(self, mock_time):
mock_time.time.side_effect = [1, 50, 100]
- self.test_client.execute = mock.Mock(side_effect=[ssh.SSHError,
- ssh.SSHError,
+ self.test_client.execute = mock.Mock(side_effect=[exceptions.SSHError,
+ exceptions.SSHError,
0])
self.test_client.wait()
self.assertEqual([mock.call("uname")] * 3,
@@ -333,7 +348,7 @@ class SSHRunTestCase(unittest.TestCase):
def test_run_nonzero_status(self, mock_select):
mock_select.select.return_value = ([], [], [])
self.fake_session.recv_exit_status.return_value = 1
- self.assertRaises(ssh.SSHError, self.test_client.run, "cmd")
+ self.assertRaises(exceptions.SSHError, self.test_client.run, "cmd")
self.assertEqual(1, self.test_client.run("cmd", raise_on_error=False))
@mock.patch("yardstick.ssh.select")
@@ -401,7 +416,7 @@ class SSHRunTestCase(unittest.TestCase):
def test_run_select_error(self, mock_select):
self.fake_session.exit_status_ready.return_value = False
mock_select.select.return_value = ([], [], [True])
- self.assertRaises(ssh.SSHError, self.test_client.run, "cmd")
+ self.assertRaises(exceptions.SSHError, self.test_client.run, "cmd")
@mock.patch("yardstick.ssh.time")
@mock.patch("yardstick.ssh.select")
@@ -409,7 +424,7 @@ class SSHRunTestCase(unittest.TestCase):
mock_time.time.side_effect = [1, 3700]
mock_select.select.return_value = ([], [], [])
self.fake_session.exit_status_ready.return_value = False
- self.assertRaises(ssh.SSHTimeout, self.test_client.run, "cmd")
+ self.assertRaises(exceptions.SSHTimeout, self.test_client.run, "cmd")
@mock.patch("yardstick.ssh.open", create=True)
def test__put_file_shell(self, mock_open):
@@ -514,7 +529,7 @@ class TestAutoConnectSSH(unittest.TestCase):
auto_connect_ssh._get_client = mock__get_client = mock.Mock()
auto_connect_ssh._connect()
- self.assertEqual(mock__get_client.call_count, 1)
+ mock__get_client.assert_called_once()
def test___init___negative(self):
with self.assertRaises(TypeError):
@@ -529,9 +544,9 @@ class TestAutoConnectSSH(unittest.TestCase):
auto_connect_ssh = AutoConnectSSH('user1', 'host1', wait=10)
auto_connect_ssh._get_client = mock__get_client = mock.Mock()
- mock__get_client.side_effect = SSHError
+ mock__get_client.side_effect = exceptions.SSHError
- with self.assertRaises(SSHTimeout):
+ with self.assertRaises(exceptions.SSHTimeout):
auto_connect_ssh._connect()
self.assertEqual(mock_time.time.call_count, 12)
@@ -547,7 +562,7 @@ class TestAutoConnectSSH(unittest.TestCase):
auto_connect_ssh.get_file_obj('remote/path', mock.Mock())
- self.assertEqual(mock_sftp.getfo.call_count, 1)
+ mock_sftp.getfo.assert_called_once()
def test__make_dict(self):
auto_connect_ssh = AutoConnectSSH('user1', 'host1')
@@ -584,7 +599,7 @@ class TestAutoConnectSSH(unittest.TestCase):
auto_connect_ssh.put('a', 'z')
with mock_scp_client_type() as mock_scp_client:
- self.assertEqual(mock_scp_client.put.call_count, 1)
+ mock_scp_client.put.assert_called_once()
@mock.patch('yardstick.ssh.SCPClient')
def test_get(self, mock_scp_client_type):
@@ -593,7 +608,7 @@ class TestAutoConnectSSH(unittest.TestCase):
auto_connect_ssh.get('a', 'z')
with mock_scp_client_type() as mock_scp_client:
- self.assertEqual(mock_scp_client.get.call_count, 1)
+ mock_scp_client.get.assert_called_once()
def test_put_file(self):
auto_connect_ssh = AutoConnectSSH('user1', 'host1')
@@ -601,4 +616,4 @@ class TestAutoConnectSSH(unittest.TestCase):
auto_connect_ssh._put_file_sftp = mock_put_sftp = mock.Mock()
auto_connect_ssh.put_file('a', 'b')
- self.assertEqual(mock_put_sftp.call_count, 1)
+ mock_put_sftp.assert_called_once()