diff options
27 files changed, 589 insertions, 325 deletions
@@ -22,6 +22,7 @@ ross.b.brattain@intel.com chenjiankun1@huawei.com rodolfo.alonso.hernandez@intel.com emma.l.foley@intel.com +abhijit.sinha@intel.com Link to TSC approval: http://meetbot.opnfv.org/meetings/ Link to approval of additional submitters: @@ -74,6 +74,10 @@ committers: email: '14_ykl@tongji.edu.cn' company: 'tongji.edu.cn' id: 'tjuyinkanglin' + - name: 'Abhijit Sinha' + email: 'abhijit.sinha@intel.com' + company: 'intel.com' + id: 'abhijitsinha' tsc: # yamllint disable rule:line-length approval: 'http//meetbot.opnfv.org/meetings/' diff --git a/ansible/roles/infra_destroy_previous_configuration/tasks/delete_vm.yml b/ansible/roles/infra_destroy_previous_configuration/tasks/delete_vm.yml new file mode 100644 index 000000000..5e43ee81e --- /dev/null +++ b/ansible/roles/infra_destroy_previous_configuration/tasks/delete_vm.yml @@ -0,0 +1,29 @@ +# Copyright (c) 2017-2018 Intel Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +--- +# Ignore errors as VM can be destroyed without been undefined. +- name: Destroy old VMs + virt: + command: destroy + name: "{{ node_item.hostname }}" + when: node_item.hostname in virt_vms.list_vms + ignore_errors: yes + +# Ignore errors as VM can be running while undefined +- name: Undefine old VMs + virt: + command: undefine + name: "{{ node_item.hostname }}" + when: node_item.hostname in virt_vms.list_vms + ignore_errors: yes diff --git a/ansible/roles/infra_destroy_previous_configuration/tasks/main.yml b/ansible/roles/infra_destroy_previous_configuration/tasks/main.yml index 5595cd501..e6c2c0229 100644 --- a/ansible/roles/infra_destroy_previous_configuration/tasks/main.yml +++ b/ansible/roles/infra_destroy_previous_configuration/tasks/main.yml @@ -26,17 +26,10 @@ register: virt_vms - name: Destroy old VMs - virt: - command: destroy - name: "{{ item.hostname }}" - when: item.hostname in virt_vms.list_vms - with_items: "{{ infra_deploy_vars.nodes }}" - -- name: Undefine old VMs - virt: - command: undefine - name: "{{ item.hostname }}" - when: item.hostname in virt_vms.list_vms + include_tasks: delete_vm.yml + extra_vars: "{{ virt_vms }}" + loop_control: + loop_var: node_item with_items: "{{ infra_deploy_vars.nodes }}" - name: Delete old networks diff --git a/docker/Dockerfile b/docker/Dockerfile index ddd8dfaf8..46e52d557 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -26,7 +26,7 @@ ENV YARDSTICK_REPO_DIR="${REPOS_DIR}/yardstick" \ RUN apt-get update && apt-get install -y git python-setuptools python-pip && apt-get -y autoremove && apt-get clean RUN easy_install -U setuptools==30.0.0 -RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 python-openstackclient==3.11.0 +RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 python-openstackclient==3.11.0 python-heatclient==1.11.0 RUN mkdir -p ${REPOS_DIR} diff --git a/docker/Dockerfile.aarch64.patch b/docker/Dockerfile.aarch64.patch index ca933514a..24e3952fb 100644 --- a/docker/Dockerfile.aarch64.patch +++ b/docker/Dockerfile.aarch64.patch @@ -39,7 +39,7 @@ index 2ee5b4c..23e5ea5 100644 +RUN apt-get update && apt-get install -y git python-setuptools python-pip && apt-get -y autoremove && \ + apt-get install -y libssl-dev && apt-get -y install libffi-dev && apt-get clean RUN easy_install -U setuptools==30.0.0 - RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 + RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 python-openstackclient==3.11.0 @@ -43,8 +44,8 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf diff --git a/nsb_setup.sh b/nsb_setup.sh index 4a8e4db93..50fc017d1 100755 --- a/nsb_setup.sh +++ b/nsb_setup.sh @@ -63,7 +63,7 @@ for i in "${pkg[@]}"; do fi done -pip install ansible==2.3.2 shade==1.17.0 docker-py==1.10.6 +pip install ansible==2.4.2 shade==1.22.2 docker-py==1.10.6 ANSIBLE_SCRIPTS="ansible" diff --git a/samples/storage_bottlenecks.yaml b/samples/storage_bottlenecks.yaml new file mode 100644 index 000000000..1aa0d7e35 --- /dev/null +++ b/samples/storage_bottlenecks.yaml @@ -0,0 +1,77 @@ +############################################################################## +# 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 +############################################################################## +--- +# Sample benchmark task config file +# measure storage performance using fio +# +# For this sample just like running the command below on the test vm and +# getting benchmark info back to the yardstick. +# +# sudo fio -filename=/home/ubuntu/data.raw -bs=4k -ipdepth=1 -rw=rw \ +# -ramp_time=10 -runtime=60 -name=yardstick-fio -ioengine=libaio \ +# -direct=1 -group_reporting -numjobs=1 -time_based \ +# --output-format=json + +schema: "yardstick:task:0.1" +run_in_parallel: true + +{% set directory = directory or '/FIO_Test' %} +{% set stack_num = stack_num or 1 %} +{% set volume_num = volume_num or "1" %} +{% set rw = rw or "randrw" %} +{% set bs = bs or "4k" %} +{% set size = size or "30g" %} +{% set rwmixwrite = rwmixwrite or "50" %} +{% set numjobs = numjobs or "1" %} +{% set direct = direct or "1" %} +{% set volume_size = volume_size or 50 %} + +scenarios: +{% for num in range(stack_num) %} +- + type: Fio + options: + filename: {{ directory }}/test + directory: {{ directory }} + bs: {{bs}} + rw: {{rw}} + size: {{size}} + rwmixwrite: {{rwmixwrite}} + numjobs: {{numjobs}} + direct: {{direct}} + ramp_time: 10 + + host: demo.storage_bottlenecks-{{num}}-{{volume_num}} + + runner: + type: Duration + duration: 60 + interval: 1 +{% endfor %} + +contexts: +{% for context_num in range(stack_num) %} +- + name: storage_bottlenecks-{{context_num}}-{{volume_num}} + image: yardstick-image + flavor: yardstick-flavor + user: ubuntu + + servers: + demo: + volume: + size: {{volume_size}} + volume_mountpoint: "/dev/vdb" + floating_ip: true + + networks: + test: + cidr: "10.0.1.0/24" + port_security_enabled: true +{% endfor %}
\ No newline at end of file diff --git a/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex.yaml b/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex.yaml index 13fe5a5a5..2e096a126 100644 --- a/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex.yaml +++ b/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex.yaml @@ -15,6 +15,7 @@ --- {% set provider = provider or none %} {% set physical_networks = physical_networks or ['physnet1', 'physnet2'] %} +{% set segmentation_id = segmentation_id or none %} schema: yardstick:task:0.1 scenarios: @@ -74,6 +75,9 @@ context: {% if provider %} provider: {{ provider }} physical_network: {{ physical_networks[0] }} + {% if segmentation_id %} + segmentation_id: {{ segmentation_id }} + {% endif %} {% endif %} port_security_enabled: False enable_dhcp: 'false' @@ -83,6 +87,9 @@ context: {% if provider %} provider: {{ provider }} physical_network: {{ physical_networks[1] }} + {% if segmentation_id %} + segmentation_id: {{ segmentation_id }} + {% endif %} {% endif %} port_security_enabled: False enable_dhcp: 'false' diff --git a/tests/unit/network_services/traffic_profile/test_traffic_profile.py b/tests/unit/network_services/traffic_profile/test_traffic_profile.py index 0bb0a88a6..37b9a08d0 100644 --- a/tests/unit/network_services/traffic_profile/test_traffic_profile.py +++ b/tests/unit/network_services/traffic_profile/test_traffic_profile.py @@ -13,14 +13,15 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# -from __future__ import absolute_import +import ipaddress -import unittest import mock +import six +import unittest from tests.unit import STL_MOCKS +from yardstick.common import exceptions as y_exc STLClient = mock.MagicMock() stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) @@ -215,11 +216,27 @@ class TestTrexProfile(unittest.TestCase): TrexProfile(TrafficProfile) self.assertEqual({}, trex_profile.generate_imix_data(False)) - def test__get_start_end_ipv6(self): - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertRaises(SystemExit, trex_profile._get_start_end_ipv6, - "1.1.1.3", "1.1.1.1") + def test__count_ip_ipv4(self): + start, end, count = TrexProfile._count_ip('1.1.1.1', '1.2.3.4') + self.assertEqual('1.1.1.1', str(start)) + self.assertEqual('1.2.3.4', str(end)) + diff = (int(ipaddress.IPv4Address(six.u('1.2.3.4'))) - + int(ipaddress.IPv4Address(six.u('1.1.1.1')))) + self.assertEqual(diff, count) + + def test__count_ip_ipv6(self): + start_ip = '0064:ff9b:0:0:0:0:9810:6414' + end_ip = '0064:ff9b:0:0:0:0:9810:6420' + start, end, count = TrexProfile._count_ip(start_ip, end_ip) + self.assertEqual(0x98106414, start) + self.assertEqual(0x98106420, end) + self.assertEqual(0x98106420 - 0x98106414, count) + + def test__count_ip_ipv6_exception(self): + start_ip = '0064:ff9b:0:0:0:0:9810:6420' + end_ip = '0064:ff9b:0:0:0:0:9810:6414' + with self.assertRaises(y_exc.IPv6RangeError): + TrexProfile._count_ip(start_ip, end_ip) def test__dscp_range_action_partial_actual_count_zero(self): traffic_profile = TrexProfile(TrafficProfile) @@ -258,13 +275,17 @@ class TestTrexProfile(unittest.TestCase): def test__general_single_action_partial(self): trex_profile = TrexProfile(TrafficProfile) - trex_profile._general_single_action_partial(ETHERNET)(SRC)(self.EXAMPLE_ETHERNET_ADDR) - self.assertEqual(self.EXAMPLE_ETHERNET_ADDR, trex_profile.ether_packet.src) + trex_profile._general_single_action_partial(ETHERNET)(SRC)( + self.EXAMPLE_ETHERNET_ADDR) + self.assertEqual(self.EXAMPLE_ETHERNET_ADDR, + trex_profile.ether_packet.src) - trex_profile._general_single_action_partial(IP)(DST)(self.EXAMPLE_IP_ADDR) + trex_profile._general_single_action_partial(IP)(DST)( + self.EXAMPLE_IP_ADDR) self.assertEqual(self.EXAMPLE_IP_ADDR, trex_profile.ip_packet.dst) - trex_profile._general_single_action_partial(IPv6)(DST)(self.EXAMPLE_IPv6_ADDR) + trex_profile._general_single_action_partial(IPv6)(DST)( + self.EXAMPLE_IPv6_ADDR) self.assertEqual(self.EXAMPLE_IPv6_ADDR, trex_profile.ip6_packet.dst) trex_profile._general_single_action_partial(UDP)(SRC_PORT)(5060) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py index af941c04f..25633384e 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py @@ -624,37 +624,34 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): self.assertIsInstance(dpdk_vnf_setup_env_helper.setup_vnf_environment(), ResourceProfile) - def test__setup_dpdk_early_success(self): - vnfd_helper = VnfdHelper(self.VNFD_0) + def test__setup_dpdk(self): ssh_helper = mock.Mock() - ssh_helper.execute.return_value = 0, 'output', '' - ssh_helper.join_bin_path.return_value = 'joined_path' - ssh_helper.provision_tool.return_value = 'provision string' - scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - dpdk_setup_helper._setup_hugepages = mock.Mock() - - self.assertIsNone(dpdk_setup_helper._setup_dpdk()) - self.assertEqual(dpdk_setup_helper.ssh_helper.execute.call_count, 2) - - @mock.patch('yardstick.ssh.SSH') - def test__setup_dpdk_short(self, _): - def execute_side(cmd): - if 'joined_path' in cmd: - return 0, 'output', '' - return 1, 'bad output', 'error output' + ssh_helper.execute = mock.Mock() + ssh_helper.execute.return_value = (0, 0, 0) + dpdk_setup_helper = DpdkVnfSetupEnvHelper(mock.ANY, ssh_helper, mock.ANY) + with mock.patch.object(dpdk_setup_helper, '_setup_hugepages') as \ + mock_setup_hp: + dpdk_setup_helper._setup_dpdk() + mock_setup_hp.assert_called_once() + ssh_helper.execute.assert_has_calls([ + mock.call('sudo modprobe uio && sudo modprobe igb_uio'), + mock.call('lsmod | grep -i igb_uio') + ]) - vnfd_helper = VnfdHelper(self.VNFD_0) + def test__setup_dpdk_igb_uio_not_loaded(self): ssh_helper = mock.Mock() - ssh_helper.execute.side_effect = execute_side - ssh_helper.join_bin_path.return_value = 'joined_path' - ssh_helper.provision_tool.return_value = 'provision string' - scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - dpdk_setup_helper._setup_hugepages = mock.Mock() - - self.assertIsNone(dpdk_setup_helper._setup_dpdk()) - self.assertEqual(dpdk_setup_helper.ssh_helper.execute.call_count, 3) + ssh_helper.execute = mock.Mock() + ssh_helper.execute.side_effect = [(0, 0, 0), (1, 0, 0)] + dpdk_setup_helper = DpdkVnfSetupEnvHelper(mock.ANY, ssh_helper, mock.ANY) + with mock.patch.object(dpdk_setup_helper, '_setup_hugepages') as \ + mock_setup_hp: + with self.assertRaises(y_exceptions.DPDKSetupDriverError): + dpdk_setup_helper._setup_dpdk() + mock_setup_hp.assert_called_once() + ssh_helper.execute.assert_has_calls([ + mock.call('sudo modprobe uio && sudo modprobe igb_uio'), + mock.call('lsmod | grep -i igb_uio') + ]) @mock.patch('yardstick.ssh.SSH') def test__setup_resources(self, _): diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index 4ba543b9e..7b7f1be32 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -95,13 +95,15 @@ class HeatContext(Context): return sorted_networks def init(self, attrs): - self.check_environment() """initializes itself from the supplied arguments""" + self.check_environment() self.name = attrs["name"] self._user = attrs.get("user") self.template_file = attrs.get("heat_template") + + self.heat_timeout = attrs.get("timeout", DEFAULT_HEAT_TIMEOUT) if self.template_file: self.heat_parameters = attrs.get("heat_parameters") return @@ -113,8 +115,6 @@ class HeatContext(Context): self._flavor = attrs.get("flavor") - self.heat_timeout = attrs.get("timeout", DEFAULT_HEAT_TIMEOUT) - self.placement_groups = [PlacementGroup(name, self, pg_attrs["policy"]) for name, pg_attrs in attrs.get( "placement_groups", {}).items()] diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py index 9b1b3f851..5fcc9182c 100644 --- a/yardstick/benchmark/core/task.py +++ b/yardstick/benchmark/core/task.py @@ -57,7 +57,7 @@ class Task(object): # pragma: no cover out_types = [s.strip() for s in dispatchers.split(',')] output_config['DEFAULT']['dispatcher'] = out_types - def start(self, args, **kwargs): + def start(self, args): """Start a benchmark scenario.""" atexit.register(self.atexit_handler) @@ -69,7 +69,7 @@ class Task(object): # pragma: no cover try: output_config = utils.parse_ini_file(CONF_FILE) - except Exception: + except Exception: # pylint: disable=broad-except # all error will be ignore, the default value is {} output_config = {} @@ -123,7 +123,7 @@ class Task(object): # pragma: no cover data = self._run(scenarios, run_in_parallel, args.output_file) except KeyboardInterrupt: raise - except Exception: + except Exception: # pylint: disable=broad-except LOG.error('Testcase: "%s" FAILED!!!', case_name, exc_info=True) testcases[case_name] = {'criteria': 'FAIL', 'tc_data': []} else: diff --git a/yardstick/benchmark/scenarios/lib/delete_network.py b/yardstick/benchmark/scenarios/lib/delete_network.py index e8796bf82..2e8b595f9 100644 --- a/yardstick/benchmark/scenarios/lib/delete_network.py +++ b/yardstick/benchmark/scenarios/lib/delete_network.py @@ -7,14 +7,12 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import print_function -from __future__ import absolute_import - import logging from yardstick.benchmark.scenarios import base import yardstick.common.openstack_utils as op_utils + LOG = logging.getLogger(__name__) @@ -30,7 +28,7 @@ class DeleteNetwork(base.Scenario): self.network_id = self.options.get("network_id", None) - self.neutron_client = op_utils.get_neutron_client() + self.shade_client = op_utils.get_shade_client() self.setup_done = False @@ -45,7 +43,7 @@ class DeleteNetwork(base.Scenario): if not self.setup_done: self.setup() - status = op_utils.delete_neutron_net(self.neutron_client, + status = op_utils.delete_neutron_net(self.shade_client, network_id=self.network_id) if status: result.update({"delete_network": 1}) @@ -53,3 +51,4 @@ class DeleteNetwork(base.Scenario): else: result.update({"delete_network": 0}) LOG.error("Delete network failed!") + return status diff --git a/yardstick/common/ansible_common.py b/yardstick/common/ansible_common.py index 9a4426bf9..be262c215 100644 --- a/yardstick/common/ansible_common.py +++ b/yardstick/common/ansible_common.py @@ -33,7 +33,7 @@ from six import StringIO from chainmap import ChainMap from yardstick.common.utils import Timer - +from yardstick.common import constants as consts cgitb.enable(format="text") @@ -435,6 +435,7 @@ class AnsibleCommon(object): ansible_dict = dict(os.environ, **{ "ANSIBLE_LOG_PATH": os.path.join(directory, log_file), "ANSIBLE_LOG_BASE": directory, + "ANSIBLE_ROLES_PATH": consts.ANSIBLE_ROLES_PATH, # # required for SSH to work # "ANSIBLE_SSH_ARGS": "-o UserKnownHostsFile=/dev/null " # "-o GSSAPIAuthentication=no " @@ -516,7 +517,7 @@ class AnsibleCommon(object): # playbook dir: use include to point to files in consts.ANSIBLE_DIR if not os.path.isdir(directory): - raise OSError("Not a directory, %s", directory) + raise OSError("Not a directory, %s" % directory) timeout = self.get_timeout(timeout, self.default_timeout) self.counter += 1 diff --git a/yardstick/common/constants.py b/yardstick/common/constants.py index 646a1f2ca..43c2c19cb 100644 --- a/yardstick/common/constants.py +++ b/yardstick/common/constants.py @@ -83,6 +83,7 @@ YARDSTICK_ROOT_PATH = dirname( TASK_LOG_DIR = get_param('dir.tasklog', '/var/log/yardstick/') CONF_SAMPLE_DIR = join(REPOS_DIR, 'etc/yardstick/') ANSIBLE_DIR = join(REPOS_DIR, 'ansible') +ANSIBLE_ROLES_PATH = join(REPOS_DIR, 'ansible/roles/') SAMPLE_CASE_DIR = join(REPOS_DIR, 'samples') TESTCASE_DIR = join(YARDSTICK_ROOT_PATH, 'tests/opnfv/test_cases/') TESTSUITE_DIR = join(YARDSTICK_ROOT_PATH, 'tests/opnfv/test_suites/') diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index e38dd246c..3e0635e46 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -63,3 +63,10 @@ class HeatTemplateError(YardstickException): """Error in Heat during the stack deployment""" message = ('Error in Heat during the creation of the OpenStack stack ' '"%(stack_name)"') + + +class IPv6RangeError(YardstickException): + message = 'Start IP "%(start_ip)s" is greater than end IP "%(end_ip)s"' + +class DPDKSetupDriverError(YardstickException): + message = '"igb_uio" driver is not loaded' diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py index c5b17c270..8f666e268 100644 --- a/yardstick/common/openstack_utils.py +++ b/yardstick/common/openstack_utils.py @@ -15,6 +15,7 @@ import logging from keystoneauth1 import loading from keystoneauth1 import session import shade +from shade import exc from cinderclient import client as cinderclient from novaclient import client as novaclient @@ -174,6 +175,7 @@ def get_glance_client(): # pragma: no cover def get_shade_client(): return shade.openstack_cloud() + # ********************************************* # NOVA # ********************************************* @@ -272,7 +274,8 @@ def create_aggregate_with_host(nova_client, aggregate_name, av_zone, def create_keypair(name, key_path=None): # pragma: no cover try: with open(key_path) as fpubkey: - keypair = get_nova_client().keypairs.create(name=name, public_key=fpubkey.read()) + keypair = get_nova_client().keypairs.create( + name=name, public_key=fpubkey.read()) return keypair except Exception: # pylint: disable=broad-except log.exception("Error [create_keypair(nova_client)]") @@ -304,9 +307,11 @@ def create_instance_and_wait_for_active(json_body): # pragma: no cover return None -def attach_server_volume(server_id, volume_id, device=None): # pragma: no cover +def attach_server_volume(server_id, volume_id, + device=None): # pragma: no cover try: - get_nova_client().volumes.create_server_volume(server_id, volume_id, device) + get_nova_client().volumes.create_server_volume(server_id, + volume_id, device) except Exception: # pylint: disable=broad-except log.exception("Error [attach_server_volume(nova_client, '%s', '%s')]", server_id, volume_id) @@ -370,7 +375,8 @@ def get_server_by_name(name): # pragma: no cover def create_flavor(name, ram, vcpus, disk, **kwargs): # pragma: no cover try: - return get_nova_client().flavors.create(name, ram, vcpus, disk, **kwargs) + return get_nova_client().flavors.create(name, ram, vcpus, + disk, **kwargs) except Exception: # pylint: disable=broad-except log.exception("Error [create_flavor(nova_client, %s, %s, %s, %s, %s)]", name, ram, disk, vcpus, kwargs['is_public']) @@ -455,13 +461,11 @@ def create_neutron_net(neutron_client, json_body): # pragma: no cover raise Exception("operation error") -def delete_neutron_net(neutron_client, network_id): # pragma: no cover +def delete_neutron_net(shade_client, network_id): try: - neutron_client.delete_network(network_id) - return True - except Exception: # pylint: disable=broad-except - log.error("Error [delete_neutron_net(neutron_client, '%s')]", - network_id) + return shade_client.delete_network(network_id) + except exc.OpenStackCloudException: + log.error("Error [delete_neutron_net(shade_client, '%s')]", network_id) return False @@ -558,7 +562,8 @@ def get_security_group_id(neutron_client, sg_name): # pragma: no cover return id -def create_security_group(neutron_client, sg_name, sg_description): # pragma: no cover +def create_security_group(neutron_client, sg_name, + sg_description): # pragma: no cover json_body = {'security_group': {'name': sg_name, 'description': sg_description}} try: @@ -611,8 +616,8 @@ def create_secgroup_rule(neutron_client, sg_id, direction, protocol, return False -def create_security_group_full(neutron_client, - sg_name, sg_description): # pragma: no cover +def create_security_group_full(neutron_client, sg_name, + sg_description): # pragma: no cover sg_id = get_security_group_id(neutron_client, sg_name) if sg_id != '': log.info("Using existing security group '%s'...", sg_name) @@ -670,22 +675,18 @@ def create_image(glance_client, image_name, file_path, disk_format, else: log.info("Creating image '%s' from '%s'...", image_name, file_path) - image = glance_client.images.create(name=image_name, - visibility=public, - disk_format=disk_format, - container_format=container_format, - min_disk=min_disk, - min_ram=min_ram, - tags=tag, - protected=protected, - **kwargs) + image = glance_client.images.create( + name=image_name, visibility=public, disk_format=disk_format, + container_format=container_format, min_disk=min_disk, + min_ram=min_ram, tags=tag, protected=protected, **kwargs) image_id = image.id with open(file_path) as image_data: glance_client.images.upload(image_id, image_data) return image_id except Exception: # pylint: disable=broad-except - log.error("Error [create_glance_image(glance_client, '%s', '%s', '%s')]", - image_name, file_path, public) + log.error( + "Error [create_glance_image(glance_client, '%s', '%s', '%s')]", + image_name, file_path, public) return None @@ -725,7 +726,8 @@ def create_volume(cinder_client, volume_name, volume_size, return None -def delete_volume(cinder_client, volume_id, forced=False): # pragma: no cover +def delete_volume(cinder_client, volume_id, + forced=False): # pragma: no cover try: if forced: try: diff --git a/yardstick/network_services/traffic_profile/traffic_profile.py b/yardstick/network_services/traffic_profile/traffic_profile.py index 3b19ff9be..8cde5e4a7 100644 --- a/yardstick/network_services/traffic_profile/traffic_profile.py +++ b/yardstick/network_services/traffic_profile/traffic_profile.py @@ -11,16 +11,16 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -""" Trex Traffic Profile definitions """ -from __future__ import absolute_import import struct import socket import logging from random import SystemRandom -import six import ipaddress +import six + +from yardstick.common import exceptions as y_exc from yardstick.network_services.traffic_profile.base import TrafficProfile from trex_stl_lib.trex_stl_client import STLStream from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats @@ -78,31 +78,32 @@ class TrexProfile(TrafficProfile): op='inc', step=1) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='mac_{}'.format(direction), - pkt_offset='Ether.{}'.format(direction)) + stl_vm_wr_flow_var = STLVmWrFlowVar( + fv_name='mac_{}'.format(direction), + pkt_offset='Ether.{}'.format(direction)) self.vm_flow_vars.append(stl_vm_wr_flow_var) return partial def _ip_range_action_partial(self, direction, count=1): # pylint: disable=unused-argument def partial(min_value, max_value, count): - ip1 = int(ipaddress.IPv4Address(min_value)) - ip2 = int(ipaddress.IPv4Address(max_value)) - actual_count = (ip2 - ip1) + _, _, actual_count = self._count_ip(min_value, max_value) if not actual_count: count = 1 elif actual_count < int(count): count = actual_count - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="ip4_{}".format(direction), - min_value=min_value, - max_value=max_value, - size=4, - limit=int(count), - seed=0x1235) + stl_vm_flow_var = STLVmFlowVarRepeatableRandom( + name="ip4_{}".format(direction), + min_value=min_value, + max_value=max_value, + size=4, + limit=int(count), + seed=0x1235) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip4_{}'.format(direction), - pkt_offset='IP.{}'.format(direction)) + stl_vm_wr_flow_var = STLVmWrFlowVar( + fv_name='ip4_{}'.format(direction), + pkt_offset='IP.{}'.format(direction)) self.vm_flow_vars.append(stl_vm_wr_flow_var) stl_vm_fix_ipv4 = STLVmFixIpv4(offset="IP") self.vm_flow_vars.append(stl_vm_fix_ipv4) @@ -111,7 +112,7 @@ class TrexProfile(TrafficProfile): def _ip6_range_action_partial(self, direction, _): def partial(min_value, max_value, count): # pylint: disable=unused-argument - min_value, max_value = self._get_start_end_ipv6(min_value, max_value) + min_value, max_value, _ = self._count_ip(min_value, max_value) stl_vm_flow_var = STLVmFlowVar(name="ip6_{}".format(direction), min_value=min_value, max_value=max_value, @@ -119,9 +120,10 @@ class TrexProfile(TrafficProfile): op='random', step=1) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip6_{}'.format(direction), - pkt_offset='IPv6.{}'.format(direction), - offset_fixup=8) + stl_vm_wr_flow_var = STLVmWrFlowVar( + fv_name='ip6_{}'.format(direction), + pkt_offset='IPv6.{}'.format(direction), + offset_fixup=8) self.vm_flow_vars.append(stl_vm_wr_flow_var) return partial @@ -149,15 +151,17 @@ class TrexProfile(TrafficProfile): elif int(count) > actual_count: count = actual_count - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="port_{}".format(field), - min_value=min_value, - max_value=max_value, - size=2, - limit=int(count), - seed=0x1235) + stl_vm_flow_var = STLVmFlowVarRepeatableRandom( + name="port_{}".format(field), + min_value=min_value, + max_value=max_value, + size=2, + limit=int(count), + seed=0x1235) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='port_{}'.format(field), - pkt_offset=self.udp[field]) + stl_vm_wr_flow_var = STLVmWrFlowVar( + fv_name='port_{}'.format(field), + pkt_offset=self.udp[field]) self.vm_flow_vars.append(stl_vm_wr_flow_var) return partial @@ -448,20 +452,18 @@ class TrexProfile(TrafficProfile): self.profile = STLProfile(self.streams) @classmethod - def _get_start_end_ipv6(cls, start_ip, end_ip): - try: - ip1 = socket.inet_pton(socket.AF_INET6, start_ip) - ip2 = socket.inet_pton(socket.AF_INET6, end_ip) - hi1, lo1 = struct.unpack('!QQ', ip1) - hi2, lo2 = struct.unpack('!QQ', ip2) - if ((hi1 << 64) | lo1) > ((hi2 << 64) | lo2): - raise SystemExit("IPv6: start_ip is greater then end_ip") - max_p1 = abs(int(lo1) - int(lo2)) - base_p1 = lo1 - except Exception as ex_error: - raise SystemExit(ex_error) - else: - return base_p1, max_p1 + base_p1 + def _count_ip(cls, start_ip, end_ip): + start = ipaddress.ip_address(six.u(start_ip)) + end = ipaddress.ip_address(six.u(end_ip)) + if start.version == 4: + return start, end, int(end) - int(start) + elif start.version == 6: + if int(start) > int(end): + raise y_exc.IPv6RangeError(start_ip=str(start), + end_ip=str(end)) + _, lo1 = struct.unpack('!QQ', start.packed) + _, lo2 = struct.unpack('!QQ', end.packed) + return lo1, lo2, lo2 - lo1 @classmethod def _get_random_value(cls, min_port, max_port): diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py index fbaaa0ca8..d57d7e601 100644 --- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py @@ -250,20 +250,12 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): self.ssh_helper.execute("sudo killall %s" % self.APP_NAME) def _setup_dpdk(self): - """ setup dpdk environment needed for vnf to run """ - + """Setup DPDK environment needed for VNF to run""" self._setup_hugepages() - self.ssh_helper.execute("sudo modprobe uio && sudo modprobe igb_uio") - - exit_status = self.ssh_helper.execute("lsmod | grep -i igb_uio")[0] - if exit_status == 0: - return - - dpdk = self.ssh_helper.join_bin_path(DPDK_VERSION) - dpdk_setup = self.ssh_helper.provision_tool(tool_file="nsb_setup.sh") - exit_status = self.ssh_helper.execute("which {} >/dev/null 2>&1".format(dpdk))[0] - if exit_status != 0: - self.ssh_helper.execute("bash %s dpdk >/dev/null 2>&1" % dpdk_setup) + self.ssh_helper.execute('sudo modprobe uio && sudo modprobe igb_uio') + exit_status = self.ssh_helper.execute('lsmod | grep -i igb_uio')[0] + if exit_status: + raise y_exceptions.DPDKSetupDriverError() def get_collectd_options(self): options = self.scenario_helper.all_options.get("collectd", {}) diff --git a/yardstick/orchestrator/heat.py b/yardstick/orchestrator/heat.py index 754482e4f..558b5d2a6 100644 --- a/yardstick/orchestrator/heat.py +++ b/yardstick/orchestrator/heat.py @@ -74,7 +74,14 @@ class HeatStack(object): if self.uuid is None: return - ret = self._cloud.delete_stack(self.uuid, wait=wait) + try: + ret = self._cloud.delete_stack(self.uuid, wait=wait) + except TypeError: + # NOTE(ralonsoh): this exception catch solves a bug in Shade, which + # tries to retrieve and read the stack status when it's already + # deleted. + ret = True + _DEPLOYED_STACKS.pop(self.uuid) self._stack = None return ret diff --git a/yardstick/tests/fixture.py b/yardstick/tests/fixture.py new file mode 100644 index 000000000..94d20eb34 --- /dev/null +++ b/yardstick/tests/fixture.py @@ -0,0 +1,47 @@ +# Copyright 2017 Intel Corporation +# All Rights Reserved. +# +# 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 fixtures +import mock +import six + +from yardstick.common import task_template + + +class PluginParserFixture(fixtures.Fixture): + """PluginParser fixture. + + This class is intended to be used as a fixture within unit tests and + therefore consumers must register it using useFixture() within their + unit test class. + """ + + def __init__(self, rendered_plugin): + super(PluginParserFixture, self).__init__() + self._rendered_plugin = rendered_plugin + + def _setUp(self): + self.addCleanup(self._restore) + self._mock_tasktemplate_render = mock.patch.object( + task_template.TaskTemplate, 'render') + self.mock_tasktemplate_render = self._mock_tasktemplate_render.start() + self.mock_tasktemplate_render.return_value = self._rendered_plugin + self._mock_open = mock.patch.object(six.moves.builtins, 'open', create=True) + self.mock_open = self._mock_open.start() + self.mock_open.side_effect = mock.mock_open() + + def _restore(self): + self._mock_tasktemplate_render.stop() + self._mock_open.stop() diff --git a/yardstick/tests/unit/benchmark/core/test_plugin.py b/yardstick/tests/unit/benchmark/core/test_plugin.py index 1d6e80574..0d14e4e86 100644 --- a/yardstick/tests/unit/benchmark/core/test_plugin.py +++ b/yardstick/tests/unit/benchmark/core/test_plugin.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. # @@ -9,94 +7,136 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -# Unittest for yardstick.benchmark.core.plugin -from __future__ import absolute_import +import copy import os -from os.path import dirname as dirname +import pkg_resources -try: - from unittest import mock -except ImportError: - import mock -import unittest +import mock +import testtools +from yardstick import ssh from yardstick.benchmark.core import plugin +from yardstick.tests import fixture + +class PluginTestCase(testtools.TestCase): -class Arg(object): + FILE = """ +schema: "yardstick:plugin:0.1" - def __init__(self): - # self.input_file = ('plugin/sample_config.yaml',) - self.input_file = [ - os.path.join(os.path.abspath( - dirname(dirname(dirname(dirname(dirname(dirname(__file__))))))), - 'plugin/sample_config.yaml')] +plugins: + name: sample +deployment: + ip: 10.1.0.50 + user: root + password: root +""" -@mock.patch('yardstick.benchmark.core.plugin.ssh') -class pluginTestCase(unittest.TestCase): + NAME = 'sample' + DEPLOYMENT = {'ip': '10.1.0.50', 'user': 'root', 'password': 'root'} def setUp(self): - self.result = {} - - def test_install(self, mock_ssh): - p = plugin.Plugin() - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - input_file = Arg() - p.install(input_file) - expected_result = {} - self.assertEqual(self.result, expected_result) - - def test_remove(self, mock_ssh): - p = plugin.Plugin() - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - input_file = Arg() - p.remove(input_file) - expected_result = {} - self.assertEqual(self.result, expected_result) - - def test_install_setup_run(self, mock_ssh): - p = plugin.Plugin() - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - plugins = { - "name": "sample" - } - deployment = { - "ip": "10.1.0.50", - "user": "root", - "password": "root" - } - plugin_name = plugins.get("name") - p._install_setup(plugin_name, deployment) - self.assertIsNotNone(p.client) - - p._run(plugin_name) - expected_result = {} - self.assertEqual(self.result, expected_result) - - def test_remove_setup_run(self, mock_ssh): - p = plugin.Plugin() - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - plugins = { - "name": "sample" - } - deployment = { - "ip": "10.1.0.50", - "user": "root", - "password": "root" - } - plugin_name = plugins.get("name") - p._remove_setup(plugin_name, deployment) - self.assertIsNotNone(p.client) - - p._run(plugin_name) - expected_result = {} - self.assertEqual(self.result, expected_result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + super(PluginTestCase, self).setUp() + self.plugin_parser = plugin.PluginParser(mock.Mock()) + self.plugin = plugin.Plugin() + self.useFixture(fixture.PluginParserFixture(PluginTestCase.FILE)) + + self._mock_ssh_from_node = mock.patch.object(ssh.SSH, 'from_node') + self.mock_ssh_from_node = self._mock_ssh_from_node.start() + self.mock_ssh_obj = mock.Mock() + self.mock_ssh_from_node.return_value = self.mock_ssh_obj + self.mock_ssh_obj.wait = mock.Mock() + self.mock_ssh_obj._put_file_shell = mock.Mock() + + self.addCleanup(self._cleanup) + + def _cleanup(self): + self._mock_ssh_from_node.stop() + + def test_install(self): + args = mock.Mock() + args.input_file = [mock.Mock()] + with mock.patch.object(self.plugin, '_install_setup') as \ + mock_install, \ + mock.patch.object(self.plugin, '_run') as mock_run: + self.plugin.install(args) + mock_install.assert_called_once_with(PluginTestCase.NAME, + PluginTestCase.DEPLOYMENT) + mock_run.assert_called_once_with(PluginTestCase.NAME) + + def test_remove(self): + args = mock.Mock() + args.input_file = [mock.Mock()] + with mock.patch.object(self.plugin, '_remove_setup') as \ + mock_remove, \ + mock.patch.object(self.plugin, '_run') as mock_run: + self.plugin.remove(args) + mock_remove.assert_called_once_with(PluginTestCase.NAME, + PluginTestCase.DEPLOYMENT) + mock_run.assert_called_once_with(PluginTestCase.NAME) + + @mock.patch.object(pkg_resources, 'resource_filename', + return_value='script') + def test__install_setup(self, mock_resource_filename): + plugin_name = 'plugin_name' + self.plugin._install_setup(plugin_name, PluginTestCase.DEPLOYMENT) + mock_resource_filename.assert_called_once_with( + 'yardstick.resources', 'scripts/install/' + plugin_name + '.bash') + self.mock_ssh_from_node.assert_called_once_with( + PluginTestCase.DEPLOYMENT) + self.mock_ssh_obj.wait.assert_called_once_with(timeout=600) + self.mock_ssh_obj._put_file_shell.assert_called_once_with( + 'script', '~/{0}.sh'.format(plugin_name)) + + @mock.patch.object(pkg_resources, 'resource_filename', + return_value='script') + @mock.patch.object(os, 'environ', return_value='1.2.3.4') + def test__install_setup_with_ip_local(self, mock_os_environ, + mock_resource_filename): + plugin_name = 'plugin_name' + deployment = copy.deepcopy(PluginTestCase.DEPLOYMENT) + deployment['ip'] = 'local' + self.plugin._install_setup(plugin_name, deployment) + mock_os_environ.__getitem__.assert_called_once_with('JUMP_HOST_IP') + mock_resource_filename.assert_called_once_with( + 'yardstick.resources', + 'scripts/install/' + plugin_name + '.bash') + self.mock_ssh_from_node.assert_called_once_with( + deployment, overrides={'ip': os.environ["JUMP_HOST_IP"]}) + self.mock_ssh_obj.wait.assert_called_once_with(timeout=600) + self.mock_ssh_obj._put_file_shell.assert_called_once_with( + 'script', '~/{0}.sh'.format(plugin_name)) + + @mock.patch.object(pkg_resources, 'resource_filename', + return_value='script') + def test__remove_setup(self, mock_resource_filename): + plugin_name = 'plugin_name' + self.plugin._remove_setup(plugin_name, PluginTestCase.DEPLOYMENT) + mock_resource_filename.assert_called_once_with( + 'yardstick.resources', + 'scripts/remove/' + plugin_name + '.bash') + self.mock_ssh_from_node.assert_called_once_with( + PluginTestCase.DEPLOYMENT) + self.mock_ssh_obj.wait.assert_called_once_with(timeout=600) + self.mock_ssh_obj._put_file_shell.assert_called_once_with( + 'script', '~/{0}.sh'.format(plugin_name)) + + @mock.patch.object(pkg_resources, 'resource_filename', + return_value='script') + @mock.patch.object(os, 'environ', return_value='1.2.3.4') + def test__remove_setup_with_ip_local(self, mock_os_environ, + mock_resource_filename): + plugin_name = 'plugin_name' + deployment = copy.deepcopy(PluginTestCase.DEPLOYMENT) + deployment['ip'] = 'local' + self.plugin._remove_setup(plugin_name, deployment) + mock_os_environ.__getitem__.assert_called_once_with('JUMP_HOST_IP') + mock_resource_filename.assert_called_once_with( + 'yardstick.resources', + 'scripts/remove/' + plugin_name + '.bash') + self.mock_ssh_from_node.assert_called_once_with( + deployment, overrides={'ip': os.environ["JUMP_HOST_IP"]}) + self.mock_ssh_obj.wait.assert_called_once_with(timeout=600) + self.mock_ssh_obj._put_file_shell.mock_os_environ( + 'script', '~/{0}.sh'.format(plugin_name)) diff --git a/yardstick/tests/unit/benchmark/core/test_task.py b/yardstick/tests/unit/benchmark/core/test_task.py index 3d9a10d88..bac035fb9 100644 --- a/yardstick/tests/unit/benchmark/core/test_task.py +++ b/yardstick/tests/unit/benchmark/core/test_task.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # @@ -9,43 +7,32 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -# Unittest for yardstick.benchmark.core.task - -from __future__ import print_function - -from __future__ import absolute_import import os -import unittest - -try: - from unittest import mock -except ImportError: - import mock +import mock +import unittest from yardstick.benchmark.core import task from yardstick.common import constants as consts -# pylint: disable=unused-argument -# disable this for now because I keep forgetting mock patch arg ordering - - class TaskTestCase(unittest.TestCase): - @mock.patch('yardstick.benchmark.core.task.Context') - def test_parse_nodes_host_target_same_context(self, mock_context): - nodes = { - "host": "node1.LF", - "target": "node2.LF" + @mock.patch.object(task, 'Context') + def test_parse_nodes_with_context_same_context(self, mock_context): + scenario_cfg = { + "nodes": { + "host": "node1.LF", + "target": "node2.LF" + } } - scenario_cfg = {"nodes": nodes} server_info = { "ip": "10.20.0.3", "user": "root", "key_filename": "/root/.ssh/id_rsa" } mock_context.get_server.return_value = server_info + context_cfg = task.parse_nodes_with_context(scenario_cfg) self.assertEqual(context_cfg["host"], server_info) @@ -57,7 +44,7 @@ class TaskTestCase(unittest.TestCase): t._set_dispatchers(output_config) self.assertEqual(output_config, output_config) - @mock.patch('yardstick.benchmark.core.task.DispatcherBase') + @mock.patch.object(task, 'DispatcherBase') def test__do_output(self, mock_dispatcher): t = task.Task() output_config = {"DEFAULT": {"dispatcher": "file, http"}} @@ -65,7 +52,7 @@ class TaskTestCase(unittest.TestCase): mock.MagicMock()]) self.assertEqual(None, t._do_output(output_config, {})) - @mock.patch('yardstick.benchmark.core.task.Context') + @mock.patch.object(task, 'Context') def test_parse_networks_from_nodes(self, mock_context): nodes = { 'node1': { @@ -129,9 +116,9 @@ class TaskTestCase(unittest.TestCase): self.assertEqual(mock_context.get_network.call_count, expected_get_network_calls) self.assertDictEqual(networks, expected) - @mock.patch('yardstick.benchmark.core.task.Context') - @mock.patch('yardstick.benchmark.core.task.base_runner') - def test_run(self, mock_base_runner, mock_ctx): + @mock.patch.object(task, 'Context') + @mock.patch.object(task, 'base_runner') + def test_run(self, mock_base_runner, *args): scenario = { 'host': 'athena.demo', 'target': 'ares.demo', @@ -152,8 +139,8 @@ class TaskTestCase(unittest.TestCase): t._run([scenario], False, "yardstick.out") self.assertTrue(runner.run.called) - @mock.patch('yardstick.benchmark.core.task.os') - def test_check_precondition(self, mock_os): + @mock.patch.object(os, 'environ') + def test_check_precondition(self, mock_os_environ): cfg = { 'precondition': { 'installer_type': 'compass', @@ -163,7 +150,7 @@ class TaskTestCase(unittest.TestCase): } t = task.TaskParser('/opt') - mock_os.environ.get.side_effect = ['compass', + mock_os_environ.get.side_effect = ['compass', 'os-nosdn', 'huawei-pod1'] result = t._check_precondition(cfg) @@ -172,82 +159,75 @@ class TaskTestCase(unittest.TestCase): def test_parse_suite_no_constraint_no_args(self): SAMPLE_SCENARIO_PATH = "no_constraint_no_args_scenario_sample.yaml" t = task.TaskParser(self._get_file_abspath(SAMPLE_SCENARIO_PATH)) - with mock.patch('yardstick.benchmark.core.task.os.environ', + with mock.patch.object(os, 'environ', new={'NODE_NAME': 'huawei-pod1', 'INSTALLER_TYPE': 'compass'}): task_files, task_args, task_args_fnames = t.parse_suite() - print("files=%s, args=%s, fnames=%s" % (task_files, task_args, - task_args_fnames)) + self.assertEqual(task_files[0], self.change_to_abspath( 'tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml')) self.assertEqual(task_files[1], self.change_to_abspath( 'tests/opnfv/test_cases/opnfv_yardstick_tc043.yaml')) - self.assertEqual(task_args[0], None) - self.assertEqual(task_args[1], None) - self.assertEqual(task_args_fnames[0], None) - self.assertEqual(task_args_fnames[1], None) - @mock.patch('yardstick.benchmark.core.task.os.environ') - def test_parse_suite_no_constraint_with_args(self, mock_environ): + self.assertIsNone(task_args[0]) + self.assertIsNone(task_args[1]) + self.assertIsNone(task_args_fnames[0]) + self.assertIsNone(task_args_fnames[1]) + + def test_parse_suite_no_constraint_with_args(self): SAMPLE_SCENARIO_PATH = "no_constraint_with_args_scenario_sample.yaml" t = task.TaskParser(self._get_file_abspath(SAMPLE_SCENARIO_PATH)) - with mock.patch('yardstick.benchmark.core.task.os.environ', + with mock.patch.object(os, 'environ', new={'NODE_NAME': 'huawei-pod1', 'INSTALLER_TYPE': 'compass'}): task_files, task_args, task_args_fnames = t.parse_suite() - print("files=%s, args=%s, fnames=%s" % (task_files, task_args, - task_args_fnames)) + self.assertEqual(task_files[0], self.change_to_abspath( 'tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml')) self.assertEqual(task_files[1], self.change_to_abspath( 'tests/opnfv/test_cases/opnfv_yardstick_tc043.yaml')) - self.assertEqual(task_args[0], None) + self.assertIsNone(task_args[0]) self.assertEqual(task_args[1], '{"host": "node1.LF","target": "node2.LF"}') - self.assertEqual(task_args_fnames[0], None) - self.assertEqual(task_args_fnames[1], None) + self.assertIsNone(task_args_fnames[0]) + self.assertIsNone(task_args_fnames[1]) - @mock.patch('yardstick.benchmark.core.task.os.environ') - def test_parse_suite_with_constraint_no_args(self, mock_environ): + def test_parse_suite_with_constraint_no_args(self): SAMPLE_SCENARIO_PATH = "with_constraint_no_args_scenario_sample.yaml" t = task.TaskParser(self._get_file_abspath(SAMPLE_SCENARIO_PATH)) - with mock.patch('yardstick.benchmark.core.task.os.environ', + with mock.patch.object(os, 'environ', new={'NODE_NAME': 'huawei-pod1', 'INSTALLER_TYPE': 'compass'}): task_files, task_args, task_args_fnames = t.parse_suite() - print("files=%s, args=%s, fnames=%s" % (task_files, task_args, - task_args_fnames)) self.assertEqual(task_files[0], self.change_to_abspath( 'tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml')) self.assertEqual(task_files[1], self.change_to_abspath( 'tests/opnfv/test_cases/opnfv_yardstick_tc043.yaml')) - self.assertEqual(task_args[0], None) - self.assertEqual(task_args[1], None) - self.assertEqual(task_args_fnames[0], None) - self.assertEqual(task_args_fnames[1], None) + self.assertIsNone(task_args[0]) + self.assertIsNone(task_args[1]) + self.assertIsNone(task_args_fnames[0]) + self.assertIsNone(task_args_fnames[1]) - @mock.patch('yardstick.benchmark.core.task.os.environ') - def test_parse_suite_with_constraint_with_args(self, mock_environ): + def test_parse_suite_with_constraint_with_args(self): SAMPLE_SCENARIO_PATH = "with_constraint_with_args_scenario_sample.yaml" t = task.TaskParser(self._get_file_abspath(SAMPLE_SCENARIO_PATH)) - with mock.patch('yardstick.benchmark.core.task.os.environ', + with mock.patch('os.environ', new={'NODE_NAME': 'huawei-pod1', 'INSTALLER_TYPE': 'compass'}): task_files, task_args, task_args_fnames = t.parse_suite() - print("files=%s, args=%s, fnames=%s" % (task_files, task_args, - task_args_fnames)) + self.assertEqual(task_files[0], self.change_to_abspath( 'tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml')) self.assertEqual(task_files[1], self.change_to_abspath( 'tests/opnfv/test_cases/opnfv_yardstick_tc043.yaml')) - self.assertEqual(task_args[0], None) + self.assertIsNone(task_args[0]) self.assertEqual(task_args[1], '{"host": "node1.LF","target": "node2.LF"}') - self.assertEqual(task_args_fnames[0], None) - self.assertEqual(task_args_fnames[1], None) + self.assertIsNone(task_args_fnames[0]) + self.assertIsNone(task_args_fnames[1]) def test_parse_options(self): options = { 'openstack': { 'EXTERNAL_NETWORK': '$network' }, - 'ndoes': ['node1', '$node'], + 'nodes': ['node1', '$node'], 'host': '$host' } @@ -258,48 +238,50 @@ class TaskTestCase(unittest.TestCase): 'host': 'server.yardstick' } - idle_result = { + expected_result = { 'openstack': { 'EXTERNAL_NETWORK': 'ext-net' }, - 'ndoes': ['node1', 'node2'], + 'nodes': ['node1', 'node2'], 'host': 'server.yardstick' } actual_result = t._parse_options(options) - self.assertEqual(idle_result, actual_result) + self.assertEqual(expected_result, actual_result) + def test_change_server_name_host_str(self): scenario = {'host': 'demo'} suffix = '-8' task.change_server_name(scenario, suffix) - self.assertTrue(scenario['host'], 'demo-8') + self.assertEqual('demo-8', scenario['host']) def test_change_server_name_host_dict(self): scenario = {'host': {'name': 'demo'}} suffix = '-8' task.change_server_name(scenario, suffix) - self.assertTrue(scenario['host']['name'], 'demo-8') + self.assertEqual('demo-8', scenario['host']['name']) def test_change_server_name_target_str(self): scenario = {'target': 'demo'} suffix = '-8' task.change_server_name(scenario, suffix) - self.assertTrue(scenario['target'], 'demo-8') + self.assertEqual('demo-8', scenario['target']) def test_change_server_name_target_dict(self): scenario = {'target': {'name': 'demo'}} suffix = '-8' task.change_server_name(scenario, suffix) - self.assertTrue(scenario['target']['name'], 'demo-8') + self.assertEqual('demo-8', scenario['target']['name']) - @mock.patch('yardstick.benchmark.core.task.utils') - @mock.patch('yardstick.benchmark.core.task.logging') - def test_set_log(self, mock_logging, mock_utils): + @mock.patch('six.moves.builtins.open', side_effect=mock.mock_open()) + @mock.patch.object(task, 'utils') + @mock.patch('logging.root') + def test_set_log(self, mock_logging_root, *args): task_obj = task.Task() task_obj.task_id = 'task_id' task_obj._set_log() - self.assertTrue(mock_logging.root.addHandler.called) + mock_logging_root.addHandler.assert_called() def _get_file_abspath(self, filename): curr_path = os.path.dirname(os.path.abspath(__file__)) diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_network.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_network.py index 5f11713fa..aef99ee94 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_network.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_network.py @@ -6,30 +6,44 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## + +from oslo_utils import uuidutils import unittest import mock -from yardstick.benchmark.scenarios.lib.delete_network import DeleteNetwork +import yardstick.common.openstack_utils as op_utils +from yardstick.benchmark.scenarios.lib import delete_network class DeleteNetworkTestCase(unittest.TestCase): - @mock.patch('yardstick.common.openstack_utils.get_neutron_client') - @mock.patch('yardstick.common.openstack_utils.delete_neutron_net') - def test_delete_network(self, mock_get_neutron_client, mock_delete_neutron_net): - options = { - 'network_id': '123-123-123' - } - args = {"options": options} - obj = DeleteNetwork(args, {}) - obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_delete_neutron_net.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + def setUp(self): + self._mock_delete_neutron_net = mock.patch.object( + op_utils, 'delete_neutron_net') + self.mock_delete_neutron_net = self._mock_delete_neutron_net.start() + self._mock_get_shade_client = mock.patch.object( + op_utils, 'get_shade_client') + self.mock_get_shade_client = self._mock_get_shade_client.start() + self._mock_log = mock.patch.object(delete_network, 'LOG') + self.mock_log = self._mock_log.start() + _uuid = uuidutils.generate_uuid() + self.args = {'options': {'network_id': _uuid}} + self._del_obj = delete_network.DeleteNetwork(self.args, mock.ANY) + + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_delete_neutron_net.stop() + self._mock_get_shade_client.stop() + self._mock_log.stop() + + def test_run(self): + self.mock_delete_neutron_net.return_value = True + self.assertTrue(self._del_obj.run({})) + self.mock_log.info.assert_called_once_with( + "Delete network successful!") + + def test_run_fail(self): + self.mock_delete_neutron_net.return_value = False + self.assertFalse(self._del_obj.run({})) + self.mock_log.error.assert_called_once_with("Delete network failed!") diff --git a/yardstick/tests/unit/common/test_openstack_utils.py b/yardstick/tests/unit/common/test_openstack_utils.py index b685e63be..8a2f5f95b 100644 --- a/yardstick/tests/unit/common/test_openstack_utils.py +++ b/yardstick/tests/unit/common/test_openstack_utils.py @@ -11,6 +11,7 @@ from oslo_utils import uuidutils import unittest import mock +from shade import exc from yardstick.common import openstack_utils @@ -54,3 +55,31 @@ class GetNetworkIdTestCase(unittest.TestCase): output = openstack_utils.get_network_id(mock_shade_client, 'network_name') self.assertEqual(None, output) + + +class DeleteNeutronNetTestCase(unittest.TestCase): + + def setUp(self): + self.mock_shade_client = mock.Mock() + self.mock_shade_client.delete_network = mock.Mock() + + def test_delete_neutron_net(self): + self.mock_shade_client.delete_network.return_value = True + output = openstack_utils.delete_neutron_net(self.mock_shade_client, + 'network_id') + self.assertTrue(output) + + def test_delete_neutron_net_fail(self): + self.mock_shade_client.delete_network.return_value = False + output = openstack_utils.delete_neutron_net(self.mock_shade_client, + 'network_id') + self.assertFalse(output) + + @mock.patch.object(openstack_utils, 'log') + def test_delete_neutron_net_exception(self, mock_logger): + self.mock_shade_client.delete_network.side_effect = ( + exc.OpenStackCloudException('error message')) + output = openstack_utils.delete_neutron_net(self.mock_shade_client, + 'network_id') + self.assertFalse(output) + mock_logger.error.assert_called_once() diff --git a/yardstick/tests/unit/orchestrator/test_heat.py b/yardstick/tests/unit/orchestrator/test_heat.py index f53c9b78c..e0a353812 100644 --- a/yardstick/tests/unit/orchestrator/test_heat.py +++ b/yardstick/tests/unit/orchestrator/test_heat.py @@ -89,6 +89,18 @@ class HeatStackTestCase(unittest.TestCase): self.assertFalse(heat._DEPLOYED_STACKS) self.mock_stack_delete.assert_called_once_with(id, wait=True) + def test_delete_bug_in_shade(self): + id = uuidutils.generate_uuid() + self.heatstack._stack = FakeStack( + outputs=mock.Mock(), status=mock.Mock(), id=id) + heat._DEPLOYED_STACKS[id] = self.heatstack._stack + self.mock_stack_delete.side_effect = TypeError() + + ret = self.heatstack.delete(wait=True) + self.assertTrue(ret) + self.assertFalse(heat._DEPLOYED_STACKS) + self.mock_stack_delete.assert_called_once_with(id, wait=True) + class HeatTemplateTestCase(unittest.TestCase): |