summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ansible/roles/install_yardstick/tasks/main.yml6
-rw-r--r--dashboard/opnfv_yardstick_tc058.json2
-rwxr-xr-xdocs/testing/developer/devguide/devguide.rst26
-rw-r--r--samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml39
-rw-r--r--samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml171
-rw-r--r--samples/vnf_samples/traffic_profiles/pktgen_throughput.yaml21
-rw-r--r--samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml47
-rw-r--r--yardstick/common/ansible_common.py36
-rw-r--r--yardstick/common/constants.py1
-rw-r--r--yardstick/common/exceptions.py4
-rw-r--r--yardstick/common/kubernetes_utils.py12
-rw-r--r--yardstick/network_services/traffic_profile/__init__.py1
-rw-r--r--yardstick/network_services/traffic_profile/pktgen.py61
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_pktgen.py103
-rw-r--r--yardstick/orchestrator/kubernetes.py2
-rw-r--r--yardstick/service/environment.py10
-rw-r--r--yardstick/tests/unit/benchmark/core/test_task.py9
-rw-r--r--yardstick/tests/unit/benchmark/core/test_testcase.py14
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py126
-rw-r--r--yardstick/tests/unit/common/test_ansible_common.py205
-rw-r--r--yardstick/tests/unit/common/test_kubernetes_utils.py21
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py63
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py79
-rw-r--r--yardstick/tests/unit/orchestrator/test_kubernetes.py2
-rw-r--r--yardstick/tests/unit/service/test_environment.py19
25 files changed, 810 insertions, 270 deletions
diff --git a/ansible/roles/install_yardstick/tasks/main.yml b/ansible/roles/install_yardstick/tasks/main.yml
index 0975efaea..203acc3e5 100644
--- a/ansible/roles/install_yardstick/tasks/main.yml
+++ b/ansible/roles/install_yardstick/tasks/main.yml
@@ -41,7 +41,7 @@
pip:
requirements: "{{ yardstick_dir }}/requirements.txt"
virtualenv: "{{ yardstick_dir }}/virtualenv"
- async: 600
+ async: 900
poll: 0
register: pip_installer
when: virtual_environment == True
@@ -49,7 +49,7 @@
- name: Install Yardstick requirements
pip:
requirements: "{{ yardstick_dir }}/requirements.txt"
- async: 600
+ async: 900
poll: 0
register: pip_installer
when: virtual_environment == False
@@ -59,7 +59,7 @@
jid: "{{ pip_installer.ansible_job_id }}"
register: job_result
until: job_result.finished
- retries: 150
+ retries: 180
- name: Install Yardstick code (venv)
pip:
diff --git a/dashboard/opnfv_yardstick_tc058.json b/dashboard/opnfv_yardstick_tc058.json
index 55b5a5f33..ed2a1750c 100644
--- a/dashboard/opnfv_yardstick_tc058.json
+++ b/dashboard/opnfv_yardstick_tc058.json
@@ -6,7 +6,7 @@
"gnetId": null,
"graphTooltip": 0,
"hideControls": false,
- "id": 33,
+ "id": null,
"links": [],
"refresh": "1m",
"rows": [
diff --git a/docs/testing/developer/devguide/devguide.rst b/docs/testing/developer/devguide/devguide.rst
index dbe92b846..91f2c2148 100755
--- a/docs/testing/developer/devguide/devguide.rst
+++ b/docs/testing/developer/devguide/devguide.rst
@@ -540,6 +540,32 @@ The final step consists in pushing the newly modified commit to Gerrit::
git review
+Backporting changes to stable branches
+--------------------------------------
+During the release cycle, when master and the ``stable/<release>`` branch have
+diverged, it may be necessary to backport (cherry-pick) changes top the
+``stable/<release>`` branch once they have merged to master.
+These changes should be identified by the committers reviewing the patch.
+Changes should be backported **as soon as possible** after merging of the
+original code.
+
+..note::
+ Besides the commit and review process below, the Jira tick must be updated to
+ add dual release versions and indicate that the change is to be backported.
+
+The process for backporting is as follows:
+
+* Committer A merges a change to master (process for normal changes).
+* Committer A cherry-picks the change to ``stable/<release>`` branch (if the
+ bug has been identified for backporting).
+* The original author should review the code and verify that it still works
+ (and give a ``+1``).
+* Committer B reviews the change, gives a ``+2`` and merges to
+ ``stable/<release>``.
+
+A backported change needs a ``+1`` and a ``+2`` from a committer who didn’t
+propose the change (i.e. minimum 3 people involved).
+
Plugins
-------
diff --git a/samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml b/samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml
new file mode 100644
index 000000000..81323e71c
--- /dev/null
+++ b/samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml
@@ -0,0 +1,39 @@
+# 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.
+---
+nsd:nsd-catalog:
+ nsd:
+ - id: cmts-tg-topology
+ name: cmts-tg-topology
+ short-name: cmts-tg-topology
+ description: cmts-tg-topology
+ constituent-vnfd:
+ - member-vnf-index: '1'
+ vnfd-id-ref: tg__0
+ VNF model: ../../vnf_descriptors/tg_pktgen.yaml
+ - member-vnf-index: '2'
+ vnfd-id-ref: vnf__0
+ VNF model: ../../vnf_descriptors/tg_pktgen.yaml
+
+ vld: []
+# - id: uplink
+# name: tg__0 to vnf__0 link 1
+# type: ELAN
+# vnfd-connection-point-ref:
+# - member-vnf-index-ref: '1'
+# vnfd-connection-point-ref: sriov01
+# vnfd-id-ref: tg__0
+# - member-vnf-index-ref: '2'
+# vnfd-connection-point-ref: sriov01
+# vnfd-id-ref: vnf__0
diff --git a/samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml b/samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml
new file mode 100644
index 000000000..cab8bb885
--- /dev/null
+++ b/samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml
@@ -0,0 +1,171 @@
+# 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.
+---
+schema: yardstick:task:0.1
+scenarios:
+- type: NSPerf
+ traffic_profile: ../../traffic_profiles/pktgen_throughput.yaml
+ topology: cmts-tg-topology.yaml
+ nodes:
+ tg__0: trafficgen-k8syardstick
+ vnf__0: vnf-k8syardstick
+ options: {}
+ runner:
+ type: IterationIPC
+ iterations: 10
+ interval: 15
+ timeout: 10000
+context:
+ name: k8syardstick
+ type: Kubernetes
+
+ servers:
+ vnf:
+ containers:
+ - image: si-docker.ir.intel.com/vcmts-ubuntu/vcmts-pktgen-uepi
+ args: ["/opt/bin/cmk isolate --conf-dir=/etc/cmk --socket-id=0 --pool=dataplane /vcmts/setup.sh anga_mac_1_ds.pcap ds"]
+ env:
+ - name: LUA_PATH
+ value: "/vcmts/Pktgen.lua"
+ - name: CMK_PROC_FS
+ value: "/host/proc"
+ resources:
+ requests:
+ pod.alpha.kubernetes.io/opaque-int-resource-cmk: "1"
+ ports:
+ - containerPort: 22022
+ volumeMounts:
+ - name: hugepages
+ mountPath: /dev/hugepages
+ - name: sysfs
+ mountPath: /sys
+ - name: sriov
+ mountPath: /sriov-cni
+ - name: host-proc
+ mountPath: /host/proc
+ readOnly: true
+ - name: cmk-install-dir
+ mountPath: /opt/bin
+ - name: cmk-conf-dir
+ mountPath: /etc/cmk
+ securityContext:
+ allowPrivilegeEscalation: true
+ privileged: true
+
+ node_ports:
+ - name: lua # Lower case alphanumeric characters or '-'
+ port: 22022
+ networks:
+ - flannel
+ - sriov01
+ volumes:
+ - name: hugepages
+ hostPath:
+ path: /dev/hugepages
+ - name: sysfs
+ hostPath:
+ path: /sys
+ - name: sriov
+ hostPath:
+ path: /var/lib/cni/sriov
+ - name: cmk-install-dir
+ hostPath:
+ path: /opt/bin
+ - name: host-proc
+ hostPath:
+ path: /proc
+ - name: cmk-conf-dir
+ hostPath:
+ path: /etc/cmk
+
+ trafficgen:
+ containers:
+ - image: si-docker.ir.intel.com/vcmts-ubuntu/vcmts-pktgen-uepi
+ args: ["/opt/bin/cmk isolate --conf-dir=/etc/cmk --socket-id=0 --pool=dataplane /vcmts/setup.sh anga_mac_1_ds.pcap ds"]
+ env:
+ - name: LUA_PATH
+ value: "/vcmts/Pktgen.lua"
+ - name: CMK_PROC_FS
+ value: "/host/proc"
+ resources:
+ requests:
+ pod.alpha.kubernetes.io/opaque-int-resource-cmk: "1"
+ ports:
+ - containerPort: 22022
+ volumeMounts:
+ - name: hugepages
+ mountPath: /dev/hugepages
+ - name: sysfs
+ mountPath: /sys
+ - name: sriov
+ mountPath: /sriov-cni
+ - name: host-proc
+ mountPath: /host/proc
+ readOnly: true
+ - name: cmk-install-dir
+ mountPath: /opt/bin
+ - name: cmk-conf-dir
+ mountPath: /etc/cmk
+ securityContext:
+ allowPrivilegeEscalation: true
+ privileged: true
+
+ node_ports:
+ - name: lua # Lower case alphanumeric characters or '-'
+ port: 22022
+ networks:
+ - flannel
+ - sriov01
+ volumes:
+ - name: hugepages
+ hostPath:
+ path: /dev/hugepages
+ - name: sysfs
+ hostPath:
+ path: /sys
+ - name: sriov
+ hostPath:
+ path: /var/lib/cni/sriov
+ - name: cmk-install-dir
+ hostPath:
+ path: /opt/bin
+ - name: host-proc
+ hostPath:
+ path: /proc
+ - name: cmk-conf-dir
+ hostPath:
+ path: /etc/cmk
+
+ networks:
+ flannel:
+ args: '[{ "delegate": { "isDefaultGateway": true }}]'
+ plugin: flannel
+ sriov01:
+ plugin: sriov
+ args: '[{"if0": "ens802f0",
+ "if0name": "net0",
+ "dpdk": {
+ "kernel_driver": "i40evf",
+ "dpdk_driver": "igb_uio",
+ "dpdk_tool": "/opt/nsb_bin/dpdk-devbind.py"}
+ }]'
+ sriov02:
+ plugin: sriov
+ args: '[{"if0": "ens802f0",
+ "if0name": "net0",
+ "dpdk": {
+ "kernel_driver": "i40evf",
+ "dpdk_driver": "igb_uio",
+ "dpdk_tool": "/opt/nsb_bin/dpdk-devbind.py"}
+ }]'
diff --git a/samples/vnf_samples/traffic_profiles/pktgen_throughput.yaml b/samples/vnf_samples/traffic_profiles/pktgen_throughput.yaml
new file mode 100644
index 000000000..e222e1d8c
--- /dev/null
+++ b/samples/vnf_samples/traffic_profiles/pktgen_throughput.yaml
@@ -0,0 +1,21 @@
+# 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.
+---
+schema: "nsb:traffic_profile:0.1"
+
+name: pktgen
+description: Traffic profile to run throughput tests
+traffic_profile:
+ traffic_type: PktgenTrafficProfile
+ duration: 15
diff --git a/samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml b/samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml
new file mode 100644
index 000000000..17e631652
--- /dev/null
+++ b/samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml
@@ -0,0 +1,47 @@
+# 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.
+---
+vnfd:vnfd-catalog:
+ vnfd:
+ - id: PktgenTrafficGen # NSB class mapping
+ name: pktgen_tg
+ short-name: pktgen_tg
+ description: Pktgen DPDK traffic generator
+ mgmt-interface:
+ vdu-id: pktgen
+ {% if ip is defined %}
+ ip: '{{ ip }}'
+ {% endif %}
+ {% if service_ports is defined and service_ports %}
+ service_ports:
+ {% for port in service_ports %}
+ - port: "{{ port['port']|int }}"
+ node_port: "{{ port['node_port']|int }}"
+ target_port: "{{ port['target_port']|int }}"
+ {% endfor %}
+ {% endif %}
+
+ vdu:
+ - id: pktgen_tg
+ name: pktgen_tg
+ description: Pktgen DPDK traffic generator
+
+ benchmark:
+ kpi:
+ - rx_throughput_fps
+ - tx_throughput_fps
+ - tx_throughput_mbps
+ - rx_throughput_mbps
+ - in_packets
+ - out_packets
diff --git a/yardstick/common/ansible_common.py b/yardstick/common/ansible_common.py
index ca5a110e2..dee7044a5 100644
--- a/yardstick/common/ansible_common.py
+++ b/yardstick/common/ansible_common.py
@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import absolute_import
-
import cgitb
import collections
import contextlib as cl
@@ -23,11 +21,11 @@ import os
from collections import Mapping, MutableMapping, Iterable, Callable, deque
from functools import partial
from itertools import chain
-from subprocess import CalledProcessError, Popen, PIPE
-from tempfile import NamedTemporaryFile
+import subprocess
+import tempfile
import six
-import six.moves.configparser as ConfigParser
+from six.moves import configparser
import yaml
from six import StringIO
from chainmap import ChainMap
@@ -134,10 +132,9 @@ class CustomTemporaryFile(object):
else:
self.data_types = self.DEFAULT_DATA_TYPES
# must open "w+" so unicode is encoded correctly
- self.creator = partial(NamedTemporaryFile, mode="w+", delete=False,
- dir=directory,
- prefix=prefix,
- suffix=self.suffix)
+ self.creator = partial(
+ tempfile.NamedTemporaryFile, mode="w+", delete=False,
+ dir=directory, prefix=prefix, suffix=self.suffix)
def make_context(self, data, write_func, descriptor='data'):
return TempfileContext(data, write_func, descriptor, self.data_types,
@@ -191,8 +188,8 @@ class FileNameGenerator(object):
if not prefix.endswith('_'):
prefix += '_'
- temp_file = NamedTemporaryFile(delete=False, dir=directory,
- prefix=prefix, suffix=suffix)
+ temp_file = tempfile.NamedTemporaryFile(delete=False, dir=directory,
+ prefix=prefix, suffix=suffix)
with cl.closing(temp_file):
return temp_file.name
@@ -474,7 +471,7 @@ class AnsibleCommon(object):
prefix = '_'.join([self.prefix, prefix, 'inventory'])
ini_temp_file = IniMapTemporaryFile(directory=directory, prefix=prefix)
- inventory_config = ConfigParser.ConfigParser(allow_no_value=True)
+ inventory_config = configparser.ConfigParser(allow_no_value=True)
# disable default lowercasing
inventory_config.optionxform = str
return ini_temp_file.make_context(self.inventory_dict, write_func,
@@ -510,7 +507,7 @@ class AnsibleCommon(object):
return timeout
def _generate_ansible_cfg(self, directory):
- parser = ConfigParser.ConfigParser()
+ parser = configparser.ConfigParser()
parser.add_section('defaults')
parser.set('defaults', 'host_key_checking', 'False')
@@ -541,12 +538,12 @@ class AnsibleCommon(object):
cmd = ['ansible', 'all', '-m', 'setup', '-i',
inventory_path, '--tree', sut_dir]
- proc = Popen(cmd, stdout=PIPE, cwd=directory)
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=directory)
output, _ = proc.communicate()
retcode = proc.wait()
LOG.debug("exit status = %s", retcode)
if retcode != 0:
- raise CalledProcessError(retcode, cmd, output)
+ raise subprocess.CalledProcessError(retcode, cmd, output)
def _gen_sut_info_dict(self, sut_dir):
sut_info = {}
@@ -617,12 +614,13 @@ class AnsibleCommon(object):
# 'timeout': timeout / 2,
})
with Timer() as timer:
- proc = Popen(cmd, stdout=PIPE, **exec_args)
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ **exec_args)
output, _ = proc.communicate()
retcode = proc.wait()
LOG.debug("exit status = %s", retcode)
if retcode != 0:
- raise CalledProcessError(retcode, cmd, output)
+ raise subprocess.CalledProcessError(retcode, cmd, output)
timeout -= timer.total_seconds()
cmd.remove("--syntax-check")
@@ -632,10 +630,10 @@ class AnsibleCommon(object):
# TODO: add timeout support of use subprocess32 backport
# 'timeout': timeout,
})
- proc = Popen(cmd, stdout=PIPE, **exec_args)
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, **exec_args)
output, _ = proc.communicate()
retcode = proc.wait()
LOG.debug("exit status = %s", retcode)
if retcode != 0:
- raise CalledProcessError(retcode, cmd, output)
+ raise subprocess.CalledProcessError(retcode, cmd, output)
return output
diff --git a/yardstick/common/constants.py b/yardstick/common/constants.py
index 4ed40f8af..3d775d48e 100644
--- a/yardstick/common/constants.py
+++ b/yardstick/common/constants.py
@@ -175,3 +175,4 @@ SCOPE_CLUSTER = 'Cluster'
# VNF definition
SSH_PORT = 22
+LUA_PORT = 22022
diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py
index 2e6cbdd7b..56b11b7aa 100644
--- a/yardstick/common/exceptions.py
+++ b/yardstick/common/exceptions.py
@@ -212,6 +212,10 @@ class WaitTimeout(YardstickException):
message = 'Wait timeout while waiting for condition'
+class PktgenActionError(YardstickException):
+ message = 'Error in "%(action)s" action'
+
+
class KubernetesApiException(YardstickException):
message = ('Kubernetes API errors. Action: %(action)s, '
'resource: %(resource)s')
diff --git a/yardstick/common/kubernetes_utils.py b/yardstick/common/kubernetes_utils.py
index f5b0443ea..c90f73e43 100644
--- a/yardstick/common/kubernetes_utils.py
+++ b/yardstick/common/kubernetes_utils.py
@@ -266,7 +266,8 @@ def create_network(scope, group, version, plural, body, namespace='default'):
action='create', resource='Custom Object: Network')
-def delete_network(scope, group, version, plural, name, namespace='default'):
+def delete_network(scope, group, version, plural, name, namespace='default', skip_codes=None):
+ skip_codes = [] if not skip_codes else skip_codes
api = get_custom_objects_api()
try:
if scope == consts.SCOPE_CLUSTER:
@@ -274,9 +275,12 @@ def delete_network(scope, group, version, plural, name, namespace='default'):
else:
api.delete_namespaced_custom_object(
group, version, namespace, plural, name, {})
- except ApiException:
- raise exceptions.KubernetesApiException(
- action='delete', resource='Custom Object: Network')
+ except ApiException as e:
+ if e.status in skip_codes:
+ LOG.info(e.reason)
+ else:
+ raise exceptions.KubernetesApiException(
+ action='delete', resource='Custom Object: Network')
def get_pod_list(namespace='default'): # pragma: no cover
diff --git a/yardstick/network_services/traffic_profile/__init__.py b/yardstick/network_services/traffic_profile/__init__.py
index 356b36bd9..a1b26a24d 100644
--- a/yardstick/network_services/traffic_profile/__init__.py
+++ b/yardstick/network_services/traffic_profile/__init__.py
@@ -27,6 +27,7 @@ def register_modules():
'yardstick.network_services.traffic_profile.prox_profile',
'yardstick.network_services.traffic_profile.prox_ramp',
'yardstick.network_services.traffic_profile.rfc2544',
+ 'yardstick.network_services.traffic_profile.pktgen',
]
for module in modules:
diff --git a/yardstick/network_services/traffic_profile/pktgen.py b/yardstick/network_services/traffic_profile/pktgen.py
new file mode 100644
index 000000000..30f81b794
--- /dev/null
+++ b/yardstick/network_services/traffic_profile/pktgen.py
@@ -0,0 +1,61 @@
+# 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.
+
+from yardstick.common import exceptions
+from yardstick.common import utils
+from yardstick.network_services.traffic_profile import base as tp_base
+
+
+class PktgenTrafficProfile(tp_base.TrafficProfile):
+ """This class handles Pktgen Trex Traffic profile execution"""
+
+ def __init__(self, tp_config): # pragma: no cover
+ super(PktgenTrafficProfile, self).__init__(tp_config)
+ self._host = None
+ self._port = None
+
+ def init(self, host, port): # pragma: no cover
+ """Initialize control parameters
+
+ :param host: (str) ip or host name
+ :param port: (int) TCP socket port number for Lua commands
+ """
+ self._host = host
+ self._port = port
+
+ def start(self):
+ if utils.send_socket_command(self._host, self._port,
+ 'pktgen.start("0")') != 0:
+ raise exceptions.PktgenActionError(action='start')
+
+ def stop(self):
+ if utils.send_socket_command(self._host, self._port,
+ 'pktgen.stop("0")') != 0:
+ raise exceptions.PktgenActionError(action='stop')
+
+ def rate(self, rate):
+ command = 'pktgen.set("0", "rate", ' + str(rate) + ')'
+ if utils.send_socket_command(self._host, self._port, command) != 0:
+ raise exceptions.PktgenActionError(action='rate')
+
+ def clear_all_stats(self):
+ if utils.send_socket_command(self._host, self._port, 'clr') != 0:
+ raise exceptions.PktgenActionError(action='clear all stats')
+
+ def help(self):
+ if utils.send_socket_command(self._host, self._port, 'help') != 0:
+ raise exceptions.PktgenActionError(action='help')
+
+ def execute_traffic(self, *args, **kwargs): # pragma: no cover
+ pass
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_pktgen.py b/yardstick/network_services/vnf_generic/vnf/tg_pktgen.py
new file mode 100644
index 000000000..9d452213f
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/tg_pktgen.py
@@ -0,0 +1,103 @@
+# 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 logging
+import multiprocessing
+import time
+import uuid
+
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.common import utils
+from yardstick.network_services.vnf_generic.vnf import base as vnf_base
+
+
+LOG = logging.getLogger(__name__)
+
+
+class PktgenTrafficGen(vnf_base.GenericTrafficGen,
+ vnf_base.GenericVNFEndpoint):
+ """DPDK Pktgen traffic generator
+
+ Website: http://pktgen-dpdk.readthedocs.io/en/latest/index.html
+ """
+
+ TIMEOUT = 30
+
+ def __init__(self, name, vnfd, task_id):
+ vnf_base.GenericTrafficGen.__init__(self, name, vnfd, task_id)
+ self.queue = multiprocessing.Queue()
+ self._id = uuid.uuid1().int
+ self._mq_producer = self._setup_mq_producer(self._id)
+ vnf_base.GenericVNFEndpoint.__init__(self, self._id, [task_id],
+ self.queue)
+ self._consumer = vnf_base.GenericVNFConsumer([task_id], self)
+ self._consumer.start_rpc_server()
+ self._traffic_profile = None
+ self._node_ip = vnfd['mgmt-interface'].get('ip')
+ self._lua_node_port = self._get_lua_node_port(
+ vnfd['mgmt-interface'].get('service_ports', []))
+ self._rate = 1
+
+ def instantiate(self, scenario_cfg, context_cfg): # pragma: no cover
+ pass
+
+ def run_traffic(self, traffic_profile):
+ self._traffic_profile = traffic_profile
+ self._traffic_profile.init(self._node_ip, self._lua_node_port)
+ utils.wait_until_true(self._is_running, timeout=self.TIMEOUT,
+ sleep=2)
+
+ def terminate(self): # pragma: no cover
+ pass
+
+ def collect_kpi(self): # pragma: no cover
+ pass
+
+ def scale(self, flavor=''): # pragma: no cover
+ pass
+
+ def wait_for_instantiate(self): # pragma: no cover
+ pass
+
+ def runner_method_start_iteration(self, ctxt, **kwargs):
+ # pragma: no cover
+ LOG.debug('Start method')
+ # NOTE(ralonsoh): 'rate' should be modified between iterations. The
+ # current implementation is just for testing.
+ self._rate += 1
+ self._traffic_profile.start()
+ self._traffic_profile.rate(self._rate)
+ time.sleep(4)
+ self._traffic_profile.stop()
+ self._mq_producer.tg_method_iteration(1, 1, {})
+
+ def runner_method_stop_iteration(self, ctxt, **kwargs): # pragma: no cover
+ # pragma: no cover
+ LOG.debug('Stop method')
+
+ @staticmethod
+ def _get_lua_node_port(service_ports):
+ for port in (port for port in service_ports if
+ int(port['port']) == constants.LUA_PORT):
+ return int(port['node_port'])
+ # NOTE(ralonsoh): in case LUA port is not present, an exception should
+ # be raised.
+
+ def _is_running(self):
+ try:
+ self._traffic_profile.help()
+ return True
+ except exceptions.PktgenActionError:
+ return False
diff --git a/yardstick/orchestrator/kubernetes.py b/yardstick/orchestrator/kubernetes.py
index 7b1450230..594f679c0 100644
--- a/yardstick/orchestrator/kubernetes.py
+++ b/yardstick/orchestrator/kubernetes.py
@@ -441,7 +441,7 @@ class NetworkObject(object):
def delete(self):
k8s_utils.delete_network(self.scope, self.group, self.version,
- self.plural, self._name)
+ self.plural, self._name, skip_codes=[404])
class KubernetesTemplate(object):
diff --git a/yardstick/service/environment.py b/yardstick/service/environment.py
index 324589f79..d910e31e9 100644
--- a/yardstick/service/environment.py
+++ b/yardstick/service/environment.py
@@ -36,7 +36,7 @@ class Environment(Service):
return self._format_sut_info(sut_info)
- def _load_pod_info(self):
+ def _load_pod_info(self): # pragma: no cover
if self.pod is None:
raise MissingPodInfoError
@@ -51,10 +51,10 @@ class Environment(Service):
except (ValueError, KeyError):
raise UnsupportedPodFormatError
- def _format_sut_info(self, sut_info):
+ def _format_sut_info(self, sut_info): # pragma: no cover
return {k: self._format_node_info(v) for k, v in sut_info.items()}
- def _format_node_info(self, node_info):
+ def _format_node_info(self, node_info): # pragma: no cover
info = []
facts = node_info.get('ansible_facts', {})
@@ -93,9 +93,9 @@ class Environment(Service):
return info
- def _get_interface_info(self, facts, name):
+ def _get_interface_info(self, facts, name): # pragma: no cover
mac = facts.get('ansible_{}'.format(name), {}).get('macaddress')
return [name, mac] if mac else []
- def _get_device_info(self, name, info):
+ def _get_device_info(self, name, info): # pragma: no cover
return ['disk_{}'.format(name), info.get('size')]
diff --git a/yardstick/tests/unit/benchmark/core/test_task.py b/yardstick/tests/unit/benchmark/core/test_task.py
index 35236637d..e1414c2ae 100644
--- a/yardstick/tests/unit/benchmark/core/test_task.py
+++ b/yardstick/tests/unit/benchmark/core/test_task.py
@@ -9,11 +9,13 @@
import copy
import io
+import logging
import os
import sys
import mock
import six
+from six.moves import builtins
import unittest
import uuid
@@ -322,9 +324,9 @@ class TaskTestCase(unittest.TestCase):
actual_result = t._parse_options(options)
self.assertEqual(expected_result, actual_result)
- @mock.patch('six.moves.builtins.open', side_effect=mock.mock_open())
+ @mock.patch.object(builtins, 'open', side_effect=mock.mock_open())
@mock.patch.object(task, 'utils')
- @mock.patch('logging.root')
+ @mock.patch.object(logging, 'root')
def test_set_log(self, mock_logging_root, *args):
task_obj = task.Task()
task_obj.task_id = 'task_id'
@@ -561,7 +563,8 @@ key2:
mock_open.assert_has_calls([mock.call('args_file'),
mock.call('task_file')])
- def test__render_task_error_arguments(self):
+ @mock.patch.object(builtins, 'print')
+ def test__render_task_error_arguments(self, *args):
with self.assertRaises(exceptions.TaskRenderArgumentError):
task.TaskParser('task_file')._render_task('value1="var3"', None)
diff --git a/yardstick/tests/unit/benchmark/core/test_testcase.py b/yardstick/tests/unit/benchmark/core/test_testcase.py
index 119465887..077848d77 100644
--- a/yardstick/tests/unit/benchmark/core/test_testcase.py
+++ b/yardstick/tests/unit/benchmark/core/test_testcase.py
@@ -7,28 +7,28 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-# Unittest for yardstick.cmd.commands.testcase
-
-from __future__ import absolute_import
-import unittest
+import mock
+from six.moves import builtins
from yardstick.benchmark.core import testcase
+from yardstick.tests.unit import base as ut_base
class Arg(object):
def __init__(self):
- self.casename = ('opnfv_yardstick_tc001',)
+ self.casename = ('opnfv_yardstick_tc001', )
-class TestcaseUT(unittest.TestCase):
+class TestcaseTestCase(ut_base.BaseUnitTestCase):
def test_list_all(self):
t = testcase.Testcase()
result = t.list_all("")
self.assertIsInstance(result, list)
- def test_show(self):
+ @mock.patch.object(builtins, 'print')
+ def test_show(self, *args):
t = testcase.Testcase()
casename = Arg()
result = t.show(casename)
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 db6f9cc89..b305fc93b 100644
--- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py
+++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py
@@ -20,6 +20,8 @@ import unittest
from yardstick import exceptions as y_exc
from yardstick.benchmark.scenarios.networking import vsperf_dpdk
+from yardstick.common import exceptions as y_exc
+from yardstick import ssh
class VsperfDPDKTestCase(unittest.TestCase):
@@ -56,80 +58,51 @@ class VsperfDPDKTestCase(unittest.TestCase):
'action': 'monitor',
}
}
-
- self.scenario = vsperf_dpdk.VsperfDPDK(self.args, self.ctx)
-
- self._mock_ssh = mock.patch.object(vsperf_dpdk, 'ssh')
+ self._mock_ssh = mock.patch.object(ssh, 'SSH')
self.mock_ssh = self._mock_ssh.start()
self._mock_subprocess_call = mock.patch.object(subprocess, 'call')
self.mock_subprocess_call = self._mock_subprocess_call.start()
+ mock_call_obj = mock.Mock()
+ mock_call_obj.execute.return_value = None
+ self.mock_subprocess_call.return_value = mock_call_obj
+
self._mock_log_info = mock.patch.object(vsperf_dpdk.LOG, 'info')
self.mock_log_info = self._mock_log_info.start()
+
self.addCleanup(self._cleanup)
+ self.scenario = vsperf_dpdk.VsperfDPDK(self.args, self.ctx)
+ self.scenario.setup()
+
def _cleanup(self):
self._mock_ssh.stop()
self._mock_subprocess_call.stop()
self._mock_log_info.stop()
def test_setup(self):
- # setup() specific mocks
- self.mock_subprocess_call().execute.return_value = None
-
- self.scenario.setup()
self.assertIsNotNone(self.scenario.client)
self.assertTrue(self.scenario.setup_done)
def test_teardown(self):
- # setup() specific mocks
- self.mock_subprocess_call().execute.return_value = None
-
- 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_is_dpdk_setup_no(self):
- # setup() specific mocks
- self.mock_subprocess_call().execute.return_value = None
-
- self.scenario.setup()
- self.assertIsNotNone(self.scenario.client)
- self.assertTrue(self.scenario.setup_done)
-
# is_dpdk_setup() specific mocks
- self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '')
+ self.mock_ssh.from_node().execute.return_value = (0, 'dummy', '')
- result = self.scenario._is_dpdk_setup()
- self.assertFalse(result)
+ self.assertFalse(self.scenario._is_dpdk_setup())
def test_is_dpdk_setup_yes(self):
- # setup() specific mocks
- self.mock_subprocess_call().execute.return_value = None
-
- self.scenario.setup()
- self.assertIsNotNone(self.scenario.client)
- self.assertTrue(self.scenario.setup_done)
-
# is_dpdk_setup() specific mocks
- self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
+ self.mock_ssh.from_node().execute.return_value = (0, '', '')
- result = self.scenario._is_dpdk_setup()
- self.assertTrue(result)
+ self.assertTrue(self.scenario._is_dpdk_setup())
@mock.patch.object(time, 'sleep')
def test_dpdk_setup_first(self, *args):
- # setup() specific mocks
- self.mock_subprocess_call().execute.return_value = None
-
- self.scenario.setup()
- self.assertIsNotNone(self.scenario.client)
- self.assertTrue(self.scenario.setup_done)
-
# is_dpdk_setup() specific mocks
- self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '')
+ self.mock_ssh.from_node().execute.return_value = (0, 'dummy', '')
self.scenario.dpdk_setup()
self.assertFalse(self.scenario._is_dpdk_setup())
@@ -137,13 +110,7 @@ class VsperfDPDKTestCase(unittest.TestCase):
@mock.patch.object(time, 'sleep')
def test_dpdk_setup_next(self, *args):
- # setup() specific mocks
- self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- self.mock_subprocess_call().execute.return_value = None
-
- self.scenario.setup()
- self.assertIsNotNone(self.scenario.client)
- self.assertTrue(self.scenario.setup_done)
+ self.mock_ssh.from_node().execute.return_value = (0, '', '')
self.scenario.dpdk_setup()
self.assertTrue(self.scenario._is_dpdk_setup())
@@ -151,75 +118,38 @@ class VsperfDPDKTestCase(unittest.TestCase):
@mock.patch.object(time, 'sleep')
def test_dpdk_setup_runtime_error(self, *args):
-
- # setup specific mocks
- self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- self.mock_subprocess_call().execute.return_value = None
-
- self.scenario.setup()
self.assertIsNotNone(self.scenario.client)
- self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ self.mock_ssh.from_node().execute.return_value = (1, '', '')
self.assertTrue(self.scenario.setup_done)
self.assertRaises(RuntimeError, self.scenario.dpdk_setup)
+ @mock.patch.object(time, 'sleep')
@mock.patch.object(subprocess, 'check_output')
- @mock.patch('time.sleep')
def test_run_ok(self, *args):
- # setup() specific mocks
- self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- self.mock_subprocess_call().execute.return_value = None
-
- self.scenario.setup()
- self.assertIsNotNone(self.scenario.client)
- self.assertTrue(self.scenario.setup_done)
-
# run() specific mocks
- self.mock_subprocess_call().execute.return_value = None
- self.mock_ssh.SSH.from_node().execute.return_value = (
+ self.mock_ssh.from_node().execute.return_value = (
0, 'throughput_rx_fps\r\n14797660.000\r\n', '')
result = {}
self.scenario.run(result)
-
self.assertEqual(result['throughput_rx_fps'], '14797660.000')
def test_run_failed_vsperf_execution(self):
- # setup() specific mocks
- self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- self.mock_subprocess_call().execute.return_value = None
+ self.mock_ssh.from_node().execute.return_value = (1, '', '')
- self.scenario.setup()
- self.assertIsNotNone(self.scenario.client)
- self.assertTrue(self.scenario.setup_done)
-
- self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
-
- result = {}
- self.assertRaises(RuntimeError, self.scenario.run, result)
+ self.assertRaises(RuntimeError, self.scenario.run, {})
def test_run_falied_csv_report(self):
- # setup() specific mocks
- self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
- self.mock_subprocess_call().execute.return_value = None
-
- self.scenario.setup()
- self.assertIsNotNone(self.scenario.client)
- self.assertTrue(self.scenario.setup_done)
-
# run() specific mocks
- self.mock_subprocess_call().execute.return_value = None
- self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '')
+ self.mock_ssh.from_node().execute.return_value = (1, '', '')
- result = {}
- self.assertRaises(RuntimeError, self.scenario.run, result)
+ self.assertRaises(RuntimeError, self.scenario.run, {})
@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 = (
+ self.mock_ssh.from_node().execute.return_value = (
0, 'throughput_rx_fps\r\n123456.000\r\n', '')
with self.assertRaises(y_exc.SLAValidationError) as raised:
@@ -232,9 +162,7 @@ class VsperfDPDKTestCase(unittest.TestCase):
@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 = (
+ self.mock_ssh.from_node().execute.return_value = (
0, 'nonexisting_metric\r\n123456.000\r\n', '')
with self.assertRaises(y_exc.SLAValidationError) as raised:
@@ -249,7 +177,7 @@ class VsperfDPDKTestCase(unittest.TestCase):
del self.scenario.scenario_cfg['sla']['throughput_rx_fps']
self.scenario.setup()
- self.mock_ssh.SSH.from_node().execute.return_value = (
+ self.mock_ssh.from_node().execute.return_value = (
0, 'throughput_rx_fps\r\n14797660.000\r\n', '')
with self.assertRaises(y_exc.SLAValidationError) as raised:
diff --git a/yardstick/tests/unit/common/test_ansible_common.py b/yardstick/tests/unit/common/test_ansible_common.py
index 48d8a60c8..bf82f6288 100644
--- a/yardstick/tests/unit/common/test_ansible_common.py
+++ b/yardstick/tests/unit/common/test_ansible_common.py
@@ -12,28 +12,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
-from __future__ import absolute_import
-
-import os
-import tempfile
+import collections
import shutil
-from collections import defaultdict
+import subprocess
+import tempfile
import mock
-import unittest
-
-from six.moves.configparser import ConfigParser
-from six.moves import StringIO
+from six import moves
+from six.moves import configparser
from yardstick.common import ansible_common
+from yardstick.tests.unit import base as ut_base
-PREFIX = 'yardstick.common.ansible_common'
+class OverwriteDictTestCase(ut_base.BaseUnitTestCase):
-class OverwriteDictTestCase(unittest.TestCase):
def test_overwrite_dict_cfg(self):
- c = ConfigParser(allow_no_value=True)
+ c = configparser.ConfigParser(allow_no_value=True)
d = {
"section_a": "empty_value",
"section_b": {"key_c": "Val_d", "key_d": "VAL_D"},
@@ -43,86 +38,78 @@ class OverwriteDictTestCase(unittest.TestCase):
# Python3 and Python2 convert empty values into None or ''
# we don't really care but we need to compare correctly for unittest
self.assertTrue(c.has_option("section_a", "empty_value"))
- self.assertEqual(sorted(c.items("section_b")), [('key_c', 'Val_d'), ('key_d', 'VAL_D')])
+ self.assertEqual(sorted(c.items("section_b")),
+ [('key_c', 'Val_d'), ('key_d', 'VAL_D')])
self.assertTrue(c.has_option("section_c", "key_c"))
self.assertTrue(c.has_option("section_c", "key_d"))
-class FilenameGeneratorTestCase(unittest.TestCase):
- @mock.patch('{}.NamedTemporaryFile'.format(PREFIX))
+class FilenameGeneratorTestCase(ut_base.BaseUnitTestCase):
+
+ @mock.patch.object(tempfile, 'NamedTemporaryFile')
def test__handle_existing_file(self, _):
- ansible_common.FileNameGenerator._handle_existing_file("/dev/null")
+ ansible_common.FileNameGenerator._handle_existing_file('/dev/null')
def test_get_generator_from_file(self):
- ansible_common.FileNameGenerator.get_generator_from_filename("/dev/null", "", "", "")
+ ansible_common.FileNameGenerator.get_generator_from_filename(
+ '/dev/null', '', '', '')
def test_get_generator_from_file_middle(self):
- ansible_common.FileNameGenerator.get_generator_from_filename("/dev/null", "", "",
- "null")
+ ansible_common.FileNameGenerator.get_generator_from_filename(
+ '/dev/null', '', '', 'null')
def test_get_generator_from_file_prefix(self):
- ansible_common.FileNameGenerator.get_generator_from_filename("/dev/null", "", "null",
- "middle")
+ ansible_common.FileNameGenerator.get_generator_from_filename(
+ '/dev/null', '', 'null', 'middle')
-class AnsibleNodeTestCase(unittest.TestCase):
- def test_ansible_node(self):
- ansible_common.AnsibleNode()
+class AnsibleNodeTestCase(ut_base.BaseUnitTestCase):
def test_ansible_node_len(self):
- a = ansible_common.AnsibleNode()
- len(a)
+ self.assertEqual(0, len(ansible_common.AnsibleNode()))
def test_ansible_node_repr(self):
- a = ansible_common.AnsibleNode()
- repr(a)
+ self.assertEqual('AnsibleNode<{}>', repr(ansible_common.AnsibleNode()))
def test_ansible_node_iter(self):
- a = ansible_common.AnsibleNode()
- for _ in a:
- pass
+ node = ansible_common.AnsibleNode(data={'a': 1, 'b': 2, 'c': 3})
+ for key in node:
+ self.assertIn(key, ('a', 'b', 'c'))
def test_is_role(self):
- a = ansible_common.AnsibleNode()
- self.assertFalse(a.is_role("", default="foo"))
+ node = ansible_common.AnsibleNode()
+ self.assertFalse(node.is_role('', default='foo'))
def test_ansible_node_get_tuple(self):
- a = ansible_common.AnsibleNode({"name": "name"})
- self.assertEqual(a.get_tuple(), ('name', a))
+ node = ansible_common.AnsibleNode({'name': 'name'})
+ self.assertEqual(node.get_tuple(), ('name', node))
def test_gen_inventory_line(self):
- a = ansible_common.AnsibleNode(defaultdict(str))
+ a = ansible_common.AnsibleNode(collections.defaultdict(str))
self.assertEqual(a.gen_inventory_line(), "")
def test_ansible_node_delitem(self):
- a = ansible_common.AnsibleNode({"name": "name"})
- del a['name']
+ node = ansible_common.AnsibleNode({'name': 'name'})
+ self.assertEqual(1, len(node))
+ del node['name']
+ self.assertEqual(0, len(node))
def test_ansible_node_getattr(self):
- a = ansible_common.AnsibleNode({"name": "name"})
- self.assertIsNone(getattr(a, "nosuch", None))
+ node = ansible_common.AnsibleNode({'name': 'name'})
+ self.assertIsNone(getattr(node, 'nosuch', None))
-class AnsibleNodeDictTestCase(unittest.TestCase):
- def test_ansible_node_dict(self):
- n = ansible_common.AnsibleNode
- ansible_common.AnsibleNodeDict(n, {})
+class AnsibleNodeDictTestCase(ut_base.BaseUnitTestCase):
def test_ansible_node_dict_len(self):
n = ansible_common.AnsibleNode
a = ansible_common.AnsibleNodeDict(n, {})
- len(a)
+ self.assertEqual(0, len(a))
def test_ansible_node_dict_repr(self):
n = ansible_common.AnsibleNode
a = ansible_common.AnsibleNodeDict(n, {})
- repr(a)
-
- def test_ansible_node_dict_iter(self):
- n = ansible_common.AnsibleNode
- a = ansible_common.AnsibleNodeDict(n, {})
- for _ in a:
- pass
+ self.assertEqual('{}', repr(a))
def test_ansible_node_dict_get(self):
n = ansible_common.AnsibleNode
@@ -144,12 +131,15 @@ class AnsibleNodeDictTestCase(unittest.TestCase):
["name ansible_ssh_pass=PASS ansible_user=user"])
-class AnsibleCommonTestCase(unittest.TestCase):
- def test_get_timeouts(self):
- self.assertAlmostEqual(ansible_common.AnsibleCommon.get_timeout(-100), 1200.0)
+class AnsibleCommonTestCase(ut_base.BaseUnitTestCase):
- def test__init__(self):
- ansible_common.AnsibleCommon({})
+ @staticmethod
+ def _delete_tmpdir(dir):
+ shutil.rmtree(dir)
+
+ def test_get_timeouts(self):
+ self.assertAlmostEqual(
+ ansible_common.AnsibleCommon.get_timeout(-100), 1200.0)
def test_reset(self):
a = ansible_common.AnsibleCommon({})
@@ -184,81 +174,68 @@ class AnsibleCommonTestCase(unittest.TestCase):
a.deploy_dir = "d"
self.assertEqual(a.deploy_dir, "d")
- @mock.patch('{}.open'.format(PREFIX))
- def test__gen_ansible_playbook_file_list(self, _):
+ @mock.patch.object(moves.builtins, 'open')
+ def test__gen_ansible_playbook_file_list(self, *args):
d = tempfile.mkdtemp()
- try:
- a = ansible_common.AnsibleCommon({})
- a._gen_ansible_playbook_file(["a"], d)
- finally:
- os.rmdir(d)
-
- @mock.patch('{}.NamedTemporaryFile'.format(PREFIX))
- @mock.patch('{}.open'.format(PREFIX))
- def test__gen_ansible_inventory_file(self, _, __):
+ self.addCleanup(self._delete_tmpdir, d)
+ a = ansible_common.AnsibleCommon({})
+ a._gen_ansible_playbook_file(["a"], d)
+
+ @mock.patch.object(tempfile, 'NamedTemporaryFile')
+ @mock.patch.object(moves.builtins, 'open')
+ def test__gen_ansible_inventory_file(self, *args):
nodes = [{
"name": "name", "user": "user", "password": "PASS",
"role": "role",
}]
d = tempfile.mkdtemp()
- try:
- a = ansible_common.AnsibleCommon(nodes)
- a.gen_inventory_ini_dict()
- inv_context = a._gen_ansible_inventory_file(d)
- with inv_context:
- c = StringIO()
- inv_context.write_func(c)
- self.assertIn("ansible_ssh_pass=PASS", c.getvalue())
- finally:
- os.rmdir(d)
-
- @mock.patch('{}.NamedTemporaryFile'.format(PREFIX))
- @mock.patch('{}.open'.format(PREFIX))
- def test__gen_ansible_playbook_file_list_multiple(self, _, __):
+ self.addCleanup(self._delete_tmpdir, d)
+ a = ansible_common.AnsibleCommon(nodes)
+ a.gen_inventory_ini_dict()
+ inv_context = a._gen_ansible_inventory_file(d)
+ with inv_context:
+ c = moves.StringIO()
+ inv_context.write_func(c)
+ self.assertIn("ansible_ssh_pass=PASS", c.getvalue())
+
+ @mock.patch.object(tempfile, 'NamedTemporaryFile')
+ @mock.patch.object(moves.builtins, 'open')
+ def test__gen_ansible_playbook_file_list_multiple(self, *args):
d = tempfile.mkdtemp()
- try:
- a = ansible_common.AnsibleCommon({})
- a._gen_ansible_playbook_file(["a", "b"], d)
- finally:
- os.rmdir(d)
-
- @mock.patch('{}.NamedTemporaryFile'.format(PREFIX))
- @mock.patch('{}.Popen'.format(PREFIX))
- @mock.patch('{}.open'.format(PREFIX))
- def test_do_install_tmp_dir(self, _, mock_popen, __):
+ self.addCleanup(self._delete_tmpdir, d)
+ a = ansible_common.AnsibleCommon({})
+ a._gen_ansible_playbook_file(["a", "b"], d)
+
+ @mock.patch.object(tempfile, 'NamedTemporaryFile')
+ @mock.patch.object(subprocess, 'Popen')
+ @mock.patch.object(moves.builtins, 'open')
+ def test_do_install_tmp_dir(self, _, mock_popen, *args):
mock_popen.return_value.communicate.return_value = "", ""
mock_popen.return_value.wait.return_value = 0
d = tempfile.mkdtemp()
- try:
- a = ansible_common.AnsibleCommon({})
- a.do_install('', d)
- finally:
- os.rmdir(d)
-
- @mock.patch('{}.NamedTemporaryFile'.format(PREFIX))
- @mock.patch('{}.Popen'.format(PREFIX))
- @mock.patch('{}.open'.format(PREFIX))
- def test_execute_ansible_check(self, _, mock_popen, __):
+ self.addCleanup(self._delete_tmpdir, d)
+ a = ansible_common.AnsibleCommon({})
+ a.do_install('', d)
+
+ @mock.patch.object(tempfile, 'NamedTemporaryFile')
+ @mock.patch.object(moves.builtins, 'open')
+ @mock.patch.object(subprocess, 'Popen')
+ def test_execute_ansible_check(self, mock_popen, *args):
mock_popen.return_value.communicate.return_value = "", ""
mock_popen.return_value.wait.return_value = 0
d = tempfile.mkdtemp()
- try:
- a = ansible_common.AnsibleCommon({})
- a.execute_ansible('', d, ansible_check=True, verbose=True)
- finally:
- os.rmdir(d)
+ self.addCleanup(self._delete_tmpdir, d)
+ a = ansible_common.AnsibleCommon({})
+ a.execute_ansible('', d, ansible_check=True, verbose=True)
def test_get_sut_info(self):
d = tempfile.mkdtemp()
a = ansible_common.AnsibleCommon({})
- try:
+ self.addCleanup(self._delete_tmpdir, d)
+ with mock.patch.object(a, '_exec_get_sut_info_cmd'):
a.get_sut_info(d)
- finally:
- shutil.rmtree(d)
def test_get_sut_info_not_exist(self):
a = ansible_common.AnsibleCommon({})
- try:
+ with self.assertRaises(OSError):
a.get_sut_info('/hello/world')
- except OSError:
- pass
diff --git a/yardstick/tests/unit/common/test_kubernetes_utils.py b/yardstick/tests/unit/common/test_kubernetes_utils.py
index 42aa9f7e0..9dca2700d 100644
--- a/yardstick/tests/unit/common/test_kubernetes_utils.py
+++ b/yardstick/tests/unit/common/test_kubernetes_utils.py
@@ -240,6 +240,19 @@ class DeleteNetworkTestCase(base.BaseUnitTestCase):
constants.SCOPE_CLUSTER, mock.ANY, mock.ANY, mock.ANY,
mock.ANY)
+ @mock.patch.object(kubernetes_utils, 'get_custom_objects_api')
+ @mock.patch.object(kubernetes_utils, 'LOG')
+ def test_execute_skip_exception(self, mock_log, mock_get_api):
+ mock_api = mock.Mock()
+ mock_api.delete_cluster_custom_object.side_effect = rest.ApiException(status=404)
+
+ mock_get_api.return_value = mock_api
+ kubernetes_utils.delete_network(
+ constants.SCOPE_CLUSTER, mock.ANY, mock.ANY, mock.ANY,
+ mock.ANY, skip_codes=[404])
+
+ mock_log.info.assert_called_once()
+
class DeletePodTestCase(base.BaseUnitTestCase):
@mock.patch.object(kubernetes_utils, 'get_core_api')
@@ -260,8 +273,9 @@ class DeletePodTestCase(base.BaseUnitTestCase):
with self.assertRaises(exceptions.KubernetesApiException):
kubernetes_utils.delete_pod(mock.ANY, skip_codes=[404])
+ @mock.patch.object(kubernetes_utils, 'LOG')
@mock.patch.object(kubernetes_utils, 'get_core_api')
- def test_execute_skip_exception(self, mock_get_api):
+ def test_execute_skip_exception(self, mock_get_api, *args):
mock_api = mock.Mock()
mock_api.delete_namespaced_pod.side_effect = rest.ApiException(status=404)
@@ -289,12 +303,11 @@ class DeleteServiceTestCase(base.BaseUnitTestCase):
with self.assertRaises(exceptions.KubernetesApiException):
kubernetes_utils.delete_service(mock.ANY, skip_codes=[404])
- @mock.patch.object(kubernetes_utils, 'get_core_api')
@mock.patch.object(kubernetes_utils, 'LOG')
- def test_execute_skip_exception(self, mock_log, mock_get_api):
+ @mock.patch.object(kubernetes_utils, 'get_core_api')
+ def test_execute_skip_exception(self, mock_get_api, *args):
mock_api = mock.Mock()
mock_api.delete_namespaced_service.side_effect = rest.ApiException(status=404)
mock_get_api.return_value = mock_api
kubernetes_utils.delete_service(mock.ANY, skip_codes=[404])
- mock_log.info.assert_called_once()
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py b/yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py
new file mode 100644
index 000000000..08542b4f1
--- /dev/null
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py
@@ -0,0 +1,63 @@
+# 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
+
+from yardstick.common import utils
+from yardstick.network_services.traffic_profile import pktgen
+from yardstick.tests.unit import base as ut_base
+
+
+class TestIXIARFC2544Profile(ut_base.BaseUnitTestCase):
+
+ def setUp(self):
+ self._tp_config = {'traffic_profile': {}}
+ self._host = 'localhost'
+ self._port = '12345'
+ self.tp = pktgen.PktgenTrafficProfile(self._tp_config)
+ self.tp.init(self._host, self._port)
+ self._mock_send_socket_command = mock.patch.object(
+ utils, 'send_socket_command', return_value=0)
+ self.mock_send_socket_command = self._mock_send_socket_command.start()
+ self.addCleanup(self._stop_mock)
+
+ def _stop_mock(self):
+ self._mock_send_socket_command.stop()
+
+ def test_start(self):
+ self.tp.start()
+ self.mock_send_socket_command.assert_called_once_with(
+ self._host, self._port, 'pktgen.start("0")')
+
+ def test_stop(self):
+ self.tp.stop()
+ self.mock_send_socket_command.assert_called_once_with(
+ self._host, self._port, 'pktgen.stop("0")')
+
+ def test_rate(self):
+ rate = 75
+ self.tp.rate(rate)
+ command = 'pktgen.set("0", "rate", 75)'
+ self.mock_send_socket_command.assert_called_once_with(
+ self._host, self._port, command)
+
+ def test_clear_all_stats(self):
+ self.tp.clear_all_stats()
+ self.mock_send_socket_command.assert_called_once_with(
+ self._host, self._port, 'clr')
+
+ def test_help(self):
+ self.tp.help()
+ self.mock_send_socket_command.assert_called_once_with(
+ self._host, self._port, 'help')
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py
new file mode 100644
index 000000000..d341b970b
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py
@@ -0,0 +1,79 @@
+# 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 uuid
+
+import mock
+
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.network_services.vnf_generic.vnf import base as vnf_base
+from yardstick.network_services.vnf_generic.vnf import tg_pktgen
+from yardstick.tests.unit import base as ut_base
+
+
+class PktgenTrafficGenTestCase(ut_base.BaseUnitTestCase):
+
+ SERVICE_PORTS = [{'port': constants.LUA_PORT,
+ 'node_port': '34501'}]
+ VNFD = {'mgmt-interface': {'ip': '1.2.3.4',
+ 'service_ports': SERVICE_PORTS},
+ 'vdu': [{'external-interface': 'interface'}],
+ 'benchmark': {'kpi': 'fake_kpi'}
+ }
+
+ def setUp(self):
+ self._id = uuid.uuid1().int
+ self._mock_vnf_consumer = mock.patch.object(vnf_base,
+ 'GenericVNFConsumer')
+ self.mock_vnf_consumer = self._mock_vnf_consumer.start()
+ self.addCleanup(self._stop_mock)
+
+ def _stop_mock(self):
+ self._mock_vnf_consumer.stop()
+
+ def test__init(self):
+ tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+ self.assertTrue(isinstance(tg, (vnf_base.GenericTrafficGen,
+ vnf_base.GenericVNFEndpoint)))
+
+ def test_run_traffic(self):
+ tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+ mock_tp = mock.Mock()
+ with mock.patch.object(tg, '_is_running', return_value=True):
+ tg.run_traffic(mock_tp)
+
+ mock_tp.init.assert_called_once_with(tg._node_ip, tg._lua_node_port)
+
+ def test__get_lua_node_port(self):
+ tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+ service_ports = [{'port': constants.LUA_PORT,
+ 'node_port': '12345'}]
+ self.assertEqual(12345, tg._get_lua_node_port(service_ports))
+
+ def test__get_lua_node_port_no_lua_port(self):
+ tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+ service_ports = [{'port': '333'}]
+ self.assertIsNone(tg._get_lua_node_port(service_ports))
+
+ def test__is_running(self):
+ tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+ with mock.patch.object(tg, '_traffic_profile'):
+ self.assertTrue(tg._is_running())
+
+ def test__is_running_exception(self):
+ tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+ with mock.patch.object(tg, '_traffic_profile') as mock_tp:
+ mock_tp.help.side_effect = exceptions.PktgenActionError()
+ self.assertFalse(tg._is_running())
diff --git a/yardstick/tests/unit/orchestrator/test_kubernetes.py b/yardstick/tests/unit/orchestrator/test_kubernetes.py
index 5a6f8c6a0..4bf678390 100644
--- a/yardstick/tests/unit/orchestrator/test_kubernetes.py
+++ b/yardstick/tests/unit/orchestrator/test_kubernetes.py
@@ -543,7 +543,7 @@ class NetworkObjectTestCase(base.BaseUnitTestCase):
net_obj._name = 'name'
net_obj.delete()
mock_delete_network.assert_called_once_with(
- 'scope', 'group', 'version', 'plural', 'name')
+ 'scope', 'group', 'version', 'plural', 'name', skip_codes=[404])
class ServiceNodePortObjectTestCase(base.BaseUnitTestCase):
diff --git a/yardstick/tests/unit/service/test_environment.py b/yardstick/tests/unit/service/test_environment.py
index be4882e30..779e6eaa0 100644
--- a/yardstick/tests/unit/service/test_environment.py
+++ b/yardstick/tests/unit/service/test_environment.py
@@ -9,9 +9,8 @@
import mock
-from yardstick.common.exceptions import UnsupportedPodFormatError
-from yardstick.service.environment import Environment
-from yardstick.service.environment import AnsibleCommon
+from yardstick.common import exceptions
+from yardstick.service import environment
from yardstick.tests.unit import base as ut_base
@@ -31,15 +30,17 @@ class EnvironmentTestCase(ut_base.BaseUnitTestCase):
]
}
- with mock.patch.object(AnsibleCommon, 'gen_inventory_ini_dict'), \
- mock.patch.object(AnsibleCommon, 'get_sut_info',
- return_value={'node1': {}}):
- env = Environment(pod=pod_info)
+ with mock.patch.object(environment.AnsibleCommon,
+ 'gen_inventory_ini_dict'), \
+ mock.patch.object(environment.AnsibleCommon, 'get_sut_info',
+ return_value={'node1': {}}), \
+ mock.patch.object(environment.Environment, '_format_sut_info'):
+ env = environment.Environment(pod=pod_info)
env.get_sut_info()
def test_get_sut_info_pod_str(self):
pod_info = 'nodes'
- env = Environment(pod=pod_info)
- with self.assertRaises(UnsupportedPodFormatError):
+ env = environment.Environment(pod=pod_info)
+ with self.assertRaises(exceptions.UnsupportedPodFormatError):
env.get_sut_info()