summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ansible/roles/install_yardstick/tasks/main.yml6
-rw-r--r--docker/k8s/Dockerfile39
-rwxr-xr-xdocs/testing/developer/devguide/devguide.rst26
-rw-r--r--yardstick/benchmark/contexts/kubernetes.py13
-rw-r--r--yardstick/common/exceptions.py24
-rw-r--r--yardstick/common/kubernetes_utils.py25
-rw-r--r--yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py12
-rw-r--r--yardstick/network_services/traffic_profile/base.py32
-rw-r--r--yardstick/network_services/traffic_profile/ixia_rfc2544.py32
-rw-r--r--yardstick/orchestrator/kubernetes.py56
-rw-r--r--yardstick/tests/unit/benchmark/contexts/test_kubernetes.py16
-rw-r--r--yardstick/tests/unit/benchmark/core/test_task.py9
-rw-r--r--yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py126
-rw-r--r--yardstick/tests/unit/common/test_kubernetes_utils.py48
-rw-r--r--yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py12
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_base.py21
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py8
-rw-r--r--yardstick/tests/unit/orchestrator/test_kubernetes.py97
18 files changed, 426 insertions, 176 deletions
diff --git a/ansible/roles/install_yardstick/tasks/main.yml b/ansible/roles/install_yardstick/tasks/main.yml
index 973b2b027..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: 300
+ 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: 300
+ 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: 100
+ retries: 180
- name: Install Yardstick code (venv)
pip:
diff --git a/docker/k8s/Dockerfile b/docker/k8s/Dockerfile
new file mode 100644
index 000000000..2f8d9b161
--- /dev/null
+++ b/docker/k8s/Dockerfile
@@ -0,0 +1,39 @@
+##############################################################################
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd 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
+##############################################################################
+
+FROM ubuntu:16.04
+
+LABEL image=opnfv/yardstick-image-k8s
+
+ARG BRANCH=master
+
+# GIT repo directory
+ENV CLONE_DEST="/opt/tempT"
+
+RUN apt-get update && apt-get install -y \
+ git bc bonnie++ fio gcc iperf3 ethtool \
+ iproute2 linux-tools-common linux-tools-generic \
+ lmbench make netperf patch perl rt-tests stress \
+ sysstat iputils-ping openssh-server sudo && \
+ apt-get -y autoremove && apt-get clean
+
+RUN rm -rf -- ${CLONE_DEST}
+RUN git clone https://github.com/kdlucas/byte-unixbench.git ${CLONE_DEST}
+RUN mkdir -p ${CLONE_DEST}/UnixBench/
+
+RUN git clone https://github.com/beefyamoeba5/ramspeed.git ${CLONE_DEST}/RAMspeed
+WORKDIR ${CLONE_DEST}/RAMspeed/ramspeed-2.6.0
+RUN mkdir -p ${CLONE_DEST}/RAMspeed/ramspeed-2.6.0/temp
+RUN bash build.sh
+
+RUN git clone https://github.com/beefyamoeba5/cachestat.git ${CLONE_DEST}/Cachestat
+
+WORKDIR /
+
+CMD /bin/bash
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/yardstick/benchmark/contexts/kubernetes.py b/yardstick/benchmark/contexts/kubernetes.py
index 704c4a022..7534c4ea5 100644
--- a/yardstick/benchmark/contexts/kubernetes.py
+++ b/yardstick/benchmark/contexts/kubernetes.py
@@ -166,8 +166,8 @@ class KubernetesContext(ctx_base.Context):
def _get_server(self, name):
node_ports = self._get_service_ports(name)
for sn_port in (sn_port for sn_port in node_ports
- if sn_port.port == constants.SSH_PORT):
- node_port = sn_port.node_port
+ if sn_port['port'] == constants.SSH_PORT):
+ node_port = sn_port['node_port']
break
else:
raise exceptions.KubernetesSSHPortNotDefined()
@@ -224,4 +224,11 @@ class KubernetesContext(ctx_base.Context):
service = k8s_utils.get_service_by_name(service_name)
if not service:
raise exceptions.KubernetesServiceObjectNotDefined()
- return service.ports
+ ports = []
+ for port in service.ports:
+ ports.append({'name': port.name,
+ 'node_port': port.node_port,
+ 'port': port.port,
+ 'protocol': port.protocol,
+ 'target_port': port.target_port})
+ return ports
diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py
index c25acbaf8..2e6cbdd7b 100644
--- a/yardstick/common/exceptions.py
+++ b/yardstick/common/exceptions.py
@@ -85,7 +85,6 @@ class InfluxDBConfigurationMissing(YardstickException):
class YardstickBannedModuleImported(YardstickException):
- # pragma: no cover
message = 'Module "%(module)s" cannnot be imported. Reason: "%(reason)s"'
@@ -95,7 +94,6 @@ class PayloadMissingAttributes(YardstickException):
class HeatTemplateError(YardstickException):
- """Error in Heat during the stack deployment"""
message = ('Error in Heat during the creation of the OpenStack stack '
'"%(stack_name)s"')
@@ -108,6 +106,10 @@ class TrafficProfileNotImplemented(YardstickException):
message = 'No implementation for traffic profile %(profile_class)s.'
+class TrafficProfileRate(YardstickException):
+ message = 'Traffic profile rate must be "<number>[fps|%]"'
+
+
class DPDKSetupDriverError(YardstickException):
message = '"igb_uio" driver is not loaded'
@@ -231,6 +233,16 @@ class KubernetesServiceObjectNotDefined(YardstickException):
message = 'ServiceObject is not defined'
+class KubernetesServiceObjectDefinitionError(YardstickException):
+ message = ('Kubernetes Service object definition error, missing '
+ 'parameters: %(missing_parameters)s')
+
+
+class KubernetesServiceObjectNameError(YardstickException):
+ message = ('Kubernetes Service object name "%(name)s" does not comply'
+ 'naming convention')
+
+
class KubernetesCRDObjectDefinitionError(YardstickException):
message = ('Kubernetes Custom Resource Definition Object error, missing '
'parameters: %(missing_parameters)s')
@@ -253,6 +265,14 @@ class KubernetesContainerPortNotDefined(YardstickException):
message = 'Container port not defined in "%(port)s"'
+class KubernetesContainerWrongImagePullPolicy(YardstickException):
+ message = 'Image pull policy must be "Always", "IfNotPresent" or "Never"'
+
+
+class KubernetesContainerCommandType(YardstickException):
+ message = '"args" and "command" must be string or list of strings'
+
+
class ScenarioCreateNetworkError(YardstickException):
message = 'Create Neutron Network Scenario failed'
diff --git a/yardstick/common/kubernetes_utils.py b/yardstick/common/kubernetes_utils.py
index 35e590f2b..f5b0443ea 100644
--- a/yardstick/common/kubernetes_utils.py
+++ b/yardstick/common/kubernetes_utils.py
@@ -75,15 +75,18 @@ def create_service(template,
raise
-def delete_service(name,
- namespace='default',
- **kwargs): # pragma: no cover
+def delete_service(name, namespace='default', skip_codes=None, **kwargs):
+ skip_codes = [] if not skip_codes else skip_codes
core_v1_api = get_core_api()
try:
body = client.V1DeleteOptions()
core_v1_api.delete_namespaced_service(name, namespace, body, **kwargs)
- except ApiException:
- LOG.exception('Delete Service failed')
+ except ApiException as e:
+ if e.status in skip_codes:
+ LOG.info(e.reason)
+ else:
+ raise exceptions.KubernetesApiException(
+ action='delete', resource='Service')
def get_service_list(namespace='default', **kwargs):
@@ -223,14 +226,18 @@ def create_custom_resource_definition(body):
action='create', resource='CustomResourceDefinition')
-def delete_custom_resource_definition(name):
+def delete_custom_resource_definition(name, skip_codes=None):
+ skip_codes = [] if not skip_codes else skip_codes
api = get_extensions_v1beta_api()
body_obj = client.V1DeleteOptions()
try:
api.delete_custom_resource_definition(name, body_obj)
- except ApiException:
- raise exceptions.KubernetesApiException(
- action='delete', resource='CustomResourceDefinition')
+ except ApiException as e:
+ if e.status in skip_codes:
+ LOG.info(e.reason)
+ else:
+ raise exceptions.KubernetesApiException(
+ action='delete', resource='CustomResourceDefinition')
def get_custom_resource_definition(kind):
diff --git a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
index 74deeecb5..cee768dba 100644
--- a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
+++ b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py
@@ -18,6 +18,7 @@ import IxNetwork
from yardstick.common import exceptions
from yardstick.common import utils
+from yardstick.network_services.traffic_profile import base as tp_base
log = logging.getLogger(__name__)
@@ -336,8 +337,8 @@ class IxNextgen(object): # pragma: no cover
- 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)
+ - Type of rate: "framesPerSecond" or "percentLineRate" ("bitsPerSecond"
+ no used)
- Frame size: custom IMIX [1] definition; a list of packet size in
bytes and the weight. E.g.:
[[64, 64, 10], [128, 128, 15], [512, 512, 5]]
@@ -355,7 +356,10 @@ class IxNextgen(object): # pragma: no cover
type = traffic_param.get('traffic_type', 'fixedDuration')
duration = traffic_param.get('duration', 30)
- rate = traffic_param['iload']
+ rate = traffic_param['rate']
+ rate_unit = (
+ 'framesPerSecond' if traffic_param['rate_unit'] ==
+ tp_base.TrafficProfileConfig.RATE_FPS else 'percentLineRate')
weighted_range_pairs = self._parse_framesize(
traffic_param['outer_l2']['framesize'])
srcmac = str(traffic_param.get('srcmac', '00:00:00:00:00:01'))
@@ -370,7 +374,7 @@ class IxNextgen(object): # pragma: no cover
'-type', type, '-duration', duration)
self.ixnet.setMultiAttribute(
config_element + '/frameRate',
- '-rate', rate, '-type', 'framesPerSecond')
+ '-rate', rate, '-type', rate_unit)
self.ixnet.setMultiAttribute(
config_element + '/frameSize',
'-type', 'weightedPairs',
diff --git a/yardstick/network_services/traffic_profile/base.py b/yardstick/network_services/traffic_profile/base.py
index f4b5b178c..a8f950b7b 100644
--- a/yardstick/network_services/traffic_profile/base.py
+++ b/yardstick/network_services/traffic_profile/base.py
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import re
+
from yardstick.common import exceptions
from yardstick.common import utils
@@ -21,10 +23,12 @@ class TrafficProfileConfig(object):
This object will parse and validate the traffic profile information.
"""
-
DEFAULT_SCHEMA = 'nsb:traffic_profile:0.1'
- DEFAULT_FRAME_RATE = 100
+ DEFAULT_FRAME_RATE = '100'
DEFAULT_DURATION = 30
+ RATE_FPS = 'fps'
+ RATE_PERCENTAGE = '%'
+ RATE_REGEX = re.compile(r'([0-9]*\.[0-9]+|[0-9]+)\s*(fps|%)*(.*)')
def __init__(self, tp_config):
self.schema = tp_config.get('schema', self.DEFAULT_SCHEMA)
@@ -32,7 +36,8 @@ class TrafficProfileConfig(object):
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.frame_rate, self.rate_unit = self._parse_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)
@@ -40,6 +45,27 @@ class TrafficProfileConfig(object):
self.upper_bound = tprofile.get('upper_bound')
self.step_interval = tprofile.get('step_interval')
+ def _parse_rate(self, rate):
+ """Parse traffic profile rate
+
+ The line rate can be defined in fps or percentage over the maximum line
+ rate:
+ - frame_rate = 5000 (by default, unit is 'fps')
+ - frame_rate = 5000fps
+ - frame_rate = 25%
+
+ :param rate: (string, int) line rate in fps or %
+ :return: (tuple: int, string) line rate number and unit
+ """
+ match = self.RATE_REGEX.match(str(rate))
+ if not match:
+ exceptions.TrafficProfileRate()
+ rate = float(match.group(1))
+ unit = match.group(2) if match.group(2) else self.RATE_FPS
+ if match.group(3):
+ raise exceptions.TrafficProfileRate()
+ return rate, unit
+
class TrafficProfile(object):
"""
diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py
index 39336785e..49bac27e4 100644
--- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py
+++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py
@@ -14,25 +14,27 @@
import logging
-from yardstick.network_services.traffic_profile.trex_traffic_profile import \
- TrexProfile
+from yardstick.network_services.traffic_profile import base as tp_base
+from yardstick.network_services.traffic_profile import trex_traffic_profile
+
LOG = logging.getLogger(__name__)
-class IXIARFC2544Profile(TrexProfile):
+class IXIARFC2544Profile(trex_traffic_profile.TrexProfile):
UPLINK = 'uplink'
DOWNLINK = 'downlink'
+ DROP_PERCENT_ROUND = 6
+ RATE_ROUND = 5
def __init__(self, yaml_data):
super(IXIARFC2544Profile, self).__init__(yaml_data)
self.rate = self.config.frame_rate
+ self.rate_unit = self.config.rate_unit
def _get_ixia_traffic_profile(self, profile_data, mac=None):
- if mac is None:
- mac = {}
-
+ mac = {} if mac is None else mac
result = {}
for traffickey, values in profile_data.items():
if not traffickey.startswith((self.UPLINK, self.DOWNLINK)):
@@ -58,8 +60,9 @@ class IXIARFC2544Profile(TrexProfile):
result[traffickey] = {
'bidir': False,
- 'iload': '100',
'id': port_id,
+ 'rate': self.rate,
+ 'rate_unit': self.rate_unit,
'outer_l2': {
'framesize': value['outer_l2']['framesize'],
'framesPerSecond': True,
@@ -83,9 +86,6 @@ class IXIARFC2544Profile(TrexProfile):
return result
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.update_frame(traffic)
ixia_obj.update_ip_packet(traffic)
ixia_obj.start_traffic()
@@ -114,9 +114,10 @@ class IXIARFC2544Profile(TrexProfile):
self.pg_id = 0
self.update_traffic_profile(traffic_generator)
self.max_rate = self.rate
- self.min_rate = 0
+ self.min_rate = 0.0
else:
- self.rate = round(float(self.max_rate + self.min_rate) / 2.0, 2)
+ self.rate = round(float(self.max_rate + self.min_rate) / 2.0,
+ self.RATE_ROUND)
traffic = self._get_ixia_traffic_profile(self.full_profile, mac)
self._ixia_traffic_generate(traffic, ixia_obj)
@@ -141,7 +142,8 @@ class IXIARFC2544Profile(TrexProfile):
try:
drop_percent = round(
- (packet_drop / float(out_packets_sum)) * 100, 2)
+ (packet_drop / float(out_packets_sum)) * 100,
+ self.DROP_PERCENT_ROUND)
except ZeroDivisionError:
LOG.info('No traffic is flowing')
@@ -150,8 +152,10 @@ class IXIARFC2544Profile(TrexProfile):
samples['DropPercentage'] = drop_percent
if first_run:
- self.rate = out_packets_sum / duration / num_ifaces
completed = True if drop_percent <= tolerance else False
+ if (first_run and
+ self.rate_unit == tp_base.TrafficProfileConfig.RATE_FPS):
+ self.rate = out_packets_sum / duration / num_ifaces
if drop_percent > tolerance:
self.max_rate = self.rate
diff --git a/yardstick/orchestrator/kubernetes.py b/yardstick/orchestrator/kubernetes.py
index 98832908c..7b1450230 100644
--- a/yardstick/orchestrator/kubernetes.py
+++ b/yardstick/orchestrator/kubernetes.py
@@ -8,8 +8,10 @@
##############################################################################
import copy
+import re
from oslo_serialization import jsonutils
+import six
from yardstick.common import constants
from yardstick.common import exceptions
@@ -21,21 +23,34 @@ class ContainerObject(object):
SSH_MOUNT_PATH = '/tmp/.ssh/'
IMAGE_DEFAULT = 'openretriever/yardstick'
- COMMAND_DEFAULT = '/bin/bash'
+ COMMAND_DEFAULT = ['/bin/bash', '-c']
RESOURCES = ('requests', 'limits')
PORT_OPTIONS = ('containerPort', 'hostIP', 'hostPort', 'name', 'protocol')
+ IMAGE_PULL_POLICY = ('Always', 'IfNotPresent', 'Never')
def __init__(self, name, ssh_key, **kwargs):
self._name = name
self._ssh_key = ssh_key
self._image = kwargs.get('image', self.IMAGE_DEFAULT)
- self._command = [kwargs.get('command', self.COMMAND_DEFAULT)]
- self._args = kwargs.get('args', [])
+ self._command = self._parse_commands(
+ kwargs.get('command', self.COMMAND_DEFAULT))
+ self._args = self._parse_commands(kwargs.get('args', []))
self._volume_mounts = kwargs.get('volumeMounts', [])
self._security_context = kwargs.get('securityContext')
self._env = kwargs.get('env', [])
self._resources = kwargs.get('resources', {})
self._ports = kwargs.get('ports', [])
+ self._image_pull_policy = kwargs.get('imagePullPolicy')
+ self._tty = kwargs.get('tty')
+ self._stdin = kwargs.get('stdin')
+
+ @staticmethod
+ def _parse_commands(command):
+ if isinstance(command, six.string_types):
+ return [command]
+ elif isinstance(command, list):
+ return command
+ raise exceptions.KubernetesContainerCommandType()
def _create_volume_mounts(self):
"""Return all "volumeMounts" items per container"""
@@ -82,6 +97,14 @@ class ContainerObject(object):
for res in (res for res in self._resources if
res in self.RESOURCES):
container['resources'][res] = self._resources[res]
+ if self._image_pull_policy:
+ if self._image_pull_policy not in self.IMAGE_PULL_POLICY:
+ raise exceptions.KubernetesContainerWrongImagePullPolicy()
+ container['imagePullPolicy'] = self._image_pull_policy
+ if self._stdin is not None:
+ container['stdin'] = self._stdin
+ if self._tty is not None:
+ container['tty'] = self._tty
return container
@@ -234,6 +257,9 @@ class ReplicationControllerObject(object):
class ServiceNodePortObject(object):
+ MANDATORY_PARAMETERS = {'port', 'name'}
+ NAME_REGEX = re.compile(r'^[a-z0-9]([-a-z0-9]*[a-z0-9])?$')
+
def __init__(self, name, **kwargs):
"""Service kind "NodePort" object
@@ -251,19 +277,27 @@ class ServiceNodePortObject(object):
}
}
- self._add_port(22, protocol='TCP')
+ self._add_port(22, 'ssh', protocol='TCP')
node_ports = copy.deepcopy(kwargs.get('node_ports', []))
for port in node_ports:
+ if not self.MANDATORY_PARAMETERS.issubset(port.keys()):
+ missing_parameters = ', '.join(
+ str(param) for param in
+ (self.MANDATORY_PARAMETERS - set(port.keys())))
+ raise exceptions.KubernetesServiceObjectDefinitionError(
+ missing_parameters=missing_parameters)
port_number = port.pop('port')
- self._add_port(port_number, **port)
+ name = port.pop('name')
+ if not self.NAME_REGEX.match(name):
+ raise exceptions.KubernetesServiceObjectNameError(name=name)
+ self._add_port(port_number, name, **port)
- def _add_port(self, port, protocol=None, name=None, targetPort=None,
+ def _add_port(self, port, name, protocol=None, targetPort=None,
nodePort=None):
- _port = {'port': port}
+ _port = {'port': port,
+ 'name': name}
if protocol:
_port['protocol'] = protocol
- if name:
- _port['name'] = name
if targetPort:
_port['targetPort'] = targetPort
if nodePort:
@@ -274,7 +308,7 @@ class ServiceNodePortObject(object):
k8s_utils.create_service(self.template)
def delete(self):
- k8s_utils.delete_service(self._name)
+ k8s_utils.delete_service(self._name, skip_codes=[404])
class CustomResourceDefinitionObject(object):
@@ -315,7 +349,7 @@ class CustomResourceDefinitionObject(object):
k8s_utils.create_custom_resource_definition(self._template)
def delete(self):
- k8s_utils.delete_custom_resource_definition(self._name)
+ k8s_utils.delete_custom_resource_definition(self._name, skip_codes=[404])
class NetworkObject(object):
diff --git a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py
index bace37653..b526e7cc7 100644
--- a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py
+++ b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py
@@ -57,6 +57,9 @@ class NodePort(object):
def __init__(self):
self.node_port = 30000
self.port = constants.SSH_PORT
+ self.name = 'port_name'
+ self.protocol = 'TCP'
+ self.target_port = constants.SSH_PORT
class Service(object):
@@ -152,8 +155,10 @@ class KubernetesTestCase(unittest.TestCase):
def test_get_server(self, mock_get_node_ip, mock_get_pod_by_name):
mock_get_pod_by_name.return_value = Pod()
mock_get_node_ip.return_value = '172.16.10.131'
- with mock.patch.object(self.k8s_context, '_get_service_ports',
- return_value=[NodePort()]):
+ with mock.patch.object(self.k8s_context, '_get_service_ports') as \
+ mock_get_sports:
+ mock_get_sports.return_value = [
+ {'port': constants.SSH_PORT, 'node_port': 30000}]
server = self.k8s_context._get_server('server_name')
self.assertEqual('server_name', server['name'])
self.assertEqual(30000, server['ssh_port'])
@@ -253,7 +258,12 @@ class KubernetesTestCase(unittest.TestCase):
name = 'rc_name'
service_ports = self.k8s_context._get_service_ports(name)
mock_get_service_by_name.assert_called_once_with(name + '-service')
- self.assertEqual(30000, service_ports[0].node_port)
+ expected = {'node_port': 30000,
+ 'port': constants.SSH_PORT,
+ 'name': 'port_name',
+ 'protocol': 'TCP',
+ 'target_port': constants.SSH_PORT}
+ self.assertEqual(expected, service_ports[0])
@mock.patch.object(k8s_utils, 'get_service_by_name',
return_value=None)
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/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_kubernetes_utils.py b/yardstick/tests/unit/common/test_kubernetes_utils.py
index bdc2c12d5..42aa9f7e0 100644
--- a/yardstick/tests/unit/common/test_kubernetes_utils.py
+++ b/yardstick/tests/unit/common/test_kubernetes_utils.py
@@ -121,6 +121,23 @@ class DeleteCustomResourceDefinitionTestCase(base.BaseUnitTestCase):
mock_delete_crd.delete_custom_resource_definition.\
assert_called_once_with('name', 'del_obj')
+ @mock.patch.object(client, 'V1DeleteOptions', return_value='del_obj')
+ @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api')
+ @mock.patch.object(kubernetes_utils, 'LOG')
+ def test_execute_skip_exception(self, mock_log, mock_get_api, mock_delobj):
+ mock_delete_crd = mock.Mock()
+ mock_delete_crd.delete_custom_resource_definition.side_effect = rest.ApiException(
+ status=404)
+
+ mock_get_api.return_value = mock_delete_crd
+ kubernetes_utils.delete_custom_resource_definition('name', skip_codes=[404])
+
+ mock_delobj.assert_called_once()
+ mock_delete_crd.delete_custom_resource_definition.assert_called_once_with(
+ 'name', 'del_obj')
+
+ mock_log.info.assert_called_once()
+
class GetCustomResourceDefinitionTestCase(base.BaseUnitTestCase):
@@ -250,3 +267,34 @@ class DeletePodTestCase(base.BaseUnitTestCase):
mock_get_api.return_value = mock_api
kubernetes_utils.delete_pod(mock.ANY, skip_codes=[404])
+
+
+class DeleteServiceTestCase(base.BaseUnitTestCase):
+ @mock.patch.object(client, "V1DeleteOptions")
+ @mock.patch.object(kubernetes_utils, 'get_core_api')
+ def test_execute_correct(self, mock_get_api, mock_options):
+ mock_api = mock.Mock()
+ mock_get_api.return_value = mock_api
+ mock_options.return_value = None
+ kubernetes_utils.delete_service("name", "default", None)
+ mock_api.delete_namespaced_service.assert_called_once_with(
+ "name", 'default', None)
+
+ @mock.patch.object(kubernetes_utils, 'get_core_api')
+ def test_execute_exception(self, mock_get_api):
+ mock_api = mock.Mock()
+ mock_api.delete_namespaced_service.side_effect = rest.ApiException(status=200)
+
+ mock_get_api.return_value = mock_api
+ 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_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/libs/ixia_libs/test_ixnet_api.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py
index 541855aa8..afa4cc3dc 100644
--- 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
@@ -28,7 +28,8 @@ TRAFFIC_PARAMETERS = {
'id': 1,
'bidir': 'False',
'duration': 60,
- 'iload': '100',
+ 'rate': 10000.5,
+ 'rate_unit': 'fps',
'outer_l2': {
'framesize': {'64B': '25', '256B': '75'}
},
@@ -65,7 +66,8 @@ TRAFFIC_PARAMETERS = {
'id': 2,
'bidir': 'False',
'duration': 60,
- 'iload': '100',
+ 'rate': 75.2,
+ 'rate_unit': '%',
'outer_l2': {
'framesize': {'128B': '35', '1024B': '65'}
},
@@ -396,6 +398,12 @@ class TestIxNextgen(unittest.TestCase):
self.assertEqual(6, len(ixnet_gen.ixnet.setMultiAttribute.mock_calls))
self.assertEqual(4, len(mock_update_frame.mock_calls))
+ ixnet_gen.ixnet.setMultiAttribute.assert_has_calls(
+ [mock.call('cfg_element/frameRate', '-rate', 10000.5,
+ '-type', 'framesPerSecond'),
+ mock.call('cfg_element/frameRate', '-rate', 75.2, '-type',
+ 'percentLineRate')],
+ any_order=True)
def test_update_frame_flow_not_present(self):
ixnet_gen = ixnet_api.IxNextgen()
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 55276af58..2a366fc94 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_base.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_base.py
@@ -82,7 +82,26 @@ class TrafficProfileConfigTestCase(unittest.TestCase):
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,
+ self.assertEqual(float(base.TrafficProfileConfig.DEFAULT_FRAME_RATE),
tp_config_obj.frame_rate)
self.assertEqual(base.TrafficProfileConfig.DEFAULT_DURATION,
tp_config_obj.duration)
+
+ def test__parse_rate(self):
+ tp_config = {'traffic_profile': {'packet_sizes': {'64B': 100}}}
+ tp_config_obj = base.TrafficProfileConfig(tp_config)
+ self.assertEqual((100.0, 'fps'), tp_config_obj._parse_rate('100 '))
+ self.assertEqual((200.5, 'fps'), tp_config_obj._parse_rate('200.5'))
+ self.assertEqual((300.8, 'fps'), tp_config_obj._parse_rate('300.8fps'))
+ self.assertEqual((400.2, 'fps'),
+ tp_config_obj._parse_rate('400.2 fps'))
+ self.assertEqual((500.3, '%'), tp_config_obj._parse_rate('500.3%'))
+ self.assertEqual((600.1, '%'), tp_config_obj._parse_rate('600.1 %'))
+
+ def test__parse_rate_exception(self):
+ tp_config = {'traffic_profile': {'packet_sizes': {'64B': 100}}}
+ tp_config_obj = base.TrafficProfileConfig(tp_config)
+ with self.assertRaises(exceptions.TrafficProfileRate):
+ tp_config_obj._parse_rate('100Fps')
+ with self.assertRaises(exceptions.TrafficProfileRate):
+ tp_config_obj._parse_rate('100 kbps')
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 3bb8b9192..4ea19a121 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
@@ -554,7 +554,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
self.assertTrue(completed)
self.assertEqual(23.0, samples['TxThroughput'])
self.assertEqual(21.0, samples['RxThroughput'])
- self.assertEqual(0.1, samples['DropPercentage'])
+ self.assertEqual(0.099651, samples['DropPercentage'])
def test_get_drop_percentage_over_drop_percentage(self):
samples = {'iface_name_1':
@@ -571,7 +571,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
self.assertFalse(completed)
self.assertEqual(23.0, samples['TxThroughput'])
self.assertEqual(21.0, samples['RxThroughput'])
- self.assertEqual(0.1, samples['DropPercentage'])
+ self.assertEqual(0.099651, samples['DropPercentage'])
self.assertEqual(rfc2544_profile.rate, rfc2544_profile.max_rate)
def test_get_drop_percentage_under_drop_percentage(self):
@@ -589,7 +589,7 @@ class TestIXIARFC2544Profile(unittest.TestCase):
self.assertFalse(completed)
self.assertEqual(23.0, samples['TxThroughput'])
self.assertEqual(21.0, samples['RxThroughput'])
- self.assertEqual(0.1, samples['DropPercentage'])
+ self.assertEqual(0.099651, samples['DropPercentage'])
self.assertEqual(rfc2544_profile.rate, rfc2544_profile.min_rate)
@mock.patch.object(ixia_rfc2544.LOG, 'info')
@@ -625,5 +625,5 @@ class TestIXIARFC2544Profile(unittest.TestCase):
self.assertTrue(completed)
self.assertEqual(23.0, samples['TxThroughput'])
self.assertEqual(21.0, samples['RxThroughput'])
- self.assertEqual(0.1, samples['DropPercentage'])
+ self.assertEqual(0.099651, samples['DropPercentage'])
self.assertEqual(33.45, rfc2544_profile.rate)
diff --git a/yardstick/tests/unit/orchestrator/test_kubernetes.py b/yardstick/tests/unit/orchestrator/test_kubernetes.py
index 8d351e419..5a6f8c6a0 100644
--- a/yardstick/tests/unit/orchestrator/test_kubernetes.py
+++ b/yardstick/tests/unit/orchestrator/test_kubernetes.py
@@ -300,7 +300,7 @@ class ContainerObjectTestCase(base.BaseUnitTestCase):
'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
args=args)
expected = {'args': args,
- 'command': [kubernetes.ContainerObject.COMMAND_DEFAULT],
+ 'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
'name': 'cname-container',
'volumeMounts': container_obj._create_volume_mounts()}
@@ -314,7 +314,7 @@ class ContainerObjectTestCase(base.BaseUnitTestCase):
'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
args=args, securityContext={'key': 'value'})
expected = {'args': args,
- 'command': [kubernetes.ContainerObject.COMMAND_DEFAULT],
+ 'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
'name': 'cname-container',
'volumeMounts': container_obj._create_volume_mounts(),
@@ -330,7 +330,7 @@ class ContainerObjectTestCase(base.BaseUnitTestCase):
args=args, env=[{'name': 'fake_var_name',
'value': 'fake_var_value'}])
expected = {'args': args,
- 'command': [kubernetes.ContainerObject.COMMAND_DEFAULT],
+ 'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
'name': 'cname-container',
'volumeMounts': container_obj._create_volume_mounts(),
@@ -351,8 +351,7 @@ class ContainerObjectTestCase(base.BaseUnitTestCase):
'invalid_varible': 'fakeinvalid_varible',
'hostIP': 'fake_port_number'}])
expected = {'args': args,
- 'command': [
- kubernetes.ContainerObject.COMMAND_DEFAULT],
+ 'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
'name': 'cname-container',
'volumeMounts': container_obj._create_volume_mounts(),
@@ -387,7 +386,7 @@ class ContainerObjectTestCase(base.BaseUnitTestCase):
'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount],
args=args, resources=resources)
expected = {'args': args,
- 'command': [kubernetes.ContainerObject.COMMAND_DEFAULT],
+ 'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
'name': 'cname-container',
'volumeMounts': container_obj._create_volume_mounts(),
@@ -395,6 +394,45 @@ class ContainerObjectTestCase(base.BaseUnitTestCase):
'limits': {'key2': 'val2'}}}
self.assertEqual(expected, container_obj.get_container_item())
+ def test_get_container_item_image_pull_policy(self):
+ container_obj = kubernetes.ContainerObject(
+ 'cname', ssh_key='fake_sshkey', imagePullPolicy='Always')
+ expected = {'args': [],
+ 'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
+ 'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
+ 'name': 'cname-container',
+ 'volumeMounts': container_obj._create_volume_mounts(),
+ 'imagePullPolicy':'Always'}
+ self.assertEqual(expected, container_obj.get_container_item())
+
+ def test_get_container_item_with_tty_stdin(self):
+ args = ['arg1', 'arg2']
+ container_obj = kubernetes.ContainerObject(
+ 'cname', 'fake_sshkey', args=args, tty=False, stdin=True)
+ expected = {'args': args,
+ 'command': kubernetes.ContainerObject.COMMAND_DEFAULT,
+ 'image': kubernetes.ContainerObject.IMAGE_DEFAULT,
+ 'name': 'cname-container',
+ 'volumeMounts': container_obj._create_volume_mounts(),
+ 'tty': False,
+ 'stdin': True}
+ self.assertEqual(expected, container_obj.get_container_item())
+
+ def test__parse_commands_string(self):
+ container_obj = kubernetes.ContainerObject('cname', 'fake_sshkey')
+ self.assertEqual(['fake command'],
+ container_obj._parse_commands('fake command'))
+
+ def test__parse_commands_list(self):
+ container_obj = kubernetes.ContainerObject('cname', 'fake_sshkey')
+ self.assertEqual(['cmd1', 'cmd2'],
+ container_obj._parse_commands(['cmd1', 'cmd2']))
+
+ def test__parse_commands_exception(self):
+ container_obj = kubernetes.ContainerObject('cname', 'fake_sshkey')
+ with self.assertRaises(exceptions.KubernetesContainerCommandType):
+ container_obj._parse_commands({})
+
class CustomResourceDefinitionObjectTestCase(base.BaseUnitTestCase):
@@ -513,24 +551,52 @@ class ServiceNodePortObjectTestCase(base.BaseUnitTestCase):
def test__init(self):
with mock.patch.object(kubernetes.ServiceNodePortObject, '_add_port') \
as mock_add_port:
- kubernetes.ServiceNodePortObject('fake_name',
- node_ports=[{'port': 80}])
+ kubernetes.ServiceNodePortObject(
+ 'fake_name', node_ports=[{'port': 80, 'name': 'web'}])
+
+ mock_add_port.assert_has_calls([mock.call(22, 'ssh', protocol='TCP'),
+ mock.call(80, 'web')])
- mock_add_port.assert_has_calls([mock.call(22, protocol='TCP'),
- mock.call(80)])
+ @mock.patch.object(kubernetes.ServiceNodePortObject, '_add_port')
+ def test__init_missing_mandatory_parameters(self, *args):
+ with self.assertRaises(
+ exceptions.KubernetesServiceObjectDefinitionError):
+ kubernetes.ServiceNodePortObject(
+ 'fake_name', node_ports=[{'port': 80}])
+ with self.assertRaises(
+ exceptions.KubernetesServiceObjectDefinitionError):
+ kubernetes.ServiceNodePortObject(
+ 'fake_name', node_ports=[{'name': 'web'}])
+
+ @mock.patch.object(kubernetes.ServiceNodePortObject, '_add_port')
+ def test__init_missing_bad_name(self, *args):
+ with self.assertRaises(
+ exceptions.KubernetesServiceObjectNameError):
+ kubernetes.ServiceNodePortObject(
+ 'fake_name', node_ports=[{'port': 80, 'name': '-web'}])
+ with self.assertRaises(
+ exceptions.KubernetesServiceObjectNameError):
+ kubernetes.ServiceNodePortObject(
+ 'fake_name', node_ports=[{'port': 80, 'name': 'Web'}])
+ with self.assertRaises(
+ exceptions.KubernetesServiceObjectNameError):
+ kubernetes.ServiceNodePortObject(
+ 'fake_name', node_ports=[{'port': 80, 'name': 'web-'}])
def test__add_port(self):
nodeport_object = kubernetes.ServiceNodePortObject('fake_name')
- port_ssh = {'port': 22,
- 'protocol': 'TCP',}
+ port_ssh = {'name': 'ssh',
+ 'port': 22,
+ 'protocol': 'TCP'}
port_definition = {'port': 80,
'protocol': 'TCP',
'name': 'web',
'targetPort': 10080,
'nodePort': 30080}
port = copy.deepcopy(port_definition)
- port.pop('port')
- nodeport_object._add_port(80, **port)
+ _port = port.pop('port')
+ name = port.pop('name')
+ nodeport_object._add_port(_port, name, **port)
self.assertEqual([port_ssh, port_definition],
nodeport_object.template['spec']['ports'])
@@ -545,7 +611,8 @@ class ServiceNodePortObjectTestCase(base.BaseUnitTestCase):
def test_delete(self, mock_delete_service):
nodeport_object = kubernetes.ServiceNodePortObject('fake_name')
nodeport_object.delete()
- mock_delete_service.assert_called_once_with('fake_name-service')
+ mock_delete_service.assert_called_once_with('fake_name-service',
+ skip_codes=[404])
class KubernetesTemplate(base.BaseUnitTestCase):