diff options
303 files changed, 7288 insertions, 2949 deletions
diff --git a/ansible/clone_repos.yml b/ansible/clone_repos.yml index 6f69b6b15..f35be0016 100644 --- a/ansible/clone_repos.yml +++ b/ansible/clone_repos.yml @@ -17,21 +17,8 @@ YARDSTICK_REPO: "{{ lookup('env', 'YARDSTICK_REPO')|default('https://gerrit.opnfv.org/gerrit/yardstick', true) }}" YARDSTICK_REPO_DIR: "{{ lookup('env', 'YARDSTICK_REPO_DIR')|default('/home/opnfv/repos/yardstick', true) }}" YARDSTICK_BRANCH: "{{ lookup('env', 'YARDSTICK_BRANCH')|default('master', true) }}" - RELENG_REPO: "{{ lookup('env', 'RELENG_REPO')|default('https://gerrit.opnfv.org/gerrit/releng', true) }}" - RELENG_REPO_DIR: "{{ lookup('env', 'RELENG_REPO_DIR')|default('/home/opnfv/repos/releng', true) }}" - RELENG_BRANCH: "{{ lookup('env', 'RELENG_BRANCH')|default('master', true) }}" - tasks: - - name: Updating releng -> "{{ RELENG_BRANCH }}" - git: - repo: "{{ RELENG_REPO }}" - dest: "{{ RELENG_REPO_DIR }}" - version: "{{ RELENG_BRANCH }}" - accept_hostkey: yes - recursive: no - force: yes - - name: Updating yardstick -> "{{ YARDSTICK_BRANCH }}" git: repo: "{{ YARDSTICK_REPO }}" diff --git a/ansible/prepare_env.yml b/ansible/prepare_env.yml index a1299c38e..321521334 100644 --- a/ansible/prepare_env.yml +++ b/ansible/prepare_env.yml @@ -28,10 +28,6 @@ - fail: msg="{{ INSTALLER_TYPE }} not in {{ INSTALLERS }}" when: not openrc_present and (INSTALLER_TYPE not in INSTALLERS) - - name: fetch OS credentials - command: "{{ RELENG_REPO_DIR }}/utils/fetch_os_creds.sh {{ '-v' if DEPLOY_TYPE == 'virt' else '' }} -d {{ OPENRC }} -i {{ INSTALLER_TYPE }} -a {{ INSTALLER_IP }}" - when: not openrc_present - roles: - role: convert_openrc diff --git a/ansible/roles/convert_openrc/tasks/main.yml b/ansible/roles/convert_openrc/tasks/main.yml index 1606b0bc5..00aa13615 100644 --- a/ansible/roles/convert_openrc/tasks/main.yml +++ b/ansible/roles/convert_openrc/tasks/main.yml @@ -18,7 +18,7 @@ - debug: var=openrc - set_fact: - yardstick_url_ip: "{{ openrc.OS_AUTH_URL|urlsplit|attr('hostname') }}" + yardstick_url_ip: "{{ openrc.OS_AUTH_URL|urlsplit('hostname') }}" - debug: var=yardstick_url_ip @@ -29,14 +29,8 @@ auth_url: "{{ openrc.OS_AUTH_URL }}" password: "{{ openrc.OS_PASSWORD }}" username: "{{ openrc.OS_USERNAME }}" - project_name: "{{ openrc.OS_PROJECT_NAME }}" -# tenant_name: "{{ openrc.OS_TENANT_NAME }}" + project_name: "{{ openrc.OS_PROJECT_NAME|default(openrc.OS_TENANT_NAME) }}" project_domain_name: "{{ openrc.OS_PROJECT_DOMAIN_NAME }}" -# user_domain_name: "{{ openrc.OS_USER_DOMAIN_NAME }}" - # BUGS: We need to specify identity_api_version == 3, but we can't do it here - # because it is not the write place - # we need to set it via OS_IDENTITY_API_VERSION or clouds.yaml -# identity_api_version: "{{ openrc.OS_IDENTITY_API_VERSION }}" - debug: var=os_auth @@ -44,7 +38,7 @@ clouds: demo: # must specify API version here - identity_api_version: "{{ openrc.OS_IDENTITY_API_VERSION }}" + identity_api_version: "{{ openrc.OS_IDENTITY_API_VERSION|default(3) }}" auth: "{{ os_auth }}" - template: diff --git a/ansible/roles/create_dockerfile/templates/centos/Dockerfile b/ansible/roles/create_dockerfile/templates/centos/Dockerfile index ca104c8f8..96d8a0041 100644 --- a/ansible/roles/create_dockerfile/templates/centos/Dockerfile +++ b/ansible/roles/create_dockerfile/templates/centos/Dockerfile @@ -18,7 +18,6 @@ ENV REPOS_DIR /home/opnfv/repos # Yardstick repo ENV YARDSTICK_REPO_DIR ${REPOS_DIR}/yardstick -ENV RELENG_REPO_DIR ${REPOS_DIR}/releng RUN yum -y install\ deltarpm \ @@ -50,7 +49,6 @@ RUN yum -y install\ RUN mkdir -p ${REPOS_DIR} && \ git config --global http.sslVerify false && \ git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/yardstick ${YARDSTICK_REPO_DIR} && \ - git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng ${RELENG_REPO_DIR} # install yardstick + dependencies # explicity pin pip version to avoid future issues like the ill-fated pip 8.0.0 release diff --git a/ansible/roles/create_dockerfile/templates/ubuntu/Dockerfile b/ansible/roles/create_dockerfile/templates/ubuntu/Dockerfile index 7fbc4f01a..6eba3a841 100644 --- a/ansible/roles/create_dockerfile/templates/ubuntu/Dockerfile +++ b/ansible/roles/create_dockerfile/templates/ubuntu/Dockerfile @@ -18,7 +18,6 @@ ENV REPOS_DIR /home/opnfv/repos # Yardstick repo ENV YARDSTICK_REPO_DIR ${REPOS_DIR}/yardstick -ENV RELENG_REPO_DIR ${REPOS_DIR}/releng RUN sed -i -e 's/^deb /deb [arch=amd64] /g;s/^deb-src /# deb-src /g' /etc/apt/sources.list && \ echo "\n\ deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ trusty main universe multiverse restricted \n\ @@ -63,7 +62,6 @@ RUN apt-get update && apt-get install -y \ RUN mkdir -p ${REPOS_DIR} && \ git config --global http.sslVerify false && \ git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/yardstick ${YARDSTICK_REPO_DIR} && \ - git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng ${RELENG_REPO_DIR} # install yardstick + dependencies # explicity pin pip version to avoid future issues like the ill-fated pip 8.0.0 release diff --git a/ansible/roles/create_storperf_admin_rc/tasks/main.yml b/ansible/roles/create_storperf_admin_rc/tasks/main.yml index bd1418e89..f63d1d814 100644 --- a/ansible/roles/create_storperf_admin_rc/tasks/main.yml +++ b/ansible/roles/create_storperf_admin_rc/tasks/main.yml @@ -12,15 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. --- -- name: Fetch TENANT_ID - os_project_facts: - name: admin - environment: "{{ openrc }}" - -- name: Fetch TENANT_ID - set_fact: - os_tenant_id: "{{ openstack_projects[0].id }}" - - name: Create storperf_admin-rc template: src: storperf_admin-rc.j2 diff --git a/ansible/roles/create_storperf_admin_rc/templates/storperf_admin-rc.j2 b/ansible/roles/create_storperf_admin_rc/templates/storperf_admin-rc.j2 index 410ab24df..888e87118 100644 --- a/ansible/roles/create_storperf_admin_rc/templates/storperf_admin-rc.j2 +++ b/ansible/roles/create_storperf_admin_rc/templates/storperf_admin-rc.j2 @@ -1,7 +1,5 @@ OS_AUTH_URL="{{ openrc.OS_AUTH_URL }}" OS_USERNAME="{{ openrc.OS_USERNAME|default('admin') }}" OS_PASSWORD="{{ openrc.OS_PASSWORD|default('console') }}" -OS_TENANT_NAME="{{ openrc.OS_TENANT_NAME|default('admin') }}" OS_VOLUME_API_VERSION="{{ openrc.OS_VOLUME_API_VERSION|default('2') }}" -OS_PROJECT_NAME="{{ openrc.OS_PROJECT_NAME|default(openrc.OS_TENANT_NAME) }}" -OS_TENANT_ID="{{ os_tenant_id }}" +OS_PROJECT_NAME="{{ openrc.OS_PROJECT_NAME|openrc.OS_TENANT_NAME|default('admin') }}" diff --git a/ansible/roles/download_l2fwd/defaults/main.yml b/ansible/roles/download_l2fwd/defaults/main.yml new file mode 100644 index 000000000..1bc76ef3e --- /dev/null +++ b/ansible/roles/download_l2fwd/defaults/main.yml @@ -0,0 +1,4 @@ +--- +l2fwd_url: "http://artifacts.opnfv.org/yardstick/third-party/l2fwd.tar" +l2fwd_file: "l2fwd.tar" +l2fwd_dest: "/home" diff --git a/ansible/roles/download_l2fwd/tasks/main.yml b/ansible/roles/download_l2fwd/tasks/main.yml new file mode 100644 index 000000000..7f2ea25c4 --- /dev/null +++ b/ansible/roles/download_l2fwd/tasks/main.yml @@ -0,0 +1,28 @@ +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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. +--- +- file: + path: "{{ l2fwd_dest }}" + state: directory + +- name: fetch dpdk + get_url: + url: "{{ l2fwd_url }}" + dest: "{{ l2fwd_dest }}" + +- unarchive: + src: "{{ l2fwd_dest }}/{{ l2fwd_file }}" + dest: "{{ l2fwd_dest }}/" + copy: no + mode: 0777 diff --git a/ansible/roles/infra_check_requirements/tasks/main.yml b/ansible/roles/infra_check_requirements/tasks/main.yml index 8d05bbdb7..a11bc56a1 100644 --- a/ansible/roles/infra_check_requirements/tasks/main.yml +++ b/ansible/roles/infra_check_requirements/tasks/main.yml @@ -34,6 +34,22 @@ msg: "Failed, not enough CPU, required: {{ vcpu_t }}, available {{ ansible_processor_vcpus }}" when: ansible_processor_vcpus < vcpu_t|int +- name: Define default network counter + set_fact: + num_default_network_detected: 0 + +- name: Increment counter for every default network detected + set_fact: + num_default_network_detected: "{{ num_default_network_detected|int + 1 }}" + when: + - item.default_gateway is defined + - item.default_gateway == True + with_items: "{{infra_deploy_vars.networks}}" + +- name: Fail if more than 1 or 0 default networks + fail: + msg: "Failed, there must be 1 default network: {{ num_default_network_detected }} detected" + when: num_default_network_detected|int != 1 - name: Fail if not enough Disk space set_fact: diff --git a/ansible/roles/infra_create_network/tasks/create_xml.yaml b/ansible/roles/infra_create_network/tasks/create_xml.yml index a01c7974a..1632e591c 100644 --- a/ansible/roles/infra_create_network/tasks/create_xml.yaml +++ b/ansible/roles/infra_create_network/tasks/create_xml.yml @@ -40,10 +40,30 @@ xpath: /network add_children: - name: "{{ item.name }}" + - forward: + mode: nat - bridge - ip pretty_print: yes +- name: Add new children nodes to "forward" node + xml: + path: "{{ xml_file }}" + xpath: /network/forward + add_children: + - nat + pretty_print: yes + +- name: Add new children nodes to "nat" node + xml: + path: "{{ xml_file }}" + xpath: /network/forward/nat + add_children: + - port: + start: "1024" + end: "65535" + pretty_print: yes + - name: Add "name" attribute to "bridge" node xml: path: "{{ xml_file }}" diff --git a/ansible/roles/infra_create_network/tasks/main.yml b/ansible/roles/infra_create_network/tasks/main.yml index eba4a3a49..025a775a1 100644 --- a/ansible/roles/infra_create_network/tasks/main.yml +++ b/ansible/roles/infra_create_network/tasks/main.yml @@ -18,5 +18,5 @@ name: infra_deploy_vars - name: Create XML file - include_tasks: create_xml.yaml + include_tasks: create_xml.yml with_items: "{{ infra_deploy_vars.networks }}" diff --git a/ansible/roles/infra_create_vms/tasks/configure_vm.yml b/ansible/roles/infra_create_vms/tasks/configure_vm.yml index 10201cf2a..c20a0b175 100644 --- a/ansible/roles/infra_create_vms/tasks/configure_vm.yml +++ b/ansible/roles/infra_create_vms/tasks/configure_vm.yml @@ -222,6 +222,10 @@ - console: type: pty tty: '/dev/pts/14' + - graphics: + type: vnc + port: '-1' + autoport: 'yes' pretty_print: yes - name: Add new children nodes to "disk" node @@ -241,6 +245,16 @@ name: virtio-disk0 pretty_print: yes +- name: Add new children nodes to "graphics" node + xml: + path: "{{ xml_file }}" + xpath: /domain/devices/graphics + add_children: + - listen: + type: address + address: 0.0.0.0 + pretty_print: yes + - name: Add new children nodes to "devices" node xml: path: "{{ xml_file }}" @@ -305,7 +319,7 @@ - name: Populate network-config and add interface to xml file include_tasks: create_interfaces.yml - extra_vars: "{{ network_config, xml_file , slot_address, mac_address_counter }}" + extra_vars: "{{ network_config xml_file slot_address mac_address_counter }}" loop_control: loop_var: interface_item with_items: "{{ node_item.interfaces }}" @@ -326,9 +340,9 @@ shell: > qemu-img convert -O qcow2 {{ node_item.image }} {{ image_dir+node_item.hostname+'.qcow2' }} -- name: Copy and convert the ubuntu image +- name: Resize image shell: > - qemu-img resize {{ image_dir+node_item.hostname+'.qcow2' }} {{ node_item.disk }}MB + qemu-img resize {{ image_dir+node_item.hostname+'.qcow2' }} {{ node_item.disk }}M - name: Define the VMs virt: diff --git a/ansible/roles/infra_create_vms/tasks/create_interfaces.yml b/ansible/roles/infra_create_vms/tasks/create_interfaces.yml index 124421b56..34bfd1b71 100644 --- a/ansible/roles/infra_create_vms/tasks/create_interfaces.yml +++ b/ansible/roles/infra_create_vms/tasks/create_interfaces.yml @@ -24,6 +24,16 @@ addresses: - {{ interface_item.ip }}/{{ interface_item.netmask }} +- name: Add default gateway + blockinfile: + path: "{{ network_config }}" + insertafter: "{{ interface_item.ip }}" + marker: "MARKER" + block: |2 + gateway4: {{ default_bridge.host_ip }} + when: + - default_bridge is defined + - default_bridge.name == interface_item.network - name: Remove the marker introduced in network-data lineinfile: diff --git a/ansible/roles/infra_create_vms/tasks/main.yml b/ansible/roles/infra_create_vms/tasks/main.yml index 62a023e7e..4d47f44ff 100644 --- a/ansible/roles/infra_create_vms/tasks/main.yml +++ b/ansible/roles/infra_create_vms/tasks/main.yml @@ -20,9 +20,15 @@ - set_fact: mac_address_counter: 0 +- set_fact: + default_bridge: "{{ item }}" + when: + - item.default_gateway is defined + - item.default_gateway == True + with_items: "{{ infra_deploy_vars.networks }}" + - name: Create XML file include_tasks: configure_vm.yml - extra_vars: "{{ mac_address_counter }}" loop_control: loop_var: node_item with_items: "{{ infra_deploy_vars.nodes }}" diff --git a/ansible/ubuntu_server_cloudimg_modify.yml b/ansible/ubuntu_server_cloudimg_modify.yml index 099d5803f..90235cc81 100644 --- a/ansible/ubuntu_server_cloudimg_modify.yml +++ b/ansible/ubuntu_server_cloudimg_modify.yml @@ -27,6 +27,7 @@ - modify_cloud_config - role: set_package_installer_proxy when: proxy_env is defined and proxy_env + - download_l2fwd - install_image_dependencies - download_unixbench - install_unixbench diff --git a/ansible/yardstick_config.yml b/ansible/yardstick_config.yml index 79ec1958e..32b853929 100644 --- a/ansible/yardstick_config.yml +++ b/ansible/yardstick_config.yml @@ -21,7 +21,6 @@ OPENRC: "{{ opnfv_root }}/openrc" INSTALLERS: [apex, compass, fuel, joid] INSTALLER_TYPE: "{{ lookup('env', 'INSTALLER_TYPE') }}" YARDSTICK_REPO_DIR: "{{ lookup('env', 'YARDSTICK_REPO_DIR')|default('/home/opnfv/repos/yardstick', true) }}" -RELENG_REPO_DIR: "{{ lookup('env', 'RELENG_REPO_DIR')|default('/home/opnfv/repos/releng', true) }}" storperf_rc: "{{ opnfv_root }}/storperf_admin-rc" DISPATCHER_TYPES: diff --git a/api/database/v2/models.py b/api/database/v2/models.py index 59dab3ebc..0ee811698 100644 --- a/api/database/v2/models.py +++ b/api/database/v2/models.py @@ -92,6 +92,7 @@ class V2Task(Base): case_name = Column(String(30)) suite = Column(Boolean) content = Column(Text) + params = Column(Text) result = Column(Text) error = Column(Text) status = Column(Integer) diff --git a/api/resources/v1/env.py b/api/resources/v1/env.py index 7c831fd74..75c981a96 100644 --- a/api/resources/v1/env.py +++ b/api/resources/v1/env.py @@ -22,6 +22,8 @@ import collections from six.moves import configparser from oslo_serialization import jsonutils from docker import Client +from docker.errors import APIError +from requests.exceptions import HTTPError from api.database.v1.handlers import AsyncTaskHandler from api.utils import influx @@ -44,7 +46,7 @@ class V1Env(ApiResource): def post(self): return self._dispatch_post() - def create_grafana(self, args): + def create_grafana(self, *args): task_id = str(uuid.uuid4()) thread = threading.Thread(target=self._create_grafana, args=(task_id,)) @@ -82,7 +84,7 @@ class V1Env(ApiResource): self._update_task_status(task_id) LOG.info('Finished') - except Exception as e: + except (APIError, HTTPError) as e: self._update_task_error(task_id, str(e)) LOG.exception('Create grafana failed') @@ -117,7 +119,7 @@ class V1Env(ApiResource): "isDefault": True, } try: - HttpClient().post(url, data, timeout=10) + HttpClient().post(url, data, timeout=60) except Exception: LOG.exception('Create datasources failed') raise @@ -145,7 +147,7 @@ class V1Env(ApiResource): return any(t in a['RepoTags'][0] for a in client.images() if a['RepoTags']) - def create_influxdb(self, args): + def create_influxdb(self, *args): task_id = str(uuid.uuid4()) thread = threading.Thread(target=self._create_influxdb, args=(task_id,)) @@ -185,7 +187,7 @@ class V1Env(ApiResource): self._update_task_status(task_id) LOG.info('Finished') - except Exception as e: + except APIError as e: self._update_task_error(task_id, str(e)) LOG.exception('Creating influxdb failed') @@ -217,7 +219,7 @@ class V1Env(ApiResource): consts.INFLUXDB_DB_NAME) client.create_database(consts.INFLUXDB_DB_NAME) LOG.info('Success to config influxDB') - except Exception: + except HTTPError: LOG.exception('Config influxdb failed') def _change_output_to_influxdb(self, ip): @@ -236,7 +238,7 @@ class V1Env(ApiResource): with open(consts.CONF_FILE, 'w') as f: parser.write(f) - def prepare_env(self, args): + def prepare_env(self, *args): task_id = str(uuid.uuid4()) thread = threading.Thread(target=self._prepare_env_daemon, @@ -287,7 +289,7 @@ class V1Env(ApiResource): self._update_task_status(task_id) LOG.info('Finished') - except Exception as e: + except (subprocess.CalledProcessError, OSError) as e: self._update_task_error(task_id, str(e)) LOG.exception('Prepare env failed') @@ -373,7 +375,7 @@ class V1Env(ApiResource): LOG.info('Source openrc: Sourcing') try: self._source_file(consts.OPENRC) - except Exception as e: + except subprocess.CalledProcessError as e: LOG.exception('Failed to source openrc') return result_handler(consts.API_ERROR, str(e)) LOG.info('Source openrc: Done') diff --git a/api/resources/v2/environments.py b/api/resources/v2/environments.py index 158e98be7..7e587be85 100644 --- a/api/resources/v2/environments.py +++ b/api/resources/v2/environments.py @@ -11,6 +11,7 @@ import logging from oslo_serialization import jsonutils from docker import Client +from docker.errors import APIError from api import ApiResource from api.database.v2.handlers import V2EnvironmentHandler @@ -20,6 +21,7 @@ from api.database.v2.handlers import V2ContainerHandler from yardstick.common.utils import result_handler from yardstick.common.utils import change_obj_to_dict from yardstick.common import constants as consts +from yardstick.service.environment import Environment LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) @@ -124,10 +126,41 @@ class V2Environment(ApiResource): LOG.debug('container name: %s', container.name) try: client.remove_container(container.name, force=True) - except Exception: + except APIError: LOG.exception('remove container failed') container_handler.delete_by_uuid(v) environment_handler.delete_by_uuid(environment_id) return result_handler(consts.API_SUCCESS, {'environment': environment_id}) + + +class V2SUT(ApiResource): + + def get(self, environment_id): + try: + uuid.UUID(environment_id) + except ValueError: + return result_handler(consts.API_ERROR, 'invalid environment id') + + environment_handler = V2EnvironmentHandler() + try: + environment = environment_handler.get_by_uuid(environment_id) + except ValueError: + return result_handler(consts.API_ERROR, 'no such environment id') + + if not environment.pod_id: + return result_handler(consts.API_SUCCESS, {'sut': {}}) + + pod_handler = V2PodHandler() + try: + pod = pod_handler.get_by_uuid(environment.pod_id) + except ValueError: + return result_handler(consts.API_ERROR, 'no such pod id') + else: + pod_content = pod.content + + env = Environment(pod=pod_content) + sut_info = env.get_sut_info() + + return result_handler(consts.API_SUCCESS, {'sut': sut_info}) diff --git a/api/resources/v2/tasks.py b/api/resources/v2/tasks.py index 25a9cf109..17241ed63 100644 --- a/api/resources/v2/tasks.py +++ b/api/resources/v2/tasks.py @@ -38,6 +38,8 @@ class V2Tasks(ApiResource): for t in tasks: result = t['result'] t['result'] = jsonutils.loads(result) if result else None + params = t['params'] + t['params'] = jsonutils.loads(params) if params else None return result_handler(consts.API_SUCCESS, {'tasks': tasks}) @@ -94,6 +96,9 @@ class V2Task(ApiResource): result = task_info['result'] task_info['result'] = jsonutils.loads(result) if result else None + params = task_info['params'] + task_info['params'] = jsonutils.loads(params) if params else None + return result_handler(consts.API_SUCCESS, {'task': task_info}) def delete(self, task_id): @@ -127,7 +132,6 @@ class V2Task(ApiResource): return result_handler(consts.API_SUCCESS, {'task': task_id}) def put(self, task_id): - try: uuid.UUID(task_id) except ValueError: @@ -166,6 +170,21 @@ class V2Task(ApiResource): return result_handler(consts.API_SUCCESS, {'uuid': task_id}) + def add_params(self, args): + task_id = args['task_id'] + try: + params = args['params'] + except KeyError: + return result_handler(consts.API_ERROR, 'params must be provided') + + LOG.info('update params info in task') + + task_handler = V2TaskHandler() + task_update_data = {'params': jsonutils.dumps(params)} + task_handler.update_attr(task_id, task_update_data) + + return result_handler(consts.API_SUCCESS, {'uuid': task_id}) + def add_case(self, args): task_id = args['task_id'] try: @@ -243,7 +262,8 @@ class V2Task(ApiResource): data = { 'inputfile': ['/tmp/{}.yaml'.format(task.case_name)], - 'task_id': task_id + 'task_id': task_id, + 'task-args': task.params } if task.suite: data.update({'suite': True}) diff --git a/api/urls.py b/api/urls.py index 4b8e39e8f..9f0abcade 100644 --- a/api/urls.py +++ b/api/urls.py @@ -26,6 +26,7 @@ urlpatterns = [ Url('/api/v2/yardstick/environments', 'v2_environments'), Url('/api/v2/yardstick/environments/action', 'v2_environments'), Url('/api/v2/yardstick/environments/<environment_id>', 'v2_environment'), + Url('/api/v2/yardstick/environments/<environment_id>/sut', 'v2_sut'), Url('/api/v2/yardstick/openrcs', 'v2_openrcs'), Url('/api/v2/yardstick/openrcs/action', 'v2_openrcs'), diff --git a/docker/Dockerfile b/docker/Dockerfile index 46e52d557..959315c6b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -21,7 +21,6 @@ ENV REPOS_DIR="/home/opnfv/repos" \ # Yardstick repo ENV YARDSTICK_REPO_DIR="${REPOS_DIR}/yardstick" \ - RELENG_REPO_DIR="${REPOS_DIR}/releng" \ STORPERF_REPO_DIR="${REPOS_DIR}/storperf" RUN apt-get update && apt-get install -y git python-setuptools python-pip && apt-get -y autoremove && apt-get clean @@ -32,7 +31,6 @@ RUN mkdir -p ${REPOS_DIR} RUN git config --global http.sslVerify false RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/yardstick ${YARDSTICK_REPO_DIR} -RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng ${RELENG_REPO_DIR} RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/storperf ${STORPERF_REPO_DIR} WORKDIR ${YARDSTICK_REPO_DIR} diff --git a/docs/testing/developer/devguide/devguide_nsb_prox.rst b/docs/testing/developer/devguide/devguide_nsb_prox.rst index fc533b2cf..22628413b 100755 --- a/docs/testing/developer/devguide/devguide_nsb_prox.rst +++ b/docs/testing/developer/devguide/devguide_nsb_prox.rst @@ -251,9 +251,11 @@ Now let's examine the components of the file in detail In this case it is ``handle_l2fwd-2.cfg`` A number of additional parameters can be added. This example - is taken from VPE:: + is for VPE:: options: + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: ``configs/handle_vpe-4.cfg`` @@ -267,6 +269,12 @@ Now let's examine the components of the file in detail ``configs/vpe_rules.lua`` : ```` prox_generate_parameter: True + ``interface_speed_gbps`` - this specifies the speed of the interface + in Gigabits Per Second. This is used to calculate pps(packets per second). + If the interfaces are of different speeds, then this specifies the speed + of the slowest interface. This parameter is optional. If omitted the + interface speed defaults to 10Gbps. + ``prox_files`` - this specified that a number of addition files need to be provided for the test to run correctly. This files could provide routing information,hashing information or a diff --git a/docs/testing/user/userguide/04-installation.rst b/docs/testing/user/userguide/04-installation.rst index 5bb64e3bb..cac814667 100644 --- a/docs/testing/user/userguide/04-installation.rst +++ b/docs/testing/user/userguide/04-installation.rst @@ -172,13 +172,13 @@ Environment variables in the ``openrc`` file have to include at least:: OS_AUTH_URL OS_USERNAME OS_PASSWORD - OS_TENANT_NAME + OS_PROJECT_NAME EXTERNAL_NETWORK A sample ``openrc`` file may look like this:: export OS_PASSWORD=console - export OS_TENANT_NAME=admin + export OS_PROJECT_NAME=admin export OS_AUTH_URL=http://172.16.1.222:35357/v2.0 export OS_USERNAME=admin export OS_VOLUME_API_VERSION=2 diff --git a/docs/testing/user/userguide/05-yardstick_plugin.rst b/docs/testing/user/userguide/05-yardstick_plugin.rst index ec0b49ff1..679ce7900 100644 --- a/docs/testing/user/userguide/05-yardstick_plugin.rst +++ b/docs/testing/user/userguide/05-yardstick_plugin.rst @@ -49,7 +49,7 @@ environment and other dependencies: 3. Make sure Jump Host have access to the OpenStack Controller API. 4. Make sure Jump Host must have internet connectivity for downloading docker image. 5. You need to know where to get basic openstack Keystone authorization info, such as - OS_PASSWORD, OS_TENANT_NAME, OS_AUTH_URL, OS_USERNAME. + OS_PASSWORD, OS_PROJECT_NAME, OS_AUTH_URL, OS_USERNAME. 6. To run a Storperf container, you need to have OpenStack Controller environment variables defined and passed to Storperf container. The best way to do this is to put environment variables in a "storperf_admin-rc" file. The storperf_admin-rc @@ -58,8 +58,6 @@ environment and other dependencies: * OS_AUTH_URL * OS_USERNAME * OS_PASSWORD -* OS_TENANT_ID -* OS_TENANT_NAME * OS_PROJECT_NAME * OS_PROJECT_ID * OS_USER_DOMAIN_ID @@ -76,8 +74,9 @@ test/ci/prepare_storperf_admin-rc.sh USERNAME=${OS_USERNAME:-admin} PASSWORD=${OS_PASSWORD:-console} + # OS_TENANT_NAME is still present to keep backward compatibility with legacy + # deployments, but should be replaced by OS_PROJECT_NAME. TENANT_NAME=${OS_TENANT_NAME:-admin} - TENANT_ID=`openstack project show admin|grep '\bid\b' |awk -F '|' '{print $3}'|sed -e 's/^[[:space:]]*//'` PROJECT_NAME=${OS_PROJECT_NAME:-$TENANT_NAME} PROJECT_ID=`openstack project show admin|grep '\bid\b' |awk -F '|' '{print $3}'|sed -e 's/^[[:space:]]*//'` USER_DOMAIN_ID=${OS_USER_DOMAIN_ID:-default} @@ -90,8 +89,6 @@ test/ci/prepare_storperf_admin-rc.sh echo "OS_PASSWORD="$PASSWORD >> ~/storperf_admin-rc echo "OS_PROJECT_NAME="$PROJECT_NAME >> ~/storperf_admin-rc echo "OS_PROJECT_ID="$PROJECT_ID >> ~/storperf_admin-rc - echo "OS_TENANT_NAME="$TENANT_NAME >> ~/storperf_admin-rc - echo "OS_TENANT_ID="$TENANT_ID >> ~/storperf_admin-rc echo "OS_USER_DOMAIN_ID="$USER_DOMAIN_ID >> ~/storperf_admin-rc diff --git a/docs/testing/user/userguide/08-api.rst b/docs/testing/user/userguide/08-api.rst index ff6e62228..79f5d64be 100644 --- a/docs/testing/user/userguide/08-api.rst +++ b/docs/testing/user/userguide/08-api.rst @@ -35,7 +35,7 @@ Prepare Yardstick test environment Example:: { - 'action': 'prepareYardstickEnv' + 'action': 'prepare_env' } This is an asynchronous API. You need to call /yardstick/asynctask API to get the task result. @@ -45,7 +45,7 @@ Start and config an InfluxDB docker container Example:: { - 'action': 'createInfluxDBContainer' + 'action': 'create_influxdb' } This is an asynchronous API. You need to call /yardstick/asynctask API to get the task result. @@ -55,7 +55,7 @@ Start and config a Grafana docker container Example:: { - 'action': 'createGrafanaContainer' + 'action': 'create_grafana' } This is an asynchronous API. You need to call /yardstick/asynctask API to get the task result. @@ -73,10 +73,15 @@ Method: GET Get the status of asynchronous tasks Example:: - http://localhost:8888/yardstick/asynctask?task_id=3f3f5e03-972a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/yardstick/asynctask?task_id=3f3f5e03-972a-4847-a5f8-154f1b31db8c The returned status will be 0(running), 1(finished) and 2(failed). +NOTE:: + + <SERVER IP>: The ip of the host where you start your yardstick container + <PORT>: The outside port of port mapping which set when you start start yardstick container + /yardstick/testcases ^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +95,7 @@ Method: GET Get a list of released test cases Example:: - http://localhost:8888/yardstick/testcases + http://<SERVER IP>:<PORT>/yardstick/testcases /yardstick/testcases/release/action @@ -106,10 +111,10 @@ Run a released test case Example:: { - 'action': 'runTestCase', + 'action': 'run_test_case', 'args': { 'opts': {}, - 'testcase': 'tc002' + 'testcase': 'opnfv_yardstick_tc002' } } @@ -129,7 +134,7 @@ Run a sample test case Example:: { - 'action': 'runTestCase', + 'action': 'run_test_case', 'args': { 'opts': {}, 'testcase': 'ping' @@ -151,7 +156,7 @@ Method: GET Get the documentation of a certain test case Example:: - http://localhost:8888/yardstick/taskcases/opnfv_yardstick_tc002/docs + http://<SERVER IP>:<PORT>/yardstick/taskcases/opnfv_yardstick_tc002/docs /yardstick/testsuites/action @@ -167,10 +172,10 @@ Run a test suite Example:: { - 'action': 'runTestSuite', + 'action': 'run_test_suite', 'args': { 'opts': {}, - 'testcase': 'smoke' + 'testsuite': 'opnfv_smoke' } } @@ -178,6 +183,7 @@ This is an asynchronous API. You need to call /yardstick/results to get the resu /yardstick/tasks/<task_id>/log +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to get the real time log of test case execution. @@ -188,7 +194,7 @@ Method: GET Get real time of test case execution Example:: - http://localhost:8888/yardstick/tasks/14795be8-f144-4f54-81ce-43f4e3eab33f/log?index=0 + http://<SERVER IP>:<PORT>/yardstick/tasks/14795be8-f144-4f54-81ce-43f4e3eab33f/log?index=0 /yardstick/results @@ -203,17 +209,18 @@ Method: GET Get test results of one task Example:: - http://localhost:8888/yardstick/results?task_id=3f3f5e03-972a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/yardstick/results?task_id=3f3f5e03-972a-4847-a5f8-154f1b31db8c This API will return a list of test case result -/api/v2/yardstick/openrcs/action +/api/v2/yardstick/openrcs +^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API provides functionality of handling OpenStack credential file (openrc). For Euphrates, it supports: 1. Upload an openrc file for an OpenStack environment; -2. Update an openrc file; +2. Update an openrc; 3. Get openrc file information; 4. Delete an openrc file. @@ -252,7 +259,6 @@ Example:: "OS_PASSWORD": "console", "OS_PROJECT_DOMAIN_NAME": "default", "OS_PROJECT_NAME": "admin", - "OS_TENANT_NAME": "admin", "OS_USERNAME": "admin", "OS_USER_DOMAIN_NAME": "default" }, @@ -261,12 +267,21 @@ Example:: } +/api/v2/yardstick/openrcs/<openrc_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API provides functionality of handling OpenStack credential file (openrc). For Euphrates, it supports: + +1. Get openrc file information; +2. Delete an openrc file. + + METHOD: GET Get openrc file information Example:: - http://localhost:8888/api/v2/yardstick/openrcs/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/openrcs/5g6g3e02-155a-4847-a5f8-154f1b31db8c METHOD: DELETE @@ -275,16 +290,15 @@ METHOD: DELETE Delete openrc file Example:: - http://localhost:8888/api/v2/yardstick/openrcs/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/openrcs/5g6g3e02-155a-4847-a5f8-154f1b31db8c -/api/v2/yardstick/pods/action +/api/v2/yardstick/pods +^^^^^^^^^^^^^^^^^^^^^^ Description: This API provides functionality of handling Yardstick pod file (pod.yaml). For Euphrates, it supports: 1. Upload a pod file; -2. Get pod file information; -3. Delete an openrc file. Which API to call will depend on the parameters. @@ -304,12 +318,20 @@ Example:: } +/api/v2/yardstick/pods/<pod_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API provides functionality of handling Yardstick pod file (pod.yaml). For Euphrates, it supports: + +1. Get pod file information; +2. Delete an openrc file. + METHOD: GET Get pod file information Example:: - http://localhost:8888/api/v2/yardstick/pods/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/pods/5g6g3e02-155a-4847-a5f8-154f1b31db8c METHOD: DELETE @@ -317,16 +339,15 @@ METHOD: DELETE Delete openrc file Example:: - http://localhost:8888/api/v2/yardstick/pods/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/pods/5g6g3e02-155a-4847-a5f8-154f1b31db8c -/api/v2/yardstick/images/action +/api/v2/yardstick/images +^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to Yardstick VM images. For Euphrates, it supports: 1. Load Yardstick VM images; -2. Get image's information; -3. Delete images. Which API to call will depend on the parameters. @@ -338,16 +359,27 @@ Load VM images Example:: { - 'action': 'load_images' + 'action': 'load_image', + 'args': { + 'name': 'yardstick-image' + } } +/api/v2/yardstick/images/<image_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to Yardstick VM images. For Euphrates, it supports: + +1. Get image's information; +2. Delete images + METHOD: GET Get image information Example:: - http://localhost:8888/api/v2/yardstick/images/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/images/5g6g3e02-155a-4847-a5f8-154f1b31db8c METHOD: DELETE @@ -355,19 +387,15 @@ METHOD: DELETE Delete images Example:: - http://localhost:8888/api/v2/yardstick/images/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/images/5g6g3e02-155a-4847-a5f8-154f1b31db8c -/api/v2/yardstick/tasks/action +/api/v2/yardstick/tasks +^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to yardstick tasks. For Euphrates, it supports: 1. Create a Yardstick task; -2. run a Yardstick task; -3. Add a test case to a task; -4. Add a test suite to a task; -5. Get a tasks' information; -6. Delete a task. Which API to call will depend on the parameters. @@ -387,20 +415,35 @@ Example:: } +/api/v2/yardstick/tasks/<task_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to yardstick tasks. For Euphrates, it supports: + +1. Add a environment to a task +2. Add a test case to a task; +3. Add a test suite to a task; +4. run a Yardstick task; +5. Get a tasks' information; +6. Delete a task. + + METHOD: PUT +Add a environment to a task -Run a task Example:: { - 'action': 'run' + 'action': 'add_environment', + 'args': { + 'environment_id': 'e3cadbbb-0419-4fed-96f1-a232daa0422a' + } } METHOD: PUT - Add a test case to a task Example:: @@ -413,8 +456,8 @@ Example:: } -METHOD: PUT +METHOD: PUT Add a test suite to a task Example:: @@ -428,29 +471,41 @@ Example:: } +METHOD: PUT + +Run a task + +Example:: + + { + 'action': 'run' + } + + + METHOD: GET Get a task's information Example:: - http://localhost:8888/api/v2/yardstick/tasks/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/tasks/5g6g3e02-155a-4847-a5f8-154f1b31db8c METHOD: DELETE Delete a task + Example:: - http://localhost:8888/api/v2/yardstick/tasks/5g6g3e02-155a-4847-a5f8-154f1b31db8c + http://<SERVER IP>:<PORT>/api/v2/yardstick/tasks/5g6g3e02-155a-4847-a5f8-154f1b31db8c -/api/v2/yardstick/testcases/action +/api/v2/yardstick/testcases +^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to yardstick testcases. For Euphrates, it supports: 1. Upload a test case; 2. Get all released test cases' information; -3. Get a certain released test case's information; -4. Delete a test case. Which API to call will depend on the parameters. @@ -475,16 +530,24 @@ METHOD: GET Get all released test cases' information Example:: - http://localhost:8888/api/v2/yardstick/testcases + http://<SERVER IP>:<PORT>/api/v2/yardstick/testcases + + +/api/v2/yardstick/testcases/<case_name> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to yardstick testcases. For Euphrates, it supports: +1. Get certain released test case's information; +2. Delete a test case. METHOD: GET -Get a certain released test case's information +Get certain released test case's information Example:: - http://localhost:8888/api/v2/yardstick/testcases/opnfv_yardstick_tc002 + http://<SERVER IP>:<PORT>/api/v2/yardstick/testcases/opnfv_yardstick_tc002 METHOD: DELETE @@ -492,17 +555,16 @@ METHOD: DELETE Delete a certain test case Example:: - http://localhost:8888/api/v2/yardstick/testcases/opnfv_yardstick_tc002 + http://<SERVER IP>:<PORT>/api/v2/yardstick/testcases/opnfv_yardstick_tc002 -/api/v2/yardstick/testsuites/action +/api/v2/yardstick/testsuites +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to yardstick test suites. For Euphrates, it supports: 1. Create a test suite; -2. Get a certain test suite's information; -3. Get all test suites; -4. Delete a test case. +2. Get all test suites; Which API to call will depend on the parameters. @@ -527,19 +589,27 @@ Example:: METHOD: GET -Get a certain test suite's information +Get all test suite Example:: - http://localhost:8888/api/v2/yardstick/testsuites/<suite_name> + http://<SERVER IP>:<PORT>/api/v2/yardstick/testsuites + + +/api/v2/yardstick/testsuites +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to yardstick test suites. For Euphrates, it supports: +1. Get certain test suite's information; +2. Delete a test case. METHOD: GET -Get all test suite +Get certain test suite's information Example:: - http://localhost:8888/api/v2/yardstick/testsuites + http://<SERVER IP>:<PORT>/api/v2/yardstick/testsuites/<suite_name> METHOD: DELETE @@ -548,17 +618,16 @@ METHOD: DELETE Delete a certain test suite Example:: - http://localhost:8888/api/v2/yardstick/testsuites/<suite_name> + http://<SERVER IP>:<PORT>/api/v2/yardstick/testsuites/<suite_name> -/api/v2/yardstick/projects/action +/api/v2/yardstick/projects +^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to yardstick test projects. For Euphrates, it supports: 1. Create a Yardstick project; -2. Get a certain project's information; -3. Get all projects; -4. Delete a project. +2. Get all projects; Which API to call will depend on the parameters. @@ -580,19 +649,27 @@ Example:: METHOD: GET -Get a certain project's information +Get all projects' information Example:: - http://localhost:8888/api/v2/yardstick/projects/<project_id> + http://<SERVER IP>:<PORT>/api/v2/yardstick/projects + +/api/v2/yardstick/projects +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to yardstick test projects. For Euphrates, it supports: + +1. Get certain project's information; +2. Delete a project. METHOD: GET -Get all projects' information +Get certain project's information Example:: - http://localhost:8888/api/v2/yardstick/projects + http://<SERVER IP>:<PORT>/api/v2/yardstick/projects/<project_id> METHOD: DELETE @@ -601,17 +678,16 @@ METHOD: DELETE Delete a certain project Example:: - http://localhost:8888/api/v2/yardstick/projects/<project_id> + http://<SERVER IP>:<PORT>/api/v2/yardstick/projects/<project_id> -/api/v2/yardstick/containers/action +/api/v2/yardstick/containers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description: This API is used to do some work related to Docker containers. For Euphrates, it supports: 1. Create a Grafana Docker container; 2. Create an InfluxDB Docker container; -3. Get a certain container's information; -4. Delete a container. Which API to call will depend on the parameters. @@ -644,13 +720,21 @@ Example:: } +/api/v2/yardstick/containers/<container_id> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Description: This API is used to do some work related to Docker containers. For Euphrates, it supports: + +1. Get certain container's information; +2. Delete a container. + METHOD: GET -Get a certain container's information +Get certain container's information Example:: - http://localhost:8888/api/v2/yardstick/containers/<container_id> + http://<SERVER IP>:<PORT>/api/v2/yardstick/containers/<container_id> METHOD: DELETE @@ -659,4 +743,4 @@ METHOD: DELETE Delete a certain container Example:: - http://localhost:8888/api/v2/yardstick/containers/<container_id> + http://<SERVER IP>:<PORT>/api/v2/yardstick/containers/<container_id> diff --git a/docs/testing/user/userguide/11-nsb-overview.rst b/docs/testing/user/userguide/11-nsb-overview.rst index 8ce90f65d..332dba47d 100644 --- a/docs/testing/user/userguide/11-nsb-overview.rst +++ b/docs/testing/user/userguide/11-nsb-overview.rst @@ -197,7 +197,9 @@ VNFs supported for chracterization: 1. CGNAPT - Carrier Grade Network Address and port Translation 2. vFW - Virtual Firewall 3. vACL - Access Control List -5. Prox - Packet pROcessing eXecution engine: - - VNF can act as Drop, Basic Forwarding (no touch), L2 Forwarding (change MAC), GRE encap/decap, Load balance based on packet fields, Symmetric load balancing, +4. Prox - Packet pROcessing eXecution engine: + - VNF can act as Drop, Basic Forwarding (no touch), + L2 Forwarding (change MAC), GRE encap/decap, Load balance based on + packet fields, Symmetric load balancing - QinQ encap/decap IPv4/IPv6, ARP, QoS, Routing, Unmpls, Policing, ACL -6. UDP_Replay +5. UDP_Replay diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc019.rst b/docs/testing/user/userguide/opnfv_yardstick_tc019.rst index 57e8ddf79..8d79e011a 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc019.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc019.rst @@ -125,7 +125,12 @@ Yardstick Test Case Description TC019 +--------------+--------------------------------------------------------------+ |post-action | It is the action when the test cases exist. It will check | | | the status of the specified process on the host, and restart | -| | the process if it is not running for next test cases | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc045.rst b/docs/testing/user/userguide/opnfv_yardstick_tc045.rst index 0b0993c34..378176090 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc045.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc045.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC045 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc046.rst b/docs/testing/user/userguide/opnfv_yardstick_tc046.rst index cce6c6884..5308c8e7b 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc046.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc046.rst @@ -127,9 +127,14 @@ Yardstick Test Case Description TC046 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc047.rst b/docs/testing/user/userguide/opnfv_yardstick_tc047.rst index 95158cfd6..bb8ffc6ab 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc047.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc047.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC047 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc048.rst b/docs/testing/user/userguide/opnfv_yardstick_tc048.rst index 21c00d1fe..1bf627282 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc048.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc048.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC048 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test case | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc049.rst b/docs/testing/user/userguide/opnfv_yardstick_tc049.rst index f58bb9989..12ed94b7d 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc049.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc049.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC049 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc053.rst b/docs/testing/user/userguide/opnfv_yardstick_tc053.rst index 3c6bbc628..7308babb8 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc053.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc053.rst @@ -135,6 +135,11 @@ Yardstick Test Case Description TC053 | | the status of the specified process on the host, and restart | | | the process if it is not running for next test cases. | | | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc056.rst b/docs/testing/user/userguide/opnfv_yardstick_tc056.rst index e6e06df57..cd8cc2f20 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc056.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc056.rst @@ -10,7 +10,7 @@ Yardstick Test Case Description TC056 +-----------------------------------------------------------------------------+ |OpenStack Controller Messaging Queue Service High Availability | -+==============+==============================================================+ ++--------------+--------------------------------------------------------------+ |test case id | OPNFV_YARDSTICK_TC056:OpenStack Controller Messaging Queue | | | Service High Availability | +--------------+--------------------------------------------------------------+ @@ -142,6 +142,11 @@ Yardstick Test Case Description TC056 | | the status of the specified process on the host, and restart | | | the process if it is not running for next test cases. | | | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc057.rst b/docs/testing/user/userguide/opnfv_yardstick_tc057.rst index 2a4ce40c0..1bb43c9e7 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc057.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc057.rst @@ -10,8 +10,11 @@ Yardstick Test Case Description TC057 +-----------------------------------------------------------------------------+ |OpenStack Controller Cluster Management Service High Availability | -+==============+==============================================================+ -|test case id | | +| | ++--------------+--------------------------------------------------------------+ +|test case id | OPNFV_YARDSTICK_TC057_HA: OpenStack Controller Cluster | +| | Management Service High Availability | +| | | +--------------+--------------------------------------------------------------+ |test purpose | This test case will verify the quorum configuration of the | | | cluster manager(pacemaker) on controller nodes. When a | @@ -53,10 +56,11 @@ Yardstick Test Case Description TC057 | | "openstack-cmd" for this monitor. | | | 2) command_name: which is the command name used for request | | | | -| | In this case, the command_name of monitor1 should be services| -| | that are managed by the cluster manager. (Since rabbitmq and | -| | haproxy are managed by pacemaker, most Openstack Services | -| | can be used to check high availability in this case) | +| | In this case, the command_name of monitor1 should be | +| | services that are managed by the cluster manager. | +| | (Since rabbitmq and haproxy are managed by pacemaker, | +| | most Openstack Services can be used to check high | +| | availability in this case) | | | | | | (e.g.) | | | monitor1: | @@ -155,11 +159,17 @@ Yardstick Test Case Description TC057 | | Result: The test case is passed or not. | | | | +--------------+------+----------------------------------+--------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the cluster messaging process(corosync) on the | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the cluster messaging process(corosync) on the | | | host, and restart the process if it is not running for next | -| | test cases | +| | test cases. | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+------+----------------------------------+--------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | +| | | +--------------+--------------------------------------------------------------+ diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc058.rst b/docs/testing/user/userguide/opnfv_yardstick_tc058.rst index fb9a4c2d1..9e8427b50 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc058.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc058.rst @@ -10,8 +10,9 @@ Yardstick Test Case Description TC058 +-----------------------------------------------------------------------------+ |OpenStack Controller Virtual Router Service High Availability | -+==============+==============================================================+ -|test case id | OPNFV_YARDSTICK_TC058:OpenStack Controller Virtual Router | +| | ++--------------+--------------------------------------------------------------+ +|test case id | OPNFV_YARDSTICK_TC058: OpenStack Controller Virtual Router | | | Service High Availability | +--------------+--------------------------------------------------------------+ |test purpose | This test case will verify the high availability of virtual | @@ -108,8 +109,9 @@ Yardstick Test Case Description TC058 |conditions | with cachestat included in the image. | | | | +--------------+--------------------------------------------------------------+ -|step 1 | Two host VMs are booted, these two hosts are in two different| -| | networks, the networks are connected by a virtual router | +|step 1 | Two host VMs are booted, these two hosts are in two | +| | different networks, the networks are connected by a virtual | +| | router. | | | | +--------------+--------------------------------------------------------------+ |step 1 | start monitors: | @@ -142,7 +144,13 @@ Yardstick Test Case Description TC058 | | Virtual machines and network created in the test case will | | | be destoryed. | | | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+------+----------------------------------+--------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | +| | | +--------------+--------------------------------------------------------------+ diff --git a/etc/infra/infra_deploy.yaml.sample b/etc/infra/infra_deploy.yaml.sample index bf07a01bc..8ed793622 100644 --- a/etc/infra/infra_deploy.yaml.sample +++ b/etc/infra/infra_deploy.yaml.sample @@ -31,5 +31,11 @@ nodes: networks: - name: management + default_gateway: True host_ip: 192.168.1.1 netmask: 255.255.255.0 + + - name: traffic + default_gateway: False # This parameter is not mandatory, default value: False + host_ip: 192.20.1.1 + netmask: 255.255.255.0 diff --git a/etc/yardstick/nodes/fuel_baremetal/pod.yaml b/etc/yardstick/nodes/fuel_baremetal/pod.yaml index 5ce555293..301433d50 100644 --- a/etc/yardstick/nodes/fuel_baremetal/pod.yaml +++ b/etc/yardstick/nodes/fuel_baremetal/pod.yaml @@ -49,3 +49,16 @@ nodes: ip: ip5 user: node_username key_filename: node_keyfile +- + name: node6 + role: Opendaylight + ip: ip6 + user: node_username + key_filename: node_keyfile +- + name: node7 + role: Gateway + ip: ip7 + user: node_username + key_filename: node_keyfile + diff --git a/gui/app/index.html b/gui/app/index.html index d959b14d2..2ea1cabe7 100644 --- a/gui/app/index.html +++ b/gui/app/index.html @@ -93,6 +93,7 @@ <script src="scripts/controllers/detail.controller.js"></script> <script src="scripts/controllers/image.controller.js"></script> <script src="scripts/controllers/pod.controller.js"></script> + <script src="scripts/controllers/sut.controller.js"></script> <script src="scripts/controllers/container.controller.js"></script> <script src="scripts/controllers/testcase.controller.js"></script> <script src="scripts/controllers/testcasedetail.controller.js"></script> diff --git a/gui/app/scripts/controllers/container.controller.js b/gui/app/scripts/controllers/container.controller.js index 3ad200a91..a7d5f0309 100644 --- a/gui/app/scripts/controllers/container.controller.js +++ b/gui/app/scripts/controllers/container.controller.js @@ -127,10 +127,15 @@ angular.module('yardStickGui2App') function chooseResult(name) { $scope.selectContainer = name; } + $scope.goBack = function goBack() { $state.go('app.projectList'); } + $scope.goNext = function goNext() { + $state.go('app.sut', {uuid: $scope.uuid}); + } + $scope.openDeleteEnv = function openDeleteEnv(id, name) { $scope.deleteName = name; $scope.deleteId = id; diff --git a/gui/app/scripts/controllers/content.controller.js b/gui/app/scripts/controllers/content.controller.js index 0288fa540..90a3f1433 100644 --- a/gui/app/scripts/controllers/content.controller.js +++ b/gui/app/scripts/controllers/content.controller.js @@ -49,6 +49,7 @@ angular.module('yardStickGui2App') $scope.gotoOpenrcPage = gotoOpenrcPage; $scope.gotoPodPage = gotoPodPage; $scope.gotoContainerPage = gotoContainerPage; + $scope.gotoSUTPage = gotoSUTPage; $scope.gotoTestcase = gotoTestcase; $scope.gotoEnviron = gotoEnviron; $scope.gotoSuite = gotoSuite; @@ -95,6 +96,12 @@ angular.module('yardStickGui2App') $state.go('app.container', { uuid: $scope.uuid }); } + function gotoSUTPage() { + $scope.path = $location.path(); + $scope.uuid = $scope.path.split('/').pop(); + $state.go('app.sut', { uuid: $scope.uuid }); + } + function gotoTestcase() { $state.go('app.testcase'); } diff --git a/gui/app/scripts/controllers/main.js b/gui/app/scripts/controllers/main.js index ceec83fa9..dc5c32670 100644 --- a/gui/app/scripts/controllers/main.js +++ b/gui/app/scripts/controllers/main.js @@ -107,7 +107,7 @@ angular.module('yardStickGui2App') $scope.envInfo = [ { name: 'OS_USERNAME', value: '' }, { name: 'OS_PASSWORD', value: '' }, - { name: 'OS_TENANT_NAME', value: '' }, + { name: 'OS_PROJECT_NAME', value: '' }, { name: 'EXTERNAL_NETWORK', value: '' } ]; @@ -298,7 +298,7 @@ angular.module('yardStickGui2App') $scope.envInfo = [ { name: 'OS_USERNAME', value: '' }, { name: 'OS_PASSWORD', value: '' }, - { name: 'OS_TENANT_NAME', value: '' }, + { name: 'OS_PROJECT_NAME', value: '' }, { name: 'EXTERNAL_NETWORK', value: '' } ]; $scope.displayOpenrcFile = null; diff --git a/gui/app/scripts/controllers/projectDetail.controller.js b/gui/app/scripts/controllers/projectDetail.controller.js index e8468045d..353e02bcf 100644 --- a/gui/app/scripts/controllers/projectDetail.controller.js +++ b/gui/app/scripts/controllers/projectDetail.controller.js @@ -439,15 +439,36 @@ angular.module('yardStickGui2App') $scope.displayTable = false; $scope.contentInfo = response.result.testcase; + $scope.optionalParams = response.result.args; } }, function(error) { - toaster.pop({ - type: 'error', - title: 'fail', - body: 'unknow error', - timeout: 3000 - }); + mainFactory.errorHandler2(error); + }) + } + + + function addParamsToTask(){ + var params = {} + angular.forEach($scope.optionalParams, function(value, name){ + if(value.value){ + params[name] = value.value; + } + }); + + mainFactory.taskAddParams().put({ + 'taskId': $scope.newUUID, + 'action': 'add_params', + 'args': { + 'params': params + } + }).$promise.then(function(resp) { + if (resp.status == 1) { + } else { + mainFactory.errorHandler1(resp); + } + }, function(error) { + mainFactory.errorHandler2(error); }) } @@ -530,6 +551,7 @@ angular.module('yardStickGui2App') function confirmAddCaseOrSuite(content) { if ($scope.selectType.name == "Test Case") { addCasetoTask(content); + addParamsToTask(); } else { addSuitetoTask(content); } diff --git a/gui/app/scripts/controllers/sut.controller.js b/gui/app/scripts/controllers/sut.controller.js new file mode 100644 index 000000000..092aabc41 --- /dev/null +++ b/gui/app/scripts/controllers/sut.controller.js @@ -0,0 +1,58 @@ +'use strict'; + +angular.module('yardStickGui2App') + .controller('SUTController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', '$location', 'ngDialog', + function($scope, $state, $stateParams, mainFactory, Upload, toaster, $location, ngDialog) { + + + init(); + $scope.showloading = false; + $scope.loadingOPENrc = false; + + function init() { + + + $scope.uuid = $stateParams.uuid; + $scope.sutInfo = {}; + getItemIdDetail(); + getSUTDetail(); + + } + + function getItemIdDetail() { + mainFactory.ItemDetail().get({ + 'envId': $scope.uuid + }).$promise.then(function(response) { + if (response.status == 1) { + $scope.envName = response.result.environment.name; + }else{ + mainFactory.errorHandler1(response); + } + }, function(error) { + mainFactory.errorHandler2(error); + }) + } + + function getSUTDetail(){ + mainFactory.SUTDetail().get({ + 'envId': $scope.uuid + }).$promise.then(function(resp){ + $scope.sutInfo = resp.result.sut; + console.log($scope.sutInfo); + }, function(error){ + }) + } + + $scope.goBack = function goBack() { + $state.go('app.projectList'); + } + + + $scope.goNext = function goNext() { + $scope.path = $location.path(); + $scope.uuid = $scope.path.split('/').pop(); + $state.go('app.container', { uuid: $scope.uuid }); + } + + } + ]); diff --git a/gui/app/scripts/controllers/taskModify.controller.js b/gui/app/scripts/controllers/taskModify.controller.js index 757d65866..c9672fea8 100644 --- a/gui/app/scripts/controllers/taskModify.controller.js +++ b/gui/app/scripts/controllers/taskModify.controller.js @@ -20,6 +20,7 @@ angular.module('yardStickGui2App') $scope.constructTestSuit = constructTestSuit; $scope.constructTestCase = constructTestCase; $scope.getTestDeatil = getTestDeatil; + $scope.getTestcaseArgs = getTestcaseArgs; $scope.confirmToServer = confirmToServer; $scope.addEnvToTask = addEnvToTask; } @@ -46,6 +47,8 @@ angular.module('yardStickGui2App') getItemIdDetail($scope.taskDetailData.environment_id); } + getTestcaseArgs(); + } }, function(error) { toaster.pop({ @@ -277,7 +280,6 @@ angular.module('yardStickGui2App') function getTestDeatil() { - if ($scope.selectType.name == 'Test Case') { getTestcaseDetail(); } else { @@ -307,6 +309,29 @@ angular.module('yardStickGui2App') } + function getTestcaseArgs(){ + mainFactory.getTestcaseDetail().get({ + 'testcasename': $scope.taskDetailData.case_name + }).$promise.then(function(resp){ + if(resp.status == 1){ + $scope.optionalParams = resp.result.args; + var params = $scope.taskDetailData.params; + if(params){ + angular.forEach($scope.optionalParams, function(value, name){ + if(name in params){ + value.value = params[name]; + } + }); + } + }else{ + mainFactory.errorHandler1(resp); + } + }, function(error){ + mainFactory.errorHandler2(error); + }); + } + + function getTestcaseDetail() { mainFactory.getTestcaseDetail().get({ 'testcasename': $scope.selectCase @@ -316,15 +341,13 @@ angular.module('yardStickGui2App') $scope.displayTable = false; $scope.contentInfo = response.result.testcase; + $scope.optionalParams = response.result.args; + }else{ + mainFactory.errorHandler1(response); } }, function(error) { - toaster.pop({ - type: 'error', - title: 'fail', - body: 'unknow error', - timeout: 3000 - }); + mainFactory.errorHandler2(error); }) } @@ -426,12 +449,38 @@ angular.module('yardStickGui2App') if ($scope.selectCase == 'Test Case' || $scope.taskDetailData.suite == false) { addCasetoTask(content); + addParamsToTask(); } else { addSuitetoTask(content); } } + function addParamsToTask(){ + var params = {} + angular.forEach($scope.optionalParams, function(value, name){ + if(value.value){ + params[name] = value.value; + } + }); + + mainFactory.taskAddParams().put({ + 'taskId': $stateParams.taskId, + 'action': 'add_params', + 'args': { + 'params': params + } + }).$promise.then(function(resp) { + if (resp.status == 1) { + } else { + mainFactory.errorHandler1(resp); + } + }, function(error) { + mainFactory.errorHandler2(error); + }) + } + + function addEnvToTask() { mainFactory.taskAddEnv().put({ diff --git a/gui/app/scripts/factory/main.factory.js b/gui/app/scripts/factory/main.factory.js index 7637a9ff3..f75369336 100644 --- a/gui/app/scripts/factory/main.factory.js +++ b/gui/app/scripts/factory/main.factory.js @@ -58,6 +58,13 @@ angular.module('yardStickGui2App') } }) }, + SUTDetail: function() { + return $resource(Base_URL + '/api/v2/yardstick/environments/:envId/sut', { envId: "@envId" }, { + 'get': { + method: 'GET' + } + }) + }, ImageDetail: function() { return $resource(Base_URL + '/api/v2/yardstick/images/:image_id', { image_id: "@image_id" }, { 'get': { @@ -214,6 +221,14 @@ angular.module('yardStickGui2App') } }) }, + + taskAddParams: function() { + return $resource(Base_URL + '/api/v2/yardstick/tasks/:taskId', { taskId: "@taskId" }, { + 'put': { + method: 'PUT' + } + }) + }, //delete operate deleteEnv: function() { return $resource(Base_URL + '/api/v2/yardstick/environments/:env_id', { env_id: '@env_id' }, { diff --git a/gui/app/scripts/router.config.js b/gui/app/scripts/router.config.js index da2eb086b..75d5372fb 100644 --- a/gui/app/scripts/router.config.js +++ b/gui/app/scripts/router.config.js @@ -116,6 +116,15 @@ angular.module('yardStickGui2App') label: 'Container Manage' } }) + .state('app.sut', { + url: '/envsut/:uuid', + templateUrl: 'views/sut.html', + controller: 'SUTController', + params: { uuid: null }, + ncyBreadcrumb: { + label: 'SUT Manage' + } + }) .state('app.projectList', { url: '/project', templateUrl: 'views/projectList.html', diff --git a/gui/app/views/container.html b/gui/app/views/container.html index b3d78bfb1..ea5902996 100644 --- a/gui/app/views/container.html +++ b/gui/app/views/container.html @@ -5,7 +5,7 @@ <div style="width:750px;"> <h3>{{envName}} -- Container - <!--<button class="btn btn-default" style="float:right">Go Next</button>--> + <button class="btn btn-default" ng-click="goNext()" style="float:right">Next</button> </h3> <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>--> diff --git a/gui/app/views/layout/sideNav.html b/gui/app/views/layout/sideNav.html index 6c4426307..2333d22d5 100644 --- a/gui/app/views/layout/sideNav.html +++ b/gui/app/views/layout/sideNav.html @@ -42,6 +42,9 @@ <div class="panel-body " style="border:none;text-align: right;cursor:pointer" ng-click="gotoContainerPage()" ng-class="{active:$state.includes('app.container')}"> Container </div> + <div class="panel-body " style="border:none;text-align: right;cursor:pointer" ng-click="gotoSUTPage()" ng-class="{active:$state.includes('app.sut')}"> + SUT + </div> <div class="panel-body " style="border:none;text-align: right;"> Others </div> @@ -151,4 +154,4 @@ .active.panel-body { background-color: #dfe3e4; } -</style>
\ No newline at end of file +</style> diff --git a/gui/app/views/modal/taskCreate.html b/gui/app/views/modal/taskCreate.html index 2d7f1dc3b..ab6ff0ca1 100644 --- a/gui/app/views/modal/taskCreate.html +++ b/gui/app/views/modal/taskCreate.html @@ -80,13 +80,20 @@ </div> </div> - <div ng-show="displayTable==false"> - <textarea ng-model="contentInfo" spellcheck="false"> - - - </textarea> - + <div ng-show="displayTable==false" style="display:flex;flex-direction:row;justify-content:space-between;margin-top:10px;"> + <textarea class="col-md-8" ng-model="contentInfo" style="margin-top:5px;" spellcheck="false"></textarea> + <div class="col-md-4" style="border:1px solid #e8e8e8;margin-top:5px;margin-left:10px;padding-top:30px;"> + <h4>Optional Paramters:</h4> + <form class="form-horizontal col-md-offset-2" style="margin-top:20px"> + <div ng-repeat="(name, value) in optionalParams" class="form-group"> + <label for="param{{$index}}" class="col-md-5" style="font-weight:normal;">{{ name }}:</label> + <div class="col-md-5"> + <input type="text" ng-model="value.value" class="form-control" id="param{{$index}}"> + </div> + </div> + </form> + </div> </div> diff --git a/gui/app/views/sut.html b/gui/app/views/sut.html new file mode 100644 index 000000000..8cf1fcd6c --- /dev/null +++ b/gui/app/views/sut.html @@ -0,0 +1,33 @@ +<!--sut management--> + +<div class="content"> + <div style="display:flex;flex-direction:row;"> + <div style="width:750px;"> + + <h3>{{envName}} -- SUT + <!--<button class="btn btn-default" style="float:right">Go Next</button>--> + + </h3> + + <h2>Hosts</h2> + <div ng-repeat="(host, info) in sutInfo"> + <hr/> + <div class="results-table" style="margin-top:30px;"> + <table class="table table-striped table-hover"> + <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"> + <tr ng-repeat="record in info"> + <td>{{ record[0] }}</td> + <td>{{ record[1] }}</td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </div> + +</div> +<toaster-container></toaster-container> + +<style> +</style> diff --git a/gui/app/views/taskmodify.html b/gui/app/views/taskmodify.html index d12df4ba2..24b3d945f 100644 --- a/gui/app/views/taskmodify.html +++ b/gui/app/views/taskmodify.html @@ -42,11 +42,20 @@ <button class="btn btn-default" style="float:right" ng-disabled="sourceShow==null" ng-click="confirmToServer(contentInfo,taskDetailData.content)">Confirm</button> </div> - - <textarea ng-model="taskDetailData.content" ng-show="sourceShow==false" style="margin-top:5px;" spellcheck="false"> - - - </textarea> + <div ng-show="sourceShow==false" style="display:flex;flex-direction:row;justify-content:space-between;margin-top:10px;"> + <textarea class="col-md-8" ng-model="taskDetailData.content" style="margin-top:5px;" spellcheck="false"></textarea> + <div class="col-md-4" style="border:1px solid #e8e8e8;margin-top:5px;margin-left:10px;padding-top:30px;"> + <h4>Optional Paramters:</h4> + <form class="form-horizontal col-md-offset-2" style="margin-top:20px"> + <div ng-repeat="(name, value) in optionalParams" class="form-group"> + <label for="param{{$index}}" class="col-md-5" style="font-weight:normal;">{{ name }}:</label> + <div class="col-md-5"> + <input type="text" ng-model="value.value" class="form-control" id="param{{$index}}"> + </div> + </div> + </form> + </div> + </div> <div ng-show="sourceShow==true"> <div style="display:flex;flex-direction:row"> @@ -102,9 +111,7 @@ <div ng-show="displayTable==false"> <textarea ng-model="contentInfo" spellcheck="false"> - </textarea> - - + </textarea> </div> </div> diff --git a/requirements.txt b/requirements.txt index aacafdf93..d45e4b149 100644 --- a/requirements.txt +++ b/requirements.txt @@ -37,11 +37,13 @@ os-client-config==1.28.0 # OSI Approved Apache Software License osc-lib==1.7.0 # OSI Approved Apache Software License oslo.config==4.11.1 # OSI Approved Apache Software License oslo.i18n==3.17.0 # OSI Approved Apache Software License +oslo.privsep===1.22.1 # OSI Approved Apache Software License oslo.serialization==2.20.1 # OSI Approved Apache Software License oslo.utils==3.28.0 # OSI Approved Apache Software License paramiko==2.2.1 # LGPL; OSI Approved GNU Library or Lesser General Public License (LGPL) pbr==3.1.1 # OSI Approved Apache Software License; Apache License, Version 2.0 pika==0.10.0 # BSD; OSI Approved BSD License +pip==9.0.1;python_version=='2.7' # MIT positional==1.1.2 # OSI Approved Apache Software License pycrypto==2.6.1 # Public Domain pyparsing==2.2.0 # MIT License; OSI Approved MIT License diff --git a/samples/MoongenL2fwd.yaml b/samples/MoongenL2fwd.yaml new file mode 100644 index 000000000..8c00bfec6 --- /dev/null +++ b/samples/MoongenL2fwd.yaml @@ -0,0 +1,96 @@ +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# 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. + +# VSPERF specific configuration file for execution of RFC2544 throughput +# traffic. Traffic executed by traffic generator is forwarded directly +# between interfaces connected to the traffic generator. So test will only +# benchmark the performance of OVS external bridge at controller node. +# Details about supported test options and test case execution can be +# found in VSPERF documentation: +# +# http://artifacts.opnfv.org/vswitchperf/docs/userguide/yardstick.html + +schema: "yardstick:task:0.1" + +scenarios: +{% for multistream in [1, 1000] %} +- + type: MoongenTestPMD + options: + multistream: {{multistream}} + frame_size: 1024 + testpmd_queue: 2 + trafficgen_port1: 'ens4' + trafficgen_port2: 'ens5' + moongen_host_user: 'root' + moongen_host_passwd: 'root' + moongen_host_ip: '192.168.37.2' + moongen_dir: '/home/lua-trafficgen' + moongen_runBidirec: 'true' + Package_Loss: 0 + SearchRuntime: 60 + moongen_port1_mac: '88:cf:98:2f:4d:ed' + moongen_port2_mac: '88:cf:98:2f:4d:ee' + forward_type: 'l2fwd' + + host: testpmd.demo + + runner: + type: Sequence + scenario_option_name: frame_size + sequence: + - 64 + + sla: + # The throughput SLA (or any other SLA) cannot be set to a meaningful + # value without knowledge of the server and networking environment, + # possibly including prior testing in that environment to establish + # a baseline SLA level under well-understood circumstances. + throughput_rx_mpps: 0.5 +{% endfor %} + +context: + name: demo + image: yardstick-image + flavor: + vcpus: 10 + ram: 20480 + disk: 6 + extra_specs: + hw:mem_page_size: "1GB" + hw:cpu_policy: "dedicated" + hw:vif_multiqueue_enabled: "true" + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + testpmd: + floating_ip: true + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' + test2: + cidr: '10.0.2.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + test3: + cidr: '10.0.3.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' diff --git a/samples/MoongenTestPMD.yaml b/samples/MoongenTestPMD.yaml new file mode 100644 index 000000000..b389a19bc --- /dev/null +++ b/samples/MoongenTestPMD.yaml @@ -0,0 +1,106 @@ +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# 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. + +# VSPERF specific configuration file for execution of RFC2544 throughput +# traffic. Traffic executed by traffic generator is forwarded directly +# between interfaces connected to the traffic generator. So test will only +# benchmark the performance of OVS external bridge at controller node. +# Details about supported test options and test case execution can be +# found in VSPERF documentation: +# +# http://artifacts.opnfv.org/vswitchperf/docs/userguide/yardstick.html + +schema: "yardstick:task:0.1" + +scenarios: +{% for multistream in [1, 1000] %} +- + type: MoongenTestPMD + options: + multistream: {{multistream}} + frame_size: 1024 + testpmd_queue: 2 + trafficgen_port1: 'ens5' + trafficgen_port2: 'ens6' + moongen_host_user: 'root' + moongen_host_passwd: 'root' + moongen_host_ip: '192.168.37.2' + moongen_dir: '/home/lua-trafficgen' + moongen_runBidirec: 'true' + Package_Loss: 0 + SearchRuntime: 60 + moongen_port1_mac: '88:cf:98:2f:4d:ed' + moongen_port2_mac: '88:cf:98:2f:4d:ee' + forward_type: 'testpmd' + + host: testpmd.demo + + runner: + type: Sequence + scenario_option_name: frame_size + sequence: + - 64 + + sla: + # The throughput SLA (or any other SLA) cannot be set to a meaningful + # value without knowledge of the server and networking environment, + # possibly including prior testing in that environment to establish + # a baseline SLA level under well-understood circumstances. + throughput_rx_mpps: 0.5 +{% endfor %} + +context: + name: demo + #image: yardstick-image + image: yardstick-nsb-image + flavor: + vcpus: 10 + ram: 20480 + disk: 6 + extra_specs: + hw:mem_page_size: "1GB" + hw:cpu_policy: "dedicated" + hw:vif_multiqueue_enabled: "true" + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + testpmd: + floating_ip: true + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' + provider: "sriov" + physical_network: "sriov2" + segmentation_id: "1063" + test2: + cidr: '10.0.2.0/24' + gateway_ip: 'null' + provider: "sriov" + physical_network: "sriov2" + segmentation_id: "1061" + #port_security_enabled: False + enable_dhcp: 'false' + test3: + cidr: '10.0.3.0/24' + provider: "sriov" + physical_network: "sriov2" + segmentation_id: "1062" + gateway_ip: 'null' + #port_security_enabled: False + enable_dhcp: 'false' diff --git a/samples/dummy.yaml b/samples/dummy.yaml index fde2907cd..2921f5d3f 100644 --- a/samples/dummy.yaml +++ b/samples/dummy.yaml @@ -22,4 +22,5 @@ scenarios: context: type: Dummy + name: Dummy diff --git a/samples/netperf_soak.yaml b/samples/netperf_soak.yaml new file mode 100644 index 000000000..a7344dae2 --- /dev/null +++ b/samples/netperf_soak.yaml @@ -0,0 +1,71 @@ +############################################################################## +# 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 +############################################################################## +--- +# Bottlenecks long duration test need Yardstick to create VM pairs and use netperf sending messages +# This yaml file for the above operations based on Netperf mode similiar as netperf.yaml +# UDP_STREAM is used and out_opt is customized + +schema: "yardstick:task:0.1" + +{% set tx_msg_size = tx_msg_size or "8K" %} +{% set rx_msg_size = rx_msg_size or "8K" %} +{% set test_time = test_time or "10" %} +{% set out_opt = out_opt or "THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY,LOCAL_CPU_UTIL,REMOTE_CPU_UTIL,LOCAL_BYTES_SENT,REMOTE_BYTES_RECVD" %} +{% set image_name = image_name or "yardstick-image" %} +{% set cpu_num = cpu_num or 1 %} +{% set ram_num = ram_num or 512 %} +{% set disk_num = disk_num or 7 %} + +scenarios: +- + type: Netperf + options: + testname: 'UDP_STREAM' + send_msg_size: {{tx_msg_size}} + recv_msg_size: {{rx_msg_size}} + duration: {{test_time}} + output_opt: {{out_opt}} + + host: netperf-host.demo + target: netperf-target.demo + + runner: + type: Iteration + iterations: 1 + interval: 1 + run_step: 'setup,run' + + sla: + mean_latency: 100 + action: monitor + +context: + name: demo + image: {{image_name}} + flavor: + vcpus: {{cpu_num}} + ram: {{ram_num}} + disk: {{disk_num}} + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + netperf-host: + floating_ip: true + placement: "pgrp1" + netperf-target: + floating_ip: false + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' diff --git a/samples/ping-mixed-network.yaml b/samples/ping-mixed-network.yaml new file mode 100644 index 000000000..76e05c9aa --- /dev/null +++ b/samples/ping-mixed-network.yaml @@ -0,0 +1,65 @@ +############################################################################## +## 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 network latency using ping +# This test case sample uses existing network to be public network, +# and also create the private network by heat like normal ping. + +schema: "yardstick:task:0.1" + +{% set public_net = public_net or 'public' %} +{% set public_subnet = public_subnet or 'public_subnet' %} +{% set provider = provider or none %} +{% set physical_network = physical_network or 'physnet1' %} +{% set segmentation_id = segmentation_id or none %} + +scenarios: +- + type: Ping + options: + packetsize: 200 + host: athena.demo + target: ares.demo + + runner: + type: Duration + duration: 60 + interval: 1 + + sla: + max_rtt: 10 + action: monitor + +context: + name: demo + image: yardstick-image + flavor: yardstick-flavor + user: ubuntu + + servers: + athena: + ares: + + networks: + test: + cidr: '10.0.1.0/24' + {% if provider == "vlan" %} + provider: {{provider}} + physical_network: {{physical_network}} + {% if segmentation_id %} + segmentation_id: {{segmentation_id}} + {% endif %} + {% endif %} + + {{ public_net }}: + net_flags: + is_existing: true + is_public: true + subnet: {{ public_subnet }} diff --git a/samples/ping-one-exising-network.yaml b/samples/ping-one-exising-network.yaml new file mode 100644 index 000000000..9e33148d6 --- /dev/null +++ b/samples/ping-one-exising-network.yaml @@ -0,0 +1,50 @@ +############################################################################## +## 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 network latency using ping +# This sample use one existing network as both public network and private network. + +schema: "yardstick:task:0.1" + +{% set public_net = public_net or 'public' %} +{% set public_subnet = public_subnet or 'public_subnet' %} + +scenarios: +- + type: Ping + options: + packetsize: 200 + host: athena.demo + target: ares.demo + + runner: + type: Duration + duration: 60 + interval: 1 + + sla: + max_rtt: 10 + action: monitor + +context: + name: demo + image: yardstick-image + flavor: yardstick-flavor + user: ubuntu + + servers: + athena: + ares: + + networks: + {{ public_net }}: + net_flags: + is_existing: true + subnet: {{ public_subnet }} diff --git a/samples/ping-two-exising-network.yaml b/samples/ping-two-exising-network.yaml new file mode 100644 index 000000000..adea43ef5 --- /dev/null +++ b/samples/ping-two-exising-network.yaml @@ -0,0 +1,58 @@ +############################################################################## +## 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 network latency using ping +# This sample use two existing network, one as public network to replace for +# floating ip, one as private network to ping between VMs. + +schema: "yardstick:task:0.1" + +{% set private_net = private_net or 'private' %} +{% set private_subnet = private_subnet or 'private_subnet' %} +{% set public_net = public_net or 'public' %} +{% set public_subnet = public_subnet or 'public_subnet' %} + +scenarios: +- + type: Ping + options: + packetsize: 200 + host: athena.demo + target: ares.demo + + runner: + type: Duration + duration: 60 + interval: 1 + + sla: + max_rtt: 10 + action: monitor + +context: + name: demo + image: yardstick-image + flavor: yardstick-flavor + user: ubuntu + + servers: + athena: + ares: + + networks: + {{ private_net }}: + net_flags: + is_existing: true + subnet: {{ private_subnet }} + {{ public_net }}: + net_flags: + is_existing: true + is_public: true + subnet: {{ public_subnet }} diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-2.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-2.yaml index b1fef6d45..69778ed8c 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-2.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-2.yaml @@ -26,6 +26,8 @@ scenarios: vnf__0: vnf_0.yardstick options: + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: "configs/handle_l2fwd-2.cfg" diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-4.yaml index e17c5c2a1..ab067a836 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-4.yaml @@ -26,6 +26,8 @@ scenarios: vnf__0: vnf_0.yardstick options: + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: "configs/handle_l2fwd-4.cfg" diff --git a/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_scale-up.yaml b/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_scale-up.yaml new file mode 100644 index 000000000..eaeee7103 --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_scale-up.yaml @@ -0,0 +1,89 @@ +# Copyright (c) 2016-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. +{% set mem = mem or 20480 %} +{% set vcpus = vcpus or 10 %} +{% set vports = vports or 2 %} +--- +schema: yardstick:task:0.1 +scenarios: +- type: NSPerf + traffic_profile: ../../traffic_profiles/ipv4_throughput-scale-up.yaml + extra_args: + vports: {{ vports }} + topology: vfw-tg-topology-scale-up.yaml + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + options: + framesize: + uplink: {64B: 100} + downlink: {64B: 100} + flow: + src_ip: [ +{% for vport in range(0,vports,2|int) %} + {'tg__0': 'xe{{vport}}'}, +{% endfor %} ] + dst_ip: [ +{% for vport in range(1,vports,2|int) %} + {'tg__0': 'xe{{vport}}'}, +{% endfor %} ] + count: 1 + traffic_type: 4 + rfc2544: + allowed_drop_rate: 0.0001 - 0.0001 + vnf__0: + rules: acl_1rule.yaml + vnf_config: {lb_config: 'SW', file: vfw_vnf_pipeline_cores_{{vcpus}}_ports_{{vports}}_lb_1_sw.conf } + runner: + type: Iteration + iterations: 10 + interval: 35 +context: + # put node context first, so we don't HEAT deploy if node has errors + name: yardstick + image: yardstick-samplevnfs + flavor: + vcpus: {{ vcpus }} + ram: {{ mem }} + disk: 6 + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: {{ vcpus }} + hw:cpu_threads: 1 + user: ubuntu + placement_groups: + pgrp1: + policy: "availability" + servers: + tg_0: + floating_ip: true + placement: "pgrp1" + vnf_0: + floating_ip: true + placement: "pgrp1" + networks: + mgmt: + cidr: '10.0.1.0/24' +{% for vport in range(1,vports,2|int) %} + uplink_{{loop.index0}}: + cidr: '10.1.{{vport}}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + downlink_{{loop.index0}}: + cidr: '10.1.{{vport+1}}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' +{% endfor %} diff --git a/samples/vnf_samples/nsut/vfw/vfw-tg-topology-scale-up.yaml b/samples/vnf_samples/nsut/vfw/vfw-tg-topology-scale-up.yaml new file mode 100644 index 000000000..d4bf8d6d1 --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/vfw-tg-topology-scale-up.yaml @@ -0,0 +1,52 @@ +# Copyright (c) 2016-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. +--- +{% set vports = get(extra_args, 'vports', '2') %} +nsd:nsd-catalog: + nsd: + - id: 3tg-topology + name: 3tg-topology + short-name: 3tg-topology + description: 3tg-topology + constituent-vnfd: + - member-vnf-index: '1' + vnfd-id-ref: tg__0 + VNF model: ../../vnf_descriptors/tg_rfc2544_tpl.yaml #VNF type + - member-vnf-index: '2' + vnfd-id-ref: vnf__0 + VNF model: ../../vnf_descriptors/vfw_vnf.yaml #VNF type + + vld: +{% for vport in range(0,vports,2|int) %} + - id: uplink_{{loop.index0}} + name: tg__0 to vnf__0 link {{vport + 1}} + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: xe{{vport}} + vnfd-id-ref: tg__0 + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: xe{{vport}} + vnfd-id-ref: vnf__0 + - id: downlink_{{loop.index0}} + name: vnf__0 to tg__0 link {{vport + 2}} + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: xe{{vport+1}} + vnfd-id-ref: vnf__0 + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: xe{{vport+1}} + vnfd-id-ref: tg__0 +{% endfor %} diff --git a/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_4_ports_2_lb_1_sw.conf b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_4_ports_2_lb_1_sw.conf new file mode 100644 index 000000000..b31d0546c --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_4_ports_2_lb_1_sw.conf @@ -0,0 +1,52 @@ +[PIPELINE0] +type = MASTER +core = 0 + +[PIPELINE1] +type = ARPICMP +core = 0 +pktq_in = SWQ0 +pktq_out = SWQ1 +pktq_in_prv = RXQ1.0 +prv_to_pub_map = (1,0) + +[PIPELINE2] +type = TXRX +core = 1 +pipeline_txrx_type = RXRX +dest_if_offset = 176 +pktq_in = RXQ1.0 RXQ0.0 +pktq_out = SWQ2 SWQ3 SWQ0 + +[PIPELINE3] +type = LOADB +core = 2 +pktq_in = SWQ2 SWQ3 +pktq_out = SWQ4 SWQ5 +outport_offset = 136 +n_vnf_threads = 1 +n_lb_tuples = 5 +loadb_debug = 0 +lib_arp_debug = 0 +prv_que_handler = (0,) + +[PIPELINE4] +type = VFW +core = 3 +pktq_in = SWQ4 SWQ5 +pktq_out = SWQ6 SWQ7 +n_rules = 10 +prv_que_handler = (0) +n_flows = 2000000 +traffic_type = 4 +pkt_type = ipv4 +tcp_be_liberal = 0 + +[PIPELINE5] +type = TXRX +core = 1 +pipeline_txrx_type = TXTX +dest_if_offset = 176 +pktq_in = SWQ6 SWQ7 SWQ1 +pktq_out = TXQ1.0 TXQ0.0 + diff --git a/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_4_ports_4_lb_1_sw.conf b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_4_ports_4_lb_1_sw.conf new file mode 100644 index 000000000..3bf8dc68b --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_4_ports_4_lb_1_sw.conf @@ -0,0 +1,52 @@ + +[PIPELINE0] +type = MASTER +core = 0 + +[PIPELINE1] +type = ARPICMP +core = 0 +pktq_in = SWQ0 +pktq_out = SWQ1 +pktq_in_prv = RXQ2.0 RXQ3.0 +prv_to_pub_map = (2,0)(3,1) + +[PIPELINE2] +type = TXRX +core = 1 +pipeline_txrx_type = RXRX +dest_if_offset = 176 +pktq_in = RXQ2.0 RXQ0.0 RXQ3.0 RXQ1.0 +pktq_out = SWQ2 SWQ3 SWQ4 SWQ5 SWQ0 + +[PIPELINE3] +type = LOADB +core = 2 +pktq_in = SWQ2 SWQ3 SWQ4 SWQ5 +pktq_out = SWQ6 SWQ7 SWQ8 SWQ9 +outport_offset = 136 +n_vnf_threads = 1 +n_lb_tuples = 5 +loadb_debug = 0 +lib_arp_debug = 0 +prv_que_handler = (0,2,) + +[PIPELINE4] +type = VFW +core = 3 +pktq_in = SWQ6 SWQ7 SWQ8 SWQ9 +pktq_out = SWQ10 SWQ11 SWQ12 SWQ13 +n_rules = 10 +prv_que_handler = (0) +n_flows = 2000000 +traffic_type = 4 +pkt_type = ipv4 +tcp_be_liberal = 0 + +[PIPELINE5] +type = TXRX +core = 1 +pipeline_txrx_type = TXTX +dest_if_offset = 176 +pktq_in = SWQ10 SWQ11 SWQ12 SWQ13 SWQ1 +pktq_out = TXQ2.0 TXQ0.0 TXQ3.0 TXQ1.0 diff --git a/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_6_ports_6_lb_1_sw.conf b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_6_ports_6_lb_1_sw.conf new file mode 100644 index 000000000..1d55d8855 --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_6_ports_6_lb_1_sw.conf @@ -0,0 +1,51 @@ +[PIPELINE0] +type = MASTER +core = 0 + +[PIPELINE1] +type = ARPICMP +core = 0 +pktq_in = SWQ0 +pktq_out = SWQ1 +pktq_in_prv = RXQ5.0 RXQ3.0 RXQ4.0 +prv_to_pub_map = (5,2)(3,0)(4,1) + +[PIPELINE2] +type = TXRX +core = 1 +pipeline_txrx_type = RXRX +dest_if_offset = 176 +pktq_in = RXQ5.0 RXQ2.0 RXQ3.0 RXQ0.0 RXQ4.0 RXQ1.0 +pktq_out = SWQ2 SWQ3 SWQ4 SWQ5 SWQ6 SWQ7 SWQ0 + +[PIPELINE3] +type = LOADB +core = 2 +pktq_in = SWQ2 SWQ3 SWQ4 SWQ5 SWQ6 SWQ7 +pktq_out = SWQ8 SWQ9 SWQ10 SWQ11 SWQ12 SWQ13 +outport_offset = 136 +n_vnf_threads = 1 +n_lb_tuples = 5 +loadb_debug = 0 +lib_arp_debug = 0 +prv_que_handler = (0,2,4,) + +[PIPELINE4] +type = VFW +core = 3 +pktq_in = SWQ8 SWQ9 SWQ10 SWQ11 SWQ12 SWQ13 +pktq_out = SWQ14 SWQ15 SWQ16 SWQ17 SWQ18 SWQ19 +n_rules = 10 +prv_que_handler = (0) +n_flows = 2000000 +traffic_type = 4 +pkt_type = ipv4 +tcp_be_liberal = 0 + +[PIPELINE5] +type = TXRX +core = 1 +pipeline_txrx_type = TXTX +dest_if_offset = 176 +pktq_in = SWQ14 SWQ15 SWQ16 SWQ17 SWQ18 SWQ19 SWQ1 +pktq_out = TXQ5.0 TXQ2.0 TXQ3.0 TXQ0.0 TXQ4.0 TXQ1.0 diff --git a/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_6_ports_8_lb_1_sw.conf b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_6_ports_8_lb_1_sw.conf new file mode 100644 index 000000000..8434fee34 --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_6_ports_8_lb_1_sw.conf @@ -0,0 +1,52 @@ +[PIPELINE0] +type = MASTER +core = 0 + +[PIPELINE1] +type = ARPICMP +core = 0 +pktq_in = SWQ0 +pktq_out = SWQ1 +pktq_in_prv = RXQ6.0 RXQ7.0 RXQ4.0 RXQ5.0 +prv_to_pub_map = (6,2)(7,3)(4,0)(5,1) + +[PIPELINE2] +type = TXRX +core = 1 +pipeline_txrx_type = RXRX +dest_if_offset = 176 +pktq_in = RXQ6.0 RXQ2.0 RXQ7.0 RXQ3.0 RXQ4.0 RXQ0.0 RXQ5.0 RXQ1.0 +pktq_out = SWQ2 SWQ3 SWQ4 SWQ5 SWQ6 SWQ7 SWQ8 SWQ9 SWQ0 + +[PIPELINE3] +type = LOADB +core = 2 +pktq_in = SWQ2 SWQ3 SWQ4 SWQ5 SWQ6 SWQ7 SWQ8 SWQ9 +pktq_out = SWQ10 SWQ11 SWQ12 SWQ13 SWQ14 SWQ15 SWQ16 SWQ17 +outport_offset = 136 +n_vnf_threads = 1 +n_lb_tuples = 5 +loadb_debug = 0 +lib_arp_debug = 0 +prv_que_handler = (0,2,4,6,) + +[PIPELINE4] +type = VFW +core = 3 +pktq_in = SWQ10 SWQ11 SWQ12 SWQ13 SWQ14 SWQ15 SWQ16 SWQ17 +pktq_out = SWQ18 SWQ19 SWQ20 SWQ21 SWQ22 SWQ23 SWQ24 SWQ25 +n_rules = 10 +prv_que_handler = (0) +n_flows = 2000000 +traffic_type = 4 +pkt_type = ipv4 +tcp_be_liberal = 0 + +[PIPELINE5] +type = TXRX +core = 1 +pipeline_txrx_type = TXTX +dest_if_offset = 176 +pktq_in = SWQ18 SWQ19 SWQ20 SWQ21 SWQ22 SWQ23 SWQ24 SWQ25 SWQ1 +pktq_out = TXQ6.0 TXQ2.0 TXQ7.0 TXQ3.0 TXQ4.0 TXQ0.0 TXQ5.0 TXQ1.0 + diff --git a/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_8_ports_10_lb_1_sw.conf b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_8_ports_10_lb_1_sw.conf new file mode 100644 index 000000000..51d97e0f8 --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/vfw_vnf_pipeline_cores_8_ports_10_lb_1_sw.conf @@ -0,0 +1,52 @@ +[PIPELINE0] +type = MASTER +core = 0 + +[PIPELINE1] +type = ARPICMP +core = 0 +pktq_in = SWQ0 +pktq_out = SWQ1 +pktq_in_prv = RXQ7.0 RXQ8.0 RXQ5.0 RXQ6.0 RXQ9.0 +prv_to_pub_map = (7,2)(8,3)(5,0)(6,1)(9,4) + +[PIPELINE2] +type = TXRX +core = 1 +pipeline_txrx_type = RXRX +dest_if_offset = 176 +pktq_in = RXQ7.0 RXQ2.0 RXQ8.0 RXQ3.0 RXQ5.0 RXQ0.0 RXQ6.0 RXQ1.0 RXQ9.0 RXQ4.0 +pktq_out = SWQ2 SWQ3 SWQ4 SWQ5 SWQ6 SWQ7 SWQ8 SWQ9 SWQ10 SWQ11 SWQ0 + +[PIPELINE3] +type = LOADB +core = 2 +pktq_in = SWQ2 SWQ3 SWQ4 SWQ5 SWQ6 SWQ7 SWQ8 SWQ9 SWQ10 SWQ11 +pktq_out = SWQ12 SWQ13 SWQ14 SWQ15 SWQ16 SWQ17 SWQ18 SWQ19 SWQ20 SWQ21 +outport_offset = 136 +n_vnf_threads = 1 +n_lb_tuples = 5 +loadb_debug = 0 +lib_arp_debug = 0 +prv_que_handler = (0,2,4,6,8,) + +[PIPELINE4] +type = VFW +core = 3 +pktq_in = SWQ12 SWQ13 SWQ14 SWQ15 SWQ16 SWQ17 SWQ18 SWQ19 SWQ20 SWQ21 +pktq_out = SWQ22 SWQ23 SWQ24 SWQ25 SWQ26 SWQ27 SWQ28 SWQ29 SWQ30 SWQ31 +n_rules = 10 +prv_que_handler = (0) +n_flows = 2000000 +traffic_type = 4 +pkt_type = ipv4 +tcp_be_liberal = 0 + +[PIPELINE5] +type = TXRX +core = 1 +pipeline_txrx_type = TXTX +dest_if_offset = 176 +pktq_in = SWQ22 SWQ23 SWQ24 SWQ25 SWQ26 SWQ27 SWQ28 SWQ29 SWQ30 SWQ31 SWQ1 +pktq_out = TXQ7.0 TXQ2.0 TXQ8.0 TXQ3.0 TXQ5.0 TXQ0.0 TXQ6.0 TXQ1.0 TXQ9.0 TXQ4.0 + diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-up.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-up.yaml new file mode 100644 index 000000000..d2cc18c15 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-up.yaml @@ -0,0 +1,102 @@ +# Copyright (c) 2016-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. + +# flow definition for ACL tests - 1K flows - ipv4 only +# +# the number of flows defines the widest range of parameters +# for example if srcip_range=1.0.0.1-1.0.0.255 and dst_ip_range=10.0.0.1-10.0.1.255 +# and it should define only 16 flows +# +# there is assumption that packets generated will have a random sequences of following addresses pairs +# in the packets +# 1. src=1.x.x.x(x.x.x =random from 1..255) dst=10.x.x.x (random from 1..512) +# 2. src=1.x.x.x(x.x.x =random from 1..255) dst=10.x.x.x (random from 1..512) +# ... +# 512. src=1.x.x.x(x.x.x =random from 1..255) dst=10.x.x.x (random from 1..512) +# +# not all combination should be filled +# Any other field with random range will be added to flow definition +# +# the example.yaml provides all possibilities for traffic generation +# +# the profile defines a public and private side to make limited traffic correlation +# between private and public side same way as it is made by IXIA solution. +# +{% set vports = get(extra_args, 'vports', '2') %} +--- +schema: "nsb:traffic_profile:0.1" + +# This file is a template, it will be filled with values from tc.yaml before passing to the traffic generator + +name: rfc2544 +description: Traffic profile to run RFC2544 latency +traffic_profile: + traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput + frame_rate: 100 # pc of linerate + # that specifies a range (e.g. ipv4 address, port) +{% set count = 0 %} +{% for vport in range(vports|int) %} +uplink_{{vport}}: + ipv4: + id: {{count + 1 }} + outer_l2: + framesize: + 64B: "{{ get(imix, 'imix.uplink.64B', '0') }}" + 128B: "{{ get(imix, 'imix.uplink.128B', '0') }}" + 256B: "{{ get(imix, 'imix.uplink.256B', '0') }}" + 373b: "{{ get(imix, 'imix.uplink.373B', '0') }}" + 512B: "{{ get(imix, 'imix.uplink.512B', '0') }}" + 570B: "{{ get(imix, 'imix.uplink.570B', '0') }}" + 1400B: "{{ get(imix, 'imix.uplink.1400B', '0') }}" + 1500B: "{{ get(imix, 'imix.uplink.1500B', '0') }}" + 1518B: "{{ get(imix, 'imix.uplink.1518B', '0') }}" + outer_l3v4: + proto: "udp" + srcip4: "{{ get(flow, 'flow.src_ip_{{vport}}', '1.1.1.1-1.1.255.255') }}" + dstip4: "{{ get(flow, 'flow.dst_ip_{{vport}}', '90.90.1.1-90.90.255.255') }}" + count: "{{ get(flow, 'flow.count', '1') }}" + ttl: 32 + dscp: 0 + outer_l4: + srcport: "{{ get(flow, 'flow.src_port_{{vport}}', '1234-4321') }}" + dstport: "{{ get(flow, 'flow.dst_port_{{vport}}', '2001-4001') }}" + count: "{{ get(flow, 'flow.count', '1') }}" +downlink_{{vport}}: + ipv4: + id: {{count + 2}} + outer_l2: + framesize: + 64B: "{{ get(imix, 'imix.downlink.64B', '0') }}" + 128B: "{{ get(imix, 'imix.downlink.128B', '0') }}" + 256B: "{{ get(imix, 'imix.downlink.256B', '0') }}" + 373b: "{{ get(imix, 'imix.downlink.373B', '0') }}" + 512B: "{{ get(imix, 'imix.downlink.512B', '0') }}" + 570B: "{{ get(imix, 'imix.downlink.570B', '0') }}" + 1400B: "{{ get(imix, 'imix.downlink.1400B', '0') }}" + 1500B: "{{ get(imix, 'imix.downlink.1500B', '0') }}" + 1518B: "{{ get(imix, 'imix.downlink.1518B', '0') }}" + + outer_l3v4: + proto: "udp" + srcip4: "{{ get(flow, 'flow.dst_ip_{{vport}}', '90.90.1.1-90.90.255.255') }}" + dstip4: "{{ get(flow, 'flow.src_ip_{{vport}}', '1.1.1.1-1.1.255.255') }}" + count: "{{ get(flow, 'flow.count', '1') }}" + ttl: 32 + dscp: 0 + outer_l4: + srcport: "{{ get(flow, 'flow.dst_port_{{vport}}', '1234-4321') }}" + dstport: "{{ get(flow, 'flow.src_port_{{vport}}', '2001-4001') }}" + count: "{{ get(flow, 'flow.count', '1') }}" +{% set count = count + 2 %} +{% endfor %}
\ No newline at end of file diff --git a/test-requirements.txt b/test-requirements.txt index ee9815c45..4828e98b0 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,6 +4,7 @@ coverage==4.4.2 # Apache 2.0; OSI Approved Apache Software License; http://www.apache.org/licenses/LICENSE-2.0; http://www.apache.org/licenses/LICENSE-2.0 fixtures==3.0.0 # OSI Approved BSD License; OSI Approved Apache Software License +oslotest===2.17.1 # OSI Approved Apache Software License packaging==16.8.0 # BSD or Apache License, Version 2.0 pyflakes==1.0.0 # MIT; OSI Approved MIT License pylint==1.8.1 # GPLv2 diff --git a/tests/ci/load_images.sh b/tests/ci/load_images.sh index caaba9e8b..d723823ee 100755 --- a/tests/ci/load_images.sh +++ b/tests/ci/load_images.sh @@ -67,6 +67,7 @@ build_yardstick_image() cd ${ANSIBLE_SCRIPTS} &&\ ansible-playbook \ -e img_property="normal" \ + -e YARD_IMG_ARCH=${YARD_IMG_ARCH} \ -vvv -i inventory.ini build_yardstick_image.yml if [ ! -f "${QCOW_IMAGE}" ]; then diff --git a/tests/ci/prepare_env.sh b/tests/ci/prepare_env.sh index caef8acce..d7c60d48f 100755 --- a/tests/ci/prepare_env.sh +++ b/tests/ci/prepare_env.sh @@ -19,7 +19,8 @@ # Extract network name from EXTERNAL_NETWORK # e.g. EXTERNAL_NETWORK='ext-net;flat;192.168.0.2;192.168.0.253;192.168.0.1;192.168.0.0/24' -export EXTERNAL_NETWORK=$(echo $EXTERNAL_NETWORK | cut -f1 -d \;) +EXTERNAL_NETWORK=$(echo ${EXTERNAL_NETWORK} | cut -f1 -d \;) +export EXTERNAL_NETWORK # Create openstack credentials echo "INFO: Creating openstack credentials .." @@ -28,44 +29,22 @@ OPENRC=/etc/yardstick/openstack.creds INSTALLERS=(apex compass fuel joid) RC_VAR_EXIST=false -if [ "${OS_AUTH_URL}" -a "${OS_USERNAME}" -a "${OS_PASSWORD}" -a "${EXTERNAL_NETWORK}" ];then +if [[ "${OS_AUTH_URL}" && "${OS_USERNAME}" && "${OS_PASSWORD}" && "${EXTERNAL_NETWORK}" ]];then RC_VAR_EXIST=true fi -if [ "${RC_VAR_EXIST}" = false ]; then - if [ ! -f $OPENRC ];then - # credentials file is not given, check if environment variables are set - # to get the creds using fetch_os_creds.sh later on - echo "INFO: Checking environment variables INSTALLER_TYPE and INSTALLER_IP" - if [ -z ${INSTALLER_TYPE} ]; then - echo "environment variable 'INSTALLER_TYPE' is not defined." - exit 1 - elif [[ ${INSTALLERS[@]} =~ ${INSTALLER_TYPE} ]]; then - echo "INSTALLER_TYPE env variable found: ${INSTALLER_TYPE}" - else - echo "Invalid env variable INSTALLER_TYPE=${INSTALLER_TYPE}" - exit 1 - fi - - if [ "$DEPLOY_TYPE" == "virt" ]; then - FETCH_CRED_ARG="-v -d $OPENRC -i ${INSTALLER_TYPE} -a ${INSTALLER_IP}" - else - FETCH_CRED_ARG="-d $OPENRC -i ${INSTALLER_TYPE} -a ${INSTALLER_IP}" - fi - - $RELENG_REPO_DIR/utils/fetch_os_creds.sh $FETCH_CRED_ARG - fi - source $OPENRC +if [[ "${RC_VAR_EXIST}" = false && -f ${OPENRC} ]]; then + . ${OPENRC} fi export EXTERNAL_NETWORK INSTALLER_TYPE DEPLOY_TYPE NODE_NAME # Prepare a admin-rc file for StorPerf integration -$YARDSTICK_REPO_DIR/tests/ci/prepare_storperf_admin-rc.sh +"${YARDSTICK_REPO_DIR}"/tests/ci/prepare_storperf_admin-rc.sh # copy Storperf related files to the deployment location if [ "$INSTALLER_TYPE" == "compass" ]; then - source $YARDSTICK_REPO_DIR/tests/ci/scp_storperf_files.sh + . "${YARDSTICK_REPO_DIR}"/tests/ci/scp_storperf_files.sh fi # Fetching id_rsa file from jump_server..." @@ -73,7 +52,7 @@ verify_connectivity() { local ip=$1 echo "Verifying connectivity to $ip..." for i in $(seq 0 10); do - if ping -c 1 -W 1 $ip > /dev/null; then + if ping -c 1 -W 1 "${ip}" > /dev/null; then echo "$ip is reachable!" return 0 fi @@ -87,34 +66,42 @@ ssh_options="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" if [ "$INSTALLER_TYPE" == "fuel" ]; then # check the connection - verify_connectivity $INSTALLER_IP + verify_connectivity "${INSTALLER_IP}" pod_yaml="$YARDSTICK_REPO_DIR/etc/yardstick/nodes/fuel_baremetal/pod.yaml" # update "ip" according to the CI env - ssh -l ubuntu ${INSTALLER_IP} -i ${SSH_KEY} ${ssh_options} \ - "sudo salt -C 'ctl* or cmp*' grains.get fqdn_ip4 --out yaml">node_info + ssh -l ubuntu "${INSTALLER_IP}" -i ${SSH_KEY} ${ssh_options} \ + "sudo salt -C 'ctl* or cmp* or odl01* or gtw*' grains.get fqdn_ip4 --out yaml">node_info - controller_ips=($(cat node_info|awk '/ctl/{getline; print $2}')) - compute_ips=($(cat node_info|awk '/cmp/{getline; print $2}')) + controller_ips=($(awk '/ctl/{getline; print $2}' < node_info)) + compute_ips=($(awk '/cmp/{getline; print $2}' < node_info)) + odl_ip=($(awk '/odl01/{getline; print $2}' < node_info)) + gateway_ip=($(awk '/gtw/{getline; print $2}' < node_info)) if [[ ${controller_ips[0]} ]]; then - sed -i "s|ip1|${controller_ips[0]}|" $pod_yaml; + sed -i "s|ip1|${controller_ips[0]}|" "${pod_yaml}" fi if [[ ${controller_ips[1]} ]]; then - sed -i "s|ip2|${controller_ips[1]}|" $pod_yaml; + sed -i "s|ip2|${controller_ips[1]}|" "${pod_yaml}" fi if [[ ${controller_ips[2]} ]]; then - sed -i "s|ip3|${controller_ips[2]}|" $pod_yaml; + sed -i "s|ip3|${controller_ips[2]}|" "${pod_yaml}" fi if [[ ${compute_ips[0]} ]]; then - sed -i "s|ip4|${compute_ips[0]}|" $pod_yaml; + sed -i "s|ip4|${compute_ips[0]}|" "${pod_yaml}" fi if [[ ${compute_ips[1]} ]]; then - sed -i "s|ip5|${compute_ips[1]}|" $pod_yaml; + sed -i "s|ip5|${compute_ips[1]}|" "${pod_yaml}" + fi + if [[ ${odl_ip[0]} ]]; then + sed -i "s|ip6|${odl_ip[0]}|" "${pod_yaml}" + fi + if [[ ${gateway_ip[0]} ]]; then + sed -i "s|ip7|${gateway_ip[0]}|" "${pod_yaml}" fi # update 'user' and 'key_filename' according to the CI env - sed -i "s|node_username|${USER_NAME}|;s|node_keyfile|${SSH_KEY}|" $pod_yaml; + sed -i "s|node_username|${USER_NAME}|;s|node_keyfile|${SSH_KEY}|" "${pod_yaml}" fi diff --git a/tests/ci/prepare_storperf_admin-rc.sh b/tests/ci/prepare_storperf_admin-rc.sh index 558375e62..ef7c2297e 100755 --- a/tests/ci/prepare_storperf_admin-rc.sh +++ b/tests/ci/prepare_storperf_admin-rc.sh @@ -15,8 +15,9 @@ AUTH_URL=${OS_AUTH_URL} USERNAME=${OS_USERNAME:-admin} PASSWORD=${OS_PASSWORD:-console} +# OS_TENANT_NAME is still present to keep backward compatibility with legacy +# deployments, but should be replaced by OS_PROJECT_NAME. TENANT_NAME=${OS_TENANT_NAME:-admin} -TENANT_ID=`openstack project show admin|grep '\bid\b' |awk -F '|' '{print $3}'|sed -e 's/^[[:space:]]*//'` PROJECT_NAME=${OS_PROJECT_NAME:-$TENANT_NAME} PROJECT_ID=`openstack project show admin|grep '\bid\b' |awk -F '|' '{print $3}'|sed -e 's/^[[:space:]]*//'` @@ -30,8 +31,6 @@ echo "OS_USERNAME="$USERNAME >> ~/storperf_admin-rc echo "OS_PASSWORD="$PASSWORD >> ~/storperf_admin-rc echo "OS_PROJECT_NAME="$PROJECT_NAME >> ~/storperf_admin-rc echo "OS_PROJECT_ID="$PROJECT_ID >> ~/storperf_admin-rc -echo "OS_TENANT_NAME="$TENANT_NAME >> ~/storperf_admin-rc -echo "OS_TENANT_ID="$TENANT_ID >> ~/storperf_admin-rc echo "OS_USER_DOMAIN_ID="$USER_DOMAIN_ID >> ~/storperf_admin-rc echo "OS_PROJECT_DOMAIN_NAME="$OS_PROJECT_DOMAIN_NAME >> ~/storperf_admin-rc echo "OS_USER_DOMAIN_NAME="$OS_USER_DOMAIN_NAME >> ~/storperf_admin-rc diff --git a/tests/opnfv/test_suites/opnfv_k8-nosdn-lb_ceph-noha_daily.yaml b/tests/opnfv/test_suites/opnfv_k8-nosdn-lb_ceph-noha_daily.yaml new file mode 100644 index 000000000..ebb21b5c7 --- /dev/null +++ b/tests/opnfv/test_suites/opnfv_k8-nosdn-lb_ceph-noha_daily.yaml @@ -0,0 +1,18 @@ +############################################################################## +# Copyright (c) 2017 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 +############################################################################## +--- +# k8 nosdn lb ceph noha daily task suite + +schema: "yardstick:suite:0.1" + +name: "k8-nosdn-lb_ceph-noha" +test_cases_dir: "tests/opnfv/test_cases/" +test_cases: +- + file_name: opnfv_yardstick_tc080.yaml diff --git a/tests/opnfv/test_suites/opnfv_os-odl-bgpvpn-noha_daily.yaml b/tests/opnfv/test_suites/opnfv_os-odl-bgpvpn-noha_daily.yaml new file mode 100644 index 000000000..e55b83301 --- /dev/null +++ b/tests/opnfv/test_suites/opnfv_os-odl-bgpvpn-noha_daily.yaml @@ -0,0 +1,23 @@ +############################################################################## +# Copyright (c) 2017 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 +############################################################################## + +--- +# os-odl-bgpvpn-noha daily task suite + +schema: "yardstick:suite:0.1" + +name: "os-odl-bgpvpn-noha" +test_cases_dir: "tests/opnfv/test_cases/" +test_cases: +- + file_name: opnfv_yardstick_tc002.yaml +- + file_name: opnfv_yardstick_tc005.yaml +- + file_name: opnfv_yardstick_tc012.yaml diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index a468b272b..5935abbac 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -12,65 +12,9 @@ # See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import absolute_import
-import mock
+from yardstick import tests
-STL_MOCKS = {
- 'trex_stl_lib': mock.MagicMock(),
- 'trex_stl_lib.base64': mock.MagicMock(),
- 'trex_stl_lib.binascii': mock.MagicMock(),
- 'trex_stl_lib.collections': mock.MagicMock(),
- 'trex_stl_lib.copy': mock.MagicMock(),
- 'trex_stl_lib.datetime': mock.MagicMock(),
- 'trex_stl_lib.functools': mock.MagicMock(),
- 'trex_stl_lib.imp': mock.MagicMock(),
- 'trex_stl_lib.inspect': mock.MagicMock(),
- 'trex_stl_lib.json': mock.MagicMock(),
- 'trex_stl_lib.linecache': mock.MagicMock(),
- 'trex_stl_lib.math': mock.MagicMock(),
- 'trex_stl_lib.os': mock.MagicMock(),
- 'trex_stl_lib.platform': mock.MagicMock(),
- 'trex_stl_lib.pprint': mock.MagicMock(),
- 'trex_stl_lib.random': mock.MagicMock(),
- 'trex_stl_lib.re': mock.MagicMock(),
- 'trex_stl_lib.scapy': mock.MagicMock(),
- 'trex_stl_lib.socket': mock.MagicMock(),
- 'trex_stl_lib.string': mock.MagicMock(),
- 'trex_stl_lib.struct': mock.MagicMock(),
- 'trex_stl_lib.sys': mock.MagicMock(),
- 'trex_stl_lib.threading': mock.MagicMock(),
- 'trex_stl_lib.time': mock.MagicMock(),
- 'trex_stl_lib.traceback': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_async_client': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_client': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_exceptions': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_ext': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_port': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_stats': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_streams': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_types': mock.MagicMock(),
- 'trex_stl_lib.types': mock.MagicMock(),
- 'trex_stl_lib.utils': mock.MagicMock(),
- 'trex_stl_lib.utils.argparse': mock.MagicMock(),
- 'trex_stl_lib.utils.collections': mock.MagicMock(),
- 'trex_stl_lib.utils.common': mock.MagicMock(),
- 'trex_stl_lib.utils.json': mock.MagicMock(),
- 'trex_stl_lib.utils.os': mock.MagicMock(),
- 'trex_stl_lib.utils.parsing_opts': mock.MagicMock(),
- 'trex_stl_lib.utils.pwd': mock.MagicMock(),
- 'trex_stl_lib.utils.random': mock.MagicMock(),
- 'trex_stl_lib.utils.re': mock.MagicMock(),
- 'trex_stl_lib.utils.string': mock.MagicMock(),
- 'trex_stl_lib.utils.sys': mock.MagicMock(),
- 'trex_stl_lib.utils.text_opts': mock.MagicMock(),
- 'trex_stl_lib.utils.text_tables': mock.MagicMock(),
- 'trex_stl_lib.utils.texttable': mock.MagicMock(),
- 'trex_stl_lib.warnings': mock.MagicMock(),
- 'trex_stl_lib.yaml': mock.MagicMock(),
- 'trex_stl_lib.zlib': mock.MagicMock(),
- 'trex_stl_lib.zmq': mock.MagicMock(),
-}
+# NOTE(ralonsoh): to be removed. Replace all occurrences of
+# tests.unit.STL_MOCKS with yardstick.tests.STL_MOCKS
+STL_MOCKS = tests.STL_MOCKS
diff --git a/tests/unit/network_services/collector/test_publisher.py b/tests/unit/network_services/collector/test_publisher.py index d1e56e114..4a175841d 100644 --- a/tests/unit/network_services/collector/test_publisher.py +++ b/tests/unit/network_services/collector/test_publisher.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/network_services/collector/test_subscriber.py b/tests/unit/network_services/collector/test_subscriber.py index f324f627d..d4b4ecf7a 100644 --- a/tests/unit/network_services/collector/test_subscriber.py +++ b/tests/unit/network_services/collector/test_subscriber.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/network_services/helpers/test_cpu.py b/tests/unit/network_services/helpers/test_cpu.py index 7ea6bd0fc..1f9d3f219 100644 --- a/tests/unit/network_services/helpers/test_cpu.py +++ b/tests/unit/network_services/helpers/test_cpu.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py b/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py index e30aee854..367072e84 100644 --- a/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py +++ b/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,6 +14,14 @@ import mock import unittest + +import os + +from yardstick.error import IncorrectConfig, SSHError +from yardstick.error import IncorrectNodeSetup +from yardstick.error import IncorrectSetup +from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkInterface +from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkNode from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelperException from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_KERNEL @@ -26,7 +32,269 @@ from yardstick.network_services.helpers.dpdkbindnic_helper import NETWORK_OTHER from yardstick.network_services.helpers.dpdkbindnic_helper import CRYPTO_OTHER +NAME = "tg_0" + + +class TestDpdkInterface(unittest.TestCase): + + SAMPLE_NETDEVS = { + 'enp11s0': { + 'address': '0a:de:ad:be:ef:f5', + 'device': '0x1533', + 'driver': 'igb', + 'ifindex': '2', + 'interface_name': 'enp11s0', + 'operstate': 'down', + 'pci_bus_id': '0000:0b:00.0', + 'subsystem_device': '0x1533', + 'subsystem_vendor': '0x15d9', + 'vendor': '0x8086' + }, + 'lan': { + 'address': '0a:de:ad:be:ef:f4', + 'device': '0x153a', + 'driver': 'e1000e', + 'ifindex': '3', + 'interface_name': 'lan', + 'operstate': 'up', + 'pci_bus_id': '0000:00:19.0', + 'subsystem_device': '0x153a', + 'subsystem_vendor': '0x15d9', + 'vendor': '0x8086' + } + } + + SAMPLE_VM_NETDEVS = { + 'eth1': { + 'address': 'fa:de:ad:be:ef:5b', + 'device': '0x0001', + 'driver': 'virtio_net', + 'ifindex': '3', + 'interface_name': 'eth1', + 'operstate': 'down', + 'pci_bus_id': '0000:00:04.0', + 'vendor': '0x1af4' + } + } + + def test_parse_netdev_info(self): + output = """\ +/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/ifindex:2 +/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/address:0a:de:ad:be:ef:f5 +/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/operstate:down +/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/vendor:0x8086 +/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/device:0x1533 +/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_vendor:0x15d9 +/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_device:0x1533 +/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/driver:igb +/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/pci_bus_id:0000:0b:00.0 +/sys/devices/pci0000:00/0000:00:19.0/net/lan/ifindex:3 +/sys/devices/pci0000:00/0000:00:19.0/net/lan/address:0a:de:ad:be:ef:f4 +/sys/devices/pci0000:00/0000:00:19.0/net/lan/operstate:up +/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/vendor:0x8086 +/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/device:0x153a +/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_vendor:0x15d9 +/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_device:0x153a +/sys/devices/pci0000:00/0000:00:19.0/net/lan/driver:e1000e +/sys/devices/pci0000:00/0000:00:19.0/net/lan/pci_bus_id:0000:00:19.0 +""" + res = DpdkBindHelper.parse_netdev_info(output) + self.assertDictEqual(res, self.SAMPLE_NETDEVS) + + def test_parse_netdev_info_virtio(self): + output = """\ +/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/ifindex:3 +/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/address:fa:de:ad:be:ef:5b +/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/operstate:down +/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/vendor:0x1af4 +/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/device:0x0001 +/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/driver:virtio_net +""" + res = DpdkBindHelper.parse_netdev_info(output) + self.assertDictEqual(res, self.SAMPLE_VM_NETDEVS) + + def test_probe_missing_values(self): + mock_dpdk_node = mock.Mock() + mock_dpdk_node.netdevs = self.SAMPLE_NETDEVS.copy() + + interface = {'local_mac': '0a:de:ad:be:ef:f5'} + dpdk_intf = DpdkInterface(mock_dpdk_node, interface) + + dpdk_intf.probe_missing_values() + self.assertEqual(interface['vpci'], '0000:0b:00.0') + + interface['local_mac'] = '0a:de:ad:be:ef:f4' + dpdk_intf.probe_missing_values() + self.assertEqual(interface['vpci'], '0000:00:19.0') + + def test_probe_missing_values_no_update(self): + mock_dpdk_node = mock.Mock() + mock_dpdk_node.netdevs = self.SAMPLE_NETDEVS.copy() + del mock_dpdk_node.netdevs['enp11s0']['driver'] + del mock_dpdk_node.netdevs['lan']['driver'] + + interface = {'local_mac': '0a:de:ad:be:ef:f5'} + dpdk_intf = DpdkInterface(mock_dpdk_node, interface) + + dpdk_intf.probe_missing_values() + self.assertNotIn('vpci', interface) + self.assertNotIn('driver', interface) + + def test_probe_missing_values_negative(self): + mock_dpdk_node = mock.Mock() + mock_dpdk_node.netdevs.values.side_effect = IncorrectNodeSetup + + interface = {'local_mac': '0a:de:ad:be:ef:f5'} + dpdk_intf = DpdkInterface(mock_dpdk_node, interface) + + with self.assertRaises(IncorrectConfig): + dpdk_intf.probe_missing_values() + + +class TestDpdkNode(unittest.TestCase): + + INTERFACES = [ + {'name': 'name1', + 'virtual-interface': { + 'local_mac': 404, + 'vpci': 'pci10', + }}, + {'name': 'name2', + 'virtual-interface': { + 'local_mac': 404, + 'vpci': 'pci2', + }}, + {'name': 'name3', + 'virtual-interface': { + 'local_mac': 404, + 'vpci': 'some-pci1', + }}, + ] + + def test_probe_dpdk_drivers(self): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 0, '', '' + + interfaces = [ + {'name': 'name1', + 'virtual-interface': { + 'local_mac': 404, + 'vpci': 'pci10', + }}, + {'name': 'name2', + 'virtual-interface': { + 'local_mac': 404, + 'vpci': 'pci2', + }}, + {'name': 'name3', + 'virtual-interface': { + 'local_mac': 404, + 'vpci': 'some-pci1', + }}, + ] + + dpdk_node = DpdkNode(NAME, interfaces, mock_ssh_helper) + dpdk_helper = dpdk_node.dpdk_helper + + dpdk_helper.probe_real_kernel_drivers = mock.Mock() + dpdk_helper.real_kernel_interface_driver_map = { + 'pci1': 'driver1', + 'pci2': 'driver2', + 'pci3': 'driver3', + 'pci4': 'driver1', + 'pci6': 'driver3', + } + + dpdk_node._probe_dpdk_drivers() + self.assertNotIn('driver', interfaces[0]['virtual-interface']) + self.assertEqual(interfaces[1]['virtual-interface']['driver'], 'driver2') + self.assertEqual(interfaces[2]['virtual-interface']['driver'], 'driver1') + + def test_check(self): + def update(): + if not mock_force_rebind.called: + raise IncorrectConfig + + interfaces[0]['virtual-interface'].update({ + 'vpci': '0000:01:02.1', + 'local_ip': '10.20.30.40', + 'netmask': '255.255.0.0', + 'driver': 'ixgbe', + }) + + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 0, '', '' + + interfaces = [ + {'name': 'name1', + 'virtual-interface': { + 'local_mac': 404, + }}, + ] + + dpdk_node = DpdkNode(NAME, interfaces, mock_ssh_helper) + dpdk_node._probe_missing_values = mock_probe_missing = mock.Mock(side_effect=update) + dpdk_node._force_rebind = mock_force_rebind = mock.Mock() + + self.assertIsNone(dpdk_node.check()) + self.assertEqual(mock_probe_missing.call_count, 2) + + @mock.patch('yardstick.network_services.helpers.dpdkbindnic_helper.DpdkInterface') + def test_check_negative(self, mock_intf_type): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 0, '', '' + + mock_intf_type().check.side_effect = SSHError + + dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper) + + with self.assertRaises(IncorrectSetup): + dpdk_node.check() + + def test_probe_netdevs(self): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 0, '', '' + + expected = {'key1': 500, 'key2': 'hello world'} + update = {'key1': 1000, 'key3': []} + + dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper) + dpdk_helper = dpdk_node.dpdk_helper + dpdk_helper.find_net_devices = mock.Mock(side_effect=[expected, update]) + + self.assertDictEqual(dpdk_node.netdevs, {}) + dpdk_node._probe_netdevs() + self.assertDictEqual(dpdk_node.netdevs, expected) + + expected = {'key1': 1000, 'key2': 'hello world', 'key3': []} + dpdk_node._probe_netdevs() + self.assertDictEqual(dpdk_node.netdevs, expected) + + def test_probe_netdevs_setup_negative(self): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 0, '', '' + + dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper) + dpdk_helper = dpdk_node.dpdk_helper + dpdk_helper.find_net_devices = mock.Mock(side_effect=DpdkBindHelperException) + + with self.assertRaises(DpdkBindHelperException): + dpdk_node._probe_netdevs() + + def test_force_rebind(self): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 0, '', '' + + dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper) + dpdk_helper = dpdk_node.dpdk_helper + dpdk_helper.force_dpdk_rebind = mock_helper_func = mock.Mock() + + dpdk_node._force_rebind() + self.assertEqual(mock_helper_func.call_count, 1) + + class TestDpdkBindHelper(unittest.TestCase): + bin_path = "/opt/nsb_bin" EXAMPLE_OUTPUT = """ Network devices using DPDK-compatible driver @@ -111,13 +379,15 @@ Other crypto devices def test___init__(self): conn = mock.Mock() conn.provision_tool = mock.Mock(return_value='path_to_tool') + conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND) dpdk_bind_helper = DpdkBindHelper(conn) self.assertEqual(conn, dpdk_bind_helper.ssh_helper) self.assertEqual(self.CLEAN_STATUS, dpdk_bind_helper.dpdk_status) self.assertIsNone(dpdk_bind_helper.status_nic_row_re) - self.assertIsNone(dpdk_bind_helper._dpdk_devbind) + self.assertEqual(dpdk_bind_helper.dpdk_devbind, + os.path.join(self.bin_path, dpdk_bind_helper.DPDK_DEVBIND)) self.assertIsNone(dpdk_bind_helper._status_cmd_attr) def test__dpdk_execute(self): @@ -125,8 +395,7 @@ Other crypto devices conn.execute = mock.Mock(return_value=(0, 'output', 'error')) conn.provision_tool = mock.Mock(return_value='tool_path') dpdk_bind_helper = DpdkBindHelper(conn) - self.assertEqual((0, 'output', 'error'), - dpdk_bind_helper._dpdk_execute('command')) + self.assertEqual((0, 'output', 'error'), dpdk_bind_helper._dpdk_execute('command')) def test__dpdk_execute_failure(self): conn = mock.Mock() @@ -141,7 +410,7 @@ Other crypto devices dpdk_bind_helper = DpdkBindHelper(conn) - dpdk_bind_helper._addline(NETWORK_KERNEL, self.ONE_INPUT_LINE) + dpdk_bind_helper._add_line(NETWORK_KERNEL, self.ONE_INPUT_LINE) self.assertIsNotNone(dpdk_bind_helper.dpdk_status) self.assertEqual(self.ONE_INPUT_LINE_PARSED, dpdk_bind_helper.dpdk_status[NETWORK_KERNEL]) @@ -161,11 +430,35 @@ Other crypto devices dpdk_bind_helper = DpdkBindHelper(conn) - dpdk_bind_helper.parse_dpdk_status_output(self.EXAMPLE_OUTPUT) + dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT) self.maxDiff = None self.assertEqual(self.PARSED_EXAMPLE, dpdk_bind_helper.dpdk_status) + def test_kernel_bound_pci_addresses(self): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 0, '', '' + + expected = ['a', 'b', 3] + + dpdk_helper = DpdkBindHelper(mock_ssh_helper) + dpdk_helper.dpdk_status = { + NETWORK_DPDK: [{'vpci': 4}, {'vpci': 5}, {'vpci': 'g'}], + NETWORK_KERNEL: [{'vpci': 'a'}, {'vpci': 'b'}, {'vpci': 3}], + CRYPTO_DPDK: [], + } + + result = dpdk_helper.kernel_bound_pci_addresses + self.assertEqual(result, expected) + + def test_find_net_devices_negative(self): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 1, 'error', 'debug' + + dpdk_helper = DpdkBindHelper(mock_ssh_helper) + + self.assertDictEqual(dpdk_helper.find_net_devices(), {}) + def test_read_status(self): conn = mock.Mock() conn.execute = mock.Mock(return_value=(0, self.EXAMPLE_OUTPUT, '')) @@ -180,7 +473,7 @@ Other crypto devices dpdk_bind_helper = DpdkBindHelper(conn) - dpdk_bind_helper.parse_dpdk_status_output(self.EXAMPLE_OUTPUT) + dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT) self.assertEqual(['0000:00:04.0', '0000:00:05.0'], dpdk_bind_helper._get_bound_pci_addresses(NETWORK_DPDK)) @@ -192,18 +485,18 @@ Other crypto devices dpdk_bind_helper = DpdkBindHelper(conn) - dpdk_bind_helper.parse_dpdk_status_output(self.EXAMPLE_OUTPUT) + dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT) self.assertEqual({'0000:00:04.0': 'igb_uio', - '0000:00:03.0': 'virtio-pci', - '0000:00:05.0': 'igb_uio', - }, - dpdk_bind_helper.interface_driver_map) + '0000:00:03.0': 'virtio-pci', + '0000:00:05.0': 'igb_uio', + }, + dpdk_bind_helper.interface_driver_map) def test_bind(self): conn = mock.Mock() conn.execute = mock.Mock(return_value=(0, '', '')) - conn.provision_tool = mock.Mock(return_value='/opt/nsb_bin/dpdk-devbind.py') + conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND) dpdk_bind_helper = DpdkBindHelper(conn) dpdk_bind_helper.read_status = mock.Mock() @@ -217,7 +510,7 @@ Other crypto devices def test_bind_single_pci(self): conn = mock.Mock() conn.execute = mock.Mock(return_value=(0, '', '')) - conn.provision_tool = mock.Mock(return_value='/opt/nsb_bin/dpdk-devbind.py') + conn.join_bin_path.return_value = os.path.join(self.bin_path, DpdkBindHelper.DPDK_DEVBIND) dpdk_bind_helper = DpdkBindHelper(conn) dpdk_bind_helper.read_status = mock.Mock() @@ -257,3 +550,84 @@ Other crypto devices } self.assertDictEqual(expected, dpdk_bind_helper.used_drivers) + + def test_force_dpdk_rebind(self): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 0, '', '' + + dpdk_helper = DpdkBindHelper(mock_ssh_helper, 'driver2') + dpdk_helper.dpdk_status = { + NETWORK_DPDK: [ + { + 'vpci': 'pci1', + }, + { + 'vpci': 'pci3', + }, + { + 'vpci': 'pci6', + }, + { + 'vpci': 'pci3', + }, + ] + } + dpdk_helper.real_kernel_interface_driver_map = { + 'pci1': 'real_driver1', + 'pci2': 'real_driver2', + 'pci3': 'real_driver1', + 'pci4': 'real_driver4', + 'pci6': 'real_driver6', + } + dpdk_helper.load_dpdk_driver = mock.Mock() + dpdk_helper.read_status = mock.Mock() + dpdk_helper.save_real_kernel_interface_driver_map = mock.Mock() + dpdk_helper.save_used_drivers = mock.Mock() + dpdk_helper.bind = mock_bind = mock.Mock() + + dpdk_helper.force_dpdk_rebind() + self.assertEqual(mock_bind.call_count, 2) + + def test_save_real_kernel_drivers(self): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.return_value = 0, '', '' + + dpdk_helper = DpdkBindHelper(mock_ssh_helper) + dpdk_helper.real_kernel_drivers = { + 'abc': '123', + } + dpdk_helper.real_kernel_interface_driver_map = { + 'abc': 'AAA', + 'def': 'DDD', + 'abs': 'AAA', + 'ghi': 'GGG', + } + + # save_used_drivers must be called before save_real_kernel_drivers can be + with self.assertRaises(AttributeError): + dpdk_helper.save_real_kernel_drivers() + + dpdk_helper.save_used_drivers() + + expected_used_drivers = { + 'AAA': ['abc', 'abs'], + 'DDD': ['def'], + 'GGG': ['ghi'], + } + dpdk_helper.save_real_kernel_drivers() + self.assertDictEqual(dpdk_helper.used_drivers, expected_used_drivers) + self.assertDictEqual(dpdk_helper.real_kernel_drivers, {}) + + def test_get_real_kernel_driver(self): + mock_ssh_helper = mock.Mock() + mock_ssh_helper.execute.side_effect = [ + (0, 'non-matching text', ''), + (0, 'pre Kernel modules: real_driver1', ''), + (0, 'before Ethernet middle Virtio network device after', ''), + ] + + dpdk_helper = DpdkBindHelper(mock_ssh_helper) + + self.assertIsNone(dpdk_helper.get_real_kernel_driver('abc')) + self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'), 'real_driver1') + self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'), DpdkBindHelper.VIRTIO_DRIVER) diff --git a/tests/unit/network_services/helpers/test_samplevnf_helper.py b/tests/unit/network_services/helpers/test_samplevnf_helper.py index 05acdfaa9..3b6c89d3a 100644 --- a/tests/unit/network_services/helpers/test_samplevnf_helper.py +++ b/tests/unit/network_services/helpers/test_samplevnf_helper.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,14 +13,12 @@ # limitations under the License. # -from __future__ import absolute_import -from __future__ import division - -import unittest - import mock +import os +import six +import unittest -from yardstick.network_services.helpers.samplevnf_helper import MultiPortConfig, PortPairs +from yardstick.network_services.helpers import samplevnf_helper from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper @@ -30,31 +26,32 @@ class TestPortPairs(unittest.TestCase): def test_port_pairs_list(self): vnfd = TestMultiPortConfig.VNFD['vnfd:vnfd-catalog']['vnfd'][0] interfaces = vnfd['vdu'][0]['external-interface'] - port_pairs = PortPairs(interfaces) + port_pairs = samplevnf_helper.PortPairs(interfaces) self.assertEqual(port_pairs.port_pair_list, [("xe0", "xe1")]) def test_valid_networks(self): vnfd = TestMultiPortConfig.VNFD['vnfd:vnfd-catalog']['vnfd'][0] interfaces = vnfd['vdu'][0]['external-interface'] - port_pairs = PortPairs(interfaces) - self.assertEqual(port_pairs.valid_networks, [("uplink_0", "downlink_0")]) + port_pairs = samplevnf_helper.PortPairs(interfaces) + self.assertEqual(port_pairs.valid_networks, [ + ("uplink_0", "downlink_0")]) def test_all_ports(self): vnfd = TestMultiPortConfig.VNFD['vnfd:vnfd-catalog']['vnfd'][0] interfaces = vnfd['vdu'][0]['external-interface'] - port_pairs = PortPairs(interfaces) + port_pairs = samplevnf_helper.PortPairs(interfaces) self.assertEqual(set(port_pairs.all_ports), {"xe0", "xe1"}) def test_uplink_ports(self): vnfd = TestMultiPortConfig.VNFD['vnfd:vnfd-catalog']['vnfd'][0] interfaces = vnfd['vdu'][0]['external-interface'] - port_pairs = PortPairs(interfaces) + port_pairs = samplevnf_helper.PortPairs(interfaces) self.assertEqual(port_pairs.uplink_ports, ["xe0"]) def test_downlink_ports(self): vnfd = TestMultiPortConfig.VNFD['vnfd:vnfd-catalog']['vnfd'][0] interfaces = vnfd['vdu'][0]['external-interface'] - port_pairs = PortPairs(interfaces) + port_pairs = samplevnf_helper.PortPairs(interfaces) self.assertEqual(port_pairs.downlink_ports, ["xe1"]) @@ -63,14 +60,14 @@ class TestMultiPortConfig(unittest.TestCase): VNFD_0 = {'short-name': 'VpeVnf', 'vdu': [{'routing_table': - [{'network': '152.16.100.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.100.20', - 'if': 'xe0'}, - {'network': '152.16.40.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.40.20', - 'if': 'xe1'}], + [{'network': '152.16.100.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'if': 'xe0'}, + {'network': '152.16.40.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'if': 'xe1'}], 'description': 'VPE approximation using DPDK', 'name': 'vpevnf-baremetal', 'nd_route_tbl': @@ -121,7 +118,7 @@ class TestMultiPortConfig(unittest.TestCase): }, 'vnfd-connection-point-ref': 'xe1', 'name': 'xe1'} - ]}], + ]}], 'description': 'Vpe approximation using DPDK', 'mgmt-interface': {'vdu-id': 'vpevnf-baremetal', @@ -143,67 +140,85 @@ class TestMultiPortConfig(unittest.TestCase): } } + def setUp(self): + self._mock_open = mock.patch.object(six.moves.builtins, 'open') + self.mock_open = self._mock_open.start() + self._mock_os = mock.patch.object(os, 'path') + self.mock_os = self._mock_os.start() + self._mock_config_parser = mock.patch.object( + samplevnf_helper, 'ConfigParser') + self.mock_config_parser = self._mock_config_parser.start() + + self.addCleanup(self._cleanup) + + def _cleanup(self): + self._mock_open.stop() + self._mock_os.stop() + self._mock_config_parser.stop() + def test_validate_ip_and_prefixlen(self): - ip_addr, prefix_len = MultiPortConfig.validate_ip_and_prefixlen('10.20.30.40', '16') + ip_addr, prefix_len = ( + samplevnf_helper.MultiPortConfig.validate_ip_and_prefixlen( + '10.20.30.40', '16')) self.assertEqual(ip_addr, '10.20.30.40') self.assertEqual(prefix_len, 16) - ip_addr, prefix_len = MultiPortConfig.validate_ip_and_prefixlen('::1', '40') + ip_addr, prefix_len = ( + samplevnf_helper.MultiPortConfig.validate_ip_and_prefixlen( + '::1', '40')) self.assertEqual(ip_addr, '0000:0000:0000:0000:0000:0000:0000:0001') self.assertEqual(prefix_len, 40) def test_validate_ip_and_prefixlen_negative(self): with self.assertRaises(AttributeError): - MultiPortConfig.validate_ip_and_prefixlen('', '') + samplevnf_helper.MultiPortConfig.validate_ip_and_prefixlen('', '') with self.assertRaises(AttributeError): - MultiPortConfig.validate_ip_and_prefixlen('10.20.30.400', '16') + samplevnf_helper.MultiPortConfig.validate_ip_and_prefixlen( + '10.20.30.400', '16') with self.assertRaises(AttributeError): - MultiPortConfig.validate_ip_and_prefixlen('10.20.30.40', '33') + samplevnf_helper.MultiPortConfig.validate_ip_and_prefixlen( + '10.20.30.40', '33') with self.assertRaises(AttributeError): - MultiPortConfig.validate_ip_and_prefixlen('::1', '129') + samplevnf_helper.MultiPortConfig.validate_ip_and_prefixlen( + '::1', '129') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test___init__(self, mock_open, mock_os, ConfigParser): + def test___init__(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) self.assertEqual(0, opnfv_vnf.swq) - mock_os.path = mock.MagicMock() - mock_os.path.isfile = mock.Mock(return_value=False) - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + self.mock_os.path = mock.MagicMock() + self.mock_os.path.isfile = mock.Mock(return_value=False) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) self.assertEqual(0, opnfv_vnf.swq) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_update_timer(self, mock_open, mock_os, ConfigParser): + def test_update_timer(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.update_write_parser = mock.MagicMock() - self.assertEqual(None, opnfv_vnf.update_timer()) + self.assertIsNone(opnfv_vnf.update_timer()) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_generate_script(self, mock_open, mock_os, ConfigParser): + def test_generate_script(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = VnfdHelper(self.VNFD_0) - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -218,15 +233,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.lb_config = 'HW' self.assertIsNotNone(opnfv_vnf.generate_script(self.VNFD)) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_generate_script_data(self, mock_open, mock_os, ConfigParser): + def test_generate_script_data(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -240,15 +253,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.generate_rule_config = mock.Mock() self.assertIsNotNone(opnfv_vnf.generate_script_data()) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_generate_rule_config(self, mock_open, mock_os, ConfigParser): + def test_generate_rule_config(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -261,9 +272,11 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.get_port_pairs = mock.Mock() opnfv_vnf.vnf_type = 'ACL' opnfv_vnf.get_ports_gateway = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway = mock.Mock(return_value=u'255.255.255.0') + opnfv_vnf.get_netmask_gateway = mock.Mock( + return_value=u'255.255.255.0') opnfv_vnf.get_ports_gateway6 = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway6 = mock.Mock(return_value=u'255.255.255.0') + opnfv_vnf.get_netmask_gateway6 = mock.Mock( + return_value=u'255.255.255.0') opnfv_vnf.txrx_pipeline = '' opnfv_vnf.vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] opnfv_vnf.interfaces = opnfv_vnf.vnfd['vdu'][0]['external-interface'] @@ -272,15 +285,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.rules = 'new' self.assertIsNotNone(opnfv_vnf.generate_rule_config()) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_generate_action_config(self, mock_open, mock_os, ConfigParser): + def test_generate_action_config(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -293,22 +304,22 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.get_port_pairs = mock.Mock() opnfv_vnf.vnf_type = 'VFW' opnfv_vnf.get_ports_gateway = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway = mock.Mock(return_value=u'255.255.255.0') + opnfv_vnf.get_netmask_gateway = mock.Mock( + return_value=u'255.255.255.0') opnfv_vnf.get_ports_gateway6 = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway6 = mock.Mock(return_value=u'255.255.255.0') + opnfv_vnf.get_netmask_gateway6 = mock.Mock( + return_value=u'255.255.255.0') opnfv_vnf.txrx_pipeline = '' opnfv_vnf.rules = '' self.assertIsNotNone(opnfv_vnf.generate_action_config()) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_generate_arp_config6(self, mock_open, mock_os, ConfigParser): + def test_generate_arp_config6(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -321,24 +332,24 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.get_port_pairs = mock.Mock() opnfv_vnf.vnf_type = 'VFW' opnfv_vnf.get_ports_gateway = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway = mock.Mock(return_value=u'255.255.255.0') + opnfv_vnf.get_netmask_gateway = mock.Mock( + return_value=u'255.255.255.0') opnfv_vnf.get_ports_gateway6 = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway6 = mock.Mock(return_value=u'255.255.255.0') + opnfv_vnf.get_netmask_gateway6 = mock.Mock( + return_value=u'255.255.255.0') opnfv_vnf.txrx_pipeline = '' opnfv_vnf.rules = '' opnfv_vnf.interfaces = mock.MagicMock() opnfv_vnf.get_ports_gateway6 = mock.Mock() self.assertIsNotNone(opnfv_vnf.generate_arp_config6()) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_generate_arp_config(self, mock_open, mock_os, ConfigParser): + def test_generate_arp_config(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -351,24 +362,24 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.get_port_pairs = mock.Mock() opnfv_vnf.vnf_type = 'VFW' opnfv_vnf.get_ports_gateway = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway = mock.Mock(return_value=u'255.255.255.0') + opnfv_vnf.get_netmask_gateway = mock.Mock( + return_value=u'255.255.255.0') opnfv_vnf.get_ports_gateway6 = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway6 = mock.Mock(return_value=u'255.255.255.0') + opnfv_vnf.get_netmask_gateway6 = mock.Mock( + return_value=u'255.255.255.0') opnfv_vnf.txrx_pipeline = '' opnfv_vnf.rules = '' opnfv_vnf.interfaces = mock.MagicMock() opnfv_vnf.get_ports_gateway6 = mock.Mock() self.assertIsNotNone(opnfv_vnf.generate_arp_config()) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_get_ports_gateway(self, mock_open, mock_os, ConfigParser): + def test_get_ports_gateway(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -387,15 +398,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] self.assertIsNotNone(opnfv_vnf.get_ports_gateway('xe0')) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_get_ports_gateway6(self, mock_open, mock_os, ConfigParser): + def test_get_ports_gateway6(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -414,15 +423,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] self.assertIsNotNone(opnfv_vnf.get_ports_gateway6('xe0')) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_get_netmask_gateway(self, mock_open, mock_os, ConfigParser): + def test_get_netmask_gateway(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -441,15 +448,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] self.assertIsNotNone(opnfv_vnf.get_netmask_gateway('xe0')) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_get_netmask_gateway6(self, mock_open, mock_os, ConfigParser): + def test_get_netmask_gateway6(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -468,16 +473,14 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] self.assertIsNotNone(opnfv_vnf.get_netmask_gateway6('xe0')) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_generate_link_config(self, mock_open, mock_os, ConfigParser): + def test_generate_link_config(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -495,20 +498,19 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] opnfv_vnf.interfaces = opnfv_vnf.vnfd['vdu'][0]['external-interface'] opnfv_vnf.all_ports = ['32', '1', '987'] - opnfv_vnf.validate_ip_and_prefixlen = mock.Mock(return_value=('10.20.30.40', 16)) + opnfv_vnf.validate_ip_and_prefixlen = mock.Mock( + return_value=('10.20.30.40', 16)) result = opnfv_vnf.generate_link_config() self.assertEqual(len(result.splitlines()), 9) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_generate_config(self, mock_open, mock_os, ConfigParser): + def test_generate_config(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.get_config_tpl_data = mock.MagicMock() opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 @@ -531,17 +533,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.is_openstack = False self.assertIsNone(opnfv_vnf.generate_config()) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_get_config_tpl_data(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_get_config_tpl_data(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -555,17 +553,13 @@ class TestMultiPortConfig(unittest.TestCase): self.assertIsNotNone(opnfv_vnf.get_config_tpl_data('filename')) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_get_txrx_tpl_data(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_get_txrx_tpl_data(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -579,17 +573,13 @@ class TestMultiPortConfig(unittest.TestCase): self.assertIsNotNone(opnfv_vnf.get_txrx_tpl_data('filename')) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_init_write_parser_template(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_init_write_parser_template(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -608,17 +598,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.write_parser.set = mock.Mock() self.assertIsNone(opnfv_vnf.init_write_parser_template('filename')) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_init_write_parser_template_2(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_init_write_parser_template_2(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -632,17 +618,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.read_parser.items = mock.MagicMock() self.assertIsNone(opnfv_vnf.init_write_parser_template('filename')) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_update_write_parser(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_update_write_parser(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -658,17 +640,13 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.pipeline_counter = 0 self.assertIsNone(opnfv_vnf.update_write_parser({'filename': 1})) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_get_worker_threads(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_get_worker_threads(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -692,17 +670,14 @@ class TestMultiPortConfig(unittest.TestCase): result = opnfv_vnf.get_worker_threads(3) self.assertEqual(2, result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_generate_next_core_id(self, mock_open, mock_os, ConfigParser, - OrderedDict): + # TODO(elfoley): Split this test into smaller tests + def test_generate_next_core_id(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -719,26 +694,22 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.worker_config = '1t' opnfv_vnf.start_core = 0 result = opnfv_vnf.generate_next_core_id() - self.assertEqual(None, result) + self.assertIsNone(result) opnfv_vnf.worker_config = '2t' opnfv_vnf.start_core = 'a' self.assertRaises(ValueError, opnfv_vnf.generate_next_core_id) opnfv_vnf.worker_config = '2t' opnfv_vnf.start_core = 1 result = opnfv_vnf.generate_next_core_id() - self.assertEqual(None, result) + self.assertIsNone(result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_generate_lb_to_port_pair_mapping(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_generate_lb_to_port_pair_mapping(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = VnfdHelper(self.VNFD_0) - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.txrx_pipeline = '' @@ -754,24 +725,20 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.worker_config = '1t' opnfv_vnf.start_core = 0 opnfv_vnf.lb_count = 1 - opnfv_vnf._port_pairs = PortPairs(vnfd_mock.interfaces) + opnfv_vnf._port_pairs = samplevnf_helper.PortPairs(vnfd_mock.interfaces) opnfv_vnf.port_pair_list = opnfv_vnf._port_pairs.port_pair_list result = opnfv_vnf.generate_lb_to_port_pair_mapping() - self.assertEqual(None, result) + self.assertIsNone(result) result = opnfv_vnf.set_priv_to_pub_mapping() self.assertEqual('(0,1)', result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_set_priv_que_handler(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_set_priv_que_handler(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = VnfdHelper(self.VNFD_0) - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -790,11 +757,10 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.start_core = 0 opnfv_vnf.lb_count = 1 result = opnfv_vnf.set_priv_que_handler() - self.assertEqual(None, result) + self.assertIsNone(result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - def test_generate_arp_route_tbl(self, *_): + def test_generate_arp_route_tbl(self): + # ELF: could n=do this in setup topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = "" @@ -821,7 +787,8 @@ class TestMultiPortConfig(unittest.TestCase): }, ] - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.all_ports = [3, 2, 5] expected = 'routeadd net 32 10.20.30.40 0xfffff000\n' \ @@ -830,17 +797,13 @@ class TestMultiPortConfig(unittest.TestCase): result = opnfv_vnf.generate_arp_route_tbl() self.assertEqual(result, expected) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_generate_arpicmp_data(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_generate_arpicmp_data(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -875,17 +838,13 @@ class TestMultiPortConfig(unittest.TestCase): result = opnfv_vnf.generate_arpicmp_data() self.assertIsNotNone(result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_generate_final_txrx_data(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_generate_final_txrx_data(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -917,17 +876,13 @@ class TestMultiPortConfig(unittest.TestCase): result = opnfv_vnf.generate_final_txrx_data() self.assertIsNotNone(result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_generate_initial_txrx_data(self, mock_open, mock_os, - ConfigParser, OrderedDict): + def test_generate_initial_txrx_data(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -971,17 +926,13 @@ class TestMultiPortConfig(unittest.TestCase): result = opnfv_vnf.generate_initial_txrx_data() self.assertIsNotNone(result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_generate_lb_data(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_generate_lb_data(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -1008,17 +959,13 @@ class TestMultiPortConfig(unittest.TestCase): result = opnfv_vnf.generate_lb_data() self.assertIsNotNone(result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_generate_vnf_data(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_generate_vnf_data(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -1057,17 +1004,13 @@ class TestMultiPortConfig(unittest.TestCase): result = opnfv_vnf.generate_vnf_data() self.assertIsNotNone(result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_generate_config_data(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_generate_config_data(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = VnfdHelper(self.VNFD_0) - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] @@ -1123,17 +1066,13 @@ class TestMultiPortConfig(unittest.TestCase): result = opnfv_vnf.generate_config_data() self.assertIsNone(result) - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.open') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.os') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.ConfigParser') - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.OrderedDict') - def test_init_eal(self, mock_open, mock_os, ConfigParser, - OrderedDict): + def test_init_eal(self): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() vnfd_mock = mock.MagicMock() - opnfv_vnf = MultiPortConfig(topology_file, config_tpl, tmp_file, vnfd_mock) + opnfv_vnf = samplevnf_helper.MultiPortConfig( + topology_file, config_tpl, tmp_file, vnfd_mock) opnfv_vnf.socket = 0 opnfv_vnf.start_core = 0 opnfv_vnf.port_pair_list = [("xe0", "xe1")] diff --git a/tests/unit/network_services/libs/ixia_libs/test_IxNet.py b/tests/unit/network_services/libs/ixia_libs/test_IxNet.py index 3f374fb50..2a97048aa 100644 --- a/tests/unit/network_services/libs/ixia_libs/test_IxNet.py +++ b/tests/unit/network_services/libs/ixia_libs/test_IxNet.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,7 +34,7 @@ class TestIxNextgen(unittest.TestCase): self.assertIsNone(ixnet_gen._bidir) @mock.patch("yardstick.network_services.libs.ixia_libs.IxNet.IxNet.sys") - def test_connect(self, mock_sys): + def test_connect(self, *args): ixnet_gen = IxNextgen() ixnet_gen.get_config = mock.MagicMock() diff --git a/tests/unit/network_services/nfvi/test_collectd.py b/tests/unit/network_services/nfvi/test_collectd.py index 866c31d32..0ae175624 100644 --- a/tests/unit/network_services/nfvi/test_collectd.py +++ b/tests/unit/network_services/nfvi/test_collectd.py @@ -34,7 +34,7 @@ class TestAmqpConsumer(unittest.TestCase): self.amqp_consumer._connection.add_on_close_callback = \ mock.Mock(return_value=0) self.amqp_consumer._connection.channel = mock.Mock(return_value=0) - self.assertEqual(None, self.amqp_consumer.on_connection_open(10)) + self.assertIsNone(self.amqp_consumer.on_connection_open(10)) def test_on_connection_closed(self): self.amqp_consumer._connection = mock.Mock(autospec=AmqpConsumer) @@ -42,13 +42,11 @@ class TestAmqpConsumer(unittest.TestCase): self.amqp_consumer._connection.ioloop.stop = mock.Mock(return_value=0) self.amqp_consumer._connection.add_timeout = mock.Mock(return_value=0) self.amqp_consumer._closing = True - self.assertEqual(None, - self.amqp_consumer.on_connection_closed("", 404, - "Not Found")) + self.assertIsNone( + self.amqp_consumer.on_connection_closed("", 404, "Not Found")) self.amqp_consumer._closing = False - self.assertEqual(None, - self.amqp_consumer.on_connection_closed("", 404, - "Not Found")) + self.assertIsNone( + self.amqp_consumer.on_connection_closed("", 404, "Not Found")) def test_reconnect(self): self.amqp_consumer._connection = mock.Mock(autospec=AmqpConsumer) @@ -56,7 +54,7 @@ class TestAmqpConsumer(unittest.TestCase): self.amqp_consumer._connection.ioloop.stop = mock.Mock(return_value=0) self.amqp_consumer.connect = mock.Mock(return_value=0) self.amqp_consumer._closing = True - self.assertEqual(None, self.amqp_consumer.reconnect()) + self.assertIsNone(self.amqp_consumer.reconnect()) def test_on_channel_open(self): self.amqp_consumer._connection = mock.Mock(autospec=AmqpConsumer) @@ -66,9 +64,8 @@ class TestAmqpConsumer(unittest.TestCase): self.amqp_consumer.add_on_channel_close_callback = mock.Mock() self.amqp_consumer._channel.exchange_declare = \ mock.Mock(return_value=0) - self.assertEqual(None, - self.amqp_consumer.on_channel_open( - self.amqp_consumer._channel)) + self.assertIsNone( + self.amqp_consumer.on_channel_open(self.amqp_consumer._channel)) def test_add_on_channel_close_callback(self): self.amqp_consumer._connection = mock.Mock(autospec=AmqpConsumer) @@ -76,46 +73,44 @@ class TestAmqpConsumer(unittest.TestCase): mock.Mock(return_value=0) self.amqp_consumer._channel = mock.Mock() self.amqp_consumer._channel.add_on_close_callback = mock.Mock() - self.assertEqual(None, - self.amqp_consumer.add_on_channel_close_callback()) + self.assertIsNone(self.amqp_consumer.add_on_channel_close_callback()) def test_on_channel_closed(self): self.amqp_consumer._connection = mock.Mock(autospec=AmqpConsumer) self.amqp_consumer._connection.close = mock.Mock(return_value=0) _channel = mock.Mock() - self.assertEqual(None, - self.amqp_consumer.on_channel_closed(_channel, - "", "")) + self.assertIsNone( + self.amqp_consumer.on_channel_closed(_channel, "", "")) def test_ion_exchange_declareok(self): self.amqp_consumer.setup_queue = mock.Mock(return_value=0) - self.assertEqual(None, self.amqp_consumer.on_exchange_declareok(10)) + self.assertIsNone(self.amqp_consumer.on_exchange_declareok(10)) def test_setup_queue(self): self.amqp_consumer._channel = mock.Mock() self.amqp_consumer._channel.add_on_close_callback = mock.Mock() - self.assertEqual(None, self.amqp_consumer.setup_queue("collectd")) + self.assertIsNone(self.amqp_consumer.setup_queue("collectd")) def test_on_queue_declareok(self): self.amqp_consumer._channel = mock.Mock() self.amqp_consumer._channel.queue_bind = mock.Mock() - self.assertEqual(None, self.amqp_consumer.on_queue_declareok(10)) + self.assertIsNone(self.amqp_consumer.on_queue_declareok(10)) def test__on_bindok(self): self.amqp_consumer._channel = mock.Mock() self.amqp_consumer._channel.basic_consume = mock.Mock() self.amqp_consumer.add_on_cancel_callback = mock.Mock() - self.assertEqual(None, self.amqp_consumer._on_bindok(10)) + self.assertIsNone(self.amqp_consumer._on_bindok(10)) def test_add_on_cancel_callback(self): self.amqp_consumer._channel = mock.Mock() self.amqp_consumer._channel.add_on_cancel_callback = mock.Mock() - self.assertEqual(None, self.amqp_consumer.add_on_cancel_callback()) + self.assertIsNone(self.amqp_consumer.add_on_cancel_callback()) def test_on_consumer_cancelled(self): self.amqp_consumer._channel = mock.Mock() self.amqp_consumer._channel.close = mock.Mock() - self.assertEqual(None, self.amqp_consumer.on_consumer_cancelled(10)) + self.assertIsNone(self.amqp_consumer.on_consumer_cancelled(10)) def test_on_message(self): body = "msg {} cpu/cpu-0/ipc 101010:10" @@ -123,25 +118,24 @@ class TestAmqpConsumer(unittest.TestCase): basic_deliver = mock.Mock() basic_deliver.delivery_tag = mock.Mock(return_value=0) self.amqp_consumer.ack_message = mock.Mock() - self.assertEqual(None, - self.amqp_consumer.on_message(10, basic_deliver, - properties, body)) + self.assertIsNone( + self.amqp_consumer.on_message(10, basic_deliver, properties, body)) def test_ack_message(self): self.amqp_consumer._channel = mock.Mock() self.amqp_consumer._channel.basic_ack = mock.Mock() - self.assertEqual(None, self.amqp_consumer.ack_message(10)) + self.assertIsNone(self.amqp_consumer.ack_message(10)) def test_on_cancelok(self): self.amqp_consumer._channel = mock.Mock() self.amqp_consumer._channel.close = mock.Mock() - self.assertEqual(None, self.amqp_consumer.on_cancelok(10)) + self.assertIsNone(self.amqp_consumer.on_cancelok(10)) def test_run(self): self.amqp_consumer._connection = mock.Mock(autospec=AmqpConsumer) self.amqp_consumer.connect = mock.Mock() self.amqp_consumer._connection.ioloop.start = mock.Mock() - self.assertEqual(None, self.amqp_consumer.run()) + self.assertIsNone(self.amqp_consumer.run()) def test_stop(self): self.amqp_consumer._connection = mock.Mock(autospec=AmqpConsumer) @@ -149,9 +143,9 @@ class TestAmqpConsumer(unittest.TestCase): self.amqp_consumer._connection.ioloop.start = mock.Mock() self.amqp_consumer._channel = mock.Mock() self.amqp_consumer._channel.basic_cancel = mock.Mock() - self.assertEqual(None, self.amqp_consumer.stop()) + self.assertIsNone(self.amqp_consumer.stop()) def test_close_connection(self): self.amqp_consumer._connection = mock.Mock(autospec=AmqpConsumer) self.amqp_consumer._connection.close = mock.Mock() - self.assertEqual(None, self.amqp_consumer.close_connection()) + self.assertIsNone(self.amqp_consumer.close_connection()) diff --git a/tests/unit/network_services/nfvi/test_resource.py b/tests/unit/network_services/nfvi/test_resource.py index 7ad166249..f5f7f0fe7 100644 --- a/tests/unit/network_services/nfvi/test_resource.py +++ b/tests/unit/network_services/nfvi/test_resource.py @@ -245,7 +245,7 @@ class TestResourceProfile(unittest.TestCase): self.resource_profile.run_collectd_amqp = \ mock.Mock(return_value=0) res = self.resource_profile.amqp_process_for_nfvi_kpi() - self.assertEqual(None, res) + self.assertIsNone(res) def test_amqp_collect_nfvi_kpi(self): self.resource_profile.amqp_client = \ @@ -271,6 +271,3 @@ class TestResourceProfile(unittest.TestCase): # TODO(efoley): Fix this incorrect test. # Should check that we don't try to stop amqp when it's not running self.assertIsNone(self.resource_profile.stop()) - -if __name__ == '__main__': - unittest.main() diff --git a/tests/unit/network_services/traffic_profile/test_base.py b/tests/unit/network_services/traffic_profile/test_base.py index 290610361..3b8804976 100644 --- a/tests/unit/network_services/traffic_profile/test_base.py +++ b/tests/unit/network_services/traffic_profile/test_base.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,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. -# -# Unittest for yardstick.network_services.traffic_profile.test_base +import sys -from __future__ import absolute_import -import unittest import mock +import unittest -from yardstick.network_services.traffic_profile.base import \ - TrafficProfile, DummyProfile +from yardstick.common import exceptions +from yardstick.network_services import traffic_profile as tprofile_package +from yardstick.network_services.traffic_profile import base +from yardstick import tests as y_tests class TestTrafficProfile(unittest.TestCase): @@ -43,20 +41,33 @@ class TestTrafficProfile(unittest.TestCase): return _mock def test___init__(self): - traffic_profile = TrafficProfile(self.TRAFFIC_PROFILE) + traffic_profile = base.TrafficProfile(self.TRAFFIC_PROFILE) self.assertEqual(self.TRAFFIC_PROFILE, traffic_profile.params) def test_execute(self): - traffic_profile = TrafficProfile(self.TRAFFIC_PROFILE) - self.assertRaises(NotImplementedError, traffic_profile.execute_traffic, {}) + traffic_profile = base.TrafficProfile(self.TRAFFIC_PROFILE) + self.assertRaises(NotImplementedError, + traffic_profile.execute_traffic, {}) + + def test_get_existing_traffic_profile(self): + traffic_profile_list = [ + 'RFC2544Profile', 'FixedProfile', 'TrafficProfileGenericHTTP', + 'IXIARFC2544Profile', 'ProxACLProfile', 'ProxBinSearchProfile', + 'ProxProfile', 'ProxRampProfile'] + with mock.patch.dict(sys.modules, y_tests.STL_MOCKS): + tprofile_package.register_modules() + + for tp in traffic_profile_list: + traffic_profile = base.TrafficProfile.get( + {'traffic_profile': {'traffic_type': tp}}) + self.assertEqual(tp, traffic_profile.__class__.__name__) - def test_get(self): - traffic_profile = TrafficProfile(self.TRAFFIC_PROFILE) - self.assertRaises(RuntimeError, traffic_profile.get, - self.TRAFFIC_PROFILE) + def test_get_non_existing_traffic_profile(self): + self.assertRaises(exceptions.TrafficProfileNotImplemented, + base.TrafficProfile.get, self.TRAFFIC_PROFILE) class TestDummyProfile(unittest.TestCase): def test_execute(self): - dummy_profile = DummyProfile(TrafficProfile) + dummy_profile = base.DummyProfile(base.TrafficProfile) self.assertIsNone(dummy_profile.execute({})) diff --git a/tests/unit/network_services/traffic_profile/test_fixed.py b/tests/unit/network_services/traffic_profile/test_fixed.py index eb182a2fb..dec94964b 100644 --- a/tests/unit/network_services/traffic_profile/test_fixed.py +++ b/tests/unit/network_services/traffic_profile/test_fixed.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -119,4 +117,4 @@ class TestFixedProfile(unittest.TestCase): fixed_profile = FixedProfile(self.TRAFFIC_PROFILE) fixed_profile.params = self.TRAFFIC_PROFILE fixed_profile.first_run = True - self.assertEqual(None, fixed_profile.execute(traffic_generator)) + self.assertIsNone(fixed_profile.execute(traffic_generator)) diff --git a/tests/unit/network_services/traffic_profile/test_http.py b/tests/unit/network_services/traffic_profile/test_http.py index e818a0528..5d8029ea0 100644 --- a/tests/unit/network_services/traffic_profile/test_http.py +++ b/tests/unit/network_services/traffic_profile/test_http.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,13 +31,11 @@ class TestTrafficProfileGenericHTTP(unittest.TestCase): traffic_profile_generic_htt_p = \ TrafficProfileGenericHTTP(TrafficProfile) traffic_generator = {} - self.assertEqual(None, - traffic_profile_generic_htt_p.execute( - traffic_generator)) + self.assertIsNone( + traffic_profile_generic_htt_p.execute(traffic_generator)) def test__send_http_request(self): traffic_profile_generic_htt_p = \ TrafficProfileGenericHTTP(TrafficProfile) - self.assertEqual(None, - traffic_profile_generic_htt_p._send_http_request( + self.assertIsNone(traffic_profile_generic_htt_p._send_http_request( "10.1.1.1", "250", "/req")) diff --git a/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py b/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py index f13945abf..e8910d62b 100644 --- a/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py +++ b/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +27,7 @@ stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) stl_patch.start() if stl_patch: - from yardstick.network_services.traffic_profile.traffic_profile \ + from yardstick.network_services.traffic_profile.trex_traffic_profile \ import TrexProfile from yardstick.network_services.traffic_profile.ixia_rfc2544 import \ IXIARFC2544Profile @@ -474,7 +472,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): r_f_c2544_profile.get_multiplier = mock.Mock() r_f_c2544_profile._ixia_traffic_generate = mock.Mock() ixia_obj = mock.MagicMock() - self.assertEqual(None, r_f_c2544_profile.execute_traffic(traffic_generator, ixia_obj)) + self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator, ixia_obj)) def test_update_traffic_profile(self): traffic_generator = mock.Mock(autospec=TrexProfile) @@ -609,10 +607,5 @@ class TestIXIARFC2544Profile(unittest.TestCase): mock.Mock(return_value={}) r_f_c2544_profile.full_profile = {} r_f_c2544_profile._ixia_traffic_generate = mock.Mock() - self.assertEqual( - None, + self.assertIsNone( r_f_c2544_profile.start_ixia_latency(traffic_generator, ixia_obj)) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/unit/network_services/traffic_profile/test_prox_profile.py b/tests/unit/network_services/traffic_profile/test_prox_profile.py index 078e72b8e..e5b36096f 100644 --- a/tests/unit/network_services/traffic_profile/test_prox_profile.py +++ b/tests/unit/network_services/traffic_profile/test_prox_profile.py @@ -31,14 +31,25 @@ if stl_patch: class TestProxProfile(unittest.TestCase): + def test_sort_vpci(self): + traffic_generator = mock.Mock() + interface_1 = {'virtual-interface': {'vpci': 'id1'}, 'name': 'name1'} + interface_2 = {'virtual-interface': {'vpci': 'id2'}, 'name': 'name2'} + interface_3 = {'virtual-interface': {'vpci': 'id3'}, 'name': 'name3'} + interfaces = [interface_2, interface_3, interface_1] + traffic_generator.vnfd_helper = { + 'vdu': [{'external-interface': interfaces}]} + output = ProxProfile.sort_vpci(traffic_generator) + self.assertEqual([interface_1, interface_2, interface_3], output) + def test_fill_samples(self): samples = {} + traffic_generator = mock.MagicMock() - traffic_generator.vpci_if_name_ascending = [ + interfaces = [ ['id1', 'name1'], - ['id2', 'name2'], + ['id2', 'name2'] ] - traffic_generator.resource_helper.sut.port_stats.side_effect = [ list(range(12)), list(range(10, 22)), @@ -54,7 +65,9 @@ class TestProxProfile(unittest.TestCase): 'out_packets': 17, }, } - ProxProfile.fill_samples(samples, traffic_generator) + with mock.patch.object(ProxProfile, 'sort_vpci', return_value=interfaces): + ProxProfile.fill_samples(samples, traffic_generator) + self.assertDictEqual(samples, expected) def test_init(self): diff --git a/tests/unit/network_services/traffic_profile/test_rfc2544.py b/tests/unit/network_services/traffic_profile/test_rfc2544.py index 221233710..cb3a547ee 100644 --- a/tests/unit/network_services/traffic_profile/test_rfc2544.py +++ b/tests/unit/network_services/traffic_profile/test_rfc2544.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,9 +13,6 @@ # limitations under the License. # -from __future__ import absolute_import -from __future__ import division - import unittest import mock @@ -29,7 +24,7 @@ stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) stl_patch.start() if stl_patch: - from yardstick.network_services.traffic_profile.traffic_profile \ + from yardstick.network_services.traffic_profile.trex_traffic_profile \ import TrexProfile from yardstick.network_services.traffic_profile.rfc2544 import \ RFC2544Profile @@ -51,34 +46,34 @@ class TestRFC2544Profile(unittest.TestCase): 'traffic_profile': {'traffic_type': 'RFC2544Profile', 'frame_rate': 100}, 'downlink_0': {'ipv4': - {'outer_l2': {'framesize': - {'64B': '100', '1518B': '0', - '128B': '0', '1400B': '0', - '256B': '0', '373b': '0', - '570B': '0'}}, - 'outer_l3v4': {'dstip4': '1.1.1.1-1.15.255.255', - 'proto': 'udp', - 'srcip4': '90.90.1.1-90.105.255.255', - 'dscp': 0, 'ttl': 32, 'count': 1}, - 'outer_l4': {'srcport': '2001', - 'dsrport': '1234', 'count': 1}}}, + {'outer_l2': {'framesize': + {'64B': '100', '1518B': '0', + '128B': '0', '1400B': '0', + '256B': '0', '373b': '0', + '570B': '0'}}, + 'outer_l3v4': {'dstip4': '1.1.1.1-1.15.255.255', + 'proto': 'udp', + 'srcip4': '90.90.1.1-90.105.255.255', + 'dscp': 0, 'ttl': 32, 'count': 1}, + 'outer_l4': {'srcport': '2001', + 'dsrport': '1234', 'count': 1}}}, 'uplink_0': {'ipv4': - {'outer_l2': {'framesize': - {'64B': '100', '1518B': '0', - '128B': '0', '1400B': '0', - '256B': '0', '373b': '0', - '570B': '0'}}, - 'outer_l3v4': {'dstip4': '9.9.1.1-90.105.255.255', - 'proto': 'udp', - 'srcip4': '1.1.1.1-1.15.255.255', - 'dscp': 0, 'ttl': 32, 'count': 1}, - 'outer_l4': {'dstport': '2001', - 'srcport': '1234', 'count': 1}}}, + {'outer_l2': {'framesize': + {'64B': '100', '1518B': '0', + '128B': '0', '1400B': '0', + '256B': '0', '373b': '0', + '570B': '0'}}, + 'outer_l3v4': {'dstip4': '9.9.1.1-90.105.255.255', + 'proto': 'udp', + 'srcip4': '1.1.1.1-1.15.255.255', + 'dscp': 0, 'ttl': 32, 'count': 1}, + 'outer_l4': {'dstport': '2001', + 'srcport': '1234', 'count': 1}}}, 'schema': 'isb:traffic_profile:0.1'} def test___init__(self): r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - assert r_f_c2544_profile.rate + self.assertIsNotNone(r_f_c2544_profile.rate) def test_execute(self): traffic_generator = mock.Mock(autospec=TrexProfile) @@ -86,12 +81,11 @@ class TestRFC2544Profile(unittest.TestCase): "uplink_0": ["xe0"], "downlink_0": ["xe1"], } - traffic_generator.client = \ - mock.Mock(return_value=True) + traffic_generator.client.return_value = True r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) r_f_c2544_profile.params = self.PROFILE r_f_c2544_profile.first_run = True - self.assertEqual(None, r_f_c2544_profile.execute_traffic(traffic_generator)) + self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator)) def test_get_drop_percentage(self): traffic_generator = mock.Mock(autospec=TrexProfile) @@ -99,7 +93,7 @@ class TestRFC2544Profile(unittest.TestCase): "uplink_0": ["xe0"], "downlink_0": ["xe1"], } - traffic_generator.client = mock.Mock(return_value=True) + traffic_generator.client.return_value = True r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) r_f_c2544_profile.params = self.PROFILE @@ -133,7 +127,7 @@ class TestRFC2544Profile(unittest.TestCase): 'rx_throughput_fps': 20, }, } - traffic_generator.generate_samples = mock.MagicMock(return_value=samples) + traffic_generator.generate_samples.return_value = samples traffic_generator.RUN_DURATION = 30 traffic_generator.rfc2544_helper.tolerance_low = 0.0001 traffic_generator.rfc2544_helper.tolerance_high = 0.0001 @@ -164,8 +158,6 @@ class TestRFC2544Profile(unittest.TestCase): "in_packets": 1000, "out_packets": 1002, } - tol_min = 0.0 - tolerance = 1.0 expected = { 'DropPercentage': 0.1996, 'RxThroughput': 33.333333333333336, @@ -181,7 +173,8 @@ class TestRFC2544Profile(unittest.TestCase): 'rx_throughput_fps': 20, }, } - traffic_generator.generate_samples = mock.MagicMock(return_value=samples) + traffic_generator.generate_samples = mock.MagicMock( + return_value=samples) traffic_generator.RUN_DURATION = 30 traffic_generator.rfc2544_helper.tolerance_low = 0.0001 traffic_generator.rfc2544_helper.tolerance_high = 0.0001 @@ -198,7 +191,7 @@ class TestRFC2544Profile(unittest.TestCase): mock.Mock(return_value=True) r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) r_f_c2544_profile.params = self.PROFILE - self.assertEqual(None, r_f_c2544_profile.execute_traffic(traffic_generator)) + self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator)) samples = {} for ifname in range(1): name = "xe{}".format(ifname) @@ -208,8 +201,6 @@ class TestRFC2544Profile(unittest.TestCase): "tx_throughput_mbps": 10, "in_packets": 1000, "out_packets": 0} - tol_min = 0.0 - tolerance = 0.0 r_f_c2544_profile.throughput_max = 0 expected = { 'DropPercentage': 100.0, 'RxThroughput': 100 / 3.0, @@ -221,7 +212,7 @@ class TestRFC2544Profile(unittest.TestCase): 'tx_throughput_mbps': 10, 'rx_throughput_fps': 20 } } - traffic_generator.generate_samples = mock.MagicMock(return_value=samples) + traffic_generator.generate_samples = mock.Mock(return_value=samples) traffic_generator.RUN_DURATION = 30 traffic_generator.rfc2544_helper.tolerance_low = 0.0001 traffic_generator.rfc2544_helper.tolerance_high = 0.0001 @@ -281,10 +272,5 @@ class TestRFC2544Profile(unittest.TestCase): r_f_c2544_profile.calculate_pps = mock.Mock(return_value=[2274546.67, 1.0]) - self.assertEqual(None, - r_f_c2544_profile.execute_latency(traffic_generator, - samples)) - - -if __name__ == '__main__': - unittest.main() + self.assertIsNone(r_f_c2544_profile.execute_latency(traffic_generator, + samples)) diff --git a/tests/unit/network_services/traffic_profile/test_traffic_profile.py b/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py index 37b9a08d0..d1009a5e8 100644 --- a/tests/unit/network_services/traffic_profile/test_traffic_profile.py +++ b/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,16 +27,16 @@ stl_patch.start() if stl_patch: from yardstick.network_services.traffic_profile.base import TrafficProfile - from yardstick.network_services.traffic_profile.traffic_profile import TrexProfile - from yardstick.network_services.traffic_profile.traffic_profile import SRC - from yardstick.network_services.traffic_profile.traffic_profile import DST - from yardstick.network_services.traffic_profile.traffic_profile import ETHERNET - from yardstick.network_services.traffic_profile.traffic_profile import IP - from yardstick.network_services.traffic_profile.traffic_profile import IPv6 - from yardstick.network_services.traffic_profile.traffic_profile import UDP - from yardstick.network_services.traffic_profile.traffic_profile import SRC_PORT - from yardstick.network_services.traffic_profile.traffic_profile import DST_PORT - from yardstick.network_services.traffic_profile.traffic_profile import TYPE_OF_SERVICE + from yardstick.network_services.traffic_profile.trex_traffic_profile import TrexProfile + from yardstick.network_services.traffic_profile.trex_traffic_profile import SRC + from yardstick.network_services.traffic_profile.trex_traffic_profile import DST + from yardstick.network_services.traffic_profile.trex_traffic_profile import ETHERNET + from yardstick.network_services.traffic_profile.trex_traffic_profile import IP + from yardstick.network_services.traffic_profile.trex_traffic_profile import IPv6 + from yardstick.network_services.traffic_profile.trex_traffic_profile import UDP + from yardstick.network_services.traffic_profile.trex_traffic_profile import SRC_PORT + from yardstick.network_services.traffic_profile.trex_traffic_profile import DST_PORT + from yardstick.network_services.traffic_profile.trex_traffic_profile import TYPE_OF_SERVICE class TestTrexProfile(unittest.TestCase): @@ -153,11 +151,11 @@ class TestTrexProfile(unittest.TestCase): trex_profile = \ TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_qinq(qinq)) + self.assertIsNone(trex_profile.set_qinq(qinq)) qinq = {"S-VLAN": {"id": "128-130", "priority": 0, "cfi": 0}, "C-VLAN": {"id": "512-515", "priority": 0, "cfi": 0}} - self.assertEqual(None, trex_profile.set_qinq(qinq)) + self.assertIsNone(trex_profile.set_qinq(qinq)) def test__set_outer_l2_fields(self): trex_profile = \ @@ -166,14 +164,14 @@ class TestTrexProfile(unittest.TestCase): "C-VLAN": {"id": 512, "priority": 0, "cfi": 0}} outer_l2 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l2'] outer_l2['QinQ'] = qinq - self.assertEqual(None, trex_profile._set_outer_l2_fields(outer_l2)) + self.assertIsNone(trex_profile._set_outer_l2_fields(outer_l2)) def test__set_outer_l3v4_fields(self): trex_profile = \ TrexProfile(TrafficProfile) outer_l3v4 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l3v4'] outer_l3v4['proto'] = 'tcp' - self.assertEqual(None, trex_profile._set_outer_l3v4_fields(outer_l3v4)) + self.assertIsNone(trex_profile._set_outer_l3v4_fields(outer_l3v4)) def test__set_outer_l3v6_fields(self): trex_profile = \ @@ -182,13 +180,13 @@ class TestTrexProfile(unittest.TestCase): outer_l3v6['proto'] = 'tcp' outer_l3v6['tc'] = 1 outer_l3v6['hlim'] = 10 - self.assertEqual(None, trex_profile._set_outer_l3v6_fields(outer_l3v6)) + self.assertIsNone(trex_profile._set_outer_l3v6_fields(outer_l3v6)) def test__set_outer_l4_fields(self): trex_profile = \ TrexProfile(TrafficProfile) outer_l4 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l4'] - self.assertEqual(None, trex_profile._set_outer_l4_fields(outer_l4)) + self.assertIsNone(trex_profile._set_outer_l4_fields(outer_l4)) def test_get_streams(self): trex_profile = \ diff --git a/tests/unit/network_services/vnf_generic/test_vnfdgen.py b/tests/unit/network_services/vnf_generic/test_vnfdgen.py index ee881c963..2ab14129b 100644 --- a/tests/unit/network_services/vnf_generic/test_vnfdgen.py +++ b/tests/unit/network_services/vnf_generic/test_vnfdgen.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py index f9a10149e..2971b55eb 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +19,7 @@ import os from tests.unit import STL_MOCKS from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh +from yardstick.common import utils STLClient = mock.MagicMock() @@ -312,7 +311,7 @@ class TestAclApproxVnf(unittest.TestCase): acl_approx_vnf.ssh_helper.run.assert_called_once() @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.YangModel") - @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.find_relative_file") + @mock.patch.object(utils, 'find_relative_file') @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") @mock.patch(SSH_HELPER) def test_instantiate(self, ssh, *args): @@ -345,4 +344,4 @@ class TestAclApproxVnf(unittest.TestCase): acl_approx_vnf.vnf_execute = mock.MagicMock() acl_approx_vnf.dpdk_devbind = "dpdk-devbind.py" acl_approx_vnf._resource_collect_stop = mock.Mock() - self.assertEqual(None, acl_approx_vnf.terminate()) + self.assertIsNone(acl_approx_vnf.terminate()) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_base.py b/tests/unit/network_services/vnf_generic/vnf/test_base.py index e9488f76f..664373f8f 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_base.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_base.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -195,7 +193,7 @@ class TestQueueFileWrapper(unittest.TestCase): def test_close(self): queue_file_wrapper = \ base.QueueFileWrapper(self.q_in, self.q_out, self.prompt) - self.assertEqual(None, queue_file_wrapper.close()) + self.assertIsNone(queue_file_wrapper.close()) def test_read(self): queue_file_wrapper = \ diff --git a/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py index 62b3c7440..edaa0ad7e 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py b/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py index ac67cc52c..bc48f994c 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,8 +22,9 @@ import mock import unittest from tests.unit import STL_MOCKS +from yardstick.common import utils from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper - +from yardstick.network_services import constants STLClient = mock.MagicMock() stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) @@ -47,7 +46,6 @@ if stl_patch: from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxVpeProfileHelper from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxlwAFTRProfileHelper - class TestCoreTuple(unittest.TestCase): def test___init__(self): core_tuple = CoreSocketTuple('core 5s6') @@ -962,7 +960,7 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): result = setup_helper.prox_config_data self.assertEqual(result, expected) - @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.find_relative_file') + @mock.patch.object(utils, 'find_relative_file') def test_build_config_file_no_additional_file(self, mock_find_path): vnf1 = { 'prox_args': {'-c': ""}, @@ -996,7 +994,7 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): self.assertEqual(helper._prox_config_data, '4') self.assertEqual(helper.remote_path, '5') - @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.find_relative_file') + @mock.patch.object(utils, 'find_relative_file') def test_build_config_file_additional_file_string(self, mock_find_path): vnf1 = { 'prox_args': {'-c': ""}, @@ -1028,7 +1026,7 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): helper.build_config_file() self.assertDictEqual(helper.additional_files, expected) - @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.find_relative_file') + @mock.patch.object(utils, 'find_relative_file') def test_build_config_file_additional_file(self, mock_find_path): vnf1 = { 'prox_args': {'-c': ""}, @@ -1538,7 +1536,9 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.port_stats.return_value = list(range(10)) - data_helper = ProxDataHelper(vnfd_helper, sut, pkt_size, 25, None) + data_helper = ProxDataHelper( + vnfd_helper, sut, pkt_size, 25, None, + constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) self.assertEqual(data_helper.rx_total, 6) self.assertEqual(data_helper.tx_total, 7) @@ -1552,7 +1552,7 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.port_stats.return_value = list(range(10)) - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None) + data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None, None) expected = { 'xe1': { @@ -1575,13 +1575,15 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.port_stats.return_value = list(range(10)) - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, 5.4) + data_helper = ProxDataHelper(vnfd_helper, sut, None, None, + 5.4, constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) data_helper._totals_and_pps = 12, 32, 4.5 data_helper.tsc_hz = 9.8 data_helper.measured_stats = {'delta': TotStatsTuple(6.1, 6.2, 6.3, 6.4)} data_helper.latency = 7 self.assertIsNone(data_helper.result_tuple) + self.assertEqual(data_helper.line_speed, 10000000000) expected = ProxTestDataTuple(5.4, 9.8, 6.1, 6.2, 6.3, 7, 12, 32, 4.5) with data_helper: @@ -1596,7 +1598,7 @@ class TestProxDataHelper(unittest.TestCase): def test___enter___negative(self): vnfd_helper = mock.MagicMock() - data_helper = ProxDataHelper(vnfd_helper, None, None, None, None) + data_helper = ProxDataHelper(vnfd_helper, None, None, None, None, None) vnfd_helper.port_pairs.all_ports = [] with self.assertRaises(AssertionError): @@ -1618,7 +1620,7 @@ class TestProxDataHelper(unittest.TestCase): sut = ProxSocketHelper(mock.MagicMock()) sut.get_all_tot_stats = mock.MagicMock(side_effect=[start, end]) - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, 5.4) + data_helper = ProxDataHelper(vnfd_helper, sut, None, None, 5.4, None) self.assertIsNone(data_helper.measured_stats) @@ -1639,7 +1641,7 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.hz.return_value = '54.6' - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None) + data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None, None) self.assertIsNone(data_helper.tsc_hz) @@ -1936,7 +1938,8 @@ class TestProxProfileHelper(unittest.TestCase): helper = ProxProfileHelper(resource_helper) - helper.run_test(120, 5, 6.5) + helper.run_test(120, 5, 6.5, + constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) class TestProxMplsProfileHelper(unittest.TestCase): @@ -2082,8 +2085,12 @@ class TestProxBngProfileHelper(unittest.TestCase): helper = ProxBngProfileHelper(resource_helper) - helper.run_test(120, 5, 6.5) - helper.run_test(-1000, 5, 6.5) # negative pkt_size is the only way to make ratio > 1 + helper.run_test(120, 5, 6.5, + constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) + + # negative pkt_size is the only way to make ratio > 1 + helper.run_test(-1000, 5, 6.5, + constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) class TestProxVpeProfileHelper(unittest.TestCase): diff --git a/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py index 08be4865b..159b1f718 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -379,6 +377,25 @@ class TestProxApproxVnf(unittest.TestCase): file_path = os.path.join(curr_path, filename) return file_path + @mock.patch('yardstick.common.utils.open', create=True) + @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.open', create=True) + @mock.patch('yardstick.network_services.helpers.iniparser.open', create=True) + @mock.patch(SSH_HELPER) + def test_run_prox(self, ssh, *_): + mock_ssh(ssh) + + prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf.scenario_helper.scenario_cfg = self.SCENARIO_CFG + prox_approx_vnf.ssh_helper.join_bin_path.return_value = '/tool_path12/tool_file34' + prox_approx_vnf.setup_helper.remote_path = 'configs/file56.cfg' + + expected = "sudo bash -c 'cd /tool_path12; " \ + "/tool_path12/tool_file34 -o cli -t -f /tmp/l3-swap-2.cfg '" + + prox_approx_vnf._run() + result = prox_approx_vnf.ssh_helper.run.call_args[0][0] + self.assertEqual(result, expected) + @mock.patch(SSH_HELPER) def bad_test_instantiate(self, *args): prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py index 9ed6fd5b3..c6292f258 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -261,7 +259,4 @@ class TestRouterVNF(unittest.TestCase): router_vnf = RouterVNF(name, vnfd) router_vnf._vnf_process = mock.MagicMock() router_vnf._vnf_process.terminate = mock.Mock() - self.assertEqual(None, router_vnf.terminate()) - -if __name__ == '__main__': - unittest.main() + self.assertIsNone(router_vnf.terminate()) 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 cc4ffa5f7..c7d2abcd5 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 @@ -1,6 +1,4 @@ -#!/usr/bin/env python - -# Copyright (c) 2017 Intel Corporation +# 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. @@ -40,7 +38,7 @@ stl_patch.start() if stl_patch: from yardstick.network_services.vnf_generic.vnf import sample_vnf - from yardstick.network_services.vnf_generic.vnf.sample_vnf import VnfSshHelper + from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFDeployHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import ResourceHelper @@ -547,9 +545,10 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): mock_meminfo.assert_called_once_with(ssh_helper) @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open') - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.find_relative_file') + @mock.patch.object(utils, 'find_relative_file') @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig') - def test_build_config(self, mock_multi_port_config_class, mock_find, *args): + @mock.patch.object(utils, 'open_relative_file') + def test_build_config(self, mock_open_rf, mock_multi_port_config_class, mock_find, *args): mock_multi_port_config = mock_multi_port_config_class() vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() @@ -566,6 +565,20 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): self.assertGreaterEqual(mock_multi_port_config.generate_config.call_count, 1) self.assertGreaterEqual(mock_multi_port_config.generate_script.call_count, 1) + scenario_helper.vnf_cfg = {'file': 'fake_file'} + dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + mock_open_rf.side_effect = mock.mock_open(read_data='fake_data') + dpdk_setup_helper.PIPELINE_COMMAND = expected = 'pipeline command' + + result = dpdk_setup_helper.build_config() + + mock_open_rf.assert_called_once() + self.assertEqual(result, expected) + self.assertGreaterEqual(ssh_helper.upload_config_file.call_count, 2) + self.assertGreaterEqual(mock_find.call_count, 1) + self.assertGreaterEqual(mock_multi_port_config.generate_config.call_count, 1) + self.assertGreaterEqual(mock_multi_port_config.generate_script.call_count, 1) + def test__build_pipeline_kwargs(self): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() @@ -601,7 +614,9 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): ssh_helper = mock.Mock() ssh_helper.execute = execute - dpdk_vnf_setup_env_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, mock.Mock()) + scenario_helper = mock.Mock() + scenario_helper.nodes = [None, None] + dpdk_vnf_setup_env_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) dpdk_vnf_setup_env_helper._validate_cpu_cfg = mock.Mock(return_value=[]) with mock.patch.object(dpdk_vnf_setup_env_helper, '_setup_dpdk'): @@ -623,21 +638,6 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): mock.call('lsmod | grep -i igb_uio') ]) - def test__setup_dpdk_igb_uio_not_loaded(self): - ssh_helper = mock.Mock() - 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, _): vnfd_helper = VnfdHelper(deepcopy(self.VNFD_0)) @@ -675,6 +675,7 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): # ssh_helper.execute = mock.Mock(return_value = (0, 'text', '')) # ssh_helper.execute.return_value = 0, 'output', '' scenario_helper = mock.Mock() + scenario_helper.nodes = [None, None] rv = ['0000:05:00.1', '0000:05:00.0'] dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) @@ -693,6 +694,7 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() + scenario_helper.nodes = [None, None] dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) dpdk_setup_helper.dpdk_bind_helper.bind = mock.Mock() dpdk_setup_helper.dpdk_bind_helper.used_drivers = { @@ -1371,7 +1373,7 @@ class TestSampleVNFDeployHelper(unittest.TestCase): @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time') @mock.patch('subprocess.check_output') - def test_deploy_vnfs_disabled(self, *args): + def test_deploy_vnfs_disabled(self, *_): vnfd_helper = mock.Mock() ssh_helper = mock.Mock() ssh_helper.join_bin_path.return_value = 'joined_path' diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py index d77068137..d831ddd3d 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,13 +13,15 @@ # limitations under the License. # -from __future__ import absolute_import +import subprocess -import unittest import mock -import subprocess +import unittest +import six from tests.unit import STL_MOCKS +from yardstick import ssh +from yardstick.common import utils STLClient = mock.MagicMock() @@ -145,13 +145,13 @@ class TestIxLoadTrafficGen(unittest.TestCase): ssh.from_node.return_value = ssh_mock vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - self.assertEqual(None, ixload_traffic_gen.listen_traffic({})) + self.assertIsNone(ixload_traffic_gen.listen_traffic({})) - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.makedirs") + @mock.patch.object(utils, 'find_relative_file') + @mock.patch.object(utils, 'makedirs') @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil") - def test_instantiate(self, call, shutil, mock_makedirs): - # pylint: disable=unused-argument + def test_instantiate(self, shutil, *args): with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) ssh_mock.execute = \ @@ -175,19 +175,18 @@ class TestIxLoadTrafficGen(unittest.TestCase): '1C/1T', 'worker_threads': 1}} }}) - with mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.open', - create=True) as mock_open: + with mock.patch.object(six.moves.builtins, 'open', + create=True) as mock_open: mock_open.return_value = mock.MagicMock() ixload_traffic_gen.instantiate(scenario_cfg, {}) @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len") - def test_run_traffic(self, call, shutil, main_open, min, max, len): - # pylint: disable=unused-argument + @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil") + def test_run_traffic(self, shutil, *args): mock_traffic_profile = mock.Mock(autospec=TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE @@ -213,13 +212,12 @@ class TestIxLoadTrafficGen(unittest.TestCase): self.assertIsNone(result) @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len") - def test_run_traffic_csv(self, call, shutil, main_open, min, max, len): - # pylint: disable=unused-argument + @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil") + def test_run_traffic_csv(self, shutil, *args): mock_traffic_profile = mock.Mock(autospec=TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE @@ -247,20 +245,15 @@ class TestIxLoadTrafficGen(unittest.TestCase): self.assertIsNone(result) @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") + @mock.patch.object(ssh, 'SSH') def test_terminate(self, *args): - with mock.patch("yardstick.ssh.SSH") as ssh: - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - self.assertEqual(None, ixload_traffic_gen.terminate()) + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) + self.assertIsNone(ixload_traffic_gen.terminate()) - @mock.patch("yardstick.ssh.SSH") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - def test_parse_csv_read(self, mock_call, mock_ssh): - # pylint: disable=unused-argument + @mock.patch.object(ssh, 'SSH') + def test_parse_csv_read(self, mock_ssh, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] kpi_data = { 'HTTP Total Throughput (Kbps)': 1, @@ -282,10 +275,9 @@ class TestIxLoadTrafficGen(unittest.TestCase): for key_left, key_right in IxLoadResourceHelper.KPI_LIST.items(): self.assertEqual(result[key_left][-1], int(kpi_data[key_right])) - @mock.patch("yardstick.ssh.SSH") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - def test_parse_csv_read_value_error(self, mock_call, mock_ssh): - # pylint: disable=unused-argument + @mock.patch.object(ssh, 'SSH') + def test_parse_csv_read_value_error(self, mock_ssh, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] http_reader = [{ 'HTTP Total Throughput (Kbps)': 1, @@ -305,10 +297,9 @@ class TestIxLoadTrafficGen(unittest.TestCase): ixload_traffic_gen.resource_helper.parse_csv_read(http_reader) self.assertDictEqual(ixload_traffic_gen.resource_helper.result, init_value) - @mock.patch("yardstick.ssh.SSH") @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - def test_parse_csv_read_error(self, mock_call, mock_ssh): - # pylint: disable=unused-argument + @mock.patch.object(ssh, 'SSH') + def test_parse_csv_read_error(self, mock_ssh, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] http_reader = [{ 'HTTP Total Throughput (Kbps)': 1, diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py index fb26f20b5..91a353d0d 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,7 +34,7 @@ if stl_patch: from yardstick.network_services.vnf_generic.vnf.tg_ping import PingTrafficGen from yardstick.network_services.vnf_generic.vnf.tg_ping import PingResourceHelper from yardstick.network_services.vnf_generic.vnf.tg_ping import PingSetupEnvHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import VnfSshHelper + from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper class TestPingResourceHelper(unittest.TestCase): diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py index 0104e7f63..2151a3284 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py @@ -423,4 +423,4 @@ class TestProxTrafficGen(unittest.TestCase): prox_traffic_gen._vnf_wrapper.setup_helper = mock.MagicMock() prox_traffic_gen._vnf_wrapper._vnf_process = mock.MagicMock() prox_traffic_gen._vnf_wrapper.resource_helper = mock.MagicMock() - self.assertEqual(None, prox_traffic_gen.terminate()) + self.assertIsNone(prox_traffic_gen.terminate()) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py index e9f718cb7..61fc012bc 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,8 +14,10 @@ # import os -import unittest + import mock +import six +import unittest from tests.unit import STL_MOCKS @@ -170,7 +170,7 @@ class TestIXIATrafficGen(unittest.TestCase): ssh.from_node.return_value = ssh_mock vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd) - self.assertEqual(None, ixnet_traffic_gen.listen_traffic({})) + self.assertIsNone(ixnet_traffic_gen.listen_traffic({})) def test_instantiate(self, *args): with mock.patch("yardstick.ssh.SSH") as ssh: @@ -228,7 +228,7 @@ class TestIXIATrafficGen(unittest.TestCase): ixnet_traffic_gen._ixia_traffic_gen.ix_stop_traffic = mock.Mock() ixnet_traffic_gen._traffic_process = mock.MagicMock() ixnet_traffic_gen._traffic_process.terminate = mock.Mock() - self.assertEqual(None, ixnet_traffic_gen.terminate()) + self.assertIsNone(ixnet_traffic_gen.terminate()) def _get_file_abspath(self, filename): curr_path = os.path.dirname(os.path.abspath(__file__)) @@ -341,7 +341,7 @@ class TestIXIATrafficGen(unittest.TestCase): 'task_path': '/path/to/task' } - @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.open', create=True) + @mock.patch.object(six.moves.builtins, 'open', create=True) @mock.patch('yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.open', mock.mock_open(), create=True) @mock.patch('yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.LOG.exception') diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py index 7342cfcdc..b9a95a945 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py index 618071507..f80d1f948 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -483,7 +481,3 @@ class TestTrexTrafficGen(unittest.TestCase): client = mock.Mock(autospec=STLClient) client.connect = mock.Mock(return_value=0) self.assertIsNotNone(trex_traffic_gen.resource_helper._connect(client)) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py b/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py index 472052b0a..4cf4320f9 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py index f0a56665c..48fc87ed4 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +20,9 @@ import os from tests.unit import STL_MOCKS from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh +from yardstick.common import utils + + STLClient = mock.MagicMock() stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) stl_patch.start() @@ -331,7 +332,7 @@ pipeline> vfw_approx_vnf._run() vfw_approx_vnf.ssh_helper.run.assert_called_once() - @mock.patch("yardstick.network_services.vnf_generic.vnf.vfw_vnf.find_relative_file") + @mock.patch.object(utils, 'find_relative_file') @mock.patch("yardstick.network_services.vnf_generic.vnf.vfw_vnf.YangModel") @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") @mock.patch(SSH_HELPER) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py index c074dfb4c..8c45d973e 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -6,6 +6,8 @@ envlist = py{27,3},pep8,functional{,-py3},coverage [testenv] usedevelop=True passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY BRANCH +setenv = + VIRTUAL_ENV={envdir} deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt diff --git a/yardstick/__init__.py b/yardstick/__init__.py index f95b0a906..9eb5db9b1 100644 --- a/yardstick/__init__.py +++ b/yardstick/__init__.py @@ -14,8 +14,9 @@ import errno # this module must only import other modules that do # not require loggers to be created, so this cannot -# include yardstick.common.utils from yardstick.common import constants +from yardstick.common import exceptions + try: # do not use yardstick.common.utils.makedirs diff --git a/yardstick/benchmark/contexts/base.py b/yardstick/benchmark/contexts/base.py index c9b5b51c9..ae8319e37 100644 --- a/yardstick/benchmark/contexts/base.py +++ b/yardstick/benchmark/contexts/base.py @@ -6,17 +6,41 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import import abc import six import yardstick.common.utils as utils +class Flags(object): + """Class to represent the status of the flags in a context""" + + _FLAGS = {'no_setup': False, + 'no_teardown': False} + + def __init__(self, **kwargs): + for name, value in self._FLAGS.items(): + setattr(self, name, value) + + for name, value in ((name, value) for (name, value) in kwargs.items() + if name in self._FLAGS): + setattr(self, name, value) + + def parse(self, **kwargs): + """Read in values matching the flags stored in this object""" + if not kwargs: + return + + for name, value in ((name, value) for (name, value) in kwargs.items() + if name in self._FLAGS): + setattr(self, name, value) + + @six.add_metaclass(abc.ABCMeta) class Context(object): """Class that represents a context in the logical model""" list = [] + SHORT_TASK_ID_LEN = 8 @staticmethod def split_name(name, sep='.'): @@ -29,10 +53,28 @@ class Context(object): def __init__(self): Context.list.append(self) + self._flags = Flags() + self._name = None + self._task_id = None - @abc.abstractmethod def init(self, attrs): - """Initiate context.""" + """Initiate context""" + self._name = attrs['name'] + self._task_id = attrs['task_id'] + self._flags.parse(**attrs.get('flags', {})) + self._name_task_id = '{}-{}'.format( + self._name, self._task_id[:self.SHORT_TASK_ID_LEN]) + + @property + def name(self): + if self._flags.no_setup or self._flags.no_teardown: + return self._name + else: + return self._name_task_id + + @property + def assigned_name(self): + return self._name @staticmethod def get_cls(context_type): diff --git a/yardstick/benchmark/contexts/dummy.py b/yardstick/benchmark/contexts/dummy.py index 8ae4b65b8..a9e4564fe 100644 --- a/yardstick/benchmark/contexts/dummy.py +++ b/yardstick/benchmark/contexts/dummy.py @@ -7,33 +7,25 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import -import logging - from yardstick.benchmark.contexts.base import Context -LOG = logging.getLogger(__name__) - - class DummyContext(Context): - """Class that handle dummy info""" - - __context_type__ = "Dummy" + """Class that handle dummy info. - def __init__(self): - super(DummyContext, self).__init__() + This class is also used to test the abstract class Context because it + provides a minimal concrete implementation of a subclass. + """ - def init(self, attrs): - pass + __context_type__ = "Dummy" def deploy(self): - """don't need to deploy""" + """Don't need to deploy""" pass def undeploy(self): - """don't need to undeploy""" - super(DummyContext, self).undeploy() + """Don't need to undeploy""" + pass def _get_server(self, attr_name): return None diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index 7b7f1be32..0d1dfb86f 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -13,7 +13,6 @@ from __future__ import print_function import collections import logging import os -import uuid import errno from collections import OrderedDict @@ -25,9 +24,12 @@ from yardstick.benchmark.contexts.model import Network from yardstick.benchmark.contexts.model import PlacementGroup, ServerGroup from yardstick.benchmark.contexts.model import Server from yardstick.benchmark.contexts.model import update_scheduler_hints -from yardstick.common.openstack_utils import get_neutron_client -from yardstick.orchestrator.heat import HeatTemplate, get_short_key_uuid +from yardstick.common import exceptions as y_exc +from yardstick.common.openstack_utils import get_shade_client +from yardstick.orchestrator.heat import HeatStack +from yardstick.orchestrator.heat import HeatTemplate from yardstick.common import constants as consts +from yardstick.common import utils from yardstick.common.utils import source_env from yardstick.ssh import SSH @@ -50,7 +52,6 @@ class HeatContext(Context): __context_type__ = "Heat" def __init__(self): - self.name = None self.stack = None self.networks = OrderedDict() self.heat_timeout = None @@ -67,14 +68,9 @@ class HeatContext(Context): self._user = None self.template_file = None self.heat_parameters = None - self.neutron_client = None - # generate an uuid to identify yardstick_key - # the first 8 digits of the uuid will be used - self.key_uuid = uuid.uuid4() + self.shade_client = None self.heat_timeout = None - self.key_filename = ''.join( - [consts.YARDSTICK_ROOT_PATH, 'yardstick/resources/files/yardstick_key-', - get_short_key_uuid(self.key_uuid)]) + self.key_filename = None super(HeatContext, self).__init__() @staticmethod @@ -95,10 +91,10 @@ class HeatContext(Context): return sorted_networks def init(self, attrs): - """initializes itself from the supplied arguments""" - self.check_environment() - self.name = attrs["name"] + """Initializes itself from the supplied arguments""" + super(HeatContext, self).init(attrs) + self.check_environment() self._user = attrs.get("user") self.template_file = attrs.get("heat_template") @@ -137,7 +133,6 @@ class HeatContext(Context): self._server_map[server.dn] = server self.attrs = attrs - SSH.gen_keys(self.key_filename) def check_environment(self): try: @@ -176,10 +171,13 @@ class HeatContext(Context): template.add_flavor(**self.flavor) self.flavors.add(flavor) - template.add_keypair(self.keypair_name, self.key_uuid) + template.add_keypair(self.keypair_name, self.name) template.add_security_group(self.secgroup_name) for network in self.networks.values(): + # Using existing network + if network.is_existing(): + continue template.add_network(network.stack_name, network.physical_network, network.provider, @@ -285,38 +283,65 @@ class HeatContext(Context): scheduler_hints) def get_neutron_info(self): - if not self.neutron_client: - self.neutron_client = get_neutron_client() + if not self.shade_client: + self.shade_client = get_shade_client() - networks = self.neutron_client.list_networks() + networks = self.shade_client.list_networks() for network in self.networks.values(): - for neutron_net in networks['networks']: - if neutron_net['name'] == network.stack_name: + for neutron_net in (net for net in networks if net.name == network.stack_name): network.segmentation_id = neutron_net.get('provider:segmentation_id') # we already have physical_network # network.physical_network = neutron_net.get('provider:physical_network') network.network_type = neutron_net.get('provider:network_type') network.neutron_info = neutron_net + def _create_new_stack(self, heat_template): + try: + return heat_template.create(block=True, + timeout=self.heat_timeout) + except KeyboardInterrupt: + raise y_exc.StackCreationInterrupt + except Exception: + LOG.exception("stack failed") + # let the other failures happen, we want stack trace + raise + + def _retrieve_existing_stack(self, stack_name): + stack = HeatStack(stack_name) + if stack.get(): + return stack + else: + LOG.warning("Stack %s does not exist", self.name) + return None + def deploy(self): """deploys template into a stack using cloud""" LOG.info("Deploying context '%s' START", self.name) + self.key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.name]) + # Permissions may have changed since creation; this can be fixed. If we + # overwrite the file, we lose future access to VMs using this key. + # As long as the file exists, even if it is unreadable, keep it intact + if not os.path.exists(self.key_filename): + SSH.gen_keys(self.key_filename) + heat_template = HeatTemplate(self.name, self.template_file, self.heat_parameters) if self.template_file is None: self._add_resources_to_template(heat_template) - try: - self.stack = heat_template.create(block=True, - timeout=self.heat_timeout) - except KeyboardInterrupt: - raise SystemExit("\nStack create interrupted") - except: - LOG.exception("stack failed") - # let the other failures happen, we want stack trace - raise + if self._flags.no_setup: + # Try to get an existing stack, returns a stack or None + self.stack = self._retrieve_existing_stack(self.name) + if not self.stack: + self.stack = self._create_new_stack(heat_template) + + else: + self.stack = self._create_new_stack(heat_template) # TODO: use Neutron to get segmentation-id self.get_neutron_info() @@ -332,18 +357,35 @@ class HeatContext(Context): LOG.info("Deploying context '%s' DONE", self.name) + @staticmethod + def _port_net_is_existing(port_info): + net_flags = port_info.get('net_flags', {}) + return net_flags.get(consts.IS_EXISTING) + + @staticmethod + def _port_net_is_public(port_info): + net_flags = port_info.get('net_flags', {}) + return net_flags.get(consts.IS_PUBLIC) + def add_server_port(self, server): - # use private ip from first port in first network - try: - private_port = next(iter(server.ports.values()))[0] - except IndexError: - LOG.exception("Unable to find first private port in %s", server.ports) - raise - server.private_ip = self.stack.outputs[private_port["stack_name"]] + server_ports = server.ports.values() + for server_port in server_ports: + port_info = server_port[0] + port_ip = self.stack.outputs[port_info["stack_name"]] + port_net_is_existing = self._port_net_is_existing(port_info) + port_net_is_public = self._port_net_is_public(port_info) + if port_net_is_existing and (port_net_is_public or + len(server_ports) == 1): + server.public_ip = port_ip + if not server.private_ip or len(server_ports) == 1: + server.private_ip = port_ip + server.interfaces = {} for network_name, ports in server.ports.items(): for port in ports: # port['port'] is either port name from mapping or default network_name + if self._port_net_is_existing(port): + continue server.interfaces[port['port']] = self.make_interface_dict(network_name, port['port'], port['stack_name'], @@ -380,20 +422,27 @@ class HeatContext(Context): "local_ip": private_ip, } + def _delete_key_file(self): + try: + utils.remove_file(self.key_filename) + utils.remove_file(self.key_filename + ".pub") + except OSError: + LOG.exception("There was an error removing the key file %s", + self.key_filename) + def undeploy(self): """undeploys stack from cloud""" + if self._flags.no_teardown: + LOG.info("Undeploying context '%s' SKIP", self.name) + return + if self.stack: LOG.info("Undeploying context '%s' START", self.name) self.stack.delete() self.stack = None LOG.info("Undeploying context '%s' DONE", self.name) - if os.path.exists(self.key_filename): - try: - os.remove(self.key_filename) - os.remove(self.key_filename + ".pub") - except OSError: - LOG.exception("Key filename %s", self.key_filename) + self._delete_key_file() super(HeatContext, self).undeploy() @@ -429,13 +478,17 @@ class HeatContext(Context): server.private_ip = self.stack.outputs.get( attr_name.get("private_ip_attr", object()), None) else: - server = self._server_map.get(attr_name, None) + try: + server = self._server_map[attr_name] + except KeyError: + attr_name_no_suffix = attr_name.split("-")[0] + server = self._server_map.get(attr_name_no_suffix, None) if server is None: return None pkey = pkg_resources.resource_string( 'yardstick.resources', - h_join('files/yardstick_key', get_short_key_uuid(self.key_uuid))).decode('utf-8') + h_join('files/yardstick_key', self.name)).decode('utf-8') result = { "user": server.context.user, diff --git a/yardstick/benchmark/contexts/kubernetes.py b/yardstick/benchmark/contexts/kubernetes.py index 2334e5076..4bea991ea 100644 --- a/yardstick/benchmark/contexts/kubernetes.py +++ b/yardstick/benchmark/contexts/kubernetes.py @@ -29,7 +29,6 @@ class KubernetesContext(Context): __context_type__ = "Kubernetes" def __init__(self): - self.name = '' self.ssh_key = '' self.key_path = '' self.public_key_path = '' @@ -38,7 +37,7 @@ class KubernetesContext(Context): super(KubernetesContext, self).__init__() def init(self, attrs): - self.name = attrs.get('name', '') + super(KubernetesContext, self).init(attrs) template_cfg = attrs.get('servers', {}) self.template = KubernetesTemplate(self.name, template_cfg) diff --git a/yardstick/benchmark/contexts/model.py b/yardstick/benchmark/contexts/model.py index ae56066ee..a55c11f79 100644 --- a/yardstick/benchmark/contexts/model.py +++ b/yardstick/benchmark/contexts/model.py @@ -18,6 +18,8 @@ import logging from collections import Mapping from six.moves import range +from yardstick.common import constants as consts + LOG = logging.getLogger(__name__) @@ -132,11 +134,28 @@ class Network(Object): if self.gateway_ip is None: self.gateway_ip = "null" - if "external_network" in attrs: - self.router = Router("router", self.name, - context, attrs["external_network"]) - - Network.list.append(self) + self.net_flags = attrs.get('net_flags', {}) + if self.is_existing(): + self.subnet = attrs.get('subnet') + if not self.subnet: + raise Warning('No subnet set in existing netwrok!') + else: + if "external_network" in attrs: + self.router = Router("router", self.name, + context, attrs["external_network"]) + Network.list.append(self) + + def is_existing(self): + net_is_existing = self.net_flags.get(consts.IS_EXISTING) + if net_is_existing and not isinstance(net_is_existing, bool): + raise SyntaxError('Network flags should be bool type!') + return net_is_existing + + def is_public(self): + net_is_public = self.net_flags.get(consts.IS_PUBLIC) + if net_is_public and not isinstance(net_is_public, bool): + raise SyntaxError('Network flags should be bool type!') + return net_is_public def has_route_to(self, network_name): """determines if this network has a route to the named network""" @@ -302,10 +321,13 @@ class Server(Object): # pragma: no cover # otherwise add a port for every network with port name as network name else: ports = [network.name] + net_flags = network.net_flags for port in ports: port_name = "{0}-{1}-port".format(server_name, port) - self.ports.setdefault(network.name, []).append( - {"stack_name": port_name, "port": port}) + port_info = {"stack_name": port_name, "port": port} + if net_flags: + port_info['net_flags'] = net_flags + self.ports.setdefault(network.name, []).append(port_info) # we can't use secgroups if port_security_enabled is False if network.port_security_enabled is False: sec_group_id = None @@ -314,11 +336,14 @@ class Server(Object): # pragma: no cover sec_group_id = self.secgroup_name # don't refactor to pass in network object, that causes JSON # circular ref encode errors - template.add_port(port_name, network.stack_name, network.subnet_stack_name, - network.vnic_type, sec_group_id=sec_group_id, + template.add_port(port_name, network, + sec_group_id=sec_group_id, provider=network.provider, allowed_address_pairs=network.allowed_address_pairs) - port_name_list.append(port_name) + if network.is_public(): + port_name_list.insert(0, port_name) + else: + port_name_list.append(port_name) if self.floating_ip: external_network = self.floating_ip["external_network"] diff --git a/yardstick/benchmark/contexts/node.py b/yardstick/benchmark/contexts/node.py index ffc82c8ed..fa619a9aa 100644 --- a/yardstick/benchmark/contexts/node.py +++ b/yardstick/benchmark/contexts/node.py @@ -35,7 +35,6 @@ class NodeContext(Context): __context_type__ = "Node" def __init__(self): - self.name = None self.file_path = None self.nodes = [] self.networks = {} @@ -60,7 +59,8 @@ class NodeContext(Context): def init(self, attrs): """initializes itself from the supplied arguments""" - self.name = attrs["name"] + super(NodeContext, self).init(attrs) + self.file_path = file_path = attrs.get("file", "pod.yaml") try: @@ -157,7 +157,7 @@ class NodeContext(Context): except StopIteration: pass else: - raise ValueError("Duplicate nodes!!! Nodes: %s %s", + raise ValueError("Duplicate nodes!!! Nodes: %s %s" % (node, duplicate)) node["name"] = attr_name @@ -204,7 +204,7 @@ class NodeContext(Context): self.client._put_file_shell(script_file, '~/{}'.format(script)) cmd = 'sudo bash {} {}'.format(script, options) - status, stdout, stderr = self.client.execute(cmd) + status, _, stderr = self.client.execute(cmd) if status: raise RuntimeError(stderr) diff --git a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py index c931d85d0..a18b42ea5 100644 --- a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py +++ b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py @@ -59,7 +59,6 @@ class OvsDpdkContext(Context): self.first_run = True self.dpdk_devbind = '' self.vm_names = [] - self.name = None self.nfvi_host = [] self.nodes = [] self.networks = {} @@ -74,8 +73,8 @@ class OvsDpdkContext(Context): def init(self, attrs): """initializes itself from the supplied arguments""" + super(OvsDpdkContext, self).init(attrs) - self.name = attrs["name"] self.file_path = attrs.get("file", "pod.yaml") self.nodes, self.nfvi_host, self.host_mgmt = \ diff --git a/yardstick/benchmark/contexts/standalone/sriov.py b/yardstick/benchmark/contexts/standalone/sriov.py index 9cca3e15c..d7620552b 100644 --- a/yardstick/benchmark/contexts/standalone/sriov.py +++ b/yardstick/benchmark/contexts/standalone/sriov.py @@ -43,7 +43,6 @@ class SriovContext(Context): self.first_run = True self.dpdk_devbind = '' self.vm_names = [] - self.name = None self.nfvi_host = [] self.nodes = [] self.networks = {} @@ -57,8 +56,8 @@ class SriovContext(Context): def init(self, attrs): """initializes itself from the supplied arguments""" + super(SriovContext, self).init(attrs) - self.name = attrs["name"] self.file_path = attrs.get("file", "pod.yaml") self.nodes, self.nfvi_host, self.host_mgmt = \ diff --git a/yardstick/benchmark/core/__init__.py b/yardstick/benchmark/core/__init__.py index 3e3aa99a1..3914e3237 100644 --- a/yardstick/benchmark/core/__init__.py +++ b/yardstick/benchmark/core/__init__.py @@ -23,6 +23,7 @@ class Param(object): self.task_args_file = kwargs.get('task-args-file') self.keep_deploy = kwargs.get('keep-deploy') self.parse_only = kwargs.get('parse-only') + self.render_only = kwargs.get('render-only') self.output_file = kwargs.get('output-file', '/tmp/yardstick.out') self.suite = kwargs.get('suite') self.task_id = kwargs.get('task_id') diff --git a/yardstick/benchmark/core/report.py b/yardstick/benchmark/core/report.py index 997a125e7..199602444 100644 --- a/yardstick/benchmark/core/report.py +++ b/yardstick/benchmark/core/report.py @@ -45,7 +45,7 @@ class Report(object): self.task_id = "" def _validate(self, yaml_name, task_id): - if re.match("^[a-z0-9_-]+$", yaml_name): + if re.match(r"^[\w-]+$", yaml_name): self.yaml_name = yaml_name else: raise ValueError("invalid yaml_name", yaml_name) @@ -102,10 +102,12 @@ class Report(object): task_time = str(task_time, 'utf8') key = str(key, 'utf8') task_time = task_time[11:] - head, sep, tail = task_time.partition('.') + head, _, tail = task_time.partition('.') task_time = head + "." + tail[:6] self.Timestamp.append(task_time) - if isinstance(task[key], float) is True: + if task[key] is None: + values.append('') + elif isinstance(task[key], (int, float)) is True: values.append(task[key]) else: values.append(ast.literal_eval(task[key])) diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py index f5d2b18ac..e7acde696 100644 --- a/yardstick/benchmark/core/task.py +++ b/yardstick/benchmark/core/task.py @@ -7,10 +7,6 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -""" Handler for yardstick command 'task' """ - -from __future__ import absolute_import -from __future__ import print_function import sys import os from collections import OrderedDict @@ -31,9 +27,10 @@ from yardstick.benchmark.runners import base as base_runner from yardstick.common.constants import CONF_FILE from yardstick.common.yaml_loader import yaml_load from yardstick.dispatcher.base import Base as DispatcherBase -from yardstick.common.task_template import TaskTemplate -from yardstick.common import utils from yardstick.common import constants +from yardstick.common import exceptions as y_exc +from yardstick.common import task_template +from yardstick.common import utils from yardstick.common.html_template import report_template output_file_default = "/tmp/yardstick.out" @@ -57,7 +54,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): + def start(self, args, **kwargs): # pylint: disable=unused-argument """Start a benchmark scenario.""" atexit.register(self.atexit_handler) @@ -89,8 +86,7 @@ class Task(object): # pragma: no cover if args.suite: # 1.parse suite, return suite_params info - task_files, task_args, task_args_fnames = \ - parser.parse_suite() + task_files, task_args, task_args_fnames = parser.parse_suite() else: task_files = [parser.path] task_args = [args.task_args] @@ -103,32 +99,33 @@ class Task(object): # pragma: no cover sys.exit(0) testcases = {} - # parse task_files - for i in range(0, len(task_files)): - one_task_start_time = time.time() - parser.path = task_files[i] - scenarios, run_in_parallel, meet_precondition, contexts = \ - parser.parse_task(self.task_id, task_args[i], - task_args_fnames[i]) - - self.contexts.extend(contexts) + tasks = self._parse_tasks(parser, task_files, args, task_args, + task_args_fnames) - if not meet_precondition: - LOG.info("meet_precondition is %s, please check envrionment", - meet_precondition) + # Execute task files. + for i, _ in enumerate(task_files): + one_task_start_time = time.time() + self.contexts.extend(tasks[i]['contexts']) + if not tasks[i]['meet_precondition']: + LOG.info('"meet_precondition" is %s, please check environment', + tasks[i]['meet_precondition']) continue - case_name = os.path.splitext(os.path.basename(task_files[i]))[0] try: - data = self._run(scenarios, run_in_parallel, output_config) + data = self._run(tasks[i]['scenarios'], + tasks[i]['run_in_parallel'], + output_config) except KeyboardInterrupt: raise except Exception: # pylint: disable=broad-except - LOG.error('Testcase: "%s" FAILED!!!', case_name, exc_info=True) - testcases[case_name] = {'criteria': 'FAIL', 'tc_data': []} + LOG.error('Testcase: "%s" FAILED!!!', tasks[i]['case_name'], + exc_info=True) + testcases[tasks[i]['case_name']] = {'criteria': 'FAIL', + 'tc_data': []} else: - LOG.info('Testcase: "%s" SUCCESS!!!', case_name) - testcases[case_name] = {'criteria': 'PASS', 'tc_data': data} + LOG.info('Testcase: "%s" SUCCESS!!!', tasks[i]['case_name']) + testcases[tasks[i]['case_name']] = {'criteria': 'PASS', + 'tc_data': data} if args.keep_deploy: # keep deployment, forget about stack @@ -151,9 +148,8 @@ class Task(object): # pragma: no cover LOG.info("Total finished in %d secs", total_end_time - total_start_time) - scenario = scenarios[0] - LOG.info("To generate report, execute command " - "'yardstick report generate %(task_id)s %(tc)s'", scenario) + LOG.info('To generate report, execute command "yardstick report ' + 'generate %s <YAML_NAME>"', self.task_id) LOG.info("Task ALL DONE, exiting") return result @@ -314,6 +310,30 @@ class Task(object): # pragma: no cover else: return op + def _parse_tasks(self, parser, task_files, args, task_args, + task_args_fnames): + tasks = [] + + # Parse task_files. + for i, _ in enumerate(task_files): + parser.path = task_files[i] + tasks.append(parser.parse_task(self.task_id, task_args[i], + task_args_fnames[i])) + tasks[i]['case_name'] = os.path.splitext( + os.path.basename(task_files[i]))[0] + + if args.render_only: + utils.makedirs(args.render_only) + for idx, task in enumerate(tasks): + output_file_name = os.path.abspath(os.path.join( + args.render_only, + '{0:03d}-{1}.yml'.format(idx, task['case_name']))) + utils.write_file(output_file_name, task['rendered']) + + sys.exit(0) + + return tasks + def run_one_scenario(self, scenario_cfg, output_config): """run one scenario using context""" runner_cfg = scenario_cfg["runner"] @@ -345,7 +365,7 @@ class Task(object): # pragma: no cover try: config_context_target(item) except KeyError: - pass + LOG.debug("Got a KeyError in config_context_target(%s)", item) else: break @@ -479,33 +499,42 @@ class TaskParser(object): # pragma: no cover return valid_task_files, valid_task_args, valid_task_args_fnames - def parse_task(self, task_id, task_args=None, task_args_file=None): - """parses the task file and return an context and scenario instances""" - LOG.info("Parsing task config: %s", self.path) + def _render_task(self, task_args, task_args_file): + """Render the input task with the given arguments + :param task_args: (dict) arguments to render the task + :param task_args_file: (str) file containing the arguments to render + the task + :return: (str) task file rendered + """ try: kw = {} if task_args_file: with open(task_args_file) as f: - kw.update(parse_task_args("task_args_file", f.read())) - kw.update(parse_task_args("task_args", task_args)) + kw.update(parse_task_args('task_args_file', f.read())) + kw.update(parse_task_args('task_args', task_args)) except TypeError: - raise TypeError() + raise y_exc.TaskRenderArgumentError() + input_task = None try: with open(self.path) as f: - try: - input_task = f.read() - rendered_task = TaskTemplate.render(input_task, **kw) - except Exception as e: - LOG.exception('Failed to render template:\n%s\n', input_task) - raise e - LOG.debug("Input task is:\n%s\n", rendered_task) - - cfg = yaml_load(rendered_task) - except IOError as ioerror: - sys.exit(ioerror) + input_task = f.read() + rendered_task = task_template.TaskTemplate.render(input_task, **kw) + LOG.debug('Input task is:\n%s', rendered_task) + parsed_task = yaml_load(rendered_task) + except (IOError, OSError): + raise y_exc.TaskReadError(task_file=self.path) + except Exception: + raise y_exc.TaskRenderError(input_task=input_task) + + return parsed_task, rendered_task + def parse_task(self, task_id, task_args=None, task_args_file=None): + """parses the task file and return an context and scenario instances""" + LOG.info("Parsing task config: %s", self.path) + + cfg, rendered = self._render_task(task_args, task_args_file) self._check_schema(cfg["schema"], "task") meet_precondition = self._check_precondition(cfg) @@ -519,17 +548,15 @@ class TaskParser(object): # pragma: no cover context_cfgs = [{"type": "Dummy"}] contexts = [] - name_suffix = '-{}'.format(task_id[:8]) for cfg_attrs in context_cfgs: - try: - cfg_attrs['name'] = '{}{}'.format(cfg_attrs['name'], - name_suffix) - except KeyError: - pass + + cfg_attrs['task_id'] = task_id # default to Heat context because we are testing OpenStack context_type = cfg_attrs.get("type", "Heat") context = Context.get(context_type) context.init(cfg_attrs) + # Update the name in case the context has used the name_suffix + cfg_attrs['name'] = context.name contexts.append(context) run_in_parallel = cfg.get("run_in_parallel", False) @@ -543,16 +570,74 @@ class TaskParser(object): # pragma: no cover # relative to task path scenario["task_path"] = os.path.dirname(self.path) - change_server_name(scenario, name_suffix) - - try: - for node in scenario['nodes']: - scenario['nodes'][node] += name_suffix - except KeyError: - pass + self._change_node_names(scenario, contexts) # TODO we need something better here, a class that represent the file - return cfg["scenarios"], run_in_parallel, meet_precondition, contexts + return {'scenarios': cfg['scenarios'], + 'run_in_parallel': run_in_parallel, + 'meet_precondition': meet_precondition, + 'contexts': contexts, + 'rendered': rendered} + + @staticmethod + def _change_node_names(scenario, contexts): + """Change the node names in a scenario, depending on the context config + + The nodes (VMs or physical servers) are referred in the context section + with the name of the server and the name of the context: + <server name>.<context name> + + If the context is going to be undeployed at the end of the test, the + task ID is suffixed to the name to avoid interferences with previous + deployments. If the context needs to be deployed at the end of the + test, the name assigned is kept. + + There are several places where a node name could appear in the scenario + configuration: + scenario: + host: athena.demo + target: kratos.demo + targets: + - athena.demo + - kratos.demo + + scenario: + options: + server_name: # JIRA: YARDSTICK-810 + host: athena.demo + target: kratos.demo + + scenario: + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + """ + def qualified_name(name): + node_name, context_name = name.split('.') + try: + ctx = next((context for context in contexts + if context.assigned_name == context_name)) + except StopIteration: + raise y_exc.ScenarioConfigContextNameNotFound( + context_name=context_name) + + return '{}.{}'.format(node_name, ctx.name) + + if 'host' in scenario: + scenario['host'] = qualified_name(scenario['host']) + if 'target' in scenario: + scenario['target'] = qualified_name(scenario['target']) + server_name = scenario.get('options', {}).get('server_name', {}) + if 'host' in server_name: + server_name['host'] = qualified_name(server_name['host']) + if 'target' in server_name: + server_name['target'] = qualified_name(server_name['target']) + if 'targets' in scenario: + for idx, target in enumerate(scenario['targets']): + scenario['targets'][idx] = qualified_name(target) + if 'nodes' in scenario: + for scenario_node, target in scenario['nodes'].items(): + scenario['nodes'][scenario_node] = qualified_name(target) def _check_schema(self, cfg_schema, schema_type): """Check if config file is using the correct schema type""" @@ -686,30 +771,3 @@ def parse_task_args(src_name, args): % {"src": src_name, "src_type": type(kw)}) raise TypeError() return kw - - -def change_server_name(scenario, suffix): - - def add_suffix(cfg, key): - try: - value = cfg[key] - except KeyError: - pass - else: - try: - value['name'] += suffix - except TypeError: - cfg[key] += suffix - - server_name = scenario.get('options', {}).get('server_name', {}) - - add_suffix(scenario, 'host') - add_suffix(scenario, 'target') - add_suffix(server_name, 'host') - add_suffix(server_name, 'target') - - try: - key = 'targets' - scenario[key] = ['{}{}'.format(a, suffix) for a in scenario[key]] - except KeyError: - pass diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/add_server_to_existing_secgroup.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/add_server_to_existing_secgroup.bash new file mode 100644 index 000000000..3a50626f5 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/add_server_to_existing_secgroup.bash @@ -0,0 +1,26 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# add server to existing security group +# parameters: $1 - server name, $2 - security group name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +SECGROUPNAME="$(openstack ${SECURE} security group list -f value -c Name | grep $2)" + +openstack ${SECURE} server add security group $1 ${SECGROUPNAME} + diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_instance_from_image.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_instance_from_image.bash new file mode 100644 index 000000000..5e0b1ccf1 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_instance_from_image.bash @@ -0,0 +1,26 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# create nova server +# parameters: $1 - server name, $2 - image name, $3 - flavor name, $4 - network name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +NETNAME="$(openstack ${SECURE} network list -f value -c Name | grep $4)" + +openstack ${SECURE} server create $1 --image $2 --flavor $3 --network ${NETNAME} + diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_instance.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_instance.bash new file mode 100644 index 000000000..008e7f5ff --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_instance.bash @@ -0,0 +1,24 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# delete nova server +# parameters: $1 - server name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +openstack ${SECURE} server delete $1 + diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/get_server_privateip.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/get_server_privateip.bash new file mode 100644 index 000000000..7f2bad540 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/get_server_privateip.bash @@ -0,0 +1,24 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# get private ip of a server +# parameter: $1 - server name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +openstack ${SECURE} server list -f value -c Name -c Networks | grep $1 | awk '{print $2}' | sed -r 's/.*=([0-9\.\:]+)[;,]*/\1/' + diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/remove_server_from_secgroup.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/remove_server_from_secgroup.bash new file mode 100644 index 000000000..61d0a2b49 --- /dev/null +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/remove_server_from_secgroup.bash @@ -0,0 +1,25 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2018 Intracom Telecom 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 +############################################################################## + +# remove server from existing security group +# parameters: $1 - server name, $2 - security group name + +set -e + +if [ $OS_INSECURE ] && [ "$(echo $OS_INSECURE | tr '[:upper:]' '[:lower:]')" = "true" ]; then + SECURE="--insecure" +else + SECURE="" +fi + +SECGROUPNAME="$(openstack ${SECURE} security group list -f value -c Name | grep $2)" + +openstack ${SECURE} server remove security group $1 ${SECGROUPNAME} diff --git a/yardstick/benchmark/scenarios/availability/operation_conf.yaml b/yardstick/benchmark/scenarios/availability/operation_conf.yaml index dc5169196..5f3f6c91e 100644 --- a/yardstick/benchmark/scenarios/availability/operation_conf.yaml +++ b/yardstick/benchmark/scenarios/availability/operation_conf.yaml @@ -35,3 +35,14 @@ get-vip-host: action_script: ha_tools/pacemaker/get_vip_host.bash rollback_script: ha_tools/pacemaker/get_resource_status.bash +start-service: + action_script: ha_tools/start_service.bash + rollback_script: ha_tools/check_process_python.bash + +add-server-to-secgroup: + action_script: ha_tools/nova/add_server_to_existing_secgroup.bash + rollback_script: ha_tools/nova/remove_server_from_secgroup.bash + +get-privateip: + action_script: ha_tools/nova/get_server_privateip.bash + rollback_script: ha_tools/nova/list_servers.bash diff --git a/yardstick/benchmark/scenarios/lib/create_network.py b/yardstick/benchmark/scenarios/lib/create_network.py index cffff132a..734820519 100644 --- a/yardstick/benchmark/scenarios/lib/create_network.py +++ b/yardstick/benchmark/scenarios/lib/create_network.py @@ -7,13 +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 +from yardstick.common import openstack_utils +from yardstick.common import exceptions + LOG = logging.getLogger(__name__) @@ -28,9 +27,14 @@ class CreateNetwork(base.Scenario): self.context_cfg = context_cfg self.options = self.scenario_cfg['options'] - self.openstack = self.options.get("openstack_paras", None) + self.network_name = self.options["network_name"] + self.shared = self.options.get("shared", False) + self.admin_state_up = self.options.get("admin_state_up", True) + self.external = self.options.get("external", False) + self.provider = self.options.get("provider") + self.project_id = self.options.get("project_id") - self.neutron_client = op_utils.get_neutron_client() + self.shade_client = openstack_utils.get_shade_client() self.setup_done = False @@ -45,20 +49,17 @@ class CreateNetwork(base.Scenario): if not self.setup_done: self.setup() - openstack_paras = {'network': self.openstack} - network_id = op_utils.create_neutron_net(self.neutron_client, - openstack_paras) - if network_id: - result.update({"network_create": 1}) - LOG.info("Create network successful!") - else: + network_id = openstack_utils.create_neutron_net( + self.shade_client, self.network_name, shared=self.shared, + admin_state_up=self.admin_state_up, external=self.external, + provider=self.provider, project_id=self.project_id) + if not network_id: result.update({"network_create": 0}) LOG.error("Create network failed!") + raise exceptions.ScenarioCreateNetworkError - try: - keys = self.scenario_cfg.get('output', '').split() - except KeyError: - pass - else: - values = [network_id] - return self._push_to_outputs(keys, values) + result.update({"network_create": 1}) + LOG.info("Create network successful!") + keys = self.scenario_cfg.get('output', '').split() + values = [network_id] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/create_subnet.py b/yardstick/benchmark/scenarios/lib/create_subnet.py index c34af8a9e..e383c99de 100644 --- a/yardstick/benchmark/scenarios/lib/create_subnet.py +++ b/yardstick/benchmark/scenarios/lib/create_subnet.py @@ -7,13 +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 +from yardstick.common import openstack_utils +from yardstick.common import exceptions + LOG = logging.getLogger(__name__) @@ -28,9 +27,23 @@ class CreateSubnet(base.Scenario): self.context_cfg = context_cfg self.options = self.scenario_cfg['options'] - self.openstack = self.options.get("openstack_paras", None) - - self.neutron_client = op_utils.get_neutron_client() + self.network_name_or_id = self.options['network_name_or_id'] + self.cidr = self.options.get('cidr') + self.ip_version = self.options.get('ip_version', 4) + self.enable_dhcp = self.options.get('enable_dhcp', False) + self.subnet_name = self.options.get('subnet_name') + self.tenant_id = self.options.get('tenant_id') + self.allocation_pools = self.options.get('allocation_pools') + self.gateway_ip = self.options.get('gateway_ip') + self.disable_gateway_ip = self.options.get('disable_gateway_ip', False) + self.dns_nameservers = self.options.get('dns_nameservers') + self.host_routes = self.options.get('host_routes') + self.ipv6_ra_mode = self.options.get('ipv6_ra_mode') + self.ipv6_address_mode = self.options.get('ipv6_address_mode') + self.use_default_subnetpool = self.options.get( + 'use_default_subnetpool', False) + + self.shade_client = openstack_utils.get_shade_client() self.setup_done = False @@ -45,22 +58,23 @@ class CreateSubnet(base.Scenario): if not self.setup_done: self.setup() - openstack_paras = {'subnets': [self.openstack]} - subnet_id = op_utils.create_neutron_subnet(self.neutron_client, - openstack_paras) - if subnet_id: - result.update({"subnet_create": 1}) - LOG.info("Create subnet successful!") - else: + subnet_id = openstack_utils.create_neutron_subnet( + self.shade_client, self.network_name_or_id, cidr=self.cidr, + ip_version=self.ip_version, enable_dhcp=self.enable_dhcp, + subnet_name=self.subnet_name, tenant_id=self.tenant_id, + allocation_pools=self.allocation_pools, gateway_ip=self.gateway_ip, + disable_gateway_ip=self.disable_gateway_ip, + dns_nameservers=self.dns_nameservers, host_routes=self.host_routes, + ipv6_ra_mode=self.ipv6_ra_mode, + ipv6_address_mode=self.ipv6_address_mode, + use_default_subnetpool=self.use_default_subnetpool) + if not subnet_id: result.update({"subnet_create": 0}) LOG.error("Create subnet failed!") + raise exceptions.ScenarioCreateSubnetError - check_result = subnet_id - - try: - keys = self.scenario_cfg.get('output', '').split() - except KeyError: - pass - else: - values = [check_result] - return self._push_to_outputs(keys, values) + result.update({"subnet_create": 1}) + LOG.info("Create subnet successful!") + keys = self.scenario_cfg.get('output', '').split() + values = [subnet_id] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/delete_router.py b/yardstick/benchmark/scenarios/lib/delete_router.py index 358fd40cf..5e7467b2c 100644 --- a/yardstick/benchmark/scenarios/lib/delete_router.py +++ b/yardstick/benchmark/scenarios/lib/delete_router.py @@ -7,13 +7,12 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import print_function -from __future__ import absolute_import - import logging +from yardstick.common import openstack_utils +from yardstick.common import exceptions from yardstick.benchmark.scenarios import base -import yardstick.common.openstack_utils as op_utils + LOG = logging.getLogger(__name__) @@ -28,9 +27,9 @@ class DeleteRouter(base.Scenario): self.context_cfg = context_cfg self.options = self.scenario_cfg['options'] - self.router_id = self.options.get("router_id", None) + self.router_id = self.options["router_id"] - self.neutron_client = op_utils.get_neutron_client() + self.shade_client = openstack_utils.get_shade_client() self.setup_done = False @@ -45,11 +44,12 @@ class DeleteRouter(base.Scenario): if not self.setup_done: self.setup() - status = op_utils.delete_neutron_router(self.neutron_client, - router_id=self.router_id) - if status: - result.update({"delete_router": 1}) - LOG.info("Delete router successful!") - else: + status = openstack_utils.delete_neutron_router(self.shade_client, + self.router_id) + if not status: result.update({"delete_router": 0}) LOG.error("Delete router failed!") + raise exceptions.ScenarioDeleteRouterError + + result.update({"delete_router": 1}) + LOG.info("Delete router successful!") diff --git a/yardstick/benchmark/scenarios/networking/moongen_testpmd.bash b/yardstick/benchmark/scenarios/networking/moongen_testpmd.bash new file mode 100644 index 000000000..3e92cc900 --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/moongen_testpmd.bash @@ -0,0 +1,62 @@ +############################################################################## +# 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 +############################################################################## +#!/bin/bash + +set -e + +# Commandline arguments +MOONGEN_PORT1_MAC=$1 # MAC address of the peer port +MOONGEN_PORT2_MAC=$2 # MAC address of the peer port +TESTPMD_QUEUE=$3 + +BIND_ROOT='/opt/nsb_bin' +DRIVER_ROOT='/opt/tempT/dpdk-17.02/' + +load_modules() +{ + if ! lsmod | grep "uio" &> /dev/null; then + modprobe uio + fi + + if ! lsmod | grep "igb_uio" &> /dev/null; then + insmod ${DRIVER_ROOT}/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko + fi + + if ! lsmod | grep "rte_kni" &> /dev/null; then + insmod ${DRIVER_ROOT}/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko + fi +} + +change_permissions() +{ + chmod 777 /sys/bus/pci/drivers/virtio-pci/* + chmod 777 /sys/bus/pci/drivers/igb_uio/* +} + +add_interface_to_dpdk(){ + interfaces=$(lspci |grep Eth |tail -n +2 |awk '{print $1}') + ${BIND_ROOT}/dpdk_nic_bind.py --bind=igb_uio $interfaces &> /dev/null +} + +run_testpmd() +{ + blacklist=$(lspci |grep Eth |awk '{print $1}'|head -1) + cd ${DRIVER_ROOT} + sudo ./x86_64-native-linuxapp-gcc/app/testpmd -c 0x3f -n 4 -b $blacklist -- -a --nb-cores=4 --coremask=0x3c --burst=64 --txd=4096 --rxd=4096 --rxq=$TESTPMD_QUEUE --txq=$TESTPMD_QUEUE --rss-udp --eth-peer=0,$MOONGEN_PORT1_MAC --eth-peer=1,$MOONGEN_PORT2_MAC --forward-mode=mac +} + +main() +{ + load_modules + change_permissions + add_interface_to_dpdk + run_testpmd +} + +main diff --git a/yardstick/benchmark/scenarios/networking/moongen_testpmd.py b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py new file mode 100644 index 000000000..86173c9da --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py @@ -0,0 +1,378 @@ +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# +# 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. +""" VsperfDPDK specific scenario definition """ + +from __future__ import absolute_import +import pkg_resources +import logging +import subprocess +import time +import re +from oslo_serialization import jsonutils + +import yardstick.ssh as ssh +import yardstick.common.utils as utils +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class MoongenTestPMD(base.Scenario): + """Execute vsperf with defined parameters + + Parameters: + frame_size - a frame size for which test should be executed; + Multiple frame sizes can be tested by modification of sequence runner + section inside TC YAML definition. + type: string + default: "64" + multistream - the number of simulated streams + type: string + default: 0 (disabled) + testpmd_queue - specifies how many queues you will use the VM + only useful when forward_type is true. + type: int + default: 1(one queue) + trafficgen_port1 - specifies device name of 1st interface connected to + the trafficgen + type: string + default: NA + trafficgen_port2 - specifies device name of 2nd interface connected to + the trafficgen + type: string + default: NA + moongen_host_user - specifies moongen host ssh user name + type: string + default: root + moongen_host_passwd - specifies moongen host ssh user password + type: string + default: root + moongen_host_ip - specifies moongen host ssh ip address + type: string + default NA + moongen_dir - specifies where is the moongen installtion dir + type: string + default NA + moongen_runBidirec - specifies moongen will run in one traffic + or two traffic. + type: string + default true + Package_Loss - specifies the package_Loss number in moongen server. + type: int + default 0(0%) + SearchRuntime - specifies the SearchRuntime and validation time + on moongen server. + type: int + default 60(s) + moongen_port1_mac - moongen server port1 mac address. + type: string + default NA + moongen_port2_mac - moongen server port2 mac address. + type: string + default NA + forward_type - VM forward type is l2fwd or testpmd. + type: string + default: testpmd + """ + __scenario_type__ = "MoongenTestPMD" + + TESTPMD_SCRIPT = 'moongen_testpmd.bash' + VSPERF_CONFIG = '/tmp/opnfv-vsperf-cfg.lua' + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.forward_setup_done = False + self.options = scenario_cfg.get('options', {}) + self.moongen_host_user = \ + self.options.get('moongen_host_user', "root") + self.moongen_host_passwd = \ + self.options.get('moongen_host_passwd', "r00t") + self.moongen_dir = \ + self.options.get('moongen_dir', '~/moongen.py') + self.testpmd_queue = \ + self.options.get('testpmd_queue', 1) + self.moongen_host_ip = \ + self.options.get('moongen_host_ip', "127.0.0.1") + self.moongen_port1_mac = \ + self.options.get('moongen_port1_mac', None) + self.moongen_port2_mac = \ + self.options.get('moongen_port2_mac', None) + self.tg_port1 = \ + self.options.get('trafficgen_port1', "enp2s0f0") + self.tg_port2 = \ + self.options.get('trafficgen_port2', "enp2s0f1") + self.forward_type = \ + self.options.get('forward_type', 'testpmd') + self.tgen_port1_mac = None + self.tgen_port2_mac = None + + def setup(self): + """scenario setup""" + host = self.context_cfg['host'] + + task_id = self.scenario_cfg['task_id'] + context_number = task_id.split('-')[0] + self.tg_port1_nw = 'demo' + \ + "-" + context_number + "-" + \ + self.options.get('trafficgen_port1_nw', 'test2') + self.tg_port2_nw = 'demo' + \ + "-" + context_number + "-" + \ + self.options.get('trafficgen_port2_nw', 'test3') + + # copy vsperf conf to VM + self.client = ssh.SSH.from_node(host, defaults={"user": "ubuntu"}) + # traffic generation could last long + self.client.wait(timeout=1800) + + self.server = ssh.SSH( + self.moongen_host_user, + self.moongen_host_ip, + password=self.moongen_host_passwd + ) + # traffic generation could last long + self.server.wait(timeout=1800) + + self.setup_done = True + + def forward_setup(self): + """forward tool setup""" + + # setup forward loopback in VM + self.testpmd_script = pkg_resources.resource_filename( + 'yardstick.benchmark.scenarios.networking', + self.TESTPMD_SCRIPT) + + self.client._put_file_shell(self.testpmd_script, + '~/testpmd_vsperf.sh') + + # disable Address Space Layout Randomization (ASLR) + cmd = "echo 0 | sudo tee /proc/sys/kernel/randomize_va_space" + self.client.send_command(cmd) + + if not self._is_forward_setup(): + self.tgen_port1_ip = \ + utils.get_port_ip(self.client, self.tg_port1) + self.tgen_port1_mac = \ + utils.get_port_mac(self.client, self.tg_port1) + self.client.run("tee ~/.testpmd.ipaddr.port1 > /dev/null", + stdin=self.tgen_port1_ip) + self.client.run("tee ~/.testpmd.macaddr.port1 > /dev/null", + stdin=self.tgen_port1_mac) + self.tgen_port2_ip = \ + utils.get_port_ip(self.client, self.tg_port2) + self.tgen_port2_mac = \ + utils.get_port_mac(self.client, self.tg_port2) + self.client.run("tee ~/.testpmd.ipaddr.port2 > /dev/null", + stdin=self.tgen_port2_ip) + self.client.run("tee ~/.testpmd.macaddr.port2 > /dev/null", + stdin=self.tgen_port2_mac) + else: + cmd = "cat ~/.testpmd.macaddr.port1" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port1_mac = stdout + cmd = "cat ~/.testpmd.ipaddr.port1" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port1_ip = stdout + cmd = "cat ~/.testpmd.macaddr.port2" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port2_mac = stdout + cmd = "cat ~/.testpmd.ipaddr.port2" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port2_ip = stdout + + LOG.info("forward type is %s", self.forward_type) + if self.forward_type == 'testpmd': + cmd = "sudo ip link set %s down" % (self.tg_port1) + LOG.debug("Executing command: %s", cmd) + self.client.execute(cmd) + cmd = "sudo ip link set %s down" % (self.tg_port2) + LOG.debug("Executing command: %s", cmd) + self.client.execute(cmd) + cmd = "screen -d -m sudo -E bash ~/testpmd_vsperf.sh %s %s %d" % \ + (self.moongen_port1_mac, self.moongen_port2_mac, + self.testpmd_queue) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + + elif self.forward_type == 'l2fwd': + cmd = ('sed -i "s/static char *net1 = \\\"eth1\\\";' + '/static char *net1 = \\\"%s %s %s\\\";/g" /home/l2fwd/l2fwd.c' + % (self.tg_port1, self.tgen_port1_ip, self.moongen_port1_mac)) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + cmd = ('sed -i "s/static char *net2 = \\\"eth2\\\";' + '/static char *net2 = \\\"%s %s %s\\\";/g" /home/l2fwd/l2fwd.c' + % (self.tg_port2, self.tgen_port2_ip, self.moongen_port2_mac)) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + cmd = ('cd /home/l2fwd/;make;./gen_debian_package.sh;' + 'sudo dpkg -i *.deb;' + 'sudo modprobe l2fwd') + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + time.sleep(1) + + self.forward_setup_done = True + + def _is_forward_setup(self): + """Is forward already setup in the host?""" + if self.forward_type is 'testpmd': + is_run = True + cmd = "ip a | grep %s 2>/dev/null" % (self.tg_port1) + LOG.debug("Executing command: %s", cmd) + _, stdout, _ = self.client.execute(cmd) + if stdout: + is_run = False + return is_run + elif self.forward_type is 'l2fwd': + cmd = ('sudo lsmod |grep l2fwd') + LOG.debug("Executing command: %s", cmd) + _, stdout, _ = self.client.execute(cmd) + if stdout: + return True + else: + return False + + def generate_config_file(self, frame_size, multistream, + runBidirec, tg_port1_vlan, tg_port2_vlan, + SearchRuntime, Package_Loss): + out_text = """\ +VSPERF { +testType = 'throughput', +nrFlows = %d, +runBidirec = %s, +frameSize = %d, +srcMacs = {\'%s\', \'%s\'}, +dstMacs = {\'%s\', \'%s\'}, +vlanIds = {%d, %d}, +searchRunTime = %d, +validationRunTime = %d, +acceptableLossPct = %d, +ports = {0,1}, +} +""" % (multistream, runBidirec, frame_size, self.moongen_port1_mac, + self.moongen_port2_mac, self.tgen_port1_mac, self.tgen_port2_mac, + tg_port1_vlan, tg_port2_vlan, SearchRuntime, SearchRuntime, Package_Loss) + with open(self.VSPERF_CONFIG, "wt") as out_file: + out_file.write(out_text) + self.CONFIG_FILE = True + + def result_to_data(self, result): + search_pattern = re.compile( + r'\[REPORT\]\s+total\:\s+' + r'Tx\s+frames\:\s+(\d+)\s+' + r'Rx\s+Frames\:\s+(\d+)\s+' + r'frame\s+loss\:\s+(\d+)\,' + r'\s+(\d+\.\d+|\d+)%\s+' + r'Tx\s+Mpps\:\s+(\d+.\d+|\d+)\s+' + r'Rx\s+Mpps\:\s+(\d+\.\d+|\d+)', + re.IGNORECASE) + results_match = search_pattern.search(result) + if results_match: + rx_mpps = float(results_match.group(6)) + tx_mpps = float(results_match.group(5)) + else: + rx_mpps = 0 + tx_mpps = 0 + test_result = {"rx_mpps": rx_mpps, "tx_mpps": tx_mpps} + self.TO_DATA = True + return test_result + + def run(self, result): + """ execute the vsperf benchmark and return test results + within result dictionary + """ + + if not self.setup_done: + self.setup() + + # get vsperf options + multistream = self.options.get("multistream", 1) + + if not self.forward_setup_done: + self.forward_setup() + + if 'frame_size' in self.options: + frame_size = self.options.get("frame_size", 64) + Package_Loss = self.options.get("Package_Loss", 0) + runBidirec = self.options.get("moongen_runBidirec", + "true") + SearchRuntime = self.options.get("SearchRuntime", 10) + + cmd = "openstack network show %s --format json -c " \ + "provider:segmentation_id" % (self.tg_port1_nw) + LOG.debug("Executing command: %s", cmd) + output = subprocess.check_output(cmd, shell=True) + try: + tg_port1_vlan = jsonutils.loads(output).get("provider:segmentation_id", 1) + except TypeError: + tg_port1_vlan = 1 + + cmd = "openstack network show %s --format json -c " \ + "provider:segmentation_id" % (self.tg_port2_nw) + LOG.debug("Executing command: %s", cmd) + output = subprocess.check_output(cmd, shell=True) + try: + tg_port2_vlan = jsonutils.loads(output).get("provider:segmentation_id", 2) + except TypeError: + tg_port2_vlan = 2 + + self.generate_config_file(frame_size, multistream, + runBidirec, tg_port1_vlan, + tg_port2_vlan, SearchRuntime, Package_Loss) + + self.server.execute("rm -f -- %s/opnfv-vsperf-cfg.lua" % + (self.moongen_dir)) + self.server._put_file_shell(self.VSPERF_CONFIG, + "%s/opnfv-vsperf-cfg.lua" + % (self.moongen_dir)) + + # execute moongen + cmd = ("cd %s;./MoonGen/build/MoonGen ./trafficgen.lua" + % (self.moongen_dir)) + status, stdout, stderr = self.server.execute(cmd) + if status: + raise RuntimeError(stderr) + + moongen_result = self.result_to_data(stdout) + LOG.info(moongen_result) + result.update(moongen_result) + + if "sla" in self.scenario_cfg: + throughput_rx_mpps = int( + self.scenario_cfg["sla"]["throughput_rx_mpps"]) + + assert throughput_rx_mpps <= moongen_result["tx_mpps"], \ + "sla_throughput_rx_mpps %f > throughput_rx_mpps(%f); " % \ + (throughput_rx_mpps, moongen_result["tx_mpps"]) + + def teardown(self): + """cleanup after the test execution""" + + # execute external setup script + self.setup_done = False diff --git a/yardstick/benchmark/scenarios/networking/netperf.py b/yardstick/benchmark/scenarios/networking/netperf.py index a8d9010ed..33c02d409 100755 --- a/yardstick/benchmark/scenarios/networking/netperf.py +++ b/yardstick/benchmark/scenarios/networking/netperf.py @@ -104,7 +104,9 @@ class Netperf(base.Scenario): cmd_args = "-H %s -l %s -t %s" % (ipaddr, testlen, testname) # get test specific options - default_args = "-O 'THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY'" + output_opt = options.get( + "output_opt", "THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY") + default_args = "-O %s" % output_opt cmd_args += " -- %s" % default_args option_pair_list = [("send_msg_size", "-m"), ("recv_msg_size", "-M"), diff --git a/yardstick/benchmark/scenarios/networking/sfc_openstack.py b/yardstick/benchmark/scenarios/networking/sfc_openstack.py index d5feabbbe..aaab2131a 100644 --- a/yardstick/benchmark/scenarios/networking/sfc_openstack.py +++ b/yardstick/benchmark/scenarios/networking/sfc_openstack.py @@ -34,11 +34,13 @@ def get_credentials(service): # pragma: no cover # The most common way to pass these info to the script is to do it through # environment variables. + # NOTE(ralonsoh): OS_TENANT_NAME is deprecated. + project_name = os.environ.get('OS_PROJECT_NAME', 'admin') creds.update({ "username": os.environ.get('OS_USERNAME', "admin"), password: os.environ.get("OS_PASSWORD", 'admin'), "auth_url": os.environ.get("OS_AUTH_URL"), - tenant: os.environ.get("OS_TENANT_NAME", "admin"), + tenant: os.environ.get("OS_TENANT_NAME", project_name), }) cacert = os.environ.get("OS_CACERT") if cacert is not None: @@ -59,7 +61,7 @@ def get_instances(nova_client): # pragma: no cover try: instances = nova_client.servers.list(search_opts={'all_tenants': 1}) return instances - except Exception as e: + except Exception as e: # pylint: disable=broad-except print("Error [get_instances(nova_client)]:", e) return None @@ -72,7 +74,7 @@ def get_SFs(nova_client): # pragma: no cover if "sfc_test" not in instance.name: SFs.append(instance) return SFs - except Exception as e: + except Exception as e: # pylint: disable=broad-except print("Error [get_SFs(nova_client)]:", e) return None @@ -93,7 +95,7 @@ def create_floating_ips(neutron_client): # pragma: no cover ip_json = neutron_client.create_floatingip({'floatingip': props}) fip_addr = ip_json['floatingip']['floating_ip_address'] ips.append(fip_addr) - except Exception as e: + except Exception as e: # pylint: disable=broad-except print("Error [create_floating_ip(neutron_client)]:", e) return None return ips @@ -106,7 +108,7 @@ def floatIPtoSFs(SFs, floatips): # pragma: no cover SF.add_floating_ip(floatips[i]) i = i + 1 return True - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(("Error [add_floating_ip(nova_client, '%s', '%s')]:" % (SF, floatips[i]), e)) return False @@ -122,7 +124,3 @@ def get_an_IP(): # pragma: no cover floatips = create_floating_ips(neutron_client) floatIPtoSFs(SFs, floatips) return floatips - - -if __name__ == '__main__': # pragma: no cover - get_an_IP() diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py index b94bfc9ab..0e4785294 100644 --- a/yardstick/benchmark/scenarios/networking/vnf_generic.py +++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py @@ -11,115 +11,38 @@ # 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. -""" NSPerf specific scenario definition """ - -from __future__ import absolute_import +import copy import logging -import errno import ipaddress - -import copy +from itertools import chain import os import sys -import re -from itertools import chain import six import yaml -from collections import defaultdict -from yardstick.benchmark.scenarios import base +from yardstick.benchmark.scenarios import base as scenario_base +from yardstick.error import IncorrectConfig from yardstick.common.constants import LOG_DIR from yardstick.common.process import terminate_children -from yardstick.common.utils import import_modules_from_package, itersubclasses -from yardstick.common.yaml_loader import yaml_load +from yardstick.common import utils from yardstick.network_services.collector.subscriber import Collector from yardstick.network_services.vnf_generic import vnfdgen from yardstick.network_services.vnf_generic.vnf.base import GenericVNF -from yardstick.network_services.traffic_profile.base import TrafficProfile +from yardstick.network_services import traffic_profile +from yardstick.network_services.traffic_profile import base as tprofile_base from yardstick.network_services.utils import get_nsb_option from yardstick import ssh - -LOG = logging.getLogger(__name__) - - -class SSHError(Exception): - """Class handles ssh connection error exception""" - pass - - -class SSHTimeout(SSHError): - """Class handles ssh connection timeout exception""" - pass - - -class IncorrectConfig(Exception): - """Class handles incorrect configuration during setup""" - pass - - -class IncorrectSetup(Exception): - """Class handles incorrect setup during setup""" - pass +traffic_profile.register_modules() -class SshManager(object): - def __init__(self, node, timeout=120): - super(SshManager, self).__init__() - self.node = node - self.conn = None - self.timeout = timeout - - def __enter__(self): - """ - args -> network device mappings - returns -> ssh connection ready to be used - """ - try: - self.conn = ssh.SSH.from_node(self.node) - self.conn.wait(timeout=self.timeout) - except SSHError as error: - LOG.info("connect failed to %s, due to %s", self.node["ip"], error) - # self.conn defaults to None - return self.conn - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.conn: - self.conn.close() - - -def find_relative_file(path, task_path): - """ - Find file in one of places: in abs of path or - relative to TC scenario file. In this order. - - :param path: - :param task_path: - :return str: full path to file - """ - # fixme: create schema to validate all fields have been provided - for lookup in [os.path.abspath(path), os.path.join(task_path, path)]: - try: - with open(lookup): - return lookup - except IOError: - pass - raise IOError(errno.ENOENT, 'Unable to find {} file'.format(path)) - - -def open_relative_file(path, task_path): - try: - return open(path) - except IOError as e: - if e.errno == errno.ENOENT: - return open(os.path.join(task_path, path)) - raise +LOG = logging.getLogger(__name__) -class NetworkServiceTestCase(base.Scenario): +class NetworkServiceTestCase(scenario_base.Scenario): """Class handles Generic framework to do pre-deployment VNF & Network service testing """ @@ -130,16 +53,12 @@ class NetworkServiceTestCase(base.Scenario): self.scenario_cfg = scenario_cfg self.context_cfg = context_cfg - # fixme: create schema to validate all fields have been provided - with open_relative_file(scenario_cfg["topology"], - scenario_cfg['task_path']) as stream: - topology_yaml = yaml_load(stream) - - self.topology = topology_yaml["nsd:nsd-catalog"]["nsd"][0] + self._render_topology() self.vnfs = [] self.collector = None self.traffic_profile = None self.node_netdevs = {} + self.bin_path = get_nsb_option('bin_path', '') def _get_ip_flow_range(self, ip_start_range): @@ -211,37 +130,47 @@ class NetworkServiceTestCase(base.Scenario): def _get_traffic_profile(self): profile = self.scenario_cfg["traffic_profile"] path = self.scenario_cfg["task_path"] - with open_relative_file(profile, path) as infile: + with utils.open_relative_file(profile, path) as infile: + return infile.read() + + def _get_topology(self): + topology = self.scenario_cfg["topology"] + path = self.scenario_cfg["task_path"] + with utils.open_relative_file(topology, path) as infile: return infile.read() def _fill_traffic_profile(self): - traffic_mapping = self._get_traffic_profile() - traffic_map_data = { + tprofile = self._get_traffic_profile() + extra_args = self.scenario_cfg.get('extra_args', {}) + tprofile_data = { 'flow': self._get_traffic_flow(), 'imix': self._get_traffic_imix(), - TrafficProfile.UPLINK: {}, - TrafficProfile.DOWNLINK: {}, + tprofile_base.TrafficProfile.UPLINK: {}, + tprofile_base.TrafficProfile.DOWNLINK: {}, + 'extra_args': extra_args } - traffic_vnfd = vnfdgen.generate_vnfd(traffic_mapping, traffic_map_data) - self.traffic_profile = TrafficProfile.get(traffic_vnfd) - return self.traffic_profile + traffic_vnfd = vnfdgen.generate_vnfd(tprofile, tprofile_data) + self.traffic_profile = tprofile_base.TrafficProfile.get(traffic_vnfd) + + def _render_topology(self): + topology = self._get_topology() + topology_args = self.scenario_cfg.get('extra_args', {}) + topolgy_data = { + 'extra_args': topology_args + } + topology_yaml = vnfdgen.generate_vnfd(topology, topolgy_data) + self.topology = topology_yaml["nsd:nsd-catalog"]["nsd"][0] def _find_vnf_name_from_id(self, vnf_id): return next((vnfd["vnfd-id-ref"] for vnfd in self.topology["constituent-vnfd"] if vnf_id == vnfd["member-vnf-index"]), None) - @staticmethod - def get_vld_networks(networks): - # network name is vld_id - vld_map = {} - for name, n in networks.items(): - try: - vld_map[n['vld_id']] = n - except KeyError: - vld_map[name] = n - return vld_map + def _find_vnfd_from_vnf_idx(self, vnf_id): + return next((vnfd + for vnfd in self.topology["constituent-vnfd"] + if vnf_id == vnfd["member-vnf-index"]), None) @staticmethod def find_node_if(nodes, name, if_name, vld_id): @@ -293,7 +222,9 @@ class NetworkServiceTestCase(base.Scenario): node1_if["peer_ifname"] = node0_if_name # just load the network - vld_networks = self.get_vld_networks(self.context_cfg["networks"]) + vld_networks = {n.get('vld_id', name): n for name, n in + self.context_cfg["networks"].items()} + node0_if["network"] = vld_networks.get(vld["id"], {}) node1_if["network"] = vld_networks.get(vld["id"], {}) @@ -332,10 +263,6 @@ class NetworkServiceTestCase(base.Scenario): node0_if["peer_intf"] = node1_copy node1_if["peer_intf"] = node0_copy - def _find_vnfd_from_vnf_idx(self, vnf_idx): - return next((vnfd for vnfd in self.topology["constituent-vnfd"] - if vnf_idx == vnfd["member-vnf-index"]), None) - def _update_context_with_topology(self): for vnfd in self.topology["constituent-vnfd"]: vnf_idx = vnfd["member-vnf-index"] @@ -343,43 +270,6 @@ class NetworkServiceTestCase(base.Scenario): vnfd = self._find_vnfd_from_vnf_idx(vnf_idx) self.context_cfg["nodes"][vnf_name].update(vnfd) - def _probe_netdevs(self, node, node_dict, timeout=120): - try: - return self.node_netdevs[node] - except KeyError: - pass - - netdevs = {} - cmd = "PATH=$PATH:/sbin:/usr/sbin ip addr show" - - with SshManager(node_dict, timeout=timeout) as conn: - if conn: - exit_status = conn.execute(cmd)[0] - if exit_status != 0: - raise IncorrectSetup("Node's %s lacks ip tool." % node) - exit_status, stdout, _ = conn.execute( - self.FIND_NETDEVICE_STRING) - if exit_status != 0: - raise IncorrectSetup( - "Cannot find netdev info in sysfs" % node) - netdevs = node_dict['netdevs'] = self.parse_netdev_info(stdout) - - self.node_netdevs[node] = netdevs - return netdevs - - @classmethod - def _probe_missing_values(cls, netdevs, network): - - mac_lower = network['local_mac'].lower() - for netdev in netdevs.values(): - if netdev['address'].lower() != mac_lower: - continue - network.update({ - 'driver': netdev['driver'], - 'vpci': netdev['pci_bus_id'], - 'ifindex': netdev['ifindex'], - }) - def _generate_pod_yaml(self): context_yaml = os.path.join(LOG_DIR, "pod-{}.yaml".format(self.scenario_cfg['task_id'])) # convert OrderedDict to a list @@ -405,82 +295,16 @@ class NetworkServiceTestCase(base.Scenario): pass return new_node - TOPOLOGY_REQUIRED_KEYS = frozenset({ - "vpci", "local_ip", "netmask", "local_mac", "driver"}) - def map_topology_to_infrastructure(self): """ This method should verify if the available resources defined in pod.yaml match the topology.yaml file. :return: None. Side effect: context_cfg is updated """ - num_nodes = len(self.context_cfg["nodes"]) - # OpenStack instance creation time is probably proportional to the number - # of instances - timeout = 120 * num_nodes - for node, node_dict in self.context_cfg["nodes"].items(): - - for network in node_dict["interfaces"].values(): - missing = self.TOPOLOGY_REQUIRED_KEYS.difference(network) - if not missing: - continue - - # only ssh probe if there are missing values - # ssh probe won't work on Ixia, so we had better define all our values - try: - netdevs = self._probe_netdevs(node, node_dict, timeout=timeout) - except (SSHError, SSHTimeout): - raise IncorrectConfig( - "Unable to probe missing interface fields '%s', on node %s " - "SSH Error" % (', '.join(missing), node)) - try: - self._probe_missing_values(netdevs, network) - except KeyError: - pass - else: - missing = self.TOPOLOGY_REQUIRED_KEYS.difference( - network) - if missing: - raise IncorrectConfig( - "Require interface fields '%s' not found, topology file " - "corrupted" % ', '.join(missing)) - - # we have to generate pod.yaml here so we have vpci and driver - self._generate_pod_yaml() # 3. Use topology file to find connections & resolve dest address self._resolve_topology() self._update_context_with_topology() - FIND_NETDEVICE_STRING = r"""find /sys/devices/pci* -type d -name net -exec sh -c '{ grep -sH ^ \ -$1/ifindex $1/address $1/operstate $1/device/vendor $1/device/device \ -$1/device/subsystem_vendor $1/device/subsystem_device ; \ -printf "%s/driver:" $1 ; basename $(readlink -s $1/device/driver); } \ -' sh \{\}/* \; -""" - BASE_ADAPTER_RE = re.compile( - '^/sys/devices/(.*)/net/([^/]*)/([^:]*):(.*)$', re.M) - - @classmethod - def parse_netdev_info(cls, stdout): - network_devices = defaultdict(dict) - matches = cls.BASE_ADAPTER_RE.findall(stdout) - for bus_path, interface_name, name, value in matches: - dirname, bus_id = os.path.split(bus_path) - if 'virtio' in bus_id: - # for some stupid reason VMs include virtio1/ - # in PCI device path - bus_id = os.path.basename(dirname) - # remove extra 'device/' from 'device/vendor, - # device/subsystem_vendor', etc. - if 'device/' in name: - name = name.split('/')[1] - network_devices[interface_name][name] = value - network_devices[interface_name][ - 'interface_name'] = interface_name - network_devices[interface_name]['pci_bus_id'] = bus_id - # convert back to regular dict - return dict(network_devices) - @classmethod def get_vnf_impl(cls, vnf_model_id): """ Find the implementing class from vnf_model["vnf"]["name"] field @@ -488,13 +312,14 @@ printf "%s/driver:" $1 ; basename $(readlink -s $1/device/driver); } \ :param vnf_model_id: parsed vnfd model ID field :return: subclass of GenericVNF """ - import_modules_from_package( + utils.import_modules_from_package( "yardstick.network_services.vnf_generic.vnf") expected_name = vnf_model_id classes_found = [] def impl(): - for name, class_ in ((c.__name__, c) for c in itersubclasses(GenericVNF)): + for name, class_ in ((c.__name__, c) for c in + utils.itersubclasses(GenericVNF)): if name == expected_name: yield class_ classes_found.append(name) @@ -547,7 +372,7 @@ printf "%s/driver:" $1 ; basename $(readlink -s $1/device/driver); } \ context_cfg = self.context_cfg vnfs = [] - # we assume OrderedDict for consistenct in instantiation + # we assume OrderedDict for consistency in instantiation for node_name, node in context_cfg["nodes"].items(): LOG.debug(node) try: @@ -556,7 +381,7 @@ printf "%s/driver:" $1 ; basename $(readlink -s $1/device/driver); } \ LOG.debug("no model for %s, skipping", node_name) continue file_path = scenario_cfg['task_path'] - with open_relative_file(file_name, file_path) as stream: + with utils.open_relative_file(file_name, file_path) as stream: vnf_model = stream.read() vnfd = vnfdgen.generate_vnfd(vnf_model, node) # TODO: here add extra context_cfg["nodes"] regardless of template @@ -606,6 +431,9 @@ printf "%s/driver:" $1 ; basename $(readlink -s $1/device/driver); } \ vnf.terminate() raise + # we have to generate pod.yaml here after VNF has probed so we know vpci and driver + self._generate_pod_yaml() + # 3. Run experiment # Start listeners first to avoid losing packets for traffic_gen in traffic_runners: diff --git a/yardstick/benchmark/scenarios/storage/fio.py b/yardstick/benchmark/scenarios/storage/fio.py index 125bc7ed4..d3ed840d8 100644 --- a/yardstick/benchmark/scenarios/storage/fio.py +++ b/yardstick/benchmark/scenarios/storage/fio.py @@ -124,12 +124,16 @@ class Fio(base.Scenario): if mount_dir: LOG.debug("Formating volume...") - self.client.execute("sudo mkfs.ext4 /dev/vdb") - cmd = "sudo mkdir %s" % mount_dir - self.client.execute(cmd) - LOG.debug("Mounting volume at: %s", mount_dir) - cmd = "sudo mount /dev/vdb %s" % mount_dir - self.client.execute(cmd) + _, stdout, _ = self.client.execute( + "lsblk -dps | grep -m 1 disk | awk '{print $1}'") + block_device = stdout.strip() + if block_device: + self.client.execute("sudo mkfs.ext4 %s" % block_device) + cmd = "sudo mkdir %s" % mount_dir + self.client.execute(cmd) + LOG.debug("Mounting volume at: %s", mount_dir) + cmd = "sudo mount %s %s" % (block_device, mount_dir) + self.client.execute(cmd) self.setup_done = True diff --git a/yardstick/cmd/cli.py b/yardstick/cmd/cli.py index 67ce11451..0bc7c1617 100644 --- a/yardstick/cmd/cli.py +++ b/yardstick/cmd/cli.py @@ -28,6 +28,8 @@ from yardstick.cmd.commands import testcase from yardstick.cmd.commands import plugin from yardstick.cmd.commands import env from yardstick.cmd.commands import report +from yardstick.common import import_tools + CONF = cfg.CONF cli_opts = [ @@ -53,7 +55,8 @@ def find_config_files(path_list): return None -class YardstickCLI(): # pragma: no cover +@import_tools.decorator_banned_modules +class YardstickCLI(object): # pragma: no cover """Command-line interface to yardstick""" # Command categories @@ -108,7 +111,7 @@ class YardstickCLI(): # pragma: no cover # register subcommands to parse additional command line arguments def parser(subparsers): - self._add_command_parsers(YardstickCLI.categories, subparsers) + self._add_command_parsers(self.categories, subparsers) category_opt = cfg.SubCommandOpt("category", title="Command categories", diff --git a/yardstick/cmd/commands/task.py b/yardstick/cmd/commands/task.py index e2e8bf67d..a3488a23d 100644 --- a/yardstick/cmd/commands/task.py +++ b/yardstick/cmd/commands/task.py @@ -7,10 +7,6 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -""" Handler for yardstick command 'task' """ -from __future__ import print_function -from __future__ import absolute_import - import logging from yardstick.benchmark.core.task import Task @@ -42,6 +38,8 @@ class TaskCommands(object): # pragma: no cover action="store_true") @cliargs("--parse-only", help="parse the config file and exit", action="store_true") + @cliargs("--render-only", help="Render the tasks files, store the result " + "in the directory given and exit", type=str, dest="render_only") @cliargs("--output-file", help="file where output is stored, default %s" % output_file_default, default=output_file_default) @cliargs("--suite", help="process test suite file instead of a task file", @@ -54,9 +52,8 @@ class TaskCommands(object): # pragma: no cover LOG.info('Task START') try: result = Task().start(param, **kwargs) - except Exception as e: + except Exception as e: # pylint: disable=broad-except self._write_error_data(e) - LOG.exception("") if result.get('result', {}).get('criteria') == 'PASS': LOG.info('Task SUCCESS') diff --git a/yardstick/common/ansible_common.py b/yardstick/common/ansible_common.py index be262c215..38d2dd7c2 100644 --- a/yardstick/common/ansible_common.py +++ b/yardstick/common/ansible_common.py @@ -31,6 +31,7 @@ import six.moves.configparser as ConfigParser import yaml from six import StringIO from chainmap import ChainMap +from oslo_serialization import jsonutils from yardstick.common.utils import Timer from yardstick.common import constants as consts @@ -508,6 +509,58 @@ class AnsibleCommon(object): timeout = 1200.0 return timeout + def _generate_ansible_cfg(self, directory): + parser = ConfigParser.ConfigParser() + parser.add_section('defaults') + parser.set('defaults', 'host_key_checking', 'False') + + cfg_path = os.path.join(directory, 'setup.cfg') + with open(cfg_path, 'w') as f: + parser.write(f) + + def get_sut_info(self, directory, sut_dir='sut'): + if not os.path.isdir(directory): + raise OSError('No such directory: %s' % directory) + + self._generate_ansible_cfg(directory) + + prefix = 'tmp' + self.gen_inventory_ini_dict() + ini_file = self._gen_ansible_inventory_file(directory, prefix=prefix) + with ini_file as f: + inventory_path = str(f) + + self._exec_get_sut_info_cmd(directory, inventory_path, sut_dir) + + sut_dir = os.path.join(directory, sut_dir) + sut_info = self._gen_sut_info_dict(sut_dir) + + return sut_info + + def _exec_get_sut_info_cmd(self, directory, inventory_path, sut_dir): + cmd = ['ansible', 'all', '-m', 'setup', '-i', + inventory_path, '--tree', sut_dir] + + proc = Popen(cmd, stdout=PIPE, cwd=directory) + output, _ = proc.communicate() + retcode = proc.wait() + LOG.debug("exit status = %s", retcode) + if retcode != 0: + raise CalledProcessError(retcode, cmd, output) + + def _gen_sut_info_dict(self, sut_dir): + sut_info = {} + + if os.path.isdir(sut_dir): + root, _, files = next(os.walk(sut_dir)) + for filename in files: + abs_path = os.path.join(root, filename) + with open(abs_path) as f: + data = jsonutils.load(f) + sut_info[filename] = data + + return sut_info + def execute_ansible(self, playbooks, directory, timeout=None, extra_vars=None, ansible_check=False, prefix='tmp', verbose=False): diff --git a/yardstick/common/constants.py b/yardstick/common/constants.py index 43c2c19cb..153bd4bf4 100644 --- a/yardstick/common/constants.py +++ b/yardstick/common/constants.py @@ -145,6 +145,10 @@ BASE_URL = 'http://localhost:5000' ENV_ACTION_API = BASE_URL + '/yardstick/env/action' ASYNC_TASK_API = BASE_URL + '/yardstick/asynctask' +# flags +IS_EXISTING = 'is_existing' +IS_PUBLIC = 'is_public' + # general TESTCASE_PRE = 'opnfv_yardstick_' TESTSUITE_PRE = 'opnfv_' diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index 3e0635e46..633b36f91 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -59,14 +59,64 @@ class FunctionNotImplemented(YardstickException): '"%(class_name)" class.') +class YardstickBannedModuleImported(YardstickException): + # pragma: no cover + message = 'Module "%(module)s" cannnot be imported. Reason: "%(reason)s"' + + class HeatTemplateError(YardstickException): """Error in Heat during the stack deployment""" message = ('Error in Heat during the creation of the OpenStack stack ' - '"%(stack_name)"') + '"%(stack_name)s"') class IPv6RangeError(YardstickException): message = 'Start IP "%(start_ip)s" is greater than end IP "%(end_ip)s"' + +class TrafficProfileNotImplemented(YardstickException): + message = 'No implementation for traffic profile %(profile_class)s.' + + class DPDKSetupDriverError(YardstickException): message = '"igb_uio" driver is not loaded' + + +class ScenarioConfigContextNameNotFound(YardstickException): + message = 'Context name "%(context_name)s" not found' + + +class StackCreationInterrupt(YardstickException): + message = 'Stack create interrupted.' + + +class TaskRenderArgumentError(YardstickException): + message = 'Error reading the task input arguments' + + +class TaskReadError(YardstickException): + message = 'Failed to read task %(task_file)s' + + +class TaskRenderError(YardstickException): + message = 'Failed to render template:\n%(input_task)s' + + +class ScenarioCreateNetworkError(YardstickException): + message = 'Create Neutron Network Scenario failed' + + +class ScenarioCreateSubnetError(YardstickException): + message = 'Create Neutron Subnet Scenario failed' + + +class ScenarioDeleteRouterError(YardstickException): + message = 'Delete Neutron Router Scenario failed' + + +class MissingPodInfoError(YardstickException): + message = 'Missing pod args, please check' + + +class UnsupportedPodFormatError(YardstickException): + message = 'Failed to load pod info, unsupported format' diff --git a/yardstick/common/import_tools.py b/yardstick/common/import_tools.py new file mode 100644 index 000000000..bf8dc7e07 --- /dev/null +++ b/yardstick/common/import_tools.py @@ -0,0 +1,31 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys + +from yardstick.common import exceptions + + +BANNED_MODULES = {'ansible': 'Module with GPLv3 license'} + + +def decorator_banned_modules(cls): + def _class(*args, **kwargs): + for module in sys.modules: + for banned_module, reason in BANNED_MODULES.items(): + if module.startswith(banned_module): + raise exceptions.YardstickBannedModuleImported( + module=banned_module, reason=reason) + return cls(*args, **kwargs) + return _class diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py index 8f666e268..84bfbbbb1 100644 --- a/yardstick/common/openstack_utils.py +++ b/yardstick/common/openstack_utils.py @@ -33,38 +33,22 @@ DEFAULT_API_VERSION = '2' # CREDENTIALS # ********************************************* def get_credentials(): - """Returns a creds dictionary filled with parsed from env""" - creds = {} - - keystone_api_version = os.getenv('OS_IDENTITY_API_VERSION') - - if keystone_api_version is None or keystone_api_version == '2': - keystone_v3 = False - tenant_env = 'OS_TENANT_NAME' - tenant = 'tenant_name' - else: - keystone_v3 = True - tenant_env = 'OS_PROJECT_NAME' - tenant = 'project_name' - - # The most common way to pass these info to the script is to do it - # through environment variables. - creds.update({ - "username": os.environ.get("OS_USERNAME"), - "password": os.environ.get("OS_PASSWORD"), - "auth_url": os.environ.get("OS_AUTH_URL"), - tenant: os.environ.get(tenant_env) - }) - - if keystone_v3: - if os.getenv('OS_USER_DOMAIN_NAME') is not None: - creds.update({ - "user_domain_name": os.getenv('OS_USER_DOMAIN_NAME') - }) - if os.getenv('OS_PROJECT_DOMAIN_NAME') is not None: - creds.update({ - "project_domain_name": os.getenv('OS_PROJECT_DOMAIN_NAME') - }) + """Returns a creds dictionary filled with parsed from env + + Keystone API version used is 3; v2 was deprecated in 2014 (Icehouse). Along + with this deprecation, environment variable 'OS_TENANT_NAME' is replaced by + 'OS_PROJECT_NAME'. + """ + creds = {'username': os.environ.get('OS_USERNAME'), + 'password': os.environ.get('OS_PASSWORD'), + 'auth_url': os.environ.get('OS_AUTH_URL'), + 'project_name': os.environ.get('OS_PROJECT_NAME') + } + + if os.getenv('OS_USER_DOMAIN_NAME'): + creds['user_domain_name'] = os.getenv('OS_USER_DOMAIN_NAME') + if os.getenv('OS_PROJECT_DOMAIN_NAME'): + creds['project_domain_name'] = os.getenv('OS_PROJECT_DOMAIN_NAME') return creds @@ -294,8 +278,7 @@ def create_instance_and_wait_for_active(json_body): # pragma: no cover VM_BOOT_TIMEOUT = 180 nova_client = get_nova_client() instance = create_instance(json_body) - count = VM_BOOT_TIMEOUT / SLEEP - for _ in range(count, -1, -1): + for _ in range(int(VM_BOOT_TIMEOUT / SLEEP)): status = get_instance_status(nova_client, instance) if status.lower() == "active": return instance @@ -452,13 +435,29 @@ def get_network_id(shade_client, network_name): return networks[0]['id'] -def create_neutron_net(neutron_client, json_body): # pragma: no cover - try: - network = neutron_client.create_network(body=json_body) - return network['network']['id'] - except Exception: # pylint: disable=broad-except - log.error("Error [create_neutron_net(neutron_client)]") - raise Exception("operation error") +def create_neutron_net(shade_client, network_name, shared=False, + admin_state_up=True, external=False, provider=None, + project_id=None): + """Create a neutron network. + + :param network_name:(string) name of the network being created. + :param shared:(bool) whether the network is shared. + :param admin_state_up:(bool) set the network administrative state. + :param external:(bool) whether this network is externally accessible. + :param provider:(dict) a dict of network provider options. + :param project_id:(string) specify the project ID this network + will be created on (admin-only). + :returns:(string) the network id. + """ + try: + networks = shade_client.create_network( + name=network_name, shared=shared, admin_state_up=admin_state_up, + external=external, provider=provider, project_id=project_id) + return networks['id'] + except exc.OpenStackCloudException as o_exc: + log.error("Error [create_neutron_net(shade_client)]." + "Exception message, '%s'", o_exc.orig_message) + return None def delete_neutron_net(shade_client, network_id): @@ -469,13 +468,55 @@ def delete_neutron_net(shade_client, network_id): return False -def create_neutron_subnet(neutron_client, json_body): # pragma: no cover - try: - subnet = neutron_client.create_subnet(body=json_body) - return subnet['subnets'][0]['id'] - except Exception: # pylint: disable=broad-except - log.error("Error [create_neutron_subnet") - raise Exception("operation error") +def create_neutron_subnet(shade_client, network_name_or_id, cidr=None, + ip_version=4, enable_dhcp=False, subnet_name=None, + tenant_id=None, allocation_pools=None, + gateway_ip=None, disable_gateway_ip=False, + dns_nameservers=None, host_routes=None, + ipv6_ra_mode=None, ipv6_address_mode=None, + use_default_subnetpool=False): + """Create a subnet on a specified network. + + :param network_name_or_id:(string) the unique name or ID of the + attached network. If a non-unique name is + supplied, an exception is raised. + :param cidr:(string) the CIDR. + :param ip_version:(int) the IP version. + :param enable_dhcp:(bool) whether DHCP is enable. + :param subnet_name:(string) the name of the subnet. + :param tenant_id:(string) the ID of the tenant who owns the network. + :param allocation_pools: A list of dictionaries of the start and end + addresses for the allocation pools. + :param gateway_ip:(string) the gateway IP address. + :param disable_gateway_ip:(bool) whether gateway IP address is enabled. + :param dns_nameservers: A list of DNS name servers for the subnet. + :param host_routes: A list of host route dictionaries for the subnet. + :param ipv6_ra_mode:(string) IPv6 Router Advertisement mode. + Valid values are: 'dhcpv6-stateful', + 'dhcpv6-stateless', or 'slaac'. + :param ipv6_address_mode:(string) IPv6 address mode. + Valid values are: 'dhcpv6-stateful', + 'dhcpv6-stateless', or 'slaac'. + :param use_default_subnetpool:(bool) use the default subnetpool for + ``ip_version`` to obtain a CIDR. It is + required to pass ``None`` to the ``cidr`` + argument when enabling this option. + :returns:(string) the subnet id. + """ + try: + subnet = shade_client.create_subnet( + network_name_or_id, cidr=cidr, ip_version=ip_version, + enable_dhcp=enable_dhcp, subnet_name=subnet_name, + tenant_id=tenant_id, allocation_pools=allocation_pools, + gateway_ip=gateway_ip, disable_gateway_ip=disable_gateway_ip, + dns_nameservers=dns_nameservers, host_routes=host_routes, + ipv6_ra_mode=ipv6_ra_mode, ipv6_address_mode=ipv6_address_mode, + use_default_subnetpool=use_default_subnetpool) + return subnet['id'] + except exc.OpenStackCloudException as o_exc: + log.error("Error [create_neutron_subnet(shade_client)]. " + "Exception message: %s", o_exc.orig_message) + return None def create_neutron_router(neutron_client, json_body): # pragma: no cover @@ -487,13 +528,12 @@ def create_neutron_router(neutron_client, json_body): # pragma: no cover raise Exception("operation error") -def delete_neutron_router(neutron_client, router_id): # pragma: no cover +def delete_neutron_router(shade_client, router_id): try: - neutron_client.delete_router(router=router_id) - return True - except Exception: # pylint: disable=broad-except - log.error("Error [delete_neutron_router(neutron_client, '%s')]", - router_id) + return shade_client.delete_router(router_id) + except exc.OpenStackCloudException as o_exc: + log.error("Error [delete_neutron_router(shade_client, '%s')]. " + "Exception message: %s", router_id, o_exc.orig_message) return False diff --git a/yardstick/common/packages.py b/yardstick/common/packages.py new file mode 100644 index 000000000..f20217fdc --- /dev/null +++ b/yardstick/common/packages.py @@ -0,0 +1,87 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import re + +import pip +from pip import exceptions as pip_exceptions +from pip.operations import freeze + +from yardstick.common import privsep + + +LOG = logging.getLogger(__name__) + +ACTION_INSTALL = 'install' +ACTION_UNINSTALL = 'uninstall' + + +@privsep.yardstick_root.entrypoint +def _pip_main(package, action, target=None): + if action == ACTION_UNINSTALL: + cmd = [action, package, '-y'] + elif action == ACTION_INSTALL: + cmd = [action, package, '--upgrade'] + if target: + cmd.append('--target=%s' % target) + return pip.main(cmd) + + +def _pip_execute_action(package, action=ACTION_INSTALL, target=None): + """Execute an action with a PIP package. + + According to [1], a package could be a URL, a local directory, a local dist + file or a requirements file. + + [1] https://pip.pypa.io/en/stable/reference/pip_install/#argument-handling + """ + try: + status = _pip_main(package, action, target) + except pip_exceptions.PipError: + status = 1 + + if not status: + LOG.info('Action "%s" executed, package %s', package, action) + else: + LOG.info('Error executing action "%s", package %s', package, action) + return status + + +def pip_remove(package): + """Remove an installed PIP package""" + return _pip_execute_action(package, action=ACTION_UNINSTALL) + + +def pip_install(package, target=None): + """Install a PIP package""" + return _pip_execute_action(package, action=ACTION_INSTALL, target=target) + + +def pip_list(pkg_name=None): + """Dict of installed PIP packages with version. + + If 'pkg_name' is not None, will return only those packages matching the + name.""" + pip_regex = re.compile(r"(?P<name>.*)==(?P<version>[\w\.]+)") + git_regex = re.compile(r".*@(?P<version>[\w]+)#egg=(?P<name>[\w]+)") + + pkg_dict = {} + for _pkg in freeze.freeze(local_only=True): + match = pip_regex.match(_pkg) or git_regex.match(_pkg) + if match and (not pkg_name or ( + pkg_name and match.group('name').find(pkg_name) != -1)): + pkg_dict[match.group('name')] = match.group('version') + + return pkg_dict diff --git a/yardstick/common/privsep.py b/yardstick/common/privsep.py new file mode 100644 index 000000000..4ae510489 --- /dev/null +++ b/yardstick/common/privsep.py @@ -0,0 +1,23 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from oslo_privsep import capabilities as c +from oslo_privsep import priv_context + +yardstick_root = priv_context.PrivContext( + "yardstick", + cfg_section="yardstick_privileged", + pypath=__name__ + ".yardstick_root", + capabilities=[c.CAP_SYS_ADMIN] +) diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py index 495290122..357f66be8 100644 --- a/yardstick/common/utils.py +++ b/yardstick/common/utils.py @@ -31,6 +31,7 @@ import six from flask import jsonify from six.moves import configparser from oslo_serialization import jsonutils +from oslo_utils import encodeutils import yardstick @@ -65,7 +66,7 @@ def itersubclasses(cls, _seen=None): yield sub -def import_modules_from_package(package): +def import_modules_from_package(package, raise_exception=False): """Import modules given a package name :param: package - Full package name. For example: rally.deploy.engines @@ -86,10 +87,27 @@ def import_modules_from_package(package): for module_name in missing_modules: try: importlib.import_module(module_name) - except (ImportError, SyntaxError): + except (ImportError, SyntaxError) as exc: + if raise_exception: + raise exc logger.exception('Unable to import module %s', module_name) +NON_NONE_DEFAULT = object() + + +def get_key_with_default(data, key, default=NON_NONE_DEFAULT): + value = data.get(key, default) + if value is NON_NONE_DEFAULT: + raise KeyError(key) + return value + + +def make_dict_from_map(data, key_map): + return {dest_key: get_key_with_default(data, src_key, default) + for dest_key, (src_key, default) in key_map.items()} + + def makedirs(d): try: os.makedirs(d) @@ -106,13 +124,12 @@ def remove_file(path): raise -def execute_command(cmd): +def execute_command(cmd, **kwargs): exec_msg = "Executing command: '%s'" % cmd logger.debug(exec_msg) - output = subprocess.check_output(cmd.split()).split(os.linesep) - - return output + output = subprocess.check_output(cmd.split(), **kwargs) + return encodeutils.safe_decode(output, incoming='utf-8').split(os.linesep) def source_env(env_file): @@ -410,3 +427,31 @@ def read_meminfo(ssh_client): output[match[0]] = match[1] return output + + +def find_relative_file(path, task_path): + """ + Find file in one of places: in abs of path or relative to a directory path, + in this order. + + :param path: + :param task_path: + :return str: full path to file + """ + # fixme: create schema to validate all fields have been provided + for lookup in [os.path.abspath(path), os.path.join(task_path, path)]: + try: + with open(lookup): + return lookup + except IOError: + pass + raise IOError(errno.ENOENT, 'Unable to find {} file'.format(path)) + + +def open_relative_file(path, task_path): + try: + return open(path) + except IOError as e: + if e.errno == errno.ENOENT: + return open(os.path.join(task_path, path)) + raise diff --git a/yardstick/error.py b/yardstick/error.py new file mode 100644 index 000000000..9b84de1af --- /dev/null +++ b/yardstick/error.py @@ -0,0 +1,48 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class SSHError(Exception): + """Class handles ssh connection error exception""" + pass + + +class SSHTimeout(SSHError): + """Class handles ssh connection timeout exception""" + pass + + +class IncorrectConfig(Exception): + """Class handles incorrect configuration during setup""" + pass + + +class IncorrectSetup(Exception): + """Class handles incorrect setup during setup""" + pass + + +class IncorrectNodeSetup(IncorrectSetup): + """Class handles incorrect setup during setup""" + pass + + +class ErrorClass(object): + + def __init__(self, *args, **kwargs): + if 'test' not in kwargs: + raise RuntimeError + + def __getattr__(self, item): + raise AttributeError diff --git a/yardstick/network_services/constants.py b/yardstick/network_services/constants.py new file mode 100644 index 000000000..0064b4fc5 --- /dev/null +++ b/yardstick/network_services/constants.py @@ -0,0 +1,19 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +REMOTE_TMP = "/tmp" +DEFAULT_VNF_TIMEOUT = 3600 +PROCESS_JOIN_TIMEOUT = 3 +ONE_GIGABIT_IN_BITS = 1000000000 +NIC_GBPS_DEFAULT = 10 diff --git a/yardstick/network_services/helpers/dpdkbindnic_helper.py b/yardstick/network_services/helpers/dpdkbindnic_helper.py index 8c44b26c2..05b822c2e 100644 --- a/yardstick/network_services/helpers/dpdkbindnic_helper.py +++ b/yardstick/network_services/helpers/dpdkbindnic_helper.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2017 Intel Corporation +# Copyright (c) 2016-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. @@ -12,11 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. import logging +import os import re -import itertools +from collections import defaultdict +from itertools import chain -import six +from yardstick.common.utils import validate_non_string_sequence +from yardstick.error import IncorrectConfig +from yardstick.error import IncorrectSetup +from yardstick.error import IncorrectNodeSetup +from yardstick.error import SSHTimeout +from yardstick.error import SSHError NETWORK_KERNEL = 'network_kernel' NETWORK_DPDK = 'network_dpdk' @@ -25,7 +32,6 @@ CRYPTO_KERNEL = 'crypto_kernel' CRYPTO_DPDK = 'crypto_dpdk' CRYPTO_OTHER = 'crypto_other' - LOG = logging.getLogger(__name__) @@ -33,6 +39,166 @@ class DpdkBindHelperException(Exception): pass +class DpdkInterface(object): + TOPOLOGY_REQUIRED_KEYS = frozenset({ + "vpci", "local_ip", "netmask", "local_mac", "driver"}) + + def __init__(self, dpdk_node, interface): + super(DpdkInterface, self).__init__() + self.dpdk_node = dpdk_node + self.interface = interface + + try: + assert self.local_mac + except (AssertionError, KeyError): + raise IncorrectConfig + + @property + def local_mac(self): + return self.interface['local_mac'] + + @property + def mac_lower(self): + return self.local_mac.lower() + + @property + def missing_fields(self): + return self.TOPOLOGY_REQUIRED_KEYS.difference(self.interface) + + @staticmethod + def _detect_socket(netdev): + try: + socket = netdev['numa_node'] + except KeyError: + # Where is this documented? + # It seems for dual-sockets systems the second socket PCI bridge + # will have an address > 0x0f, e.g. + # Bridge PCI->PCI (P#524320 busid=0000:80:02.0 id=8086:6f04 + if netdev['pci_bus_id'][5] == "0": + socket = 0 + else: + # this doesn't handle quad-sockets + # TODO: fix this for quad-socket + socket = 1 + return socket + + def probe_missing_values(self): + try: + for netdev in self.dpdk_node.netdevs.values(): + if netdev['address'].lower() == self.mac_lower: + socket = self._detect_socket(netdev) + self.interface.update({ + 'vpci': netdev['pci_bus_id'], + 'driver': netdev['driver'], + 'socket': socket, + # don't need ifindex + }) + + except KeyError: + # if we don't find all the keys then don't update + pass + + except (IncorrectNodeSetup, SSHError, SSHTimeout): + raise IncorrectConfig( + "Unable to probe missing interface fields '%s', on node %s " + "SSH Error" % (', '.join(self.missing_fields), self.dpdk_node.node_key)) + + +class DpdkNode(object): + + def __init__(self, node_name, interfaces, ssh_helper, timeout=120): + super(DpdkNode, self).__init__() + self.interfaces = interfaces + self.ssh_helper = ssh_helper + self.node_key = node_name + self.timeout = timeout + self._dpdk_helper = None + self.netdevs = {} + + try: + self.dpdk_interfaces = {intf['name']: DpdkInterface(self, intf['virtual-interface']) + for intf in self.interfaces} + except IncorrectConfig: + template = "MAC address is required for all interfaces, missing on: {}" + errors = (intf['name'] for intf in self.interfaces if + 'local_mac' not in intf['virtual-interface']) + raise IncorrectSetup(template.format(", ".join(errors))) + + @property + def dpdk_helper(self): + if not isinstance(self._dpdk_helper, DpdkBindHelper): + self._dpdk_helper = DpdkBindHelper(self.ssh_helper) + return self._dpdk_helper + + @property + def _interface_missing_iter(self): + return chain.from_iterable(self._interface_missing_map.values()) + + @property + def _interface_missing_map(self): + return {name: intf.missing_fields for name, intf in self.dpdk_interfaces.items()} + + def _probe_netdevs(self): + self.netdevs.update(self.dpdk_helper.find_net_devices()) + + def _force_rebind(self): + return self.dpdk_helper.force_dpdk_rebind() + + def _probe_dpdk_drivers(self): + self.dpdk_helper.probe_real_kernel_drivers() + for pci, driver in self.dpdk_helper.real_kernel_interface_driver_map.items(): + for intf in self.interfaces: + vintf = intf['virtual-interface'] + # stupid substring matches + # don't use netdev use interface + if vintf['vpci'].endswith(pci): + vintf['driver'] = driver + # we can't update netdevs because we may not have netdev info + + def _probe_missing_values(self): + for intf in self.dpdk_interfaces.values(): + intf.probe_missing_values() + + def check(self): + # only ssh probe if there are missing values + # ssh probe won't work on Ixia, so we had better define all our values + try: + missing_fields_set = set(self._interface_missing_iter) + + # if we are only missing driver then maybe we can get kernel module + # this requires vpci + if missing_fields_set == {'driver'}: + self._probe_dpdk_drivers() + # we can't reprobe missing values because we may not have netdev info + + # if there are any other missing then we have to netdev probe + if missing_fields_set.difference({'driver'}): + self._probe_netdevs() + try: + self._probe_missing_values() + except IncorrectConfig: + # ignore for now + pass + + # check again and verify we have all the fields + if set(self._interface_missing_iter): + # last chance fallback, rebind everything and probe + # this probably won't work + self._force_rebind() + self._probe_netdevs() + self._probe_missing_values() + + errors = ("{} missing: {}".format(name, ", ".join(missing_fields)) for + name, missing_fields in self._interface_missing_map.items() if + missing_fields) + errors = "\n".join(errors) + if errors: + raise IncorrectSetup(errors) + + finally: + self._dpdk_helper = None + + class DpdkBindHelper(object): DPDK_STATUS_CMD = "{dpdk_devbind} --status" DPDK_BIND_CMD = "sudo {dpdk_devbind} {force} -b {driver} {vpci}" @@ -42,6 +208,8 @@ class DpdkBindHelper(object): SKIP_RE = re.compile('(====|<none>|^$)') NIC_ROW_FIELDS = ['vpci', 'dev_type', 'iface', 'driver', 'unused', 'active'] + UIO_DRIVER = "uio" + HEADER_DICT_PAIRS = [ (re.compile('^Network.*DPDK.*$'), NETWORK_DPDK), (re.compile('^Network.*kernel.*$'), NETWORK_KERNEL), @@ -51,6 +219,42 @@ class DpdkBindHelper(object): (re.compile('^Other crypto.*$'), CRYPTO_OTHER), ] + FIND_NETDEVICE_STRING = r"""\ +find /sys/devices/pci* -type d -name net -exec sh -c '{ grep -sH ^ \ +$1/ifindex $1/address $1/operstate $1/device/vendor $1/device/device \ +$1/device/subsystem_vendor $1/device/subsystem_device $1/device/numa_node ; \ +printf "%s/driver:" $1 ; basename $(readlink -s $1/device/driver); } \ +' sh \{\}/* \; +""" + + BASE_ADAPTER_RE = re.compile('^/sys/devices/(.*)/net/([^/]*)/([^:]*):(.*)$', re.M) + DPDK_DEVBIND = "dpdk-devbind.py" + + @classmethod + def parse_netdev_info(cls, stdout): + network_devices = defaultdict(dict) + match_iter = (match.groups() for match in cls.BASE_ADAPTER_RE.finditer(stdout)) + for bus_path, interface_name, name, value in match_iter: + dir_name, bus_id = os.path.split(bus_path) + if 'virtio' in bus_id: + # for some stupid reason VMs include virtio1/ + # in PCI device path + bus_id = os.path.basename(dir_name) + + # remove extra 'device/' from 'device/vendor, + # device/subsystem_vendor', etc. + if 'device' in name: + name = name.split('/')[1] + + network_devices[interface_name].update({ + name: value, + 'interface_name': interface_name, + 'pci_bus_id': bus_id, + }) + + # convert back to regular dict + return dict(network_devices) + def clean_status(self): self.dpdk_status = { NETWORK_KERNEL: [], @@ -61,11 +265,17 @@ class DpdkBindHelper(object): CRYPTO_OTHER: [], } - def __init__(self, ssh_helper): + # TODO: add support for driver other than igb_uio + def __init__(self, ssh_helper, dpdk_driver="igb_uio"): + self.ssh_helper = ssh_helper + self.real_kernel_interface_driver_map = {} + self.dpdk_driver = dpdk_driver self.dpdk_status = None self.status_nic_row_re = None - self._dpdk_devbind = None + self.dpdk_devbind = self.ssh_helper.join_bin_path(self.DPDK_DEVBIND) self._status_cmd_attr = None + self.used_drivers = None + self.real_kernel_drivers = {} self.ssh_helper = ssh_helper self.clean_status() @@ -73,15 +283,16 @@ class DpdkBindHelper(object): def _dpdk_execute(self, *args, **kwargs): res = self.ssh_helper.execute(*args, **kwargs) if res[0] != 0: - raise DpdkBindHelperException('{} command failed with rc={}'.format( - self.dpdk_devbind, res[0])) + template = '{} command failed with rc={}' + raise DpdkBindHelperException(template.format(self.dpdk_devbind, res[0])) return res - @property - def dpdk_devbind(self): - if self._dpdk_devbind is None: - self._dpdk_devbind = self.ssh_helper.provision_tool(tool_file="dpdk-devbind.py") - return self._dpdk_devbind + def load_dpdk_driver(self): + cmd_template = "sudo modprobe {} && sudo modprobe {}" + self.ssh_helper.execute(cmd_template.format(self.UIO_DRIVER, self.dpdk_driver)) + + def check_dpdk_driver(self): + return self.ssh_helper.execute("lsmod | grep -i {}".format(self.dpdk_driver))[0] @property def _status_cmd(self): @@ -89,12 +300,14 @@ class DpdkBindHelper(object): self._status_cmd_attr = self.DPDK_STATUS_CMD.format(dpdk_devbind=self.dpdk_devbind) return self._status_cmd_attr - def _addline(self, active_list, line): + def _add_line(self, active_list, line): if active_list is None: return + res = self.NIC_ROW_RE.match(line) if res is None: return + new_data = {k: v for k, v in zip(self.NIC_ROW_FIELDS, res.groups())} new_data['active'] = bool(new_data['active']) self.dpdk_status[active_list].append(new_data) @@ -106,14 +319,14 @@ class DpdkBindHelper(object): return a_dict return active_dict - def parse_dpdk_status_output(self, input): + def _parse_dpdk_status_output(self, output): active_dict = None self.clean_status() - for a_row in input.splitlines(): + for a_row in output.splitlines(): if self.SKIP_RE.match(a_row): continue active_dict = self._switch_active_dict(a_row, active_dict) - self._addline(active_dict, a_row) + self._add_line(active_dict, a_row) return self.dpdk_status def _get_bound_pci_addresses(self, active_dict): @@ -130,31 +343,85 @@ class DpdkBindHelper(object): @property def interface_driver_map(self): return {interface['vpci']: interface['driver'] - for interface in itertools.chain.from_iterable(self.dpdk_status.values())} + for interface in chain.from_iterable(self.dpdk_status.values())} def read_status(self): - return self.parse_dpdk_status_output(self._dpdk_execute(self._status_cmd)[1]) + return self._parse_dpdk_status_output(self._dpdk_execute(self._status_cmd)[1]) + + def find_net_devices(self): + exit_status, stdout, _ = self.ssh_helper.execute(self.FIND_NETDEVICE_STRING) + if exit_status != 0: + return {} + + return self.parse_netdev_info(stdout) def bind(self, pci_addresses, driver, force=True): - # accept single PCI or list of PCI - if isinstance(pci_addresses, six.string_types): - pci_addresses = [pci_addresses] + # accept single PCI or sequence of PCI + pci_addresses = validate_non_string_sequence(pci_addresses, [pci_addresses]) + cmd = self.DPDK_BIND_CMD.format(dpdk_devbind=self.dpdk_devbind, driver=driver, vpci=' '.join(list(pci_addresses)), force='--force' if force else '') LOG.debug(cmd) self._dpdk_execute(cmd) + # update the inner status dict self.read_status() + def probe_real_kernel_drivers(self): + self.read_status() + self.save_real_kernel_interface_driver_map() + + def force_dpdk_rebind(self): + self.load_dpdk_driver() + self.read_status() + self.save_real_kernel_interface_driver_map() + self.save_used_drivers() + + real_driver_map = {} + # only rebind devices that are bound to DPDK + for pci in self.dpdk_bound_pci_addresses: + # messy + real_driver = self.real_kernel_interface_driver_map[pci] + real_driver_map.setdefault(real_driver, []).append(pci) + for real_driver, pcis in real_driver_map.items(): + self.bind(pcis, real_driver, force=True) + def save_used_drivers(self): # invert the map, so we can bind by driver type self.used_drivers = {} - # sort for stabililty + # sort for stability for vpci, driver in sorted(self.interface_driver_map.items()): self.used_drivers.setdefault(driver, []).append(vpci) + KERNEL_DRIVER_RE = re.compile(r"Kernel modules: (\S+)", re.M) + VIRTIO_DRIVER_RE = re.compile(r"Ethernet.*Virtio network device", re.M) + VIRTIO_DRIVER = "virtio-pci" + + def save_real_kernel_drivers(self): + # invert the map, so we can bind by driver type + self.real_kernel_drivers = {} + # sort for stability + for vpci, driver in sorted(self.real_kernel_interface_driver_map.items()): + self.used_drivers.setdefault(driver, []).append(vpci) + + def get_real_kernel_driver(self, pci): + out = self.ssh_helper.execute('lspci -k -s %s' % pci)[1] + match = self.KERNEL_DRIVER_RE.search(out) + if match: + return match.group(1) + + match = self.VIRTIO_DRIVER_RE.search(out) + if match: + return self.VIRTIO_DRIVER + + return None + + def save_real_kernel_interface_driver_map(self): + iter1 = ((pci, self.get_real_kernel_driver(pci)) for pci in self.interface_driver_map) + self.real_kernel_interface_driver_map = {pci: driver for pci, driver in iter1 if driver} + def rebind_drivers(self, force=True): for driver, vpcis in self.used_drivers.items(): self.bind(vpcis, driver, force) diff --git a/yardstick/network_services/traffic_profile/__init__.py b/yardstick/network_services/traffic_profile/__init__.py index e69de29bb..356b36bd9 100644 --- a/yardstick/network_services/traffic_profile/__init__.py +++ b/yardstick/network_services/traffic_profile/__init__.py @@ -0,0 +1,33 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import importlib + + +def register_modules(): + modules = [ + 'yardstick.network_services.traffic_profile.trex_traffic_profile', + 'yardstick.network_services.traffic_profile.fixed', + 'yardstick.network_services.traffic_profile.http', + 'yardstick.network_services.traffic_profile.http_ixload', + 'yardstick.network_services.traffic_profile.ixia_rfc2544', + 'yardstick.network_services.traffic_profile.prox_ACL', + 'yardstick.network_services.traffic_profile.prox_binsearch', + 'yardstick.network_services.traffic_profile.prox_profile', + 'yardstick.network_services.traffic_profile.prox_ramp', + 'yardstick.network_services.traffic_profile.rfc2544', + ] + + for module in modules: + importlib.import_module(module) diff --git a/yardstick/network_services/traffic_profile/base.py b/yardstick/network_services/traffic_profile/base.py index ad256b444..162bab2bc 100644 --- a/yardstick/network_services/traffic_profile/base.py +++ b/yardstick/network_services/traffic_profile/base.py @@ -11,10 +11,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -""" Base class for the generic traffic profile implementation """ -from __future__ import absolute_import -from yardstick.common.utils import import_modules_from_package, itersubclasses +from yardstick.common import exceptions +from yardstick.common import utils class TrafficProfile(object): @@ -33,13 +32,12 @@ class TrafficProfile(object): :return: """ profile_class = tp_config["traffic_profile"]["traffic_type"] - import_modules_from_package( - "yardstick.network_services.traffic_profile") try: - return next(c for c in itersubclasses(TrafficProfile) + return next(c for c in utils.itersubclasses(TrafficProfile) if c.__name__ == profile_class)(tp_config) except StopIteration: - raise RuntimeError("No implementation for %s", profile_class) + raise exceptions.TrafficProfileNotImplemented( + profile_class=profile_class) def __init__(self, tp_config): # e.g. RFC2544 start_ip, stop_ip, drop_rate, diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py index 3ab157dc7..7f047226b 100644 --- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py +++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py @@ -15,7 +15,7 @@ from __future__ import absolute_import import logging -from yardstick.network_services.traffic_profile.traffic_profile import \ +from yardstick.network_services.traffic_profile.trex_traffic_profile import \ TrexProfile LOG = logging.getLogger(__name__) diff --git a/yardstick/network_services/traffic_profile/prox_binsearch.py b/yardstick/network_services/traffic_profile/prox_binsearch.py index 5700f98e5..c3277fb12 100644 --- a/yardstick/network_services/traffic_profile/prox_binsearch.py +++ b/yardstick/network_services/traffic_profile/prox_binsearch.py @@ -20,6 +20,7 @@ import datetime import time from yardstick.network_services.traffic_profile.prox_profile import ProxProfile +from yardstick.network_services import constants LOG = logging.getLogger(__name__) @@ -99,9 +100,13 @@ class ProxBinSearchProfile(ProxProfile): # throughput and packet loss from the most recent successful test successful_pkt_loss = 0.0 + line_speed = traffic_gen.scenario_helper.all_options.get( + "interface_speed_gbps", constants.NIC_GBPS_DEFAULT) * constants.ONE_GIGABIT_IN_BITS for test_value in self.bounds_iterator(LOG): result, port_samples = self._profile_helper.run_test(pkt_size, duration, - test_value, self.tolerated_loss) + test_value, + self.tolerated_loss, + line_speed) self.curr_time = time.time() diff_time = self.curr_time - self.prev_time self.prev_time = self.curr_time diff --git a/yardstick/network_services/traffic_profile/prox_profile.py b/yardstick/network_services/traffic_profile/prox_profile.py index 170dfd96f..343ef1da2 100644 --- a/yardstick/network_services/traffic_profile/prox_profile.py +++ b/yardstick/network_services/traffic_profile/prox_profile.py @@ -29,8 +29,22 @@ class ProxProfile(TrafficProfile): """ @staticmethod + def sort_vpci(traffic_gen): + """Return the list of external interfaces ordered by vpci and name + + :param traffic_gen: (ProxTrafficGen) traffic generator + :return: list of ordered interfaces + """ + def key_func(interface): + return interface['virtual-interface']['vpci'], interface['name'] + + return sorted(traffic_gen.vnfd_helper['vdu'][0]['external-interface'], + key=key_func) + + @staticmethod def fill_samples(samples, traffic_gen): - for vpci_idx, intf in enumerate(traffic_gen.vpci_if_name_ascending): + vpci_if_name_ascending = ProxProfile.sort_vpci(traffic_gen) + for vpci_idx, intf in enumerate(vpci_if_name_ascending): name = intf[1] # TODO: VNFDs KPIs values needs to be mapped to TRex structure xe_port = traffic_gen.resource_helper.sut.port_stats([vpci_idx]) diff --git a/yardstick/network_services/traffic_profile/rfc2544.py b/yardstick/network_services/traffic_profile/rfc2544.py index b1ca8a345..83020c85c 100644 --- a/yardstick/network_services/traffic_profile/rfc2544.py +++ b/yardstick/network_services/traffic_profile/rfc2544.py @@ -21,7 +21,7 @@ from trex_stl_lib.trex_stl_client import STLStream from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats from trex_stl_lib.trex_stl_streams import STLTXCont -from yardstick.network_services.traffic_profile.traffic_profile \ +from yardstick.network_services.traffic_profile.trex_traffic_profile \ import TrexProfile LOGGING = logging.getLogger(__name__) diff --git a/yardstick/network_services/traffic_profile/traffic_profile.py b/yardstick/network_services/traffic_profile/trex_traffic_profile.py index 8cde5e4a7..f5e3923d5 100644 --- a/yardstick/network_services/traffic_profile/traffic_profile.py +++ b/yardstick/network_services/traffic_profile/trex_traffic_profile.py @@ -21,7 +21,7 @@ import ipaddress import six from yardstick.common import exceptions as y_exc -from yardstick.network_services.traffic_profile.base import TrafficProfile +from yardstick.network_services.traffic_profile import base from trex_stl_lib.trex_stl_client import STLStream from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats from trex_stl_lib.trex_stl_streams import STLTXCont @@ -48,7 +48,7 @@ TYPE_OF_SERVICE = 'tos' LOG = logging.getLogger(__name__) -class TrexProfile(TrafficProfile): +class TrexProfile(base.TrafficProfile): """ This class handles Trex Traffic profile generation and execution """ PROTO_MAP = { @@ -127,7 +127,7 @@ class TrexProfile(TrafficProfile): self.vm_flow_vars.append(stl_vm_wr_flow_var) return partial - def _dscp_range_action_partial(self, *_): + def _dscp_range_action_partial(self, *args): def partial(min_value, max_value, count): # pylint: disable=unused-argument stl_vm_flow_var = STLVmFlowVar(name="dscp", diff --git a/yardstick/network_services/utils.py b/yardstick/network_services/utils.py index 7a1815eb9..4b987fafe 100644 --- a/yardstick/network_services/utils.py +++ b/yardstick/network_services/utils.py @@ -121,7 +121,6 @@ def provision_tool(connection, tool_path, tool_file=None): tool_path = get_nsb_option('tool_path') if tool_file: tool_path = os.path.join(tool_path, tool_file) - bin_path = get_nsb_option("bin_path") exit_status = connection.execute("which %s > /dev/null 2>&1" % tool_path)[0] if exit_status == 0: return encodeutils.safe_decode(tool_path, incoming='utf-8').rstrip() diff --git a/yardstick/network_services/vnf_generic/vnf/acl_vnf.py b/yardstick/network_services/vnf_generic/vnf/acl_vnf.py index 1390dd02e..f3cafef7a 100644 --- a/yardstick/network_services/vnf_generic/vnf/acl_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/acl_vnf.py @@ -12,11 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import -from __future__ import print_function import logging -from yardstick.benchmark.scenarios.networking.vnf_generic import find_relative_file +from yardstick.common import utils from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, DpdkVnfSetupEnvHelper from yardstick.network_services.yang_model import YangModel @@ -62,8 +60,9 @@ class AclApproxVnf(SampleVNF): self.acl_rules = None def _start_vnf(self): - yang_model_path = find_relative_file(self.scenario_helper.options['rules'], - self.scenario_helper.task_path) + yang_model_path = utils.find_relative_file( + self.scenario_helper.options['rules'], + self.scenario_helper.task_path) yang_model = YangModel(yang_model_path) self.acl_rules = yang_model.get_rules() super(AclApproxVnf, self)._start_vnf() diff --git a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py index edb29640e..31ed30140 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py @@ -30,12 +30,12 @@ import six from six.moves import cStringIO from six.moves import zip, StringIO -from yardstick.benchmark.scenarios.networking.vnf_generic import find_relative_file from yardstick.common import utils from yardstick.common.utils import SocketTopology, join_non_strings, try_int from yardstick.network_services.helpers.iniparser import ConfigParser from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper +from yardstick.network_services import constants PROX_PORT = 8474 @@ -45,7 +45,6 @@ SECTION_CONTENTS = 1 LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) -TEN_GIGABIT = 1e10 BITS_PER_BYTE = 8 RETRY_SECONDS = 60 RETRY_INTERVAL = 1 @@ -467,13 +466,14 @@ class ProxSocketHelper(object): core_data['current'] = core_data[key1] + core_data[key2] self.set_speed(core_data['cores'], core_data['current']) - def set_pps(self, cores, pps, pkt_size): + def set_pps(self, cores, pps, pkt_size, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): """ set packets per second for specific cores on the remote instance """ msg = "Set packets per sec for core(s) %s to %g%% of line rate (packet size: %d)" LOG.debug(msg, cores, pps, pkt_size) # speed in percent of line-rate - speed = float(pps) * (pkt_size + 20) / TEN_GIGABIT / BITS_PER_BYTE + speed = float(pps) * (pkt_size + 20) / line_speed / BITS_PER_BYTE self._run_template_over_cores("speed {} 0 {}\n", cores, speed) def lat_stats(self, cores, task=0): @@ -812,7 +812,7 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): options = self.scenario_helper.options config_path = options['prox_config'] config_file = os.path.basename(config_path) - config_path = find_relative_file(config_path, task_path) + config_path = utils.find_relative_file(config_path, task_path) self.additional_files = {} try: @@ -829,7 +829,7 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): prox_files = [prox_files] for key_prox_file in prox_files: base_prox_file = os.path.basename(key_prox_file) - key_prox_path = find_relative_file(key_prox_file, task_path) + key_prox_path = utils.find_relative_file(key_prox_file, task_path) remote_prox_file = self.copy_to_target(key_prox_path, base_prox_file) self.additional_files[base_prox_file] = remote_prox_file @@ -982,12 +982,13 @@ class ProxResourceHelper(ClientResourceHelper): class ProxDataHelper(object): - def __init__(self, vnfd_helper, sut, pkt_size, value, tolerated_loss): + def __init__(self, vnfd_helper, sut, pkt_size, value, tolerated_loss, line_speed): super(ProxDataHelper, self).__init__() self.vnfd_helper = vnfd_helper self.sut = sut self.pkt_size = pkt_size self.value = value + self.line_speed = line_speed self.tolerated_loss = tolerated_loss self.port_count = len(self.vnfd_helper.port_pairs.all_ports) self.tsc_hz = None @@ -1073,9 +1074,7 @@ class ProxDataHelper(object): self.tsc_hz = float(self.sut.hz()) def line_rate_to_pps(self): - # NOTE: to fix, don't hardcode 10Gb/s - return self.port_count * TEN_GIGABIT / BITS_PER_BYTE / (self.pkt_size + 20) - + return self.port_count * self.line_speed / BITS_PER_BYTE / (self.pkt_size + 20) class ProxProfileHelper(object): @@ -1154,8 +1153,10 @@ class ProxProfileHelper(object): return cores - def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): - data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, + value, tolerated_loss, line_speed) with data_helper, self.traffic_context(pkt_size, value): with data_helper.measure_tot_stats(): @@ -1411,8 +1412,10 @@ class ProxBngProfileHelper(ProxProfileHelper): time.sleep(3) self.sut.stop(self.all_rx_cores) - def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): - data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, + value, tolerated_loss, line_speed) with data_helper, self.traffic_context(pkt_size, value): with data_helper.measure_tot_stats(): @@ -1598,8 +1601,10 @@ class ProxVpeProfileHelper(ProxProfileHelper): time.sleep(3) self.sut.stop(self.all_rx_cores) - def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): - data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, + value, tolerated_loss, line_speed) with data_helper, self.traffic_context(pkt_size, value): with data_helper.measure_tot_stats(): @@ -1787,8 +1792,10 @@ class ProxlwAFTRProfileHelper(ProxProfileHelper): time.sleep(3) self.sut.stop(self.all_rx_cores) - def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): - data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0, + line_speed=(constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, + value, tolerated_loss, line_speed) with data_helper, self.traffic_context(pkt_size, value): with data_helper.measure_tot_stats(): diff --git a/yardstick/network_services/vnf_generic/vnf/prox_vnf.py b/yardstick/network_services/vnf_generic/vnf/prox_vnf.py index ee7735972..285e08659 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_vnf.py @@ -21,7 +21,8 @@ import time from yardstick.common.process import check_if_process_failed from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxDpdkVnfSetupEnvHelper from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxResourceHelper -from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, PROCESS_JOIN_TIMEOUT +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF +from yardstick.network_services import constants LOG = logging.getLogger(__name__) @@ -135,5 +136,5 @@ class ProxApproxVnf(SampleVNF): self._tear_down() if self._vnf_process is not None: LOG.debug("joining before terminate %s", self._vnf_process.name) - self._vnf_process.join(PROCESS_JOIN_TIMEOUT) + self._vnf_process.join(constants.PROCESS_JOIN_TIMEOUT) self._vnf_process.terminate() diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py index 200930322..addbd9aa4 100644 --- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2017 Intel Corporation +# Copyright (c) 2016-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. @@ -16,6 +16,7 @@ from collections import Mapping import logging from multiprocessing import Queue, Value, Process + import os import posixpath import re @@ -23,78 +24,33 @@ import subprocess import time import six -from six.moves import cStringIO from trex_stl_lib.trex_stl_client import LoggerApi from trex_stl_lib.trex_stl_client import STLClient from trex_stl_lib.trex_stl_exceptions import STLError from yardstick.benchmark.contexts.base import Context -from yardstick.benchmark.scenarios.networking.vnf_generic import find_relative_file from yardstick.common import exceptions as y_exceptions -from yardstick.common import utils from yardstick.common.process import check_if_process_failed -from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper -from yardstick.network_services.helpers.samplevnf_helper import PortPairs +from yardstick.common import utils +from yardstick.network_services import constants +from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper, DpdkNode from yardstick.network_services.helpers.samplevnf_helper import MultiPortConfig +from yardstick.network_services.helpers.samplevnf_helper import PortPairs from yardstick.network_services.nfvi.resource import ResourceProfile from yardstick.network_services.utils import get_nsb_option -from yardstick.network_services.vnf_generic.vnf.base import GenericVNF from yardstick.network_services.vnf_generic.vnf.base import GenericTrafficGen +from yardstick.network_services.vnf_generic.vnf.base import GenericVNF from yardstick.network_services.vnf_generic.vnf.base import QueueFileWrapper -from yardstick.ssh import AutoConnectSSH - +from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper -DPDK_VERSION = "dpdk-16.07" LOG = logging.getLogger(__name__) -REMOTE_TMP = "/tmp" -DEFAULT_VNF_TIMEOUT = 3600 -PROCESS_JOIN_TIMEOUT = 3 - - -class VnfSshHelper(AutoConnectSSH): - - def __init__(self, node, bin_path, wait=None): - self.node = node - kwargs = self.args_from_node(self.node) - if wait: - kwargs.setdefault('wait', wait) - - super(VnfSshHelper, self).__init__(**kwargs) - self.bin_path = bin_path - - @staticmethod - def get_class(): - # must return static class name, anything else refers to the calling class - # i.e. the subclass, not the superclass - return VnfSshHelper - - def copy(self): - # this copy constructor is different from SSH classes, since it uses node - return self.get_class()(self.node, self.bin_path) - - def upload_config_file(self, prefix, content): - cfg_file = os.path.join(REMOTE_TMP, prefix) - LOG.debug(content) - file_obj = cStringIO(content) - self.put_file_obj(file_obj, cfg_file) - return cfg_file - - def join_bin_path(self, *args): - return os.path.join(self.bin_path, *args) - - def provision_tool(self, tool_path=None, tool_file=None): - if tool_path is None: - tool_path = self.bin_path - return super(VnfSshHelper, self).provision_tool(tool_path, tool_file) - - class SetupEnvHelper(object): - CFG_CONFIG = os.path.join(REMOTE_TMP, "sample_config") - CFG_SCRIPT = os.path.join(REMOTE_TMP, "sample_script") + CFG_CONFIG = os.path.join(constants.REMOTE_TMP, "sample_config") + CFG_SCRIPT = os.path.join(constants.REMOTE_TMP, "sample_script") DEFAULT_CONFIG_TPL_CFG = "sample.cfg" PIPELINE_COMMAND = '' VNF_TYPE = "SAMPLE" @@ -175,6 +131,7 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): vnf_cfg = self.scenario_helper.vnf_cfg task_path = self.scenario_helper.task_path + config_file = vnf_cfg.get('file') lb_count = vnf_cfg.get('lb_count', 3) lb_config = vnf_cfg.get('lb_config', 'SW') worker_config = vnf_cfg.get('worker_config', '1C/1T') @@ -187,7 +144,8 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): 'vnf_type': self.VNF_TYPE, } - config_tpl_cfg = find_relative_file(self.DEFAULT_CONFIG_TPL_CFG, task_path) + config_tpl_cfg = utils.find_relative_file(self.DEFAULT_CONFIG_TPL_CFG, + task_path) config_basename = posixpath.basename(self.CFG_CONFIG) script_basename = posixpath.basename(self.CFG_SCRIPT) multiport = MultiPortConfig(self.scenario_helper.topology, @@ -202,12 +160,20 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): self.socket) multiport.generate_config() - with open(self.CFG_CONFIG) as handle: - new_config = handle.read() - - new_config = self._update_traffic_type(new_config, traffic_options) - new_config = self._update_packet_type(new_config, traffic_options) - + if config_file: + with utils.open_relative_file(config_file, task_path) as infile: + new_config = ['[EAL]'] + vpci = [] + for port in self.vnfd_helper.port_pairs.all_ports: + interface = self.vnfd_helper.find_interface(name=port) + vpci.append(interface['virtual-interface']["vpci"]) + new_config.extend('w = {0}'.format(item) for item in vpci) + new_config = '\n'.join(new_config) + '\n' + infile.read() + else: + with open(self.CFG_CONFIG) as handle: + new_config = handle.read() + new_config = self._update_traffic_type(new_config, traffic_options) + new_config = self._update_packet_type(new_config, traffic_options) self.ssh_helper.upload_config_file(config_basename, new_config) self.ssh_helper.upload_config_file(script_basename, multiport.generate_script(self.vnfd_helper)) @@ -236,7 +202,6 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): def setup_vnf_environment(self): self._setup_dpdk() - self.bound_pci = [v['virtual-interface']["vpci"] for v in self.vnfd_helper.interfaces] self.kill_vnf() # bind before _setup_resources so we can use dpdk_port_num self._detect_and_bind_drivers() @@ -254,10 +219,11 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): def _setup_dpdk(self): """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: - raise y_exceptions.DPDKSetupDriverError() + self.dpdk_bind_helper.load_dpdk_driver() + + exit_status = self.dpdk_bind_helper.check_dpdk_driver() + if exit_status == 0: + return def get_collectd_options(self): options = self.scenario_helper.all_options.get("collectd", {}) @@ -284,9 +250,22 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): plugins=plugins, interval=collectd_options.get("interval"), timeout=self.scenario_helper.timeout) + def _check_interface_fields(self): + num_nodes = len(self.scenario_helper.nodes) + # OpenStack instance creation time is probably proportional to the number + # of instances + timeout = 120 * num_nodes + dpdk_node = DpdkNode(self.scenario_helper.name, self.vnfd_helper.interfaces, + self.ssh_helper, timeout) + dpdk_node.check() + def _detect_and_bind_drivers(self): interfaces = self.vnfd_helper.interfaces + self._check_interface_fields() + # check for bound after probe + self.bound_pci = [v['virtual-interface']["vpci"] for v in interfaces] + self.dpdk_bind_helper.read_status() self.dpdk_bind_helper.save_used_drivers() @@ -390,7 +369,7 @@ class ClientResourceHelper(ResourceHelper): try: return self.client.get_stats(*args, **kwargs) except STLError: - LOG.exception("TRex client not connected") + LOG.error('TRex client not connected') return {} def generate_samples(self, ports, key=None, default=None): @@ -628,8 +607,10 @@ class ScenarioHelper(object): @property def timeout(self): - return self.options.get('timeout', DEFAULT_VNF_TIMEOUT) - + test_duration = self.scenario_cfg.get('runner', {}).get('duration', + self.options.get('timeout', constants.DEFAULT_VNF_TIMEOUT)) + test_timeout = self.options.get('timeout', constants.DEFAULT_VNF_TIMEOUT) + return test_duration if test_duration > test_timeout else test_timeout class SampleVNF(GenericVNF): """ Class providing file-like API for generic VNF implementation """ @@ -813,7 +794,7 @@ class SampleVNF(GenericVNF): if self._vnf_process is not None: # be proper and join first before we kill LOG.debug("joining before terminate %s", self._vnf_process.name) - self._vnf_process.join(PROCESS_JOIN_TIMEOUT) + self._vnf_process.join(constants.PROCESS_JOIN_TIMEOUT) self._vnf_process.terminate() # no terminate children here because we share processes with tg @@ -957,12 +938,12 @@ class SampleVNFTrafficGen(GenericTrafficGen): if self._traffic_process is not None: # be proper and try to join before terminating LOG.debug("joining before terminate %s", self._traffic_process.name) - self._traffic_process.join(PROCESS_JOIN_TIMEOUT) + self._traffic_process.join(constants.PROCESS_JOIN_TIMEOUT) self._traffic_process.terminate() if self._tg_process is not None: # be proper and try to join before terminating LOG.debug("joining before terminate %s", self._tg_process.name) - self._tg_process.join(PROCESS_JOIN_TIMEOUT) + self._tg_process.join(constants.PROCESS_JOIN_TIMEOUT) self._tg_process.terminate() # no terminate children here because we share processes with vnf diff --git a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py index 3ab30b53e..02e7803f7 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py @@ -22,10 +22,10 @@ import shutil from collections import OrderedDict from subprocess import call -from yardstick.common.utils import makedirs +from yardstick.common import utils from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper -from yardstick.benchmark.scenarios.networking.vnf_generic import find_relative_file + LOG = logging.getLogger(__name__) @@ -93,9 +93,10 @@ class IxLoadResourceHelper(ClientResourceHelper): def setup(self): # NOTE: fixup scenario_helper to hanlde ixia self.resource_file_name = \ - find_relative_file(self.scenario_helper.scenario_cfg['ixia_profile'], - self.scenario_helper.scenario_cfg["task_path"]) - makedirs(self.RESULTS_MOUNT) + utils.find_relative_file( + self.scenario_helper.scenario_cfg['ixia_profile'], + self.scenario_helper.scenario_cfg["task_path"]) + utils.makedirs(self.RESULTS_MOUNT) cmd = MOUNT_CMD.format(self.vnfd_helper.mgmt_interface, self) LOG.debug(cmd) @@ -103,7 +104,7 @@ class IxLoadResourceHelper(ClientResourceHelper): call(cmd, shell=True) shutil.rmtree(self.RESULTS_MOUNT, ignore_errors=True) - makedirs(self.RESULTS_MOUNT) + utils.makedirs(self.RESULTS_MOUNT) shutil.copy(self.resource_file_name, self.RESULTS_MOUNT) def make_aggregates(self): diff --git a/yardstick/network_services/vnf_generic/vnf/tg_prox.py b/yardstick/network_services/vnf_generic/vnf/tg_prox.py index 151252ce8..282dd92c5 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_prox.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_prox.py @@ -30,20 +30,6 @@ class ProxTrafficGen(SampleVNFTrafficGen): LUA_PARAMETER_NAME = "gen" WAIT_TIME = 1 - @staticmethod - def _sort_vpci(vnfd): - """ - - :param vnfd: vnfd.yaml - :return: trex_cfg.yaml file - """ - - def key_func(interface): - return interface["virtual-interface"]["vpci"], interface["name"] - - ext_intf = vnfd["vdu"][0]["external-interface"] - return sorted(ext_intf, key=key_func) - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): # don't call superclass, use custom wrapper of ProxApproxVnf self._vnf_wrapper = ProxApproxVnf(name, vnfd, setup_env_helper_type, resource_helper_type) @@ -59,10 +45,6 @@ class ProxTrafficGen(SampleVNFTrafficGen): self._tg_process = None self._traffic_process = None - # used for generating stats - self.vpci_if_name_ascending = self._sort_vpci(vnfd) - self.resource_helper.vpci_if_name_ascending = self._sort_vpci(vnfd) - def terminate(self): self._vnf_wrapper.terminate() super(ProxTrafficGen, self).terminate() diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py index 12510db96..265d0b7a9 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py @@ -19,11 +19,11 @@ import os import logging import sys -from yardstick.common.utils import ErrorClass +from yardstick.common import utils +from yardstick import error from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper -from yardstick.benchmark.scenarios.networking.vnf_generic import find_relative_file LOG = logging.getLogger(__name__) @@ -36,7 +36,7 @@ sys.path.append(IXNET_LIB) try: from IxNet import IxNextgen except ImportError: - IxNextgen = ErrorClass + IxNextgen = error.ErrorClass class IxiaRfc2544Helper(Rfc2544ResourceHelper): @@ -122,8 +122,9 @@ class IxiaResourceHelper(ClientResourceHelper): # we don't know client_file_name until runtime as instantiate client_file_name = \ - find_relative_file(self.scenario_helper.scenario_cfg['ixia_profile'], - self.scenario_helper.scenario_cfg["task_path"]) + utils.find_relative_file( + self.scenario_helper.scenario_cfg['ixia_profile'], + self.scenario_helper.scenario_cfg["task_path"]) self.client.ix_load_config(client_file_name) time.sleep(WAIT_AFTER_CFG_LOAD) diff --git a/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py b/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py index 6c95648ce..61e99855f 100644 --- a/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py @@ -12,10 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import import logging -from yardstick.benchmark.scenarios.networking.vnf_generic import find_relative_file +from yardstick.common import utils from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, DpdkVnfSetupEnvHelper from yardstick.network_services.yang_model import YangModel @@ -60,8 +59,9 @@ class FWApproxVnf(SampleVNF): self.vfw_rules = None def _start_vnf(self): - yang_model_path = find_relative_file(self.scenario_helper.options['rules'], - self.scenario_helper.task_path) + yang_model_path = utils.find_relative_file( + self.scenario_helper.options['rules'], + self.scenario_helper.task_path) yang_model = YangModel(yang_model_path) self.vfw_rules = yang_model.get_rules() super(FWApproxVnf, self)._start_vnf() diff --git a/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py b/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py new file mode 100644 index 000000000..de6fd9329 --- /dev/null +++ b/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py @@ -0,0 +1,61 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import os + +from six.moves import StringIO + +from yardstick.network_services import constants +from yardstick.ssh import AutoConnectSSH + +LOG = logging.getLogger(__name__) + + +class VnfSshHelper(AutoConnectSSH): + + def __init__(self, node, bin_path, wait=None): + self.node = node + kwargs = self.args_from_node(self.node) + if wait: + # if wait is defined here we want to override + kwargs['wait'] = wait + + super(VnfSshHelper, self).__init__(**kwargs) + self.bin_path = bin_path + + @staticmethod + def get_class(): + # must return static class name, anything else refers to the calling class + # i.e. the subclass, not the superclass + return VnfSshHelper + + def copy(self): + # this copy constructor is different from SSH classes, since it uses node + return self.get_class()(self.node, self.bin_path) + + def upload_config_file(self, prefix, content): + cfg_file = os.path.join(constants.REMOTE_TMP, prefix) + LOG.debug(content) + file_obj = StringIO(content) + self.put_file_obj(file_obj, cfg_file) + return cfg_file + + def join_bin_path(self, *args): + return os.path.join(self.bin_path, *args) + + def provision_tool(self, tool_path=None, tool_file=None): + if tool_path is None: + tool_path = self.bin_path + return super(VnfSshHelper, self).provision_tool(tool_path, tool_file) diff --git a/yardstick/orchestrator/heat.py b/yardstick/orchestrator/heat.py index 3c3d28146..d69f86044 100644 --- a/yardstick/orchestrator/heat.py +++ b/yardstick/orchestrator/heat.py @@ -26,21 +26,16 @@ import shade import yardstick.common.openstack_utils as op_utils from yardstick.common import exceptions from yardstick.common import template_format +from yardstick.common import constants as consts log = logging.getLogger(__name__) -HEAT_KEY_UUID_LENGTH = 8 - PROVIDER_SRIOV = "sriov" _DEPLOYED_STACKS = {} -def get_short_key_uuid(uuid): - return str(uuid)[:HEAT_KEY_UUID_LENGTH] - - class HeatStack(object): """Represents a Heat stack (deployed template) """ @@ -50,6 +45,13 @@ class HeatStack(object): self._cloud = shade.openstack_cloud() self._stack = None + def _update_stack_tracking(self): + outputs = self._stack.outputs + self.outputs = {output['output_key']: output['output_value'] for output + in outputs} + if self.uuid: + _DEPLOYED_STACKS[self.uuid] = self._stack + def create(self, template, heat_parameters, wait, timeout): """Creates an OpenStack stack from a template""" with tempfile.NamedTemporaryFile('wb', delete=False) as template_file: @@ -58,11 +60,21 @@ class HeatStack(object): self._stack = self._cloud.create_stack( self.name, template_file=template_file.name, wait=wait, timeout=timeout, **heat_parameters) - outputs = self._stack.outputs - self.outputs = {output['output_key']: output['output_value'] for output - in outputs} - if self.uuid: - _DEPLOYED_STACKS[self.uuid] = self._stack + + self._update_stack_tracking() + + def get(self): + """Retrieves an existing stack from the target cloud + + Returns a bool indicating whether the stack exists in the target cloud + If the stack exists, it will be stored as self._stack + """ + self._stack = self._cloud.get_stack(self.name) + if not self._stack: + return False + + self._update_stack_tracking() + return True @staticmethod def stacks_exist(): @@ -322,21 +334,24 @@ name (i.e. %s). } } - def add_port(self, name, network_name, subnet_name, vnic_type, sec_group_id=None, + def add_port(self, name, network, sec_group_id=None, provider=None, allowed_address_pairs=None): """add to the template a named Neutron Port """ - log.debug("adding Neutron::Port '%s', network:'%s', subnet:'%s', vnic_type:'%s', " - "secgroup:%s", name, network_name, subnet_name, vnic_type, sec_group_id) + net_is_existing = network.net_flags.get(consts.IS_EXISTING) + depends_on = [] if net_is_existing else [network.subnet_stack_name] + fixed_ips = [{'subnet': network.subnet}] if net_is_existing else [ + {'subnet': {'get_resource': network.subnet_stack_name}}] + network_ = network.name if net_is_existing else { + 'get_resource': network.stack_name} self.resources[name] = { 'type': 'OS::Neutron::Port', - 'depends_on': [subnet_name], + 'depends_on': depends_on, 'properties': { 'name': name, - 'binding:vnic_type': vnic_type, - 'fixed_ips': [{'subnet': {'get_resource': subnet_name}}], - 'network_id': {'get_resource': network_name}, - 'replacement_policy': 'AUTO', + 'binding:vnic_type': network.vnic_type, + 'fixed_ips': fixed_ips, + 'network': network_, } } @@ -353,6 +368,8 @@ name (i.e. %s). self.resources[name]['properties'][ 'allowed_address_pairs'] = allowed_address_pairs + log.debug("adding Neutron::Port %s", self.resources[name]) + self._template['outputs'][name] = { 'description': 'Address for interface %s' % name, 'value': {'get_attr': [name, 'fixed_ips', 0, 'ip_address']} @@ -413,7 +430,7 @@ name (i.e. %s). } } - def add_keypair(self, name, key_uuid): + def add_keypair(self, name, key_id): """add to the template a Nova KeyPair""" log.debug("adding Nova::KeyPair '%s'", name) self.resources[name] = { @@ -425,7 +442,7 @@ name (i.e. %s). pkg_resources.resource_string( 'yardstick.resources', 'files/yardstick_key-' + - get_short_key_uuid(key_uuid) + '.pub'), + key_id + '.pub'), 'utf-8') } } diff --git a/yardstick/service/__init__.py b/yardstick/service/__init__.py new file mode 100644 index 000000000..1c3953de6 --- /dev/null +++ b/yardstick/service/__init__.py @@ -0,0 +1,12 @@ +############################################################################## +# Copyright (c) 2016 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 +############################################################################## + + +class Service(object): + pass diff --git a/yardstick/service/environment.py b/yardstick/service/environment.py new file mode 100644 index 000000000..324589f79 --- /dev/null +++ b/yardstick/service/environment.py @@ -0,0 +1,101 @@ +############################################################################## +# Copyright (c) 2016 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 +############################################################################## +import tempfile +import logging +import collections + +from oslo_serialization import jsonutils + +from yardstick.service import Service +from yardstick.common.exceptions import MissingPodInfoError +from yardstick.common.exceptions import UnsupportedPodFormatError +from yardstick.common.ansible_common import AnsibleCommon + +LOG = logging.getLogger(__name__) + + +class Environment(Service): + def __init__(self, pod=None): + super(Environment, self).__init__() + # pod can be a dict or a json format string + self.pod = pod + + def get_sut_info(self): + temdir = tempfile.mkdtemp(prefix='sut') + + nodes = self._load_pod_info() + ansible = AnsibleCommon(nodes=nodes) + ansible.gen_inventory_ini_dict() + sut_info = ansible.get_sut_info(temdir) + + return self._format_sut_info(sut_info) + + def _load_pod_info(self): + if self.pod is None: + raise MissingPodInfoError + + if isinstance(self.pod, collections.Mapping): + try: + return self.pod['nodes'] + except KeyError: + raise UnsupportedPodFormatError + + try: + return jsonutils.loads(self.pod)['nodes'] + except (ValueError, KeyError): + raise UnsupportedPodFormatError + + def _format_sut_info(self, sut_info): + return {k: self._format_node_info(v) for k, v in sut_info.items()} + + def _format_node_info(self, node_info): + info = [] + facts = node_info.get('ansible_facts', {}) + + info.append(['hostname', facts.get('ansible_hostname')]) + + info.append(['product_name', facts.get('ansible_product_name')]) + info.append(['product_version', facts.get('ansible_product_version')]) + + processors = facts.get('ansible_processor', []) + try: + processor_type = '{} {}'.format(processors[0], processors[1]) + except IndexError: + LOG.exception('No Processor in SUT data') + processor_type = None + + info.append(['processor_type', processor_type]) + info.append(['architecture', facts.get('ansible_architecture')]) + info.append(['processor_cores', facts.get('ansible_processor_cores')]) + info.append(['processor_vcpus', facts.get('ansible_processor_vcpus')]) + + memory = facts.get('ansible_memtotal_mb') + memory = round(memory * 1.0 / 1024, 2) if memory else None + info.append(['memory', '{} GB'.format(memory)]) + + devices = facts.get('ansible_devices', {}) + info.extend([self._get_device_info(k, v) for k, v in devices.items()]) + + lsb_description = facts.get('ansible_lsb', {}).get('description') + info.append(['OS', lsb_description]) + + interfaces = facts.get('ansible_interfaces') + info.append(['interfaces', interfaces]) + if isinstance(interfaces, collections.Sequence): + info.extend([self._get_interface_info(facts, i) for i in interfaces]) + info = [i for i in info if i] + + return info + + def _get_interface_info(self, facts, name): + mac = facts.get('ansible_{}'.format(name), {}).get('macaddress') + return [name, mac] if mac else [] + + def _get_device_info(self, name, info): + return ['disk_{}'.format(name), info.get('size')] diff --git a/yardstick/ssh.py b/yardstick/ssh.py index 6ddf327f2..d7adc0d05 100644 --- a/yardstick/ssh.py +++ b/yardstick/ssh.py @@ -78,7 +78,7 @@ from oslo_utils import encodeutils from scp import SCPClient import six -from yardstick.common.utils import try_int +from yardstick.common.utils import try_int, NON_NONE_DEFAULT, make_dict_from_map from yardstick.network_services.utils import provision_tool @@ -102,6 +102,7 @@ class SSH(object): """Represent ssh connection.""" SSH_PORT = paramiko.config.SSH_PORT + DEFAULT_WAIT_TIMEOUT = 120 @staticmethod def gen_keys(key_filename, bit_count=2048): @@ -120,6 +121,18 @@ class SSH(object): # i.e. the subclass, not the superclass return SSH + @classmethod + def get_arg_key_map(cls): + return { + 'user': ('user', NON_NONE_DEFAULT), + 'host': ('ip', NON_NONE_DEFAULT), + 'port': ('ssh_port', cls.SSH_PORT), + 'pkey': ('pkey', None), + 'key_filename': ('key_filename', None), + 'password': ('password', None), + 'name': ('name', None), + } + def __init__(self, user, host, port=None, pkey=None, key_filename=None, password=None, name=None): """Initialize SSH client. @@ -137,6 +150,7 @@ class SSH(object): else: self.log = logging.getLogger(__name__) + self.wait_timeout = self.DEFAULT_WAIT_TIMEOUT self.user = user self.host = host # everybody wants to debug this in the caller, do it here instead @@ -162,16 +176,9 @@ class SSH(object): overrides = {} if defaults is None: defaults = {} + params = ChainMap(overrides, node, defaults) - return { - 'user': params['user'], - 'host': params['ip'], - 'port': params.get('ssh_port', cls.SSH_PORT), - 'pkey': params.get('pkey'), - 'key_filename': params.get('key_filename'), - 'password': params.get('password'), - 'name': params.get('name'), - } + return make_dict_from_map(params, cls.get_arg_key_map()) @classmethod def from_node(cls, node, overrides=None, defaults=None): @@ -186,7 +193,7 @@ class SSH(object): return key_class.from_private_key(key) except paramiko.SSHException as e: errors.append(e) - raise SSHError("Invalid pkey: %s" % (errors)) + raise SSHError("Invalid pkey: %s" % errors) @property def is_connected(self): @@ -287,7 +294,7 @@ class SSH(object): while True: # Block until data can be read/write. - r, w, e = select.select([session], writes, [session], 1) + e = select.select([session], writes, [session], 1)[2] if session.recv_ready(): data = encodeutils.safe_decode(session.recv(4096), 'utf-8') @@ -361,17 +368,20 @@ class SSH(object): stderr.seek(0) return exit_status, stdout.read(), stderr.read() - def wait(self, timeout=120, interval=1): + def wait(self, timeout=None, interval=1): """Wait for the host will be available via ssh.""" - start_time = time.time() + if timeout is None: + timeout = self.wait_timeout + + end_time = time.time() + timeout while True: try: return self.execute("uname") except (socket.error, SSHError) as e: self.log.debug("Ssh is still unavailable: %r", e) time.sleep(interval) - if time.time() > (start_time + timeout): - raise SSHTimeout("Timeout waiting for '%s'", self.host) + if time.time() > end_time: + raise SSHTimeout("Timeout waiting for '%s'" % self.host) def put(self, files, remote_path=b'.', recursive=False): client = self._get_client() @@ -447,24 +457,40 @@ class SSH(object): class AutoConnectSSH(SSH): + @classmethod + def get_arg_key_map(cls): + arg_key_map = super(AutoConnectSSH, cls).get_arg_key_map() + arg_key_map['wait'] = ('wait', True) + return arg_key_map + # always wait or we will get OpenStack SSH errors def __init__(self, user, host, port=None, pkey=None, key_filename=None, password=None, name=None, wait=True): super(AutoConnectSSH, self).__init__(user, host, port, pkey, key_filename, password, name) - self._wait = wait + if wait and wait is not True: + self.wait_timeout = int(wait) def _make_dict(self): data = super(AutoConnectSSH, self)._make_dict() data.update({ - 'wait': self._wait + 'wait': self.wait_timeout }) return data def _connect(self): if not self.is_connected: - self._get_client() - if self._wait: - self.wait() + interval = 1 + timeout = self.wait_timeout + + end_time = time.time() + timeout + while True: + try: + return self._get_client() + except (socket.error, SSHError) as e: + self.log.debug("Ssh is still unavailable: %r", e) + time.sleep(interval) + if time.time() > end_time: + raise SSHTimeout("Timeout waiting for '%s'" % self.host) def drop_connection(self): """ Don't close anything, just force creation of a new client """ diff --git a/yardstick/tests/__init__.py b/yardstick/tests/__init__.py index e69de29bb..56e3106b8 100644 --- a/yardstick/tests/__init__.py +++ b/yardstick/tests/__init__.py @@ -0,0 +1,75 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import mock + + +STL_MOCKS = { + 'trex_stl_lib': mock.MagicMock(), + 'trex_stl_lib.base64': mock.MagicMock(), + 'trex_stl_lib.binascii': mock.MagicMock(), + 'trex_stl_lib.collections': mock.MagicMock(), + 'trex_stl_lib.copy': mock.MagicMock(), + 'trex_stl_lib.datetime': mock.MagicMock(), + 'trex_stl_lib.functools': mock.MagicMock(), + 'trex_stl_lib.imp': mock.MagicMock(), + 'trex_stl_lib.inspect': mock.MagicMock(), + 'trex_stl_lib.json': mock.MagicMock(), + 'trex_stl_lib.linecache': mock.MagicMock(), + 'trex_stl_lib.math': mock.MagicMock(), + 'trex_stl_lib.os': mock.MagicMock(), + 'trex_stl_lib.platform': mock.MagicMock(), + 'trex_stl_lib.pprint': mock.MagicMock(), + 'trex_stl_lib.random': mock.MagicMock(), + 'trex_stl_lib.re': mock.MagicMock(), + 'trex_stl_lib.scapy': mock.MagicMock(), + 'trex_stl_lib.socket': mock.MagicMock(), + 'trex_stl_lib.string': mock.MagicMock(), + 'trex_stl_lib.struct': mock.MagicMock(), + 'trex_stl_lib.sys': mock.MagicMock(), + 'trex_stl_lib.threading': mock.MagicMock(), + 'trex_stl_lib.time': mock.MagicMock(), + 'trex_stl_lib.traceback': mock.MagicMock(), + 'trex_stl_lib.trex_stl_async_client': mock.MagicMock(), + 'trex_stl_lib.trex_stl_client': mock.MagicMock(), + 'trex_stl_lib.trex_stl_exceptions': mock.MagicMock(), + 'trex_stl_lib.trex_stl_ext': mock.MagicMock(), + 'trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(), + 'trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(), + 'trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(), + 'trex_stl_lib.trex_stl_port': mock.MagicMock(), + 'trex_stl_lib.trex_stl_stats': mock.MagicMock(), + 'trex_stl_lib.trex_stl_streams': mock.MagicMock(), + 'trex_stl_lib.trex_stl_types': mock.MagicMock(), + 'trex_stl_lib.types': mock.MagicMock(), + 'trex_stl_lib.utils': mock.MagicMock(), + 'trex_stl_lib.utils.argparse': mock.MagicMock(), + 'trex_stl_lib.utils.collections': mock.MagicMock(), + 'trex_stl_lib.utils.common': mock.MagicMock(), + 'trex_stl_lib.utils.json': mock.MagicMock(), + 'trex_stl_lib.utils.os': mock.MagicMock(), + 'trex_stl_lib.utils.parsing_opts': mock.MagicMock(), + 'trex_stl_lib.utils.pwd': mock.MagicMock(), + 'trex_stl_lib.utils.random': mock.MagicMock(), + 'trex_stl_lib.utils.re': mock.MagicMock(), + 'trex_stl_lib.utils.string': mock.MagicMock(), + 'trex_stl_lib.utils.sys': mock.MagicMock(), + 'trex_stl_lib.utils.text_opts': mock.MagicMock(), + 'trex_stl_lib.utils.text_tables': mock.MagicMock(), + 'trex_stl_lib.utils.texttable': mock.MagicMock(), + 'trex_stl_lib.warnings': mock.MagicMock(), + 'trex_stl_lib.yaml': mock.MagicMock(), + 'trex_stl_lib.zlib': mock.MagicMock(), + 'trex_stl_lib.zmq': mock.MagicMock(), +} diff --git a/yardstick/tests/functional/base.py b/yardstick/tests/functional/base.py new file mode 100644 index 000000000..51be013a1 --- /dev/null +++ b/yardstick/tests/functional/base.py @@ -0,0 +1,46 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import abc +import six + +from oslo_config import cfg +from oslotest import base + + +CONF = cfg.CONF + + +@six.add_metaclass(abc.ABCMeta) +class BaseFunctionalTestCase(base.BaseTestCase): + """Base class for functional tests.""" + + def setUp(self): + super(BaseFunctionalTestCase, self).setUp() + + def config(self, **kw): + """Override some configuration values. + + The keyword arguments are the names of configuration options to + override and their values. + + If a group argument is supplied, the overrides are applied to + the specified configuration option group. + + All overrides are automatically cleared at the end of the current + test by the fixtures cleanup process. + """ + group = kw.pop('group', None) + for k, v in kw.items(): + CONF.set_override(k, v, group) diff --git a/yardstick/tests/functional/benchmark/__init__.py b/yardstick/tests/functional/benchmark/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/functional/benchmark/__init__.py diff --git a/yardstick/tests/functional/benchmark/scenarios/__init__.py b/yardstick/tests/functional/benchmark/scenarios/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/functional/benchmark/scenarios/__init__.py diff --git a/yardstick/tests/functional/benchmark/scenarios/networking/__init__.py b/yardstick/tests/functional/benchmark/scenarios/networking/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/functional/benchmark/scenarios/networking/__init__.py diff --git a/yardstick/tests/functional/benchmark/scenarios/networking/test_vnf_generic.py b/yardstick/tests/functional/benchmark/scenarios/networking/test_vnf_generic.py new file mode 100644 index 000000000..38f1a978d --- /dev/null +++ b/yardstick/tests/functional/benchmark/scenarios/networking/test_vnf_generic.py @@ -0,0 +1,195 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import copy +import sys + +import mock +import unittest + +from yardstick import tests as y_tests +from yardstick.common import utils + + +with mock.patch.dict(sys.modules, y_tests.STL_MOCKS): + from yardstick.benchmark.scenarios.networking import vnf_generic + + +TRAFFIC_PROFILE_1 = """ +schema: nsb:traffic_profile:0.1 +name: rfc2544 +description: Traffic profile to run RFC2544 latency +traffic_profile: + traffic_type : RFC2544Profile + frame_rate : 100 +uplink_0: + ipv4: + id: 1 + outer_l2: + framesize: + 64B: "{{get(imix, 'imix.uplink.64B', '0') }}" + 128B: "{{get(imix, 'imix.uplink.128B', '0') }}" +""" + +TRAFFIC_PROFILE_2 = """ +{% set vports = get(extra_args, 'vports', 1) %} +traffic_profile: + traffic_type : RFC2544Profile +{% for vport in range(vports|int) %} +uplink_{{vport}}: + ipv4: 192.168.0.{{vport}} +{% endfor %} +""" + +TOPOLOGY_PROFILE = """ +{% set vports = get(extra_args, 'vports', 2) %} +nsd:nsd-catalog: + nsd: + - id: 3tg-topology + vld: +{% for vport in range(0,vports,2|int) %} + - id: uplink_{{loop.index0}} + name: tg__0 to vnf__0 link {{vport + 1}} + vnfd-connection-point-ref: + - vnfd-connection-point-ref: xe{{vport}} + - id: downlink_{{loop.index0}} + name: vnf__0 to tg__0 link {{vport + 2}} + vnfd-connection-point-ref: + - vnfd-connection-point-ref: xe{{vport+1}} +{% endfor %} +""" + +class VnfGenericTestCase(unittest.TestCase): + + def setUp(self): + scenario_cfg = {'topology': 'fake_topology', + 'task_path': 'fake_path', + 'traffic_profile': 'fake_fprofile_path'} + context_cfg = {} + topology_yaml = {'nsd:nsd-catalog': {'nsd': [mock.Mock()]}} + + with mock.patch.object(utils, 'open_relative_file') as mock_open_path: + mock_open_path.side_effect = mock.mock_open(read_data=str(topology_yaml)) + self.ns_testcase = vnf_generic.NetworkServiceTestCase(scenario_cfg, + context_cfg) + self.ns_testcase._get_traffic_profile = mock.Mock() + self.ns_testcase._get_topology = mock.Mock() + + def test__fill_traffic_profile_no_args(self): + traffic_profile = copy.deepcopy(TRAFFIC_PROFILE_1) + self.ns_testcase._get_traffic_profile.return_value = traffic_profile + + self.ns_testcase._fill_traffic_profile() + config = self.ns_testcase.traffic_profile.params + self.assertEqual('nsb:traffic_profile:0.1', config['schema']) + self.assertEqual('rfc2544', config['name']) + self.assertEqual('Traffic profile to run RFC2544 latency', + config['description']) + t_profile = {'traffic_type': 'RFC2544Profile', + 'frame_rate': 100} + self.assertEqual(t_profile, config['traffic_profile']) + uplink_0 = { + 'ipv4': {'id': 1, + 'outer_l2': {'framesize': {'128B': '0', '64B': '0'}} + } + } + self.assertEqual(uplink_0, config['uplink_0']) + + def test__fill_traffic_profile_with_args(self): + traffic_profile = copy.deepcopy(TRAFFIC_PROFILE_2) + self.ns_testcase._get_traffic_profile.return_value = traffic_profile + self.ns_testcase.scenario_cfg['extra_args'] = {'vports': 3} + + self.ns_testcase._fill_traffic_profile() + config = self.ns_testcase.traffic_profile.params + self.assertEqual({'ipv4': '192.168.0.0'}, config['uplink_0']) + self.assertEqual({'ipv4': '192.168.0.1'}, config['uplink_1']) + self.assertEqual({'ipv4': '192.168.0.2'}, config['uplink_2']) + self.assertNotIn('uplink_3', config) + + def test__fill_traffic_profile_incorrect_args(self): + traffic_profile = copy.deepcopy(TRAFFIC_PROFILE_2) + self.ns_testcase._get_traffic_profile.return_value = traffic_profile + self.ns_testcase.scenario_cfg['extra_args'] = {'incorrect_vports': 3} + + self.ns_testcase._fill_traffic_profile() + config = self.ns_testcase.traffic_profile.params + self.assertEqual({'ipv4': '192.168.0.0'}, config['uplink_0']) + self.assertNotIn('uplink_1', config) + + def test__render_topology_with_args(self): + topology_profile = copy.deepcopy(TOPOLOGY_PROFILE) + self.ns_testcase._get_topology.return_value = topology_profile + self.ns_testcase.scenario_cfg['extra_args'] = {'vports': 6} + + self.ns_testcase._render_topology() + topology = self.ns_testcase.topology + self.assertEqual("3tg-topology", topology['id']) + vld = self.ns_testcase.topology['vld'] + self.assertEqual(len(vld), 6) + for index, vport in enumerate(range(0, 6, 2)): + self.assertEqual('uplink_{}'.format(index), vld[vport]['id']) + self.assertEqual('tg__0 to vnf__0 link {}'.format(vport + 1), vld[vport]['name']) + self.assertEqual('xe{}'.format(vport), + vld[vport]['vnfd-connection-point-ref'][0] + ['vnfd-connection-point-ref']) + + self.assertEqual('downlink_{}'.format(index), vld[vport + 1]['id']) + self.assertEqual('vnf__0 to tg__0 link {}'.format(vport + 2), vld[vport + 1]['name']) + self.assertEqual('xe{}'.format(vport + 1), + vld[vport + 1]['vnfd-connection-point-ref'][0] + ['vnfd-connection-point-ref']) + + def test__render_topology_incorrect_args(self): + topology_profile = copy.deepcopy(TOPOLOGY_PROFILE) + self.ns_testcase._get_topology.return_value = topology_profile + self.ns_testcase.scenario_cfg['extra_args'] = {'fake_vports': 5} + + self.ns_testcase._render_topology() + + topology = self.ns_testcase.topology + self.assertEqual("3tg-topology", topology['id']) + vld = self.ns_testcase.topology['vld'] + self.assertEqual(len(vld), 2) + + self.assertEqual('uplink_0', vld[0]['id']) + self.assertEqual('tg__0 to vnf__0 link 1', vld[0]['name']) + self.assertEqual('xe0', + vld[0]['vnfd-connection-point-ref'][0]['vnfd-connection-point-ref']) + + self.assertEqual('downlink_0', vld[1]['id']) + self.assertEqual('vnf__0 to tg__0 link 2', vld[1]['name']) + self.assertEqual('xe1', + vld[1]['vnfd-connection-point-ref'][0]['vnfd-connection-point-ref']) + + def test__render_topology_no_args(self): + topology_profile = copy.deepcopy(TOPOLOGY_PROFILE) + self.ns_testcase._get_topology.return_value = topology_profile + + self.ns_testcase._render_topology() + + topology = self.ns_testcase.topology + self.assertEqual("3tg-topology", topology['id']) + vld = self.ns_testcase.topology['vld'] + self.assertEqual(len(vld), 2) + + self.assertEqual('uplink_0', vld[0]['id']) + self.assertEqual('tg__0 to vnf__0 link 1', vld[0]['name']) + self.assertEqual('xe0', + vld[0]['vnfd-connection-point-ref'][0]['vnfd-connection-point-ref']) + + self.assertEqual('downlink_0', vld[1]['id']) + self.assertEqual('vnf__0 to tg__0 link 2', vld[1]['name']) + self.assertEqual('xe1', + vld[1]['vnfd-connection-point-ref'][0]['vnfd-connection-point-ref']) diff --git a/yardstick/tests/functional/common/fake_directory_package/README.md b/yardstick/tests/functional/common/fake_directory_package/README.md new file mode 100644 index 000000000..689e47039 --- /dev/null +++ b/yardstick/tests/functional/common/fake_directory_package/README.md @@ -0,0 +1,2 @@ +# yardstick_new_plugin +Yardstick plugin diff --git a/yardstick/tests/functional/common/fake_directory_package/setup.py b/yardstick/tests/functional/common/fake_directory_package/setup.py new file mode 100644 index 000000000..cf938ef4f --- /dev/null +++ b/yardstick/tests/functional/common/fake_directory_package/setup.py @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from setuptools import setup, find_packages + +setup( + name='yardstick_new_plugin_2', + version='1.0.0', + packages=find_packages(), + include_package_data=True, + url='https://www.opnfv.org', + entry_points={ + 'yardstick.scenarios': [ + 'Dummy2 = yardstick_new_plugin.benchmark.scenarios.dummy2.dummy2:' + 'Dummy2', + ] + }, +) diff --git a/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/__init__.py b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/__init__.py diff --git a/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/__init__.py b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/__init__.py diff --git a/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/scenarios/__init__.py b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/scenarios/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/scenarios/__init__.py diff --git a/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/scenarios/dummy2/__init__.py b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/scenarios/dummy2/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/scenarios/dummy2/__init__.py diff --git a/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/scenarios/dummy2/dummy2.py b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/scenarios/dummy2/dummy2.py new file mode 100644 index 000000000..a2211ec51 --- /dev/null +++ b/yardstick/tests/functional/common/fake_directory_package/yardstick_new_plugin_2/benchmark/scenarios/dummy2/dummy2.py @@ -0,0 +1,40 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from yardstick.benchmark.scenarios import base + + +LOG = logging.getLogger(__name__) + + +class Dummy2(base.Scenario): + """Execute Dummy (v2!) echo""" + __scenario_type__ = "Dummy2" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.setup_done = False + + def setup(self): + self.setup_done = True + + def run(self, result): + if not self.setup_done: + self.setup() + + result["hello"] = "yardstick" + LOG.info("Dummy (v2!) echo hello yardstick!") diff --git a/yardstick/tests/functional/common/fake_pip_package/yardstick_new_plugin-1.0.0.tar.gz b/yardstick/tests/functional/common/fake_pip_package/yardstick_new_plugin-1.0.0.tar.gz Binary files differnew file mode 100644 index 000000000..e5379a78a --- /dev/null +++ b/yardstick/tests/functional/common/fake_pip_package/yardstick_new_plugin-1.0.0.tar.gz diff --git a/yardstick/tests/functional/common/test_packages.py b/yardstick/tests/functional/common/test_packages.py new file mode 100644 index 000000000..5dead4e55 --- /dev/null +++ b/yardstick/tests/functional/common/test_packages.py @@ -0,0 +1,94 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from os import path +import re + +from yardstick.common import packages +from yardstick.common import utils +from yardstick.tests.functional import base + + +class PipPackagesTestCase(base.BaseFunctionalTestCase): + + TMP_FOLDER = '/tmp/pip_packages/' + PYTHONPATH = 'PYTHONPATH=%s' % TMP_FOLDER + + def setUp(self): + super(PipPackagesTestCase, self).setUp() + privsep_helper = os.path.join( + os.getenv('VIRTUAL_ENV'), 'bin', 'privsep-helper') + self.config( + helper_command=' '.join(['sudo', '-EH', privsep_helper]), + group='yardstick_privileged') + self.addCleanup(self._cleanup) + + def _cleanup(self): + utils.execute_command('sudo rm -rf %s' % self.TMP_FOLDER) + + def _remove_package(self, package): + os.system('%s pip uninstall %s -y' % (self.PYTHONPATH, package)) + + def _list_packages(self): + pip_list_regex = re.compile( + r"(?P<name>[\w\.-]+) \((?P<version>[\w\d_\.\-]+),*.*\)") + pkg_dict = {} + pkgs = utils.execute_command('pip list', + env={'PYTHONPATH': self.TMP_FOLDER}) + for line in pkgs: + match = pip_list_regex.match(line) + if match and match.group('name'): + pkg_dict[match.group('name')] = match.group('version') + return pkg_dict + + def test_install_from_folder(self): + dirname = path.dirname(__file__) + package_dir = dirname + '/fake_directory_package' + package_name = 'yardstick-new-plugin-2' + self.addCleanup(self._remove_package, package_name) + self._remove_package(package_name) + self.assertFalse(package_name in self._list_packages()) + + self.assertEqual(0, packages.pip_install(package_dir, self.TMP_FOLDER)) + self.assertTrue(package_name in self._list_packages()) + + def test_install_from_pip_package(self): + dirname = path.dirname(__file__) + package_path = (dirname + + '/fake_pip_package/yardstick_new_plugin-1.0.0.tar.gz') + package_name = 'yardstick-new-plugin' + self.addCleanup(self._remove_package, package_name) + self._remove_package(package_name) + self.assertFalse(package_name in self._list_packages()) + + self.assertEqual(0, packages.pip_install(package_path, self.TMP_FOLDER)) + self.assertTrue(package_name in self._list_packages()) + + # NOTE(ralonsoh): an stable test plugin project is needed in OPNFV git + # server to execute this test. + # def test_install_from_url(self): + + def test_pip_freeze(self): + # NOTE (ralonsoh): from requirements.txt file. The best way to test + # this function is to parse requirements.txt and test-requirements.txt + # and check all packages. + pkgs_ref = {'Babel': '2.3.4', + 'SQLAlchemy': '1.1.12', + 'influxdb': '4.1.1', + 'netifaces': '0.10.6', + 'unicodecsv': '0.14.1'} + pkgs = packages.pip_list() + for name, version in (pkgs_ref.items()): + self.assertEqual(version, pkgs[name]) diff --git a/yardstick/tests/unit/__init__.py b/yardstick/tests/unit/__init__.py index a468b272b..c05f91c81 100644 --- a/yardstick/tests/unit/__init__.py +++ b/yardstick/tests/unit/__init__.py @@ -12,65 +12,12 @@ # See the License for the specific language governing permissions and
# limitations under the License.
-from __future__ import absolute_import
+import sys
+
import mock
+from yardstick import tests
+
-STL_MOCKS = {
- 'trex_stl_lib': mock.MagicMock(),
- 'trex_stl_lib.base64': mock.MagicMock(),
- 'trex_stl_lib.binascii': mock.MagicMock(),
- 'trex_stl_lib.collections': mock.MagicMock(),
- 'trex_stl_lib.copy': mock.MagicMock(),
- 'trex_stl_lib.datetime': mock.MagicMock(),
- 'trex_stl_lib.functools': mock.MagicMock(),
- 'trex_stl_lib.imp': mock.MagicMock(),
- 'trex_stl_lib.inspect': mock.MagicMock(),
- 'trex_stl_lib.json': mock.MagicMock(),
- 'trex_stl_lib.linecache': mock.MagicMock(),
- 'trex_stl_lib.math': mock.MagicMock(),
- 'trex_stl_lib.os': mock.MagicMock(),
- 'trex_stl_lib.platform': mock.MagicMock(),
- 'trex_stl_lib.pprint': mock.MagicMock(),
- 'trex_stl_lib.random': mock.MagicMock(),
- 'trex_stl_lib.re': mock.MagicMock(),
- 'trex_stl_lib.scapy': mock.MagicMock(),
- 'trex_stl_lib.socket': mock.MagicMock(),
- 'trex_stl_lib.string': mock.MagicMock(),
- 'trex_stl_lib.struct': mock.MagicMock(),
- 'trex_stl_lib.sys': mock.MagicMock(),
- 'trex_stl_lib.threading': mock.MagicMock(),
- 'trex_stl_lib.time': mock.MagicMock(),
- 'trex_stl_lib.traceback': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_async_client': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_client': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_exceptions': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_ext': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_port': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_stats': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_streams': mock.MagicMock(),
- 'trex_stl_lib.trex_stl_types': mock.MagicMock(),
- 'trex_stl_lib.types': mock.MagicMock(),
- 'trex_stl_lib.utils': mock.MagicMock(),
- 'trex_stl_lib.utils.argparse': mock.MagicMock(),
- 'trex_stl_lib.utils.collections': mock.MagicMock(),
- 'trex_stl_lib.utils.common': mock.MagicMock(),
- 'trex_stl_lib.utils.json': mock.MagicMock(),
- 'trex_stl_lib.utils.os': mock.MagicMock(),
- 'trex_stl_lib.utils.parsing_opts': mock.MagicMock(),
- 'trex_stl_lib.utils.pwd': mock.MagicMock(),
- 'trex_stl_lib.utils.random': mock.MagicMock(),
- 'trex_stl_lib.utils.re': mock.MagicMock(),
- 'trex_stl_lib.utils.string': mock.MagicMock(),
- 'trex_stl_lib.utils.sys': mock.MagicMock(),
- 'trex_stl_lib.utils.text_opts': mock.MagicMock(),
- 'trex_stl_lib.utils.text_tables': mock.MagicMock(),
- 'trex_stl_lib.utils.texttable': mock.MagicMock(),
- 'trex_stl_lib.warnings': mock.MagicMock(),
- 'trex_stl_lib.yaml': mock.MagicMock(),
- 'trex_stl_lib.zlib': mock.MagicMock(),
- 'trex_stl_lib.zmq': mock.MagicMock(),
-}
+mock_stl = mock.patch.dict(sys.modules, tests.STL_MOCKS)
+mock_stl.start()
diff --git a/yardstick/tests/unit/apiserver/resources/test_env_action.py b/yardstick/tests/unit/apiserver/resources/test_env_action.py index cf646a29c..657841669 100644 --- a/yardstick/tests/unit/apiserver/resources/test_env_action.py +++ b/yardstick/tests/unit/apiserver/resources/test_env_action.py @@ -33,11 +33,3 @@ class EnvTestCase(APITestCase): time.sleep(0) self.assertIn(u'status', resp) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/apiserver/utils/test_influx.py b/yardstick/tests/unit/apiserver/utils/test_influx.py index 883608bb2..dce6c1cec 100644 --- a/yardstick/tests/unit/apiserver/utils/test_influx.py +++ b/yardstick/tests/unit/apiserver/utils/test_influx.py @@ -50,11 +50,3 @@ class QueryTestCase(unittest.TestCase): influx.query(sql) except Exception as e: # pylint: disable=broad-except self.assertIsInstance(e, RuntimeError) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/base.py b/yardstick/tests/unit/base.py new file mode 100644 index 000000000..b943efc2b --- /dev/null +++ b/yardstick/tests/unit/base.py @@ -0,0 +1,23 @@ +# Copyright 2018 Intel Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import abc + +import six +import unittest + + +@six.add_metaclass(abc.ABCMeta) +class BaseUnitTestCase(unittest.TestCase): + """Base class for unit tests""" diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py index 02a85525a..0223fd3ff 100644 --- a/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py +++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py @@ -26,14 +26,6 @@ class OvsDpdkContextTestCase(unittest.TestCase): NODES_ovs_dpdk_SAMPLE = "nodes_ovs_dpdk_sample.yaml" NODES_DUPLICATE_SAMPLE = "nodes_duplicate_sample.yaml" - ATTRS = { - 'name': 'StandaloneOvsDpdk', - 'file': 'pod', - 'flavor': {}, - 'servers': {}, - 'networks': {}, - } - NETWORKS = { 'mgmt': {'cidr': '152.16.100.10/24'}, 'private_0': { @@ -55,7 +47,17 @@ class OvsDpdkContextTestCase(unittest.TestCase): } def setUp(self): + self.attrs = { + 'name': 'foo', + 'task_id': '1234567890', + 'file': self._get_file_abspath(self.NODES_ovs_dpdk_SAMPLE) + } self.ovs_dpdk = ovs_dpdk.OvsDpdkContext() + self.addCleanup(self._remove_contexts) + + def _remove_contexts(self): + if self.ovs_dpdk in self.ovs_dpdk.list: + self.ovs_dpdk._delete_context() @mock.patch('yardstick.benchmark.contexts.standalone.model.Server') @mock.patch('yardstick.benchmark.contexts.standalone.model.StandaloneContextHelper') @@ -66,9 +68,18 @@ class OvsDpdkContextTestCase(unittest.TestCase): self.assertTrue(self.ovs_dpdk.first_run) def test_init(self): + ATTRS = { + 'name': 'StandaloneOvsDpdk', + 'task_id': '1234567890', + 'file': 'pod', + 'flavor': {}, + 'servers': {}, + 'networks': {}, + } + self.ovs_dpdk.helper.parse_pod_file = mock.Mock( return_value=[{}, {}, {}]) - self.assertIsNone(self.ovs_dpdk.init(self.ATTRS)) + self.assertIsNone(self.ovs_dpdk.init(ATTRS)) def test_setup_ovs(self): with mock.patch("yardstick.ssh.SSH") as ssh: @@ -186,12 +197,7 @@ class OvsDpdkContextTestCase(unittest.TestCase): def test__get_server_with_dic_attr_name(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_ovs_dpdk_SAMPLE) - } - - self.ovs_dpdk.init(attrs) + self.ovs_dpdk.init(self.attrs) attr_name = {'name': 'foo.bar'} result = self.ovs_dpdk._get_server(attr_name) @@ -200,14 +206,9 @@ class OvsDpdkContextTestCase(unittest.TestCase): def test__get_server_not_found(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_ovs_dpdk_SAMPLE) - } - self.ovs_dpdk.helper.parse_pod_file = mock.Mock( return_value=[{}, {}, {}]) - self.ovs_dpdk.init(attrs) + self.ovs_dpdk.init(self.attrs) attr_name = 'bar.foo' result = self.ovs_dpdk._get_server(attr_name) @@ -216,12 +217,7 @@ class OvsDpdkContextTestCase(unittest.TestCase): def test__get_server_mismatch(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_ovs_dpdk_SAMPLE) - } - - self.ovs_dpdk.init(attrs) + self.ovs_dpdk.init(self.attrs) attr_name = 'bar.foo1' result = self.ovs_dpdk._get_server(attr_name) @@ -230,31 +226,23 @@ class OvsDpdkContextTestCase(unittest.TestCase): def test__get_server_duplicate(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_DUPLICATE_SAMPLE) - } + self.attrs['file'] = self._get_file_abspath(self.NODES_DUPLICATE_SAMPLE) - self.ovs_dpdk.init(attrs) + self.ovs_dpdk.init(self.attrs) - attr_name = 'node1.foo' + attr_name = 'node1.foo-12345678' with self.assertRaises(ValueError): self.ovs_dpdk._get_server(attr_name) def test__get_server_found(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_ovs_dpdk_SAMPLE) - } - - self.ovs_dpdk.init(attrs) + self.ovs_dpdk.init(self.attrs) - attr_name = 'node1.foo' + attr_name = 'node1.foo-12345678' result = self.ovs_dpdk._get_server(attr_name) self.assertEqual(result['ip'], '10.229.47.137') - self.assertEqual(result['name'], 'node1.foo') + self.assertEqual(result['name'], 'node1.foo-12345678') self.assertEqual(result['user'], 'root') self.assertEqual(result['key_filename'], '/root/.yardstick_key') diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py index f323fcd3c..f0953ef55 100644 --- a/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py +++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py @@ -29,6 +29,7 @@ class SriovContextTestCase(unittest.TestCase): ATTRS = { 'name': 'StandaloneSriov', + 'task_id': '1234567890', 'file': 'pod', 'flavor': {}, 'servers': {}, @@ -56,7 +57,17 @@ class SriovContextTestCase(unittest.TestCase): } def setUp(self): + self.attrs = { + 'name': 'foo', + 'task_id': '1234567890', + 'file': self._get_file_abspath(self.NODES_SRIOV_SAMPLE) + } self.sriov = sriov.SriovContext() + self.addCleanup(self._remove_contexts) + + def _remove_contexts(self): + if self.sriov in self.sriov.list: + self.sriov._delete_context() @mock.patch('yardstick.benchmark.contexts.standalone.sriov.Libvirt') @mock.patch('yardstick.benchmark.contexts.standalone.model.StandaloneContextHelper') @@ -105,12 +116,7 @@ class SriovContextTestCase(unittest.TestCase): def test__get_server_with_dic_attr_name(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SRIOV_SAMPLE) - } - - self.sriov.init(attrs) + self.sriov.init(self.attrs) attr_name = {'name': 'foo.bar'} result = self.sriov._get_server(attr_name) @@ -119,13 +125,8 @@ class SriovContextTestCase(unittest.TestCase): def test__get_server_not_found(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SRIOV_SAMPLE) - } - self.sriov.helper.parse_pod_file = mock.Mock(return_value=[{}, {}, {}]) - self.sriov.init(attrs) + self.sriov.init(self.attrs) attr_name = 'bar.foo' result = self.sriov._get_server(attr_name) @@ -134,12 +135,7 @@ class SriovContextTestCase(unittest.TestCase): def test__get_server_mismatch(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SRIOV_SAMPLE) - } - - self.sriov.init(attrs) + self.sriov.init(self.attrs) attr_name = 'bar.foo1' result = self.sriov._get_server(attr_name) @@ -148,25 +144,29 @@ class SriovContextTestCase(unittest.TestCase): def test__get_server_duplicate(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_DUPLICATE_SAMPLE) - } + self.attrs['file'] = self._get_file_abspath(self.NODES_DUPLICATE_SAMPLE) - self.sriov.init(attrs) + self.sriov.init(self.attrs) - attr_name = 'node1.foo' + attr_name = 'node1.foo-12345678' with self.assertRaises(ValueError): self.sriov._get_server(attr_name) def test__get_server_found(self): - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SRIOV_SAMPLE) - } + self.sriov.init(self.attrs) + + attr_name = 'node1.foo-12345678' + result = self.sriov._get_server(attr_name) + + self.assertEqual(result['ip'], '10.229.47.137') + self.assertEqual(result['name'], 'node1.foo-12345678') + self.assertEqual(result['user'], 'root') + self.assertEqual(result['key_filename'], '/root/.yardstick_key') - self.sriov.init(attrs) + def test__get_server_no_task_id(self): + self.attrs['flags'] = {'no_setup': True} + self.sriov.init(self.attrs) attr_name = 'node1.foo' result = self.sriov._get_server(attr_name) diff --git a/yardstick/tests/unit/benchmark/contexts/test_base.py b/yardstick/tests/unit/benchmark/contexts/test_base.py new file mode 100644 index 000000000..153c6a527 --- /dev/null +++ b/yardstick/tests/unit/benchmark/contexts/test_base.py @@ -0,0 +1,43 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +from yardstick.benchmark.contexts import base + + +class FlagsTestCase(unittest.TestCase): + + def setUp(self): + self.flags = base.Flags() + + def test___init__(self): + self.assertFalse(self.flags.no_setup) + self.assertFalse(self.flags.no_teardown) + + def test___init__with_flags(self): + flags = base.Flags(no_setup=True) + self.assertTrue(flags.no_setup) + self.assertFalse(flags.no_teardown) + + def test_parse(self): + self.flags.parse(no_setup=True, no_teardown="False") + + self.assertTrue(self.flags.no_setup) + self.assertEqual(self.flags.no_teardown, "False") + + def test_parse_forbidden_flags(self): + self.flags.parse(foo=42) + with self.assertRaises(AttributeError): + _ = self.flags.foo diff --git a/yardstick/tests/unit/benchmark/contexts/test_dummy.py b/yardstick/tests/unit/benchmark/contexts/test_dummy.py index 1a54035df..e393001a1 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_dummy.py +++ b/yardstick/tests/unit/benchmark/contexts/test_dummy.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # @@ -9,9 +7,6 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -# Unittest for yardstick.benchmark.contexts.dummy - -from __future__ import absolute_import import unittest from yardstick.benchmark.contexts import dummy @@ -20,10 +15,55 @@ from yardstick.benchmark.contexts import dummy class DummyContextTestCase(unittest.TestCase): def setUp(self): + self.attrs = { + 'name': 'foo', + 'task_id': '1234567890', + } self.test_context = dummy.DummyContext() + self.addCleanup(self.test_context._delete_context) + + def test___init__(self): + self.assertFalse(self.test_context._flags.no_setup) + self.assertFalse(self.test_context._flags.no_teardown) + self.assertIsNone(self.test_context._name) + self.assertIsNone(self.test_context._task_id) + + def test_init(self): + self.test_context.init(self.attrs) + self.assertEqual(self.test_context._name, 'foo') + self.assertEqual(self.test_context._task_id, '1234567890') + self.assertFalse(self.test_context._flags.no_setup) + self.assertFalse(self.test_context._flags.no_teardown) + + self.assertEqual(self.test_context.name, 'foo-12345678') + self.assertEqual(self.test_context.assigned_name, 'foo') + + def test_init_flags_no_setup(self): + self.attrs['flags'] = {'no_setup': True, 'no_teardown': False} + + self.test_context.init(self.attrs) + + self.assertEqual(self.test_context._name, 'foo') + self.assertEqual(self.test_context._task_id, '1234567890') + self.assertTrue(self.test_context._flags.no_setup) + self.assertFalse(self.test_context._flags.no_teardown) + + self.assertEqual(self.test_context.name, 'foo') + self.assertEqual(self.test_context.assigned_name, 'foo') + + def test_init_flags_no_teardown(self): + self.attrs['flags'] = {'no_setup': False, 'no_teardown': True} + + self.test_context.init(self.attrs) + + self.assertFalse(self.test_context._flags.no_setup) + self.assertTrue(self.test_context._flags.no_teardown) + + self.assertEqual(self.test_context.name, 'foo') + self.assertEqual(self.test_context.assigned_name, 'foo') def test__get_server(self): - self.test_context.init(None) + self.test_context.init(self.attrs) self.test_context.deploy() result = self.test_context._get_server(None) diff --git a/yardstick/tests/unit/benchmark/contexts/test_heat.py b/yardstick/tests/unit/benchmark/contexts/test_heat.py index 4348bb052..625f97bf4 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_heat.py +++ b/yardstick/tests/unit/benchmark/contexts/test_heat.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Ericsson AB and others. # @@ -13,13 +11,16 @@ from collections import OrderedDict from itertools import count import logging import os -import uuid import mock import unittest +from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts import heat from yardstick.benchmark.contexts import model +from yardstick.common import constants as consts +from yardstick.common import exceptions as y_exc +from yardstick import ssh LOG = logging.getLogger(__name__) @@ -33,10 +34,18 @@ class HeatContextTestCase(unittest.TestCase): def setUp(self): self.test_context = heat.HeatContext() + self.addCleanup(self._remove_contexts) self.mock_context = mock.Mock(spec=heat.HeatContext()) + def _remove_contexts(self): + if self.test_context in self.test_context.list: + self.test_context._delete_context() + def test___init__(self): - self.assertIsNone(self.test_context.name) + self.assertIsNone(self.test_context._name) + self.assertIsNone(self.test_context._task_id) + self.assertFalse(self.test_context._flags.no_setup) + self.assertFalse(self.test_context._flags.no_teardown) self.assertIsNone(self.test_context.stack) self.assertEqual(self.test_context.networks, OrderedDict()) self.assertEqual(self.test_context.servers, []) @@ -50,8 +59,7 @@ class HeatContextTestCase(unittest.TestCase): self.assertIsNone(self.test_context._user) self.assertIsNone(self.test_context.template_file) self.assertIsNone(self.test_context.heat_parameters) - self.assertIsNotNone(self.test_context.key_uuid) - self.assertIsNotNone(self.test_context.key_filename) + self.assertIsNone(self.test_context.key_filename) @mock.patch('yardstick.benchmark.contexts.heat.PlacementGroup') @mock.patch('yardstick.benchmark.contexts.heat.ServerGroup') @@ -64,6 +72,7 @@ class HeatContextTestCase(unittest.TestCase): networks = {'bar': {'cidr': '10.0.1.0/24'}} servers = {'baz': {'floating_ip': True, 'placement': 'pgrp1'}} attrs = {'name': 'foo', + 'task_id': '1234567890', 'placement_groups': pgs, 'server_groups': sgs, 'networks': networks, @@ -71,9 +80,13 @@ class HeatContextTestCase(unittest.TestCase): self.test_context.init(attrs) - self.assertEqual(self.test_context.name, "foo") - self.assertEqual(self.test_context.keypair_name, "foo-key") - self.assertEqual(self.test_context.secgroup_name, "foo-secgroup") + self.assertFalse(self.test_context._flags.no_setup) + self.assertFalse(self.test_context._flags.no_teardown) + self.assertEqual(self.test_context._name, "foo") + self.assertEqual(self.test_context._task_id, '1234567890') + self.assertEqual(self.test_context.name, "foo-12345678") + self.assertEqual(self.test_context.keypair_name, "foo-12345678-key") + self.assertEqual(self.test_context.secgroup_name, "foo-12345678-secgroup") mock_pg.assert_called_with('pgrp1', self.test_context, pgs['pgrp1']['policy']) @@ -90,40 +103,76 @@ class HeatContextTestCase(unittest.TestCase): servers['baz']) self.assertEqual(len(self.test_context.servers), 1) - if os.path.exists(self.test_context.key_filename): - try: - os.remove(self.test_context.key_filename) - os.remove(self.test_context.key_filename + ".pub") - except OSError: - LOG.exception("key_filename: %s", - self.test_context.key_filename) + def test_init_no_name_or_task_id(self): + attrs = {} + self.assertRaises(KeyError, self.test_context.init, attrs) + + def test_name(self): + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) + self.assertEqual(self.test_context.name, 'foo-12345678') + self.assertEqual(self.test_context.assigned_name, 'foo') + + def test_name_flags(self): + self.test_context._flags = base.Flags( + **{"no_setup": True, "no_teardown": True}) + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + + self.assertEqual(self.test_context.name, 'foo') + self.assertEqual(self.test_context.assigned_name, 'foo') + + def test_init_no_setup_no_teardown(self): + + attrs = {'name': 'foo', + 'task_id': '1234567890', + 'placement_groups': {}, + 'server_groups': {}, + 'networks': {}, + 'servers': {}, + 'flags': { + 'no_setup': True, + 'no_teardown': True, + }, + } + + self.test_context.init(attrs) + self.assertTrue(self.test_context._flags.no_setup) + self.assertTrue(self.test_context._flags.no_teardown) @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') def test__add_resources_to_template_no_servers(self, mock_template): - - self.test_context.keypair_name = "foo-key" - self.test_context.secgroup_name = "foo-secgroup" + self.test_context._name = 'ctx' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) + self.test_context.keypair_name = "ctx-key" + self.test_context.secgroup_name = "ctx-secgroup" self.test_context.key_uuid = "2f2e4997-0a8e-4eb7-9fa4-f3f8fbbc393b" - netattrs = {'cidr': '10.0.0.0/24', 'provider': None, 'external_network': 'ext_net'} - self.mock_context.name = 'bar' + netattrs = {'cidr': '10.0.0.0/24', 'provider': None, + 'external_network': 'ext_net'} + self.test_context.networks = OrderedDict( - {"fool-network": model.Network("fool-network", self.mock_context, + {"mynet": model.Network("mynet", self.test_context, netattrs)}) self.test_context._add_resources_to_template(mock_template) mock_template.add_keypair.assert_called_with( - "foo-key", - "2f2e4997-0a8e-4eb7-9fa4-f3f8fbbc393b") - mock_template.add_security_group.assert_called_with("foo-secgroup") -# mock_template.add_network.assert_called_with("bar-fool-network", 'physnet1', None) + "ctx-key", + "ctx-12345678") + mock_template.add_security_group.assert_called_with("ctx-secgroup") + mock_template.add_network.assert_called_with( + "ctx-12345678-mynet", 'physnet1', None, None, None, None) mock_template.add_router.assert_called_with( - "bar-fool-network-router", + "ctx-12345678-mynet-router", netattrs["external_network"], - "bar-fool-network-subnet") + "ctx-12345678-mynet-subnet") mock_template.add_router_interface.assert_called_with( - "bar-fool-network-router-if0", - "bar-fool-network-router", - "bar-fool-network-subnet") + "ctx-12345678-mynet-router-if0", + "ctx-12345678-mynet-router", + "ctx-12345678-mynet-subnet") @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') def test_attrs_get(self, *args): @@ -148,23 +197,162 @@ class HeatContextTestCase(unittest.TestCase): with self.assertRaises(AttributeError): self.test_context.user = 'foo' + def test__create_new_stack(self): + template = mock.Mock() + self.test_context._create_new_stack(template) + template.create.assert_called_once() + + def test__create_new_stack_stack_create_failed(self): + template = mock.Mock() + template.create.side_effect = y_exc.HeatTemplateError + + self.assertRaises(y_exc.HeatTemplateError, + self.test_context._create_new_stack, + template) + + def test__create_new_stack_keyboard_interrupt(self): + template = mock.Mock() + template.create.side_effect = KeyboardInterrupt + self.assertRaises(y_exc.StackCreationInterrupt, + self.test_context._create_new_stack, + template) + + @mock.patch.object(os.path, 'exists', return_value=True) + @mock.patch.object(heat.HeatContext, '_add_resources_to_template') + @mock.patch.object(heat.HeatContext, '_create_new_stack') + def test_deploy_stack_creation_failed(self, mock_create, + mock_resources_template, mock_path_exists): + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = 'foo-12345678' + mock_create.side_effect = y_exc.HeatTemplateError + self.assertRaises(y_exc.HeatTemplateError, + self.test_context.deploy) + + mock_path_exists.assert_called_once() + mock_resources_template.assert_called_once() + + @mock.patch.object(os.path, 'exists', return_value=False) + @mock.patch.object(ssh.SSH, 'gen_keys') @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') - def test_deploy(self, mock_template): - self.test_context.name = 'foo' + def test_deploy(self, mock_template, mock_genkeys, mock_path_exists): + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) self.test_context.template_file = '/bar/baz/some-heat-file' self.test_context.heat_parameters = {'image': 'cirros'} self.test_context.get_neutron_info = mock.MagicMock() self.test_context.deploy() - mock_template.assert_called_with('foo', + mock_template.assert_called_with('foo-12345678', '/bar/baz/some-heat-file', {'image': 'cirros'}) self.assertIsNotNone(self.test_context.stack) + key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.test_context._name_task_id]) + mock_genkeys.assert_called_once_with(key_filename) + mock_path_exists.assert_called_once_with(key_filename) + + @mock.patch.object(heat, 'HeatTemplate') + @mock.patch.object(os.path, 'exists', return_value=False) + @mock.patch.object(ssh.SSH, 'gen_keys') + @mock.patch.object(heat.HeatContext, '_retrieve_existing_stack') + @mock.patch.object(heat.HeatContext, '_create_new_stack') + def test_deploy_no_setup(self, mock_create_new_stack, + mock_retrieve_existing_stack, mock_genkeys, mock_path_exists, + *args): + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + self.test_context.template_file = '/bar/baz/some-heat-file' + self.test_context.heat_parameters = {'image': 'cirros'} + self.test_context.get_neutron_info = mock.MagicMock() + self.test_context._flags.no_setup = True + self.test_context.deploy() + + mock_create_new_stack.assert_not_called() + mock_retrieve_existing_stack.assert_called_with(self.test_context.name) + self.assertIsNotNone(self.test_context.stack) + key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.test_context._name]) + mock_genkeys.assert_called_once_with(key_filename) + mock_path_exists.assert_called_once_with(key_filename) + + @mock.patch.object(heat, 'HeatTemplate') + @mock.patch.object(os.path, 'exists', return_value=False) + @mock.patch.object(ssh.SSH, 'gen_keys') + @mock.patch.object(heat.HeatContext, '_create_new_stack') + @mock.patch.object(heat.HeatContext, '_retrieve_existing_stack', + return_value=None) + def test_deploy_try_retrieve_context_does_not_exist(self, + mock_retrieve_stack, mock_create_new_stack, mock_genkeys, + mock_path_exists, *args): + self.test_context._name = 'demo' + self.test_context._task_id = '1234567890' + self.test_context._flags.no_setup = True + self.test_context.template_file = '/bar/baz/some-heat-file' + self.test_context.get_neutron_info = mock.MagicMock() + + self.test_context.deploy() + + mock_retrieve_stack.assert_called_once_with(self.test_context._name) + mock_create_new_stack.assert_called() + key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.test_context._name]) + mock_genkeys.assert_called_once_with(key_filename) + mock_path_exists.assert_called_once_with(key_filename) + + @mock.patch.object(heat, 'HeatTemplate', return_value='heat_template') + @mock.patch.object(heat.HeatContext, '_add_resources_to_template') + @mock.patch.object(os.path, 'exists', return_value=False) + @mock.patch.object(ssh.SSH, 'gen_keys') + def test_deploy_ssh_key_before_adding_resources(self, mock_genkeys, + mock_path_exists, mock_add_resources, *args): + mock_manager = mock.Mock() + mock_manager.attach_mock(mock_add_resources, + '_add_resources_to_template') + mock_manager.attach_mock(mock_genkeys, 'gen_keys') + mock_manager.reset_mock() + self.test_context._name_task_id = 'demo-12345678' + self.test_context.get_neutron_info = mock.Mock() + with mock.patch.object(self.test_context, '_create_new_stack') as \ + mock_create_stack, \ + mock.patch.object(self.test_context, 'get_neutron_info') as \ + mock_neutron_info: + self.test_context.deploy() + + mock_neutron_info.assert_called_once() + mock_create_stack.assert_called_once() + key_filename = ''.join( + [consts.YARDSTICK_ROOT_PATH, + 'yardstick/resources/files/yardstick_key-', + self.test_context._name_task_id]) + mock_genkeys.assert_called_once_with(key_filename) + mock_path_exists.assert_called_with(key_filename) + + mock_call_gen_keys = mock.call.gen_keys(key_filename) + mock_call_add_resources = ( + mock.call._add_resources_to_template('heat_template')) + self.assertTrue(mock_manager.mock_calls.index(mock_call_gen_keys) < + mock_manager.mock_calls.index(mock_call_add_resources)) + + def test_check_for_context(self): + pass + # check that the context exists def test_add_server_port(self): network1 = mock.MagicMock() network2 = mock.MagicMock() - self.test_context.name = 'foo' + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) self.test_context.stack = mock.MagicMock() self.test_context.networks = { 'a': network1, @@ -173,15 +361,15 @@ class HeatContextTestCase(unittest.TestCase): self.test_context.stack.outputs = { u'b': u'10.20.30.45', u'b-subnet_id': 1, - u'foo-a-subnet-cidr': u'10.20.0.0/15', - u'foo-a-subnet-gateway_ip': u'10.20.30.1', + u'foo-12345678-a-subnet-cidr': u'10.20.0.0/15', + u'foo-12345678-a-subnet-gateway_ip': u'10.20.30.1', u'b-mac_address': u'00:01', u'b-device_id': u'dev21', u'b-network_id': u'net789', u'd': u'40.30.20.15', u'd-subnet_id': 2, - u'foo-c-subnet-cidr': u'40.30.0.0/18', - u'foo-c-subnet-gateway_ip': u'40.30.20.254', + u'foo-12345678-c-subnet-cidr': u'40.30.0.0/18', + u'foo-12345678-c-subnet-gateway_ip': u'40.30.20.254', u'd-mac_address': u'00:10', u'd-device_id': u'dev43', u'd-network_id': u'net987', @@ -192,6 +380,7 @@ class HeatContextTestCase(unittest.TestCase): u'e-network_id': u'net987', } server = mock.MagicMock() + server.private_ip = None server.ports = OrderedDict([ ('a', [{'stack_name': 'b', 'port': 'port_a'}]), ('c', [{'stack_name': 'd', 'port': 'port_c'}, @@ -218,17 +407,41 @@ class HeatContextTestCase(unittest.TestCase): self.assertEqual(len(server.interfaces), 3) self.assertDictEqual(server.interfaces['port_a'], expected) + @mock.patch('yardstick.benchmark.contexts.heat.os') + @mock.patch.object(heat.HeatContext, '_delete_key_file') @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') - def test_undeploy(self, mock_template): + def test_undeploy(self, mock_template, mock_delete_key, *args): self.test_context.stack = mock_template + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) + # mock_os.path.exists.return_value = True + self.test_context.key_filename = 'foo/bar/foobar' self.test_context.undeploy() - self.assertTrue(mock_template.delete.called) + mock_delete_key.assert_called() + mock_template.delete.assert_called_once() + + @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') + def test_undeploy_no_teardown(self, mock_template): + self.test_context.stack = mock_template + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + self.test_context._flags.no_teardown = True + self.test_context.undeploy() + + mock_template.delete.assert_not_called() @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') @mock.patch('yardstick.benchmark.contexts.heat.os') def test_undeploy_key_filename(self, mock_os, mock_template): self.test_context.stack = mock_template + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id) mock_os.path.exists.return_value = True + self.test_context.key_filename = 'foo/bar/foobar' self.assertIsNone(self.test_context.undeploy()) @mock.patch("yardstick.benchmark.contexts.heat.pkg_resources") @@ -249,24 +462,27 @@ class HeatContextTestCase(unittest.TestCase): baz3_server.public_ip = '127.0.0.3' baz3_server.context.user = 'zab' - self.test_context.name = 'bar' + self.test_context._name = 'bar' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) self.test_context._user = 'bot' self.test_context.stack = mock.Mock() self.test_context.stack.outputs = { 'private_ip': '10.0.0.1', 'public_ip': '127.0.0.1', } - self.test_context.key_uuid = uuid.uuid4() self.test_context._server_map = { 'baz3': baz3_server, 'foo2': foo2_server, } attr_name = { - 'name': 'foo.bar', + 'name': 'foo.bar-12345678', 'private_ip_attr': 'private_ip', 'public_ip_attr': 'public_ip', } + self.test_context.key_uuid = 'foo-42' result = self.test_context._get_server(attr_name) self.assertEqual(result['user'], 'bot') self.assertEqual(result['ip'], '127.0.0.1') @@ -288,22 +504,26 @@ class HeatContextTestCase(unittest.TestCase): baz3_server.public_ip = '127.0.0.3' baz3_server.context.user = 'zab' - self.test_context.name = 'bar' + self.test_context._name = 'bar' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) self.test_context._user = 'bot' self.test_context.stack = mock.Mock() self.test_context.stack.outputs = { 'private_ip': '10.0.0.1', 'public_ip': '127.0.0.1', } - self.test_context.key_uuid = uuid.uuid4() self.test_context._server_map = { 'baz3': baz3_server, 'foo2': foo2_server, } attr_name = { - 'name': 'foo.bar', + 'name': 'foo.bar-12345678', } + + self.test_context.key_uuid = 'foo-42' result = self.test_context._get_server(attr_name) self.assertEqual(result['user'], 'bot') # no private ip attr mapping in the map results in None value in the result @@ -327,13 +547,14 @@ class HeatContextTestCase(unittest.TestCase): baz3_server.public_ip = None baz3_server.context.user = 'zab' - self.test_context.name = 'bar1' + self.test_context._name = 'bar1' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = 'bar1-12345678' self.test_context.stack = mock.Mock() self.test_context.stack.outputs = { 'private_ip': '10.0.0.1', 'public_ip': '127.0.0.1', } - self.test_context.key_uuid = uuid.uuid4() self.test_context.generate_routing_table = mock.MagicMock(return_value=[]) self.test_context._server_map = { @@ -365,19 +586,19 @@ class HeatContextTestCase(unittest.TestCase): baz3_server.public_ip = None baz3_server.context.user = 'zab' - self.test_context.name = 'bar1' + self.test_context._name = 'bar1' self.test_context.stack = mock.Mock() self.test_context.stack.outputs = { 'private_ip': '10.0.0.1', 'public_ip': '127.0.0.1', } - self.test_context.key_uuid = uuid.uuid4() self.test_context._server_map = { 'baz3': baz3_server, 'foo2': foo2_server, 'wow4': None, } + self.test_context.key_uuid = 'foo-42' attr_name = 'wow4' result = self.test_context._get_server(attr_name) self.assertIsNone(result) @@ -398,18 +619,21 @@ class HeatContextTestCase(unittest.TestCase): baz3_server.public_ip = None baz3_server.context.user = 'zab' - self.test_context.name = 'bar1' + self.test_context._name = 'bar1' + self.test_context._task_id = '1235467890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) self.test_context.stack = mock.Mock() self.test_context.stack.outputs = { 'private_ip': '10.0.0.1', 'public_ip': '127.0.0.1', } - self.test_context.key_uuid = uuid.uuid4() self.test_context._server_map = { 'baz3': baz3_server, 'foo2': foo2_server, } + self.test_context.key_uuid = 'foo-42' attr_name = { 'name': 'foo.wow4', 'private_ip_attr': 'private_ip', @@ -434,18 +658,18 @@ class HeatContextTestCase(unittest.TestCase): baz3_server.public_ip = None baz3_server.context.user = 'zab' - self.mock_context.name = 'bar1' + self.mock_context._name = 'bar1' self.test_context.stack = mock.Mock() self.mock_context.stack.outputs = { 'private_ip': '10.0.0.1', 'public_ip': '127.0.0.1', } - self.mock_context.key_uuid = uuid.uuid4() self.mock_context._server_map = { 'baz3': baz3_server, 'foo2': foo2_server, } + self.test_context.key_uuid = 'foo-42' attr_name = 'foo.wow4' result = self.test_context._get_server(attr_name) self.assertIsNone(result) diff --git a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py index e149e0d18..4dd9d40d1 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py +++ b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py @@ -10,13 +10,13 @@ import mock import unittest -from yardstick.benchmark.contexts.base import Context from yardstick.benchmark.contexts import kubernetes context_cfg = { 'type': 'Kubernetes', 'name': 'k8s', + 'task_id': '1234567890', 'servers': { 'host': { 'image': 'openretriever/yardstick', @@ -40,11 +40,12 @@ class KubernetesTestCase(unittest.TestCase): def setUp(self): self.k8s_context = kubernetes.KubernetesContext() + self.addCleanup(self._remove_contexts) self.k8s_context.init(context_cfg) - def tearDown(self): - # clear kubernetes contexts from global list so we don't break other tests - Context.list = [] + def _remove_contexts(self): + if self.k8s_context in self.k8s_context.list: + self.k8s_context._delete_context() @mock.patch.object(kubernetes.KubernetesContext, '_delete_services') @mock.patch.object(kubernetes.KubernetesContext, '_delete_ssh_key') @@ -57,10 +58,10 @@ class KubernetesTestCase(unittest.TestCase): mock_delete_services): self.k8s_context.undeploy() - self.assertTrue(mock_delete_ssh.called) - self.assertTrue(mock_delete_rcs.called) - self.assertTrue(mock_delete_pods.called) - self.assertTrue(mock_delete_services.called) + mock_delete_ssh.assert_called_once() + mock_delete_rcs.assert_called_once() + mock_delete_pods.assert_called_once() + mock_delete_services.assert_called_once() @mock.patch.object(kubernetes.KubernetesContext, '_create_services') @mock.patch.object(kubernetes.KubernetesContext, '_wait_until_running') @@ -76,11 +77,11 @@ class KubernetesTestCase(unittest.TestCase): with mock.patch("yardstick.benchmark.contexts.kubernetes.time"): self.k8s_context.deploy() - self.assertTrue(mock_set_ssh_key.called) - self.assertTrue(mock_create_rcs.called) - self.assertTrue(mock_create_services.called) - self.assertTrue(mock_get_rc_pods.called) - self.assertTrue(mock_wait_until_running.called) + mock_set_ssh_key.assert_called_once() + mock_create_rcs.assert_called_once() + mock_create_services.assert_called_once() + mock_get_rc_pods.assert_called_once() + mock_wait_until_running.assert_called_once() @mock.patch.object(kubernetes, 'paramiko', **{"resource_filename.return_value": ""}) @mock.patch.object(kubernetes, 'pkg_resources', **{"resource_filename.return_value": ""}) @@ -92,8 +93,8 @@ class KubernetesTestCase(unittest.TestCase): self.k8s_context._set_ssh_key() self.k8s_context._delete_ssh_key() - self.assertTrue(mock_create.called) - self.assertTrue(mock_delete.called) + mock_create.assert_called_once() + mock_delete.assert_called_once() @mock.patch.object(kubernetes.k8s_utils, 'read_pod_status') def test_wait_until_running(self, mock_read_pod_status): @@ -135,42 +136,34 @@ class KubernetesTestCase(unittest.TestCase): @mock.patch.object(kubernetes.KubernetesContext, '_create_rc') def test_create_rcs(self, mock_create_rc): self.k8s_context._create_rcs() - self.assertTrue(mock_create_rc.called) + mock_create_rc.assert_called() @mock.patch.object(kubernetes.k8s_utils, 'create_replication_controller') def test_create_rc(self, mock_create_replication_controller): self.k8s_context._create_rc({}) - self.assertTrue(mock_create_replication_controller.called) + mock_create_replication_controller.assert_called_once() @mock.patch.object(kubernetes.KubernetesContext, '_delete_rc') def test_delete_rcs(self, mock_delete_rc): self.k8s_context._delete_rcs() - self.assertTrue(mock_delete_rc.called) + mock_delete_rc.assert_called() @mock.patch.object(kubernetes.k8s_utils, 'delete_replication_controller') def test_delete_rc(self, mock_delete_replication_controller): self.k8s_context._delete_rc({}) - self.assertTrue(mock_delete_replication_controller.called) + mock_delete_replication_controller.assert_called_once() @mock.patch.object(kubernetes.k8s_utils, 'get_node_list') def test_get_node_ip(self, mock_get_node_list): self.k8s_context._get_node_ip() - self.assertTrue(mock_get_node_list.called) + mock_get_node_list.assert_called_once() @mock.patch('yardstick.orchestrator.kubernetes.ServiceObject.create') def test_create_services(self, mock_create): self.k8s_context._create_services() - self.assertTrue(mock_create.called) + mock_create.assert_called() @mock.patch('yardstick.orchestrator.kubernetes.ServiceObject.delete') def test_delete_services(self, mock_delete): self.k8s_context._delete_services() - self.assertTrue(mock_delete.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_delete.assert_called() diff --git a/yardstick/tests/unit/benchmark/contexts/test_model.py b/yardstick/tests/unit/benchmark/contexts/test_model.py index 28011d494..20cc00b4e 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_model.py +++ b/yardstick/tests/unit/benchmark/contexts/test_model.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Ericsson AB and others. # @@ -241,6 +239,7 @@ class ServerTestCase(unittest.TestCase): mock_network.vnic_type = 'normal' mock_network.subnet_stack_name = 'some-network-stack-subnet' mock_network.provider = 'sriov' + mock_network.net_flags = {} mock_network.external_network = 'ext_net' mock_network.router = model.Router('some-router', 'some-network', self.mock_context, 'ext_net') @@ -250,9 +249,7 @@ class ServerTestCase(unittest.TestCase): mock_template.add_port.assert_called_with( 'some-server-some-network-port', - mock_network.stack_name, - mock_network.subnet_stack_name, - mock_network.vnic_type, + mock_network, sec_group_id=self.mock_context.secgroup_name, provider=mock_network.provider, allowed_address_pairs=mock_network.allowed_address_pairs) @@ -513,6 +510,7 @@ class ServerTestCase(unittest.TestCase): mock_network = mock.Mock() mock_network.allowed_address_pairs = ["1", "2"] mock_network.vnic_type = 'normal' + mock_network.net_flags = {} mock_network.configure_mock(name='some-network', stack_name='some-network-stack', subnet_stack_name='some-network-stack-subnet', provider='some-provider') @@ -522,9 +520,7 @@ class ServerTestCase(unittest.TestCase): mock_template.add_port.assert_called_with( 'ServerFlavor-2-some-network-port', - mock_network.stack_name, - mock_network.subnet_stack_name, - mock_network.vnic_type, + mock_network, provider=mock_network.provider, sec_group_id=self.mock_context.secgroup_name, allowed_address_pairs=mock_network.allowed_address_pairs) @@ -556,6 +552,7 @@ class ServerTestCase(unittest.TestCase): mock_network.name = 'some-network' mock_network.stack_name = 'some-network-stack' mock_network.subnet_stack_name = 'some-network-stack-subnet' + mock_network.net_flags = {} test_server._add_instance(mock_template, 'ServerFlavor-3', [mock_network], 'hints') diff --git a/yardstick/tests/unit/benchmark/contexts/test_node.py b/yardstick/tests/unit/benchmark/contexts/test_node.py index 5329d30f4..8b232481b 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_node.py +++ b/yardstick/tests/unit/benchmark/contexts/test_node.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015-2017 Huawei Technologies Co.,Ltd and others. # @@ -9,9 +7,6 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -# Unittest for yardstick.benchmark.contexts.node - -from __future__ import absolute_import import os import unittest import errno @@ -21,10 +16,6 @@ from yardstick.common import constants as consts from yardstick.benchmark.contexts import node -# pylint: disable=unused-argument -# disable this for now because I keep forgetting mock patch arg ordering - - class NodeContextTestCase(unittest.TestCase): PREFIX = 'yardstick.benchmark.contexts.node' @@ -34,7 +25,17 @@ class NodeContextTestCase(unittest.TestCase): def setUp(self): self.test_context = node.NodeContext() + self.addCleanup(self._remove_contexts) self.os_path_join = os.path.join + self.attrs = { + 'name': 'foo', + 'task_id': '1234567890', + 'file': self._get_file_abspath(self.NODES_SAMPLE) + } + + def _remove_contexts(self): + if self.test_context in self.test_context.list: + self.test_context._delete_context() def _get_file_abspath(self, filename): curr_path = os.path.dirname(os.path.abspath(__file__)) @@ -42,7 +43,7 @@ class NodeContextTestCase(unittest.TestCase): return file_path def test___init__(self): - self.assertIsNone(self.test_context.name) + self.assertIsNone(self.test_context._name) self.assertIsNone(self.test_context.file_path) self.assertEqual(self.test_context.nodes, []) self.assertEqual(self.test_context.controllers, []) @@ -74,6 +75,7 @@ class NodeContextTestCase(unittest.TestCase): attrs = { 'name': 'foo', + 'task_id': '1234567890', 'file': error_path, } read_mock.side_effect = IOError(errno.EBUSY, 'busy') @@ -97,37 +99,19 @@ class NodeContextTestCase(unittest.TestCase): self.assertEqual(str(raised.exception), str(read_mock.side_effect)) def test_read_config_file(self): - - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SAMPLE) - } - - self.test_context.init(attrs) + self.test_context.init(self.attrs) self.assertIsNotNone(self.test_context.read_config_file()) def test__dispatch_script(self): - - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SAMPLE) - } - - self.test_context.init(attrs) + self.test_context.init(self.attrs) self.test_context.env = {'bash': [{'script': 'dummy'}]} self.test_context._execute_script = mock.Mock() self.assertEqual(self.test_context._dispatch_script('bash'), None) def test__dispatch_ansible(self): - - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SAMPLE) - } - - self.test_context.init(attrs) + self.test_context.init(self.attrs) self.test_context.env = {'ansible': [{'script': 'dummy'}]} self.test_context._do_ansible_job = mock.Mock() @@ -136,19 +120,13 @@ class NodeContextTestCase(unittest.TestCase): self.assertEqual(self.test_context._dispatch_ansible('ansible'), None) @mock.patch("{}.AnsibleCommon".format(PREFIX)) - def test__do_ansible_job(self, mock_ansible): - self.assertEqual(None, self.test_context._do_ansible_job('dummy')) - - def test_successful_init(self): - - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SAMPLE) - } + def test__do_ansible_job(self, *args): + self.assertIsNone(self.test_context._do_ansible_job('dummy')) - self.test_context.init(attrs) + def test_init(self): + self.test_context.init(self.attrs) - self.assertEqual(self.test_context.name, "foo") + self.assertEqual(self.test_context.name, "foo-12345678") self.assertEqual(len(self.test_context.nodes), 4) self.assertEqual(len(self.test_context.controllers), 2) self.assertEqual(len(self.test_context.computes), 1) @@ -156,95 +134,59 @@ class NodeContextTestCase(unittest.TestCase): self.assertEqual(len(self.test_context.baremetals), 1) self.assertEqual(self.test_context.baremetals[0]["name"], "node4") - def test__get_server_with_dic_attr_name(self): - - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SAMPLE) - } - - self.test_context.init(attrs) - - attr_name = {'name': 'foo.bar'} - result = self.test_context._get_server(attr_name) + def test__get_server_with_dict_attr_name(self): + self.test_context.init(self.attrs) + result = self.test_context._get_server({'name': 'node1.foo-12345678'}) - self.assertEqual(result, None) + self.assertIsNone(result, None) def test__get_server_not_found(self): + self.test_context.init(self.attrs) - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SAMPLE) - } - - self.test_context.init(attrs) - - attr_name = 'bar.foo' - result = self.test_context._get_server(attr_name) - - self.assertEqual(result, None) + self.assertIsNone(self.test_context._get_server('bar.foo-12345678')) def test__get_server_mismatch(self): + self.test_context.init(self.attrs) - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SAMPLE) - } - - self.test_context.init(attrs) - - attr_name = 'bar.foo1' - result = self.test_context._get_server(attr_name) - - self.assertEqual(result, None) + self.assertIsNone(self.test_context._get_server('bar.foo1')) def test__get_server_duplicate(self): + self.attrs['file'] = self._get_file_abspath( + self.NODES_DUPLICATE_SAMPLE) + self.test_context.init(self.attrs) - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_DUPLICATE_SAMPLE) - } - - self.test_context.init(attrs) - - attr_name = 'node1.foo' with self.assertRaises(ValueError): - self.test_context._get_server(attr_name) + self.test_context._get_server('node1.foo-12345678') def test__get_server_found(self): + self.test_context.init(self.attrs) - attrs = { - 'name': 'foo', - 'file': self._get_file_abspath(self.NODES_SAMPLE) - } - - self.test_context.init(attrs) - - attr_name = 'node1.foo' - result = self.test_context._get_server(attr_name) + result = self.test_context._get_server('node1.foo-12345678') self.assertEqual(result['ip'], '10.229.47.137') - self.assertEqual(result['name'], 'node1.foo') + self.assertEqual(result['name'], 'node1.foo-12345678') self.assertEqual(result['user'], 'root') self.assertEqual(result['key_filename'], '/root/.yardstick_key') @mock.patch('{}.NodeContext._dispatch_script'.format(PREFIX)) def test_deploy(self, dispatch_script_mock): obj = node.NodeContext() + self.addCleanup(obj._delete_context) obj.env = { 'type': 'script' } obj.deploy() - self.assertTrue(dispatch_script_mock.called) + dispatch_script_mock.assert_called_once() @mock.patch('{}.NodeContext._dispatch_ansible'.format(PREFIX)) def test_deploy_anisible(self, dispatch_ansible_mock): obj = node.NodeContext() + self.addCleanup(obj._delete_context) obj.env = { 'type': 'ansible' } obj.deploy() - self.assertTrue(dispatch_ansible_mock.called) + dispatch_ansible_mock.assert_called_once() @mock.patch('{}.NodeContext._dispatch_script'.format(PREFIX)) def test_undeploy(self, dispatch_script_mock): @@ -253,7 +195,7 @@ class NodeContextTestCase(unittest.TestCase): 'type': 'script' } obj.undeploy() - self.assertTrue(dispatch_script_mock.called) + dispatch_script_mock.assert_called_once() @mock.patch('{}.NodeContext._dispatch_ansible'.format(PREFIX)) def test_undeploy_anisble(self, dispatch_ansible_mock): @@ -262,12 +204,13 @@ class NodeContextTestCase(unittest.TestCase): 'type': 'ansible' } obj.undeploy() - self.assertTrue(dispatch_ansible_mock.called) + dispatch_ansible_mock.assert_called_once() @mock.patch('{}.ssh.SSH._put_file_shell'.format(PREFIX)) @mock.patch('{}.ssh.SSH.execute'.format(PREFIX)) def test_execute_remote_script(self, execute_mock, put_file_mock): obj = node.NodeContext() + self.addCleanup(obj._delete_context) obj.env = {'prefix': 'yardstick.benchmark.scenarios.compute'} node_name_args = 'node5' obj.nodes = [{ @@ -281,35 +224,42 @@ class NodeContextTestCase(unittest.TestCase): execute_mock.return_value = (0, '', '') obj._execute_remote_script('node5', info) - self.assertTrue(put_file_mock.called) - self.assertTrue(execute_mock.called) + put_file_mock.assert_called_once() + execute_mock.assert_called() @mock.patch('{}.NodeContext._execute_local_script'.format(PREFIX)) def test_execute_script_local(self, local_execute_mock): node_name = 'local' info = {} - node.NodeContext()._execute_script(node_name, info) - self.assertTrue(local_execute_mock.called) + obj = node.NodeContext() + self.addCleanup(obj._delete_context) + obj._execute_script(node_name, info) + local_execute_mock.assert_called_once() @mock.patch('{}.NodeContext._execute_remote_script'.format(PREFIX)) def test_execute_script_remote(self, remote_execute_mock): node_name = 'node5' info = {} - node.NodeContext()._execute_script(node_name, info) - self.assertTrue(remote_execute_mock.called) + obj = node.NodeContext() + self.addCleanup(obj._delete_context) + obj._execute_script(node_name, info) + remote_execute_mock.assert_called_once() def test_get_script(self): script_args = 'hello.bash' info_args = { 'script': script_args } - script, options = node.NodeContext()._get_script(info_args) + obj = node.NodeContext() + self.addCleanup(obj._delete_context) + script, options = obj._get_script(info_args) self.assertEqual(script_args, script) self.assertEqual('', options) def test_node_info(self): node_name_args = 'node5' obj = node.NodeContext() + self.addCleanup(obj._delete_context) obj.nodes = [{'name': node_name_args, 'check': node_name_args}] node_info = obj._get_node_info(node_name_args) self.assertEqual(node_info.get('check'), node_name_args) @@ -318,6 +268,7 @@ class NodeContextTestCase(unittest.TestCase): def test_get_client(self, wait_mock): node_name_args = 'node5' obj = node.NodeContext() + self.addCleanup(obj._delete_context) obj.nodes = [{ 'name': node_name_args, 'user': 'ubuntu', @@ -325,29 +276,41 @@ class NodeContextTestCase(unittest.TestCase): 'pwd': 'ubuntu', }] obj._get_client(node_name_args) - self.assertTrue(wait_mock.called) + wait_mock.assert_called_once() def test_get_server(self): - self.test_context.name = 'vnf1' - self.test_context.nodes = [{'name': 'my', 'value': 100}] + self.test_context.init(self.attrs) + self.test_context._name = 'foo' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) + self.assertEqual('foo-12345678', self.test_context.name) + self.assertIsNotNone(self.test_context._task_id) - with self.assertRaises(ValueError): - self.test_context.get_server('my.vnf2') + result = self.test_context.get_server('node1.foo-12345678') - expected = {'name': 'my.vnf1', 'value': 100, 'interfaces': {}} - result = self.test_context.get_server('my.vnf1') - self.assertDictEqual(result, expected) + self.assertEqual(result['ip'], '10.229.47.137') + self.assertEqual(result['name'], 'node1.foo-12345678') + self.assertEqual(result['user'], 'root') + self.assertEqual(result['key_filename'], '/root/.yardstick_key') + + def test_get_server_server_not_in_context(self): + self.test_context.init(self.attrs) + + with self.assertRaises(ValueError): + self.test_context.get_server('my2.foo-12345678') def test_get_context_from_server(self): - self.test_context.name = 'vnf1' + self.test_context._name = 'vnf1' + self.test_context._task_id = '1234567890' + self.test_context._name_task_id = '{}-{}'.format( + self.test_context._name, self.test_context._task_id[:8]) self.test_context.nodes = [{'name': 'my', 'value': 100}] self.test_context.attrs = {'attr1': 200} - with self.assertRaises(ValueError): - self.test_context.get_context_from_server('my.vnf2') - - result = self.test_context.get_context_from_server('my.vnf1') - self.assertIs(result, self.test_context) + self.assertIs( + self.test_context.get_context_from_server('my.vnf1-12345678'), + self.test_context) # TODO: Split this into more granular tests def test__get_network(self): @@ -393,11 +356,3 @@ class NodeContextTestCase(unittest.TestCase): expected = network1 result = self.test_context._get_network(attr_name) self.assertDictEqual(result, expected) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/core/test_report.py b/yardstick/tests/unit/benchmark/core/test_report.py index 3d9a503b6..a684ad750 100644 --- a/yardstick/tests/unit/benchmark/core/test_report.py +++ b/yardstick/tests/unit/benchmark/core/test_report.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2017 Rajesh Kudaka. # diff --git a/yardstick/tests/unit/benchmark/core/test_task.py b/yardstick/tests/unit/benchmark/core/test_task.py index ee00d8826..1ce30eacb 100644 --- a/yardstick/tests/unit/benchmark/core/test_task.py +++ b/yardstick/tests/unit/benchmark/core/test_task.py @@ -7,13 +7,22 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import copy +import io import os +import sys import mock +import six import unittest +import uuid +from yardstick.benchmark.contexts import dummy from yardstick.benchmark.core import task from yardstick.common import constants as consts +from yardstick.common import exceptions +from yardstick.common import task_template +from yardstick.common import utils class TaskTestCase(unittest.TestCase): @@ -57,7 +66,7 @@ class TaskTestCase(unittest.TestCase): mock_dispatcher.get = mock.MagicMock(return_value=[dispatcher1, dispatcher2]) - self.assertEqual(None, t._do_output(output_config, {})) + self.assertIsNone(t._do_output(output_config, {})) @mock.patch.object(task, 'Context') def test_parse_networks_from_nodes(self, mock_context): @@ -144,7 +153,7 @@ class TaskTestCase(unittest.TestCase): runner.get_result.return_value = [] mock_base_runner.Runner.get.return_value = runner t._run([scenario], False, "yardstick.out") - self.assertTrue(runner.run.called) + runner.run.assert_called_once() @mock.patch.object(os, 'environ') def test_check_precondition(self, mock_os_environ): @@ -174,7 +183,6 @@ class TaskTestCase(unittest.TestCase): '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.assertIsNone(task_args[0]) self.assertIsNone(task_args[1]) self.assertIsNone(task_args_fnames[0]) @@ -256,30 +264,37 @@ class TaskTestCase(unittest.TestCase): actual_result = t._parse_options(options) self.assertEqual(expected_result, actual_result) + def test_parse_options_no_teardown(self): + options = { + 'openstack': { + 'EXTERNAL_NETWORK': '$network' + }, + 'nodes': ['node1', '$node'], + 'host': '$host', + 'contexts' : {'name': "my-context", + 'no_teardown': True} + } - def test_change_server_name_host_str(self): - scenario = {'host': 'demo'} - suffix = '-8' - task.change_server_name(scenario, suffix) - 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.assertEqual('demo-8', scenario['host']['name']) + t = task.Task() + t.outputs = { + 'network': 'ext-net', + 'node': 'node2', + 'host': 'server.yardstick' + } - def test_change_server_name_target_str(self): - scenario = {'target': 'demo'} - suffix = '-8' - task.change_server_name(scenario, suffix) - self.assertEqual('demo-8', scenario['target']) + expected_result = { + 'openstack': { + 'EXTERNAL_NETWORK': 'ext-net' + }, + 'nodes': ['node1', 'node2'], + 'host': 'server.yardstick', + 'contexts': {'name': 'my-context', + 'no_teardown': True, + } + } - def test_change_server_name_target_dict(self): - scenario = {'target': {'name': 'demo'}} - suffix = '-8' - task.change_server_name(scenario, suffix) - self.assertEqual('demo-8', scenario['target']['name']) + 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(task, 'utils') @@ -299,9 +314,219 @@ class TaskTestCase(unittest.TestCase): return os.path.join(consts.YARDSTICK_ROOT_PATH, filepath) -def main(): - unittest.main() +class TaskParserTestCase(unittest.TestCase): + + TASK = """ +{% set value1 = value1 or 'var1' %} +{% set value2 = value2 or 'var2' %} +key1: {{ value1 }} +key2: + - {{ value2 }}""" + TASK_RENDERED_1 = u""" -if __name__ == '__main__': - main() + +key1: var1 +key2: + - var2""" + + TASK_RENDERED_2 = u""" + + +key1: var3 +key2: + - var4""" + + def setUp(self): + self.parser = task.TaskParser('fake/path') + self.scenario = { + 'host': 'athena.demo', + 'target': 'kratos.demo', + 'targets': [ + 'ares.demo', 'mars.demo' + ], + 'options': { + 'server_name': { + 'host': 'jupiter.demo', + 'target': 'saturn.demo', + }, + }, + 'nodes': { + 'tg__0': 'tg_0.demo', + 'vnf__0': 'vnf_0.demo', + } + } + + def test__change_node_names(self): + + ctx_attrs = { + 'name': 'demo', + 'task_id': '1234567890', + 'servers': [ + 'athena', 'kratos', + 'ares', 'mars', + 'jupiter', 'saturn', + 'tg_0', 'vnf_0' + ] + } + + my_context = dummy.DummyContext() + my_context.init(ctx_attrs) + + expected_scenario = { + 'host': 'athena.demo-12345678', + 'target': 'kratos.demo-12345678', + 'targets': [ + 'ares.demo-12345678', 'mars.demo-12345678' + ], + 'options': { + 'server_name': { + 'host': 'jupiter.demo-12345678', + 'target': 'saturn.demo-12345678', + }, + }, + 'nodes': { + 'tg__0': 'tg_0.demo-12345678', + 'vnf__0': 'vnf_0.demo-12345678', + } + } + + scenario = copy.deepcopy(self.scenario) + + self.parser._change_node_names(scenario, [my_context]) + self.assertEqual(scenario, expected_scenario) + + def test__change_node_names_context_not_found(self): + scenario = copy.deepcopy(self.scenario) + self.assertRaises(exceptions.ScenarioConfigContextNameNotFound, + self.parser._change_node_names, + scenario, []) + + def test__change_node_names_context_name_unchanged(self): + ctx_attrs = { + 'name': 'demo', + 'task_id': '1234567890', + 'flags': { + 'no_setup': True, + 'no_teardown': True + } + } + + my_context = dummy.DummyContext() + my_context.init(ctx_attrs) + + scenario = copy.deepcopy(self.scenario) + expected_scenario = copy.deepcopy(self.scenario) + + self.parser._change_node_names(scenario, [my_context]) + self.assertEqual(scenario, expected_scenario) + + def test__parse_tasks(self): + task_obj = task.Task() + _uuid = uuid.uuid4() + task_obj.task_id = _uuid + task_files = ['/directory/task_file_name.yml'] + mock_parser = mock.Mock() + mock_parser.parse_task.return_value = {'rendered': 'File content'} + mock_args = mock.Mock() + mock_args.render_only = False + + tasks = task_obj._parse_tasks(mock_parser, task_files, mock_args, + ['arg1'], ['file_arg1']) + self.assertEqual( + [{'rendered': 'File content', 'case_name': 'task_file_name'}], + tasks) + mock_parser.parse_task.assert_called_once_with( + _uuid, 'arg1', 'file_arg1') + + @mock.patch.object(sys, 'exit') + @mock.patch.object(utils, 'write_file') + @mock.patch.object(utils, 'makedirs') + def test__parse_tasks_render_only(self, mock_makedirs, mock_write_file, + mock_exit): + task_obj = task.Task() + _uuid = uuid.uuid4() + task_obj.task_id = _uuid + task_files = ['/directory/task_file_name.yml'] + mock_parser = mock.Mock() + mock_parser.parse_task.return_value = {'rendered': 'File content'} + mock_args = mock.Mock() + mock_args.render_only = '/output_directory' + + task_obj._parse_tasks(mock_parser, task_files, mock_args, + ['arg1'], ['file_arg1']) + mock_makedirs.assert_called_once_with('/output_directory') + mock_write_file.assert_called_once_with( + '/output_directory/000-task_file_name.yml', 'File content') + mock_exit.assert_called_once_with(0) + + def test__render_task_no_args(self): + task_parser = task.TaskParser('task_file') + task_str = io.StringIO(six.text_type(self.TASK)) + with mock.patch.object(six.moves.builtins, 'open', + return_value=task_str) as mock_open: + parsed, rendered = task_parser._render_task(None, None) + + self.assertEqual(self.TASK_RENDERED_1, rendered) + self.assertEqual({'key1': 'var1', 'key2': ['var2']}, parsed) + mock_open.assert_called_once_with('task_file') + + def test__render_task_arguments(self): + task_parser = task.TaskParser('task_file') + task_str = io.StringIO(six.text_type(self.TASK)) + with mock.patch.object(six.moves.builtins, 'open', + return_value=task_str) as mock_open: + parsed, rendered = task_parser._render_task('value1: "var1"', None) + + self.assertEqual(self.TASK_RENDERED_1, rendered) + self.assertEqual({'key1': 'var1', 'key2': ['var2']}, parsed) + mock_open.assert_called_once_with('task_file') + + def test__render_task_file_arguments(self): + task_parser = task.TaskParser('task_file') + with mock.patch.object(six.moves.builtins, 'open') as mock_open: + mock_open.side_effect = ( + io.StringIO(six.text_type('value2: var4')), + io.StringIO(six.text_type(self.TASK)) + ) + parsed, rendered = task_parser._render_task('value1: "var3"', + 'args_file') + + self.assertEqual(self.TASK_RENDERED_2, rendered) + self.assertEqual({'key1': 'var3', 'key2': ['var4']}, parsed) + mock_open.assert_has_calls([mock.call('args_file'), + mock.call('task_file')]) + + def test__render_task_error_arguments(self): + with self.assertRaises(exceptions.TaskRenderArgumentError): + task.TaskParser('task_file')._render_task('value1="var3"', None) + + def test__render_task_error_task_file(self): + task_parser = task.TaskParser('task_file') + with mock.patch.object(six.moves.builtins, 'open') as mock_open: + mock_open.side_effect = ( + io.StringIO(six.text_type('value2: var4')), + IOError() + ) + with self.assertRaises(exceptions.TaskReadError): + task_parser._render_task('value1: "var3"', 'args_file') + + mock_open.assert_has_calls([mock.call('args_file'), + mock.call('task_file')]) + + def test__render_task_render_error(self): + task_parser = task.TaskParser('task_file') + with mock.patch.object(six.moves.builtins, 'open') as mock_open, \ + mock.patch.object(task_template.TaskTemplate, 'render', + side_effect=TypeError) as mock_render: + mock_open.side_effect = ( + io.StringIO(six.text_type('value2: var4')), + io.StringIO(six.text_type(self.TASK)) + ) + with self.assertRaises(exceptions.TaskRenderError): + task_parser._render_task('value1: "var3"', 'args_file') + + mock_open.assert_has_calls([mock.call('args_file'), + mock.call('task_file')]) + mock_render.assert_has_calls( + [mock.call(self.TASK, value1='var3', value2='var4')]) diff --git a/yardstick/tests/unit/benchmark/core/test_testcase.py b/yardstick/tests/unit/benchmark/core/test_testcase.py index 1f5aad75e..119465887 100644 --- a/yardstick/tests/unit/benchmark/core/test_testcase.py +++ b/yardstick/tests/unit/benchmark/core/test_testcase.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # @@ -35,11 +33,3 @@ class TestcaseUT(unittest.TestCase): casename = Arg() result = t.show(casename) self.assertTrue(result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/runner/test_base.py b/yardstick/tests/unit/benchmark/runner/test_base.py index 59739c54f..727207f5a 100644 --- a/yardstick/tests/unit/benchmark/runner/test_base.py +++ b/yardstick/tests/unit/benchmark/runner/test_base.py @@ -90,11 +90,3 @@ class RunnerTestCase(unittest.TestCase): with self.assertRaises(NotImplementedError): runner._run_benchmark(mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock()) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/runner/test_search.py b/yardstick/tests/unit/benchmark/runner/test_search.py index 1bc07448d..4e5b4fe77 100644 --- a/yardstick/tests/unit/benchmark/runner/test_search.py +++ b/yardstick/tests/unit/benchmark/runner/test_search.py @@ -17,15 +17,8 @@ import time import mock import unittest -from yardstick.tests.unit import STL_MOCKS - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.benchmark.runners.search import SearchRunner - from yardstick.benchmark.runners.search import SearchRunnerHelper +from yardstick.benchmark.runners.search import SearchRunner +from yardstick.benchmark.runners.search import SearchRunnerHelper class TestSearchRunnerHelper(unittest.TestCase): diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py index f0921c0f6..d5c95a086 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_general.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_general.py index 612b5a662..c1b3c0d72 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_general.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_general.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Juan Qiu and others # juan_ qiu@tongji.edu.cn diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_process.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_process.py index 0a8e8322a..2e9f1c6bb 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_process.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_process.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py index 9bc04ebf4..ce972779d 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py @@ -113,7 +113,3 @@ class BaseMonitorTestCase(unittest.TestCase): except Exception: # pylint: disable=broad-except pass self.assertIsNone(cls) - - -if __name__ == "__main__": - unittest.main() diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_baseresultchecker.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_baseresultchecker.py index ae74d241c..d4df02819 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_baseresultchecker.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_baseresultchecker.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huan Li and others # lihuansse@tongji.edu.cn diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_director.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_director.py index 72ce7b0d5..e49544e1c 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_director.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_director.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huan Li and others # lihuansse@tongji.edu.cn diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_general.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_general.py index 7022ea678..5907c8b6a 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_general.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_general.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huan Li and others # lihuansse@tongji.edu.cn diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_multi.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_multi.py index 0d61d9b15..e9c680257 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_multi.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_multi.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huan Li and others # lihuansse@tongji.edu.cn diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_process.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_process.py index 41ce5445e..a6d2ca398 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_process.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_monitor_process.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_operation_general.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_operation_general.py index a965f7f64..2b09c0385 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_operation_general.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_operation_general.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huan Li and others # lihuansse@tongji.edu.cn diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_result_checker_general.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_result_checker_general.py index 234adcb6e..324a5bda2 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_result_checker_general.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_result_checker_general.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huan Li and others # lihuansse@tongji.edu.cn diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_util.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_util.py index 548efe91b..4d97585d4 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_util.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_util.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Kanglin Yin and others # 14_ykl@tongji.edu.cn diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_cachestat.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_cachestat.py index b0ddfc6b4..6f66c30f9 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_cachestat.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_cachestat.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. # diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_computecapacity.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_computecapacity.py index 7b9a5ad4a..4bef589f4 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_computecapacity.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_computecapacity.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. # diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_cpuload.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_cpuload.py index 840ac7885..da6e6a22e 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_cpuload.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_cpuload.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Ericsson AB and others. # diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py index 51ffd2488..f24ec24ec 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and other. # @@ -166,10 +164,3 @@ class CyclictestTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, c.run, result) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py index b3152d12c..9640ce000 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Ericsson AB and others. # @@ -193,10 +191,3 @@ class LmbenchTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, l.run, self.result) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_memload.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_memload.py index ebae9993d..8213d4490 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_memload.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_memload.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. # @@ -109,11 +107,3 @@ class MEMLoadTestCase(unittest.TestCase): with open(output) as f: sample_output = f.read() return sample_output - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_plugintest.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_plugintest.py index 680f6ad65..875301729 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_plugintest.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_plugintest.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. # diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py index 26a26cdf7..03003d01f 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and other. # @@ -157,11 +155,3 @@ class QemuMigrateTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, q.run, result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py index 4f71fbb36..dcc0e810d 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. # @@ -235,10 +233,3 @@ class RamspeedTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'No such type_id: 30 for \ Ramspeed scenario') self.assertRaises(RuntimeError, r.run, self.result) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_spec_cpu.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_spec_cpu.py index 74612d7b6..643e1eae2 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_spec_cpu.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_spec_cpu.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. # @@ -75,11 +73,3 @@ class SpecCPUTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, s.run, self.result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_spec_cpu_for_vm.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_spec_cpu_for_vm.py index c428e1fb8..74ef576b6 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_spec_cpu_for_vm.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_spec_cpu_for_vm.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. # @@ -76,9 +74,3 @@ class SpecCPUforVMTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, s.run, self.result) - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py index fec355b45..6339a2dcd 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and other. # @@ -162,10 +160,3 @@ class UnixbenchTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, u.run, result) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/dummy/test_dummy.py b/yardstick/tests/unit/benchmark/scenarios/dummy/test_dummy.py index bc5131806..875302da8 100644 --- a/yardstick/tests/unit/benchmark/scenarios/dummy/test_dummy.py +++ b/yardstick/tests/unit/benchmark/scenarios/dummy/test_dummy.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py index bda07f723..af4f0c8ab 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py @@ -27,7 +27,7 @@ class AddMemoryLoadTestCase(unittest.TestCase): mock_from_node().execute.return_value = (0, '0 2048 512', '') obj = AddMemoryLoad(scenario_cfg, context_cfg) obj.run({}) - self.assertTrue(mock_from_node.called) + mock_from_node.assert_called() @mock.patch('yardstick.ssh.SSH.from_node') def test_add_memory_load_without_load(self, mock_from_node): @@ -41,7 +41,7 @@ class AddMemoryLoadTestCase(unittest.TestCase): } obj = AddMemoryLoad(scenario_cfg, context_cfg) obj.run({}) - self.assertTrue(mock_from_node.called) + mock_from_node.assert_called_once() @mock.patch('yardstick.ssh.SSH.from_node') def test_add_memory_load_without_args(self, mock_from_node): @@ -54,12 +54,4 @@ class AddMemoryLoadTestCase(unittest.TestCase): } obj = AddMemoryLoad(scenario_cfg, context_cfg) obj.run({}) - self.assertTrue(mock_from_node.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_from_node.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_attach_volume.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_attach_volume.py index 25b911d5e..2964ecc14 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_attach_volume.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_attach_volume.py @@ -23,12 +23,4 @@ class AttachVolumeTestCase(unittest.TestCase): args = {"options": options} obj = AttachVolume(args, {}) obj.run({}) - self.assertTrue(mock_attach_server_volume.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_attach_server_volume.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_check_connectivity.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_check_connectivity.py index 7188c29d5..a48353a4f 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_check_connectivity.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_check_connectivity.py @@ -76,11 +76,3 @@ class CheckConnectivityTestCase(unittest.TestCase): obj.setup() mock_ssh.SSH.execute.return_value = (0, '100', '') - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py index f983f9c5b..270c9d3c9 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py @@ -19,7 +19,7 @@ class CheckNumaInfoTestCase(unittest.TestCase): scenario_cfg = {'info1': {}, 'info2': {}} obj = CheckNumaInfo(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_check_vm2.called) + mock_check_vm2.assert_called_once() def test_check_vm2_status_length_eq_1(self): info1 = { @@ -74,11 +74,3 @@ class CheckNumaInfoTestCase(unittest.TestCase): obj = CheckNumaInfo(scenario_cfg, {}) status = obj._check_vm2_status(info1, info2) self.assertFalse(status) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_check_value.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_check_value.py index 5a40e7d8f..7a2324b3d 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_check_value.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_check_value.py @@ -33,10 +33,3 @@ class CheckValueTestCase(unittest.TestCase): obj = CheckValue(scenario_cfg, {}) self.assertRaises(AssertionError, obj.run, self.result) self.assertEqual({}, self.result) - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_flavor.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_flavor.py index 036ae952d..0b175fae8 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_flavor.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_flavor.py @@ -26,12 +26,4 @@ class CreateFlavorTestCase(unittest.TestCase): args = {"options": options} obj = CreateFlavor(args, {}) obj.run({}) - self.assertTrue(mock_create_flavor.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_create_flavor.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_image.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_image.py index b26957979..639cf2906 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_image.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_image.py @@ -33,11 +33,3 @@ class CreateImageTestCase(unittest.TestCase): obj.run({}) mock_create_image.assert_called_once() mock_get_glance_client.assert_called_once() - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_keypair.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_keypair.py index 10e351b5e..1c3d6cebc 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_keypair.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_keypair.py @@ -25,11 +25,3 @@ class CreateKeypairTestCase(unittest.TestCase): obj = create_keypair.CreateKeypair(args, {}) obj.run({}) mock_op_utils.create_keypair.assert_called_once() - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_network.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_network.py index e0382851f..17a4ef2e1 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_network.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_network.py @@ -6,33 +6,52 @@ # 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.create_network import CreateNetwork +from yardstick.common import openstack_utils +from yardstick.common import exceptions +from yardstick.benchmark.scenarios.lib import create_network class CreateNetworkTestCase(unittest.TestCase): - @mock.patch('yardstick.common.openstack_utils.get_neutron_client') - @mock.patch('yardstick.common.openstack_utils.create_neutron_net') - def test_create_network(self, mock_get_neutron_client, mock_create_neutron_net): - options = { - 'openstack_paras': { - 'name': 'yardstick_net', - 'admin_state_up': 'True' - } - } - args = {"options": options} - obj = CreateNetwork(args, {}) - obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_neutron_net.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + def setUp(self): + + self._mock_create_neutron_net = mock.patch.object( + openstack_utils, 'create_neutron_net') + self.mock_create_neutron_net = self._mock_create_neutron_net.start() + self._mock_get_shade_client = mock.patch.object( + openstack_utils, 'get_shade_client') + self.mock_get_shade_client = self._mock_get_shade_client.start() + self._mock_log = mock.patch.object(create_network, 'LOG') + self.mock_log = self._mock_log.start() + self.args = {'options': {'network_name': 'yardstick_net'}} + self.result = {} + + self._cnet_obj = create_network.CreateNetwork(self.args, mock.ANY) + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_create_neutron_net.stop() + self._mock_get_shade_client.stop() + self._mock_log.stop() + + def test_run(self): + _uuid = uuidutils.generate_uuid() + self._cnet_obj.scenario_cfg = {'output': 'id'} + self.mock_create_neutron_net.return_value = _uuid + output = self._cnet_obj.run(self.result) + self.assertEqual({"network_create": 1}, self.result) + self.assertEqual({'id': _uuid}, output) + self.mock_log.info.asset_called_once_with('Create network successful!') + + def test_run_fail_exception(self): + self.mock_create_neutron_net.return_value = None + with self.assertRaises(exceptions.ScenarioCreateNetworkError): + self._cnet_obj.run(self.result) + self.assertEqual({"network_create": 0}, self.result) + self.mock_log.error.assert_called_once_with( + 'Create network failed!') diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_port.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_port.py index 0f15058da..bea02a630 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_port.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_port.py @@ -24,12 +24,4 @@ class CreatePortTestCase(unittest.TestCase): args = {"options": options} obj = CreatePort(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_neutron_client.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_router.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_router.py index 8f3914b83..3469a2a06 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_router.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_router.py @@ -26,13 +26,5 @@ class CreateRouterTestCase(unittest.TestCase): args = {"options": options} obj = CreateRouter(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_neutron_router.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_neutron_client.assert_called_once() + mock_create_neutron_router.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py index c1c137cda..21158ab17 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_sec_group.py @@ -26,13 +26,5 @@ class CreateSecGroupTestCase(unittest.TestCase): args = {"options": options} obj = CreateSecgroup(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_security_group_full.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_neutron_client.assert_called_once() + mock_create_security_group_full.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_server.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_server.py index 74003b995..9d6d8cb1b 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_server.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_server.py @@ -28,15 +28,7 @@ class CreateServerTestCase(unittest.TestCase): } obj = CreateServer(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_get_glance_client.called) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_instance_and_wait_for_active.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_nova_client.assert_called_once() + mock_get_glance_client.assert_called_once() + mock_get_neutron_client.assert_called_once() + mock_create_instance_and_wait_for_active.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py index b7f29dfe4..856e985c4 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py @@ -6,35 +6,53 @@ # 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.create_subnet import CreateSubnet +from yardstick.common import openstack_utils +from yardstick.common import exceptions +from yardstick.benchmark.scenarios.lib import create_subnet class CreateSubnetTestCase(unittest.TestCase): - @mock.patch('yardstick.common.openstack_utils.get_neutron_client') - @mock.patch('yardstick.common.openstack_utils.create_neutron_subnet') - def test_create_subnet(self, mock_get_neutron_client, mock_create_neutron_subnet): - options = { - 'openstack_paras': { - 'network_id': '123-123-123', - 'name': 'yardstick_subnet', - 'cidr': '10.10.10.0/24', - 'ip_version': '4' - } - } - args = {"options": options} - obj = CreateSubnet(args, {}) - obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_create_neutron_subnet.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + def setUp(self): + + self._mock_create_neutron_subnet = mock.patch.object( + openstack_utils, 'create_neutron_subnet') + self.mock_create_neutron_subnet = ( + self._mock_create_neutron_subnet.start()) + self._mock_get_shade_client = mock.patch.object( + openstack_utils, 'get_shade_client') + self.mock_get_shade_client = self._mock_get_shade_client.start() + self._mock_log = mock.patch.object(create_subnet, 'LOG') + self.mock_log = self._mock_log.start() + self.args = {'options': {'network_name_or_id': 'yardstick_net'}} + self.result = {"subnet_create": 0} + + self._csubnet_obj = create_subnet.CreateSubnet(self.args, mock.ANY) + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_create_neutron_subnet.stop() + self._mock_get_shade_client.stop() + self._mock_log.stop() + + def test_run(self): + _uuid = uuidutils.generate_uuid() + self._csubnet_obj.scenario_cfg = {'output': 'id'} + self.mock_create_neutron_subnet.return_value = _uuid + output = self._csubnet_obj.run(self.result) + self.assertDictEqual({"subnet_create": 1}, self.result) + self.assertDictEqual({'id': _uuid}, output) + self.mock_log.info.asset_called_once_with('Create subnet successful!') + + def test_run_fail(self): + self._csubnet_obj.scenario_cfg = {'output': 'id'} + self.mock_create_neutron_subnet.return_value = None + with self.assertRaises(exceptions.ScenarioCreateSubnetError): + self._csubnet_obj.run(self.result) + self.assertDictEqual({"subnet_create": 0}, self.result) + self.mock_log.error.assert_called_once_with('Create subnet failed!') diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_volume.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_volume.py index ca055db2f..30333dda8 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_volume.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_volume.py @@ -94,15 +94,7 @@ class CreateVolumeTestCase(unittest.TestCase): args = {"options": options} scenario = create_volume.CreateVolume(args, {}) scenario.run() - self.assertTrue(mock_create_volume.called) - self.assertTrue(mock_image_id.called) - self.assertTrue(mock_get_glance_client.called) - self.assertTrue(mock_get_cinder_client.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_create_volume.assert_called_once() + mock_image_id.assert_called_once() + mock_get_glance_client.assert_called_once() + mock_get_cinder_client.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py index 4a91b8939..24dbf8a16 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_flavor.py @@ -23,13 +23,5 @@ class DeleteFlavorTestCase(unittest.TestCase): args = {"options": options} obj = DeleteFlavor(args, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_delete_flavor.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_nova_client.assert_called_once() + mock_delete_flavor.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_floating_ip.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_floating_ip.py index df2321292..3185ec59f 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_floating_ip.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_floating_ip.py @@ -23,13 +23,5 @@ class DeleteFloatingIpTestCase(unittest.TestCase): args = {"options": options} obj = DeleteFloatingIp(args, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_delete_floating_ip.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_nova_client.assert_called_once() + mock_delete_floating_ip.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py index 9edc2ff1d..e382d46fa 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py @@ -24,14 +24,6 @@ class DeleteImageTestCase(unittest.TestCase): args = {"options": options} obj = DeleteImage(args, {}) obj.run({}) - self.assertTrue(mock_delete_image.called) - self.assertTrue(mock_image_id.called) - self.assertTrue(mock_get_glance_client.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_delete_image.assert_called_once() + mock_image_id.assert_called_once() + mock_get_glance_client.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_keypair.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_keypair.py index 73894a903..6e790ba90 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_keypair.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_keypair.py @@ -23,13 +23,5 @@ class DeleteKeypairTestCase(unittest.TestCase): args = {"options": options} obj = DeleteKeypair(args, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_delete_keypair.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_nova_client.assert_called_once() + mock_delete_keypair.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_port.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_port.py index de3179b2d..9fd318580 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_port.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_port.py @@ -22,12 +22,4 @@ class DeletePortTestCase(unittest.TestCase): args = {"options": options} obj = DeletePort(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_neutron_client.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router.py index 73cb81278..b76100f19 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router.py @@ -6,30 +6,49 @@ # 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_router import DeleteRouter +from yardstick.common import openstack_utils +from yardstick.common import exceptions +from yardstick.benchmark.scenarios.lib import delete_router class DeleteRouterTestCase(unittest.TestCase): - @mock.patch('yardstick.common.openstack_utils.get_neutron_client') - @mock.patch('yardstick.common.openstack_utils.delete_neutron_router') - def test_delete_router(self, mock_get_neutron_client, mock_delete_neutron_router): - options = { - 'router_id': '123-123-123' - } - args = {"options": options} - obj = DeleteRouter(args, {}) - obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_delete_neutron_router.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + def setUp(self): + self._mock_delete_neutron_router = mock.patch.object( + openstack_utils, 'delete_neutron_router') + self.mock_delete_neutron_router = ( + self._mock_delete_neutron_router.start()) + self._mock_get_shade_client = mock.patch.object( + openstack_utils, 'get_shade_client') + self.mock_get_shade_client = self._mock_get_shade_client.start() + self._mock_log = mock.patch.object(delete_router, 'LOG') + self.mock_log = self._mock_log.start() + self.args = {'options': {'router_id': uuidutils.generate_uuid()}} + self.result = {"delete_router": 0} + + self._del_obj = delete_router.DeleteRouter(self.args, mock.ANY) + + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_delete_neutron_router.stop() + self._mock_get_shade_client.stop() + self._mock_log.stop() + + def test_run(self): + self.mock_delete_neutron_router.return_value = True + self.assertIsNone(self._del_obj.run(self.result)) + self.assertEqual({"delete_router": 1}, self.result) + self.mock_log.info.assert_called_once_with("Delete router successful!") + + def test_run_fail(self): + self.mock_delete_neutron_router.return_value = False + with self.assertRaises(exceptions.ScenarioDeleteRouterError): + self._del_obj.run(self.result) + self.assertEqual({"delete_router": 0}, self.result) + self.mock_log.error.assert_called_once_with("Delete router failed!") diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_gateway.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_gateway.py index 3cfc4ed21..0c9cf7c17 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_gateway.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_gateway.py @@ -23,13 +23,5 @@ class DeleteRouterGatewayTestCase(unittest.TestCase): args = {"options": options} obj = DeleteRouterGateway(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_remove_gateway_router.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_neutron_client.assert_called_once() + mock_remove_gateway_router.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_interface.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_interface.py index 67aff1091..9e9c5a5b6 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_interface.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_router_interface.py @@ -24,13 +24,5 @@ class DeleteRouterInterfaceTestCase(unittest.TestCase): args = {"options": options} obj = DeleteRouterInterface(args, {}) obj.run({}) - self.assertTrue(mock_get_neutron_client.called) - self.assertTrue(mock_remove_interface_router.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_neutron_client.assert_called_once() + mock_remove_interface_router.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_server.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_server.py index 622ead5ac..eee565de7 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_server.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_server.py @@ -23,13 +23,5 @@ class DeleteServerTestCase(unittest.TestCase): args = {"options": options} obj = DeleteServer(args, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_delete_instance.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_nova_client.assert_called_once() + mock_delete_instance.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_volume.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_volume.py index 9438b077a..93f76e819 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_volume.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_volume.py @@ -23,13 +23,5 @@ class DeleteVolumeTestCase(unittest.TestCase): args = {"options": options} obj = DeleteVolume(args, {}) obj.run({}) - self.assertTrue(mock_get_cinder_client.called) - self.assertTrue(mock_delete_volume.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_cinder_client.assert_called_once() + mock_delete_volume.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_detach_volume.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_detach_volume.py index 87af63a55..9794d2129 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_detach_volume.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_detach_volume.py @@ -23,12 +23,4 @@ class DetachVolumeTestCase(unittest.TestCase): args = {"options": options} obj = DetachVolume(args, {}) obj.run({}) - self.assertTrue(mock_detach_volume.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_detach_volume.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_flavor.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_flavor.py index bf12e0a32..15a6f7c8f 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_flavor.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_flavor.py @@ -22,12 +22,4 @@ class GetFlavorTestCase(unittest.TestCase): args = {"options": options} obj = GetFlavor(args, {}) obj.run({}) - self.assertTrue(mock_get_flavor_by_name.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_flavor_by_name.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py index f046c92ea..879b2b988 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py @@ -25,9 +25,9 @@ class GetMigrateTargetHostTestCase(unittest.TestCase): mock_get_nova_client): obj = GetMigrateTargetHost({}, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_get_current_host_name.called) - self.assertTrue(mock_get_migrate_host.called) + mock_get_nova_client.assert_called_once() + mock_get_current_host_name.assert_called_once() + mock_get_migrate_host.assert_called_once() @mock.patch('{}.openstack_utils.get_nova_client'.format(BASE)) def test_get_migrate_host(self, mock_get_nova_client): @@ -39,13 +39,5 @@ class GetMigrateTargetHostTestCase(unittest.TestCase): mock_get_nova_client().hosts.list_all.return_value = [A('compute')] obj = GetMigrateTargetHost({}, {}) host = obj._get_migrate_host('host5') - self.assertTrue(mock_get_nova_client.called) + mock_get_nova_client.assert_called() self.assertEqual(host, 'host4') - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py index 50d5238d7..bea978b8a 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py @@ -44,8 +44,8 @@ class GetNumaInfoTestCase(unittest.TestCase): } obj = GetNumaInfo(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_get_current_host_name.called) - self.assertTrue(mock_check_numa_node.called) + mock_get_current_host_name.assert_called_once() + mock_check_numa_node.assert_called_once() @mock.patch('yardstick.ssh.SSH.from_node') @mock.patch('{}.GetNumaInfo._get_current_host_name'.format(BASE)) @@ -101,11 +101,3 @@ class GetNumaInfoTestCase(unittest.TestCase): obj = GetNumaInfo(scenario_cfg, {}) result = obj._get_current_host_name('1') self.assertEqual(result, 'host5') - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server.py index aebbf5416..83ec903bc 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server.py @@ -25,8 +25,8 @@ class GetServerTestCase(unittest.TestCase): } obj = GetServer(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - self.assertTrue(mock_get_server_by_name.called) + mock_get_nova_client.assert_called_once() + mock_get_server_by_name.assert_called_once() @mock.patch('yardstick.common.openstack_utils.get_nova_client') def test_get_server_with_id(self, mock_get_nova_client): @@ -39,12 +39,4 @@ class GetServerTestCase(unittest.TestCase): mock_get_nova_client().servers.get.return_value = None obj = GetServer(scenario_cfg, {}) obj.run({}) - self.assertTrue(mock_get_nova_client.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_get_nova_client.assert_called() diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py index 3d20d5439..04fca16aa 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py @@ -31,11 +31,3 @@ class GetServerIpTestCase(unittest.TestCase): obj = GetServerIp(scenario_cfg, {}) result = obj.run({}) self.assertEqual(result, {'ip': '127.0.0.1'}) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py index 4d3745230..74144afd5 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Ericsson AB and others. # @@ -67,7 +65,7 @@ class IperfTestCase(unittest.TestCase): p.target = mock_ssh.SSH.from_node() p.teardown() - self.assertTrue(mock_ssh.SSH.from_node().close.called) + mock_ssh.SSH.from_node().close.assert_called() mock_ssh.SSH.from_node().execute.assert_called_with("pkill iperf3") def test_iperf_successful_no_sla(self, mock_ssh): @@ -193,10 +191,3 @@ class IperfTestCase(unittest.TestCase): with open(output) as f: sample_output = f.read() return sample_output - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py new file mode 100644 index 000000000..620155c7e --- /dev/null +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python + +# Copyright 2017 Nokia +# +# 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. + +# Unittest for yardstick.benchmark.scenarios.networking.MoongenTestPMD + +from __future__ import absolute_import +try: + from unittest import mock +except ImportError: + import mock +import unittest + +from yardstick.benchmark.scenarios.networking import moongen_testpmd + + +@mock.patch('yardstick.benchmark.scenarios.networking.moongen_testpmd.subprocess') +class MoongenTestPMDTestCase(unittest.TestCase): + + def setUp(self): + self.ctx = { + "host": { + "ip": "10.229.47.137", + "user": "ubuntu", + "password": "ubuntu", + }, + } + self.TestPMDargs = { + 'task_id': "1234-5678", + 'options': { + 'multistream': 1, + 'frame_size': 1024, + 'testpmd_queue': 2, + 'trafficgen_port1': 'ens5', + 'trafficgen_port2': 'ens6', + 'moongen_host_user': 'root', + 'moongen_host_passwd': 'root', + 'moongen_host_ip': '10.5.201.151', + 'moongen_dir': '/home/lua-trafficgen', + 'moongen_runBidirec': 'true', + 'Package_Loss': 0, + 'SearchRuntime': 60, + 'moongen_port1_mac': '88:cf:98:2f:4d:ed', + 'moongen_port2_mac': '88:cf:98:2f:4d:ee', + 'forward_type': 'testpmd', + }, + 'sla': { + 'metrics': 'throughput_rx_mpps', + 'throughput_rx_mpps': 0.5, + 'action': 'monitor', + } + } + self.L2fwdargs = { + 'task_id': "1234-5678", + 'options': { + 'multistream': 1, + 'frame_size': 1024, + 'testpmd_queue': 2, + 'trafficgen_port1': 'ens5', + 'trafficgen_port2': 'ens6', + 'moongen_host_user': 'root', + 'moongen_host_passwd': 'root', + 'moongen_host_ip': '10.5.201.151', + 'moongen_dir': '/home/lua-trafficgen', + 'moongen_runBidirec': 'true', + 'Package_Loss': 0, + 'SearchRuntime': 60, + 'moongen_port1_mac': '88:cf:98:2f:4d:ed', + 'moongen_port2_mac': '88:cf:98:2f:4d:ee', + 'forward_type': 'l2fwd', + }, + 'sla': { + 'metrics': 'throughput_rx_mpps', + 'throughput_rx_mpps': 0.5, + 'action': 'monitor', + } + } + + self._mock_ssh = mock.patch( + 'yardstick.benchmark.scenarios.networking.moongen_testpmd.ssh') + self.mock_ssh = self._mock_ssh.start() + + self.addCleanup(self._cleanup) + + def _cleanup(self): + self._mock_ssh.stop() + + def test_MoongenTestPMD_setup(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + def test_MoongenTestPMD_teardown(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + p.teardown() + self.assertFalse(p.setup_done) + + def test_MoongenTestPMD_l2fwd_is_forward_setup_no(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + result = p._is_forward_setup() + self.assertFalse(result) + + def test_MoongenTestPMD_l2fwd_is_forward_setup_yes(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + + result = p._is_forward_setup() + self.assertTrue(result) + + def test_MoongenTestPMD_testpmd_is_forward_setup_no(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + + result = p._is_forward_setup() + self.assertFalse(result) + + def test_MoongenTestPMD_testpmd_is_forward_setup_yes(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + result = p._is_forward_setup() + self.assertTrue(result) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_testpmd_forward_setup_first(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + + p.forward_setup() + self.assertFalse(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_testpmd_dpdk_setup_next(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + p.forward_setup() + self.assertTrue(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_l2fwd_forward_setup_first(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + p.forward_setup() + self.assertFalse(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_l2fwd_dpdk_setup_next(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + p.forward_setup() + self.assertTrue(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + def test_moongen_testpmd_generate_config_file(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.generate_config_file(frame_size=1, multistream=1, + runBidirec="True", tg_port1_vlan=1, + tg_port2_vlan=2, SearchRuntime=1, + Package_Loss=0) + self.assertTrue(p.CONFIG_FILE) + + def test_moongen_testpmd_result_to_data_match(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + mock_subprocess.call().execute.return_value = None + result = ("[REPORT]Device 1->0: Tx frames: 420161490 Rx Frames: 420161490" + " frame loss: 0, 0.000000% Rx Mpps: 7.002708\n[REPORT] " + "total: Tx frames: 840321216 Rx Frames: 840321216 frame loss: " + "0, 0.000000% Tx Mpps: 14.005388 Rx Mpps: 14.005388\n'") + p.result_to_data(result=result) + self.assertTrue(p.TO_DATA) + + def test_moongen_testpmd_result_to_data_not_match(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + mock_subprocess.call().execute.return_value = None + result = ("") + p.result_to_data(result=result) + self.assertTrue(p.TO_DATA) + + @mock.patch('time.sleep') + def test_moongen_testpmd_run_ok(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + p.setup_done = True + p.forward_setup_done = True + p.setup() + + # run() specific mocks + p.server = self.mock_ssh.SSH.from_node() + mock_subprocess.call().execute.return_value = None + mock_subprocess.call().execute.return_value = None + result = ("[REPORT]Device 1->0: Tx frames: 420161490 Rx Frames: 420161490" + " frame loss: 0, 0.000000% Rx Mpps: 7.002708\n[REPORT] " + "total: Tx frames: 840321216 Rx Frames: 840321216 frame loss: " + "0, 0.000000% Tx Mpps: 14.005388 Rx Mpps: 14.005388\n'") + self.mock_ssh.SSH.from_node().execute.return_value = ( + 0, result, '') + + test_result = {} + p.run(test_result) + + self.assertEqual(test_result['rx_mpps'], 14.005388) + + def test_moongen_testpmd_run_falied_vsperf_execution(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # run() specific mocks + mock_subprocess.call().execute.return_value = None + mock_subprocess.call().execute.return_value = None + self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + + result = {} + self.assertRaises(RuntimeError, p.run, result) + + def test_moongen_testpmd_run_falied_csv_report(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # run() specific mocks + mock_subprocess.call().execute.return_value = None + mock_subprocess.call().execute.return_value = None + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + + result = {} + self.assertRaises(RuntimeError, p.run, result) + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py index d82a00931..5907562c2 100755 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # @@ -121,10 +119,3 @@ class NetperfTestCase(unittest.TestCase): with open(output) as f: sample_output = f.read() return sample_output - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py index 8be9bb94d..956a9c078 100755 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # @@ -121,10 +119,3 @@ class NetperfNodeTestCase(unittest.TestCase): with open(output) as f: sample_output = f.read() return sample_output - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_netutilization.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_netutilization.py index 1227e056e..4cdfde6b1 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_netutilization.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_netutilization.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd and other. # diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_networkcapacity.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_networkcapacity.py index 3e7a3c5ee..36e8c8a77 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_networkcapacity.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_networkcapacity.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. # diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_nstat.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_nstat.py index 7dd5351b1..b02d58437 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_nstat.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_nstat.py @@ -103,11 +103,3 @@ class NstatTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, n.run, result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py index 06353249a..4adfab120 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Ericsson AB and others. # @@ -92,10 +90,3 @@ class PingTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, p.run, result) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py index d2be6f576..4662c8537 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Ericsson AB and others. # @@ -116,10 +114,3 @@ class PingTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.side_effect = [ (0, 'host1', ''), (1, '', 'FOOBAR')] self.assertRaises(RuntimeError, p.run, result) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py index acd9027d3..6aea03aee 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py @@ -665,11 +665,3 @@ class PktgenTestCase(unittest.TestCase): expected_result["packets_received"] = 149300 expected_result["packetsize"] = 60 self.assertEqual(result, expected_result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py index 99399abdc..976087148 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py @@ -176,11 +176,3 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase): self.mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, p.run, result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py index 1b12bd507..e90fb07c7 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python ############################################################################## # Copyright (c) 2017 Nokia and others. # @@ -192,11 +191,3 @@ class PktgenDPDKTestCase(unittest.TestCase): mock_ssh.SSH().execute.assert_called_with( "sudo /dpdk/destdir/bin/dpdk-procinfo -- --stats-reset > /dev/null 2>&1") - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_sfc.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_sfc.py index 78c0352dd..a5e5e39dc 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_sfc.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_sfc.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Ericsson AB and others. # @@ -68,10 +66,3 @@ class SfcTestCase(unittest.TestCase): self.sfc.setup() self.sfc.run(result) self.sfc.teardown() - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py index fb55b5ea0..9bfbf0752 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,27 +11,29 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# - -# Unittest for yardstick.benchmark.scenarios.networking.test_vnf_generic - -from __future__ import absolute_import +from copy import deepcopy import os -import errno -import unittest -import mock +import sys -from copy import deepcopy +import mock +import unittest -from yardstick.tests.unit import STL_MOCKS -from yardstick.benchmark.scenarios.networking.vnf_generic import \ - SshManager, NetworkServiceTestCase, IncorrectConfig, \ - open_relative_file +from yardstick import tests +from yardstick.common import utils from yardstick.network_services.collector.subscriber import Collector -from yardstick.network_services.vnf_generic.vnf.base import \ - GenericTrafficGen, GenericVNF +from yardstick.network_services.traffic_profile import base +from yardstick.network_services.vnf_generic import vnfdgen +from yardstick.error import IncorrectConfig +from yardstick.network_services.vnf_generic.vnf.base import GenericTrafficGen +from yardstick.network_services.vnf_generic.vnf.base import GenericVNF + + +stl_patch = mock.patch.dict(sys.modules, tests.STL_MOCKS) +stl_patch.start() +if stl_patch: + from yardstick.benchmark.scenarios.networking import vnf_generic # pylint: disable=unused-argument # disable this for now because I keep forgetting mock patch arg ordering @@ -317,6 +317,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7', 'tc': 'tc_ipv4_1Mflow_64B_packetsize', 'traffic_profile': 'ipv4_throughput_vpe.yaml', + 'extra_args': {'arg1': 'value1', 'arg2': 'value2'}, 'type': 'ISB', 'tc_options': { 'rfc2544': { @@ -345,25 +346,16 @@ class TestNetworkServiceTestCase(unittest.TestCase): }, } - self.s = NetworkServiceTestCase(self.scenario_cfg, self.context_cfg) + self.s = vnf_generic.NetworkServiceTestCase(self.scenario_cfg, + self.context_cfg) def _get_file_abspath(self, filename): curr_path = os.path.dirname(os.path.abspath(__file__)) file_path = os.path.join(curr_path, filename) return file_path - def test_ssh_manager(self): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, "")) - ssh.from_node.return_value = ssh_mock - for _, node_dict in self.context_cfg["nodes"].items(): - with SshManager(node_dict) as conn: - self.assertIsNotNone(conn) - def test___init__(self): - assert self.topology + self.assertIsNotNone(self.topology) def test__get_ip_flow_range_string(self): self.scenario_cfg["traffic_options"]["flow"] = \ @@ -415,7 +407,10 @@ class TestNetworkServiceTestCase(unittest.TestCase): 'public_ip': ['1.1.1.1'], }, } - + # NOTE(ralonsoh): check the expected output. This test could be + # incorrect + # result = {'flow': {'dst_ip0': '152.16.40.2-152.16.40.254', + # 'src_ip0': '152.16.100.2-152.16.100.254'}} self.assertEqual({'flow': {}}, self.s._get_traffic_flow()) def test___get_traffic_flow_error(self): @@ -425,16 +420,16 @@ class TestNetworkServiceTestCase(unittest.TestCase): def test_get_vnf_imp(self): vnfd = COMPLETE_TREX_VNFD['vnfd:vnfd-catalog']['vnfd'][0]['class-name'] - with mock.patch.dict("sys.modules", STL_MOCKS): + with mock.patch.dict(sys.modules, tests.STL_MOCKS): self.assertIsNotNone(self.s.get_vnf_impl(vnfd)) - with self.assertRaises(IncorrectConfig) as raised: - self.s.get_vnf_impl('NonExistentClass') + with self.assertRaises(vnf_generic.IncorrectConfig) as raised: + self.s.get_vnf_impl('NonExistentClass') - exc_str = str(raised.exception) - print(exc_str) - self.assertIn('No implementation', exc_str) - self.assertIn('found in', exc_str) + exc_str = str(raised.exception) + print(exc_str) + self.assertIn('No implementation', exc_str) + self.assertIn('found in', exc_str) def test_load_vnf_models_invalid(self): self.context_cfg["nodes"]['tg__1']['VNF model'] = \ @@ -456,39 +451,37 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.s.load_vnf_models(self.scenario_cfg, self.context_cfg)) def test_map_topology_to_infrastructure(self): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, "")) - ssh.from_node.return_value = ssh_mock - self.s.map_topology_to_infrastructure() + self.s.map_topology_to_infrastructure() nodes = self.context_cfg["nodes"] - self.assertEqual( - "../../vnf_descriptors/tg_rfc2544_tpl.yaml", nodes['tg__1']['VNF model']) - self.assertEqual("../../vnf_descriptors/vpe_vnf.yaml", + self.assertEqual('../../vnf_descriptors/tg_rfc2544_tpl.yaml', + nodes['tg__1']['VNF model']) + self.assertEqual('../../vnf_descriptors/vpe_vnf.yaml', nodes['vnf__1']['VNF model']) def test_map_topology_to_infrastructure_insufficient_nodes(self): - del self.context_cfg['nodes']['vnf__1'] - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(1, SYS_CLASS_NET + IP_ADDR_SHOW, "")) - ssh.from_node.return_value = ssh_mock + cfg = deepcopy(self.context_cfg) + del cfg['nodes']['vnf__1'] + cfg_patch = mock.patch.object(self.s, 'context_cfg', cfg) + with cfg_patch: with self.assertRaises(IncorrectConfig): self.s.map_topology_to_infrastructure() def test_map_topology_to_infrastructure_config_invalid(self): - cfg = dict(self.context_cfg) + ssh_mock = mock.Mock() + ssh_mock.execute.return_value = 0, SYS_CLASS_NET + IP_ADDR_SHOW, "" + + cfg = deepcopy(self.s.context_cfg) + + # delete all, we don't know which will come first del cfg['nodes']['vnf__1']['interfaces']['xe0']['local_mac'] - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, "")) - ssh.from_node.return_value = ssh_mock + del cfg['nodes']['vnf__1']['interfaces']['xe1']['local_mac'] + del cfg['nodes']['tg__1']['interfaces']['xe0']['local_mac'] + del cfg['nodes']['tg__1']['interfaces']['xe1']['local_mac'] + config_patch = mock.patch.object(self.s, 'context_cfg', cfg) + with config_patch: with self.assertRaises(IncorrectConfig): self.s.map_topology_to_infrastructure() @@ -503,10 +496,8 @@ class TestNetworkServiceTestCase(unittest.TestCase): for interface in self.tg__1['interfaces'].values(): del interface['local_mac'] - with mock.patch( - "yardstick.benchmark.scenarios.networking.vnf_generic.LOG"): - with self.assertRaises(IncorrectConfig) as raised: - self.s._resolve_topology() + with self.assertRaises(vnf_generic.IncorrectConfig) as raised: + self.s._resolve_topology() self.assertIn('not found', str(raised.exception)) @@ -518,10 +509,8 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.s.topology["vld"][0]['vnfd-connection-point-ref'].append( self.s.topology["vld"][0]['vnfd-connection-point-ref'][0]) - with mock.patch( - "yardstick.benchmark.scenarios.networking.vnf_generic.LOG"): - with self.assertRaises(IncorrectConfig) as raised: - self.s._resolve_topology() + with self.assertRaises(vnf_generic.IncorrectConfig) as raised: + self.s._resolve_topology() self.assertIn('wrong endpoint count', str(raised.exception)) @@ -529,10 +518,8 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.s.topology["vld"][0]['vnfd-connection-point-ref'] = \ self.s.topology["vld"][0]['vnfd-connection-point-ref'][:1] - with mock.patch( - "yardstick.benchmark.scenarios.networking.vnf_generic.LOG"): - with self.assertRaises(IncorrectConfig) as raised: - self.s._resolve_topology() + with self.assertRaises(vnf_generic.IncorrectConfig) as raised: + self.s._resolve_topology() self.assertIn('wrong endpoint count', str(raised.exception)) @@ -578,7 +565,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs) self.s._fill_traffic_profile = \ mock.Mock(return_value=TRAFFIC_PROFILE) - self.assertEqual(None, self.s.setup()) + self.assertIsNone(self.s.setup()) def test_setup_exception(self): with mock.patch("yardstick.ssh.SSH") as ssh: @@ -625,15 +612,48 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.assertEqual({'imix': {'64B': 100}}, self.s._get_traffic_imix()) - def test__fill_traffic_profile(self): - with mock.patch.dict("sys.modules", STL_MOCKS): - self.scenario_cfg["traffic_profile"] = \ - self._get_file_abspath("ipv4_throughput_vpe.yaml") - self.scenario_cfg["traffic_options"]["flow"] = \ - self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml") - self.scenario_cfg["traffic_options"]["imix"] = \ - self._get_file_abspath("imix_voice.yaml") - self.assertIsNotNone(self.s._fill_traffic_profile()) + @mock.patch.object(base.TrafficProfile, 'get') + @mock.patch.object(vnfdgen, 'generate_vnfd') + def test__fill_traffic_profile(self, mock_generate, mock_tprofile_get): + fake_tprofile = mock.Mock() + fake_vnfd = mock.Mock() + with mock.patch.object(self.s, '_get_traffic_profile', + return_value=fake_tprofile) as mock_get_tp: + mock_generate.return_value = fake_vnfd + self.s._fill_traffic_profile() + mock_get_tp.assert_called_once() + mock_generate.assert_called_once_with( + fake_tprofile, + {'downlink': {}, + 'extra_args': {'arg1': 'value1', 'arg2': 'value2'}, + 'flow': {'flow': {}}, + 'imix': {'imix': {'64B': 100}}, + 'uplink': {}} + ) + mock_tprofile_get.assert_called_once_with(fake_vnfd) + + @mock.patch.object(utils, 'open_relative_file') + def test__get_topology(self, mock_open_path): + self.s.scenario_cfg['topology'] = 'fake_topology' + self.s.scenario_cfg['task_path'] = 'fake_path' + mock_open_path.side_effect = mock.mock_open(read_data='fake_data') + self.assertEqual('fake_data', self.s._get_topology()) + mock_open_path.assert_called_once_with('fake_topology', 'fake_path') + + @mock.patch.object(vnfdgen, 'generate_vnfd') + def test__render_topology(self, mock_generate): + fake_topology = 'fake_topology' + mock_generate.return_value = {'nsd:nsd-catalog': {'nsd': ['fake_nsd']}} + with mock.patch.object(self.s, '_get_topology', + return_value=fake_topology) as mock_get_topology: + self.s._render_topology() + mock_get_topology.assert_called_once() + + mock_generate.assert_called_once_with( + fake_topology, + {'extra_args': {'arg1': 'value1', 'arg2': 'value2'}} + ) + self.assertEqual(self.s.topology, 'fake_nsd') def test_teardown(self): vnf = mock.Mock(autospec=GenericVNF) @@ -658,141 +678,3 @@ class TestNetworkServiceTestCase(unittest.TestCase): mock.Mock(return_value=True) with self.assertRaises(RuntimeError): self.s.teardown() - - SAMPLE_NETDEVS = { - 'enp11s0': { - 'address': '0a:de:ad:be:ef:f5', - 'device': '0x1533', - 'driver': 'igb', - 'ifindex': '2', - 'interface_name': 'enp11s0', - 'operstate': 'down', - 'pci_bus_id': '0000:0b:00.0', - 'subsystem_device': '0x1533', - 'subsystem_vendor': '0x15d9', - 'vendor': '0x8086' - }, - 'lan': { - 'address': '0a:de:ad:be:ef:f4', - 'device': '0x153a', - 'driver': 'e1000e', - 'ifindex': '3', - 'interface_name': 'lan', - 'operstate': 'up', - 'pci_bus_id': '0000:00:19.0', - 'subsystem_device': '0x153a', - 'subsystem_vendor': '0x15d9', - 'vendor': '0x8086' - } - } - - SAMPLE_VM_NETDEVS = { - 'eth1': { - 'address': 'fa:de:ad:be:ef:5b', - 'device': '0x0001', - 'driver': 'virtio_net', - 'ifindex': '3', - 'interface_name': 'eth1', - 'operstate': 'down', - 'pci_bus_id': '0000:00:04.0', - 'vendor': '0x1af4' - } - } - - def test_parse_netdev_info(self): - output = """\ -/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/ifindex:2 -/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/address:0a:de:ad:be:ef:f5 -/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/operstate:down -/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/vendor:0x8086 -/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/device:0x1533 -/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_vendor:0x15d9 -/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_device:0x1533 -/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/driver:igb -/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/pci_bus_id:0000:0b:00.0 -/sys/devices/pci0000:00/0000:00:19.0/net/lan/ifindex:3 -/sys/devices/pci0000:00/0000:00:19.0/net/lan/address:0a:de:ad:be:ef:f4 -/sys/devices/pci0000:00/0000:00:19.0/net/lan/operstate:up -/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/vendor:0x8086 -/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/device:0x153a -/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_vendor:0x15d9 -/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_device:0x153a -/sys/devices/pci0000:00/0000:00:19.0/net/lan/driver:e1000e -/sys/devices/pci0000:00/0000:00:19.0/net/lan/pci_bus_id:0000:00:19.0 -""" - res = NetworkServiceTestCase.parse_netdev_info(output) - assert res == self.SAMPLE_NETDEVS - - def test_parse_netdev_info_virtio(self): - output = """\ -/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/ifindex:3 -/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/address:fa:de:ad:be:ef:5b -/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/operstate:down -/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/vendor:0x1af4 -/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/device:0x0001 -/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/driver:virtio_net -""" - res = NetworkServiceTestCase.parse_netdev_info(output) - assert res == self.SAMPLE_VM_NETDEVS - - def test_probe_missing_values(self): - netdevs = self.SAMPLE_NETDEVS.copy() - network = {'local_mac': '0a:de:ad:be:ef:f5'} - NetworkServiceTestCase._probe_missing_values(netdevs, network) - assert network['vpci'] == '0000:0b:00.0' - - network = {'local_mac': '0a:de:ad:be:ef:f4'} - NetworkServiceTestCase._probe_missing_values(netdevs, network) - assert network['vpci'] == '0000:00:19.0' - - # TODO: Split this into several tests, for different IOError sub-types - def test_open_relative_path(self): - mock_open = mock.mock_open() - mock_open_result = mock_open() - mock_open_call_count = 1 # initial call to get result - - module_name = \ - 'yardstick.benchmark.scenarios.networking.vnf_generic.open' - - # test - with mock.patch(module_name, mock_open, create=True): - self.assertEqual(open_relative_file( - 'foo', 'bar'), mock_open_result) - - mock_open_call_count += 1 # one more call expected - self.assertEqual(mock_open.call_count, mock_open_call_count) - self.assertIn('foo', mock_open.call_args_list[-1][0][0]) - self.assertNotIn('bar', mock_open.call_args_list[-1][0][0]) - - def open_effect(*args, **kwargs): - if kwargs.get('name', args[0]) == os.path.join('bar', 'foo'): - return mock_open_result - raise IOError(errno.ENOENT, 'not found') - - mock_open.side_effect = open_effect - self.assertEqual(open_relative_file( - 'foo', 'bar'), mock_open_result) - - mock_open_call_count += 2 # two more calls expected - self.assertEqual(mock_open.call_count, mock_open_call_count) - self.assertIn('foo', mock_open.call_args_list[-1][0][0]) - self.assertIn('bar', mock_open.call_args_list[-1][0][0]) - - # test an IOError of type ENOENT - mock_open.side_effect = IOError(errno.ENOENT, 'not found') - with self.assertRaises(IOError): - # the second call still raises - open_relative_file('foo', 'bar') - - mock_open_call_count += 2 # two more calls expected - self.assertEqual(mock_open.call_count, mock_open_call_count) - self.assertIn('foo', mock_open.call_args_list[-1][0][0]) - self.assertIn('bar', mock_open.call_args_list[-1][0][0]) - - # test an IOError other than ENOENT - mock_open.side_effect = IOError(errno.EBUSY, 'busy') - with self.assertRaises(IOError): - open_relative_file('foo', 'bar') - - mock_open_call_count += 1 # one more call expected - self.assertEqual(mock_open.call_count, mock_open_call_count) diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py index be8ac55d0..419605b26 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright 2016 Intel Corporation. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -126,11 +124,3 @@ class VsperfTestCase(unittest.TestCase): result = {} self.assertRaises(RuntimeError, p.run, result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() 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 1923960e9..1d2278e21 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py @@ -211,11 +211,3 @@ class VsperfDPDKTestCase(unittest.TestCase): result = {} self.assertRaises(RuntimeError, self.scenario.run, result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/parser/test_parser.py b/yardstick/tests/unit/benchmark/scenarios/parser/test_parser.py index ee2bbc07d..9fd5cce38 100644 --- a/yardstick/tests/unit/benchmark/scenarios/parser/test_parser.py +++ b/yardstick/tests/unit/benchmark/scenarios/parser/test_parser.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and other. # @@ -70,10 +68,3 @@ class ParserTestCase(unittest.TestCase): self.mock_call.return_value = 0 self.scenario.teardown() self.assertTrue(self.scenario.teardown_done) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/storage/test_bonnie.py b/yardstick/tests/unit/benchmark/scenarios/storage/test_bonnie.py index b98dceae7..d78506584 100644 --- a/yardstick/tests/unit/benchmark/scenarios/storage/test_bonnie.py +++ b/yardstick/tests/unit/benchmark/scenarios/storage/test_bonnie.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. # @@ -9,8 +7,6 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -# Unittest for yardstick.benchmark.scenarios.storage.bonnie.Bonnie - from __future__ import absolute_import import unittest @@ -65,11 +61,3 @@ class BonnieTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, b.run, self.result) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py b/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py index 0cffea224..f149cee69 100644 --- a/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py +++ b/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Ericsson AB and others. # @@ -63,6 +61,22 @@ class FioTestCase(unittest.TestCase): } args = {'options': options} p = fio.Fio(args, self.ctx) + mock_ssh.SSH.from_node().execute.return_value = (0, '/dev/vdb', '') + p.setup() + + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + def test_fio_job_file_no_disk__setup(self, mock_ssh): + + options = { + 'job_file': 'job_file.ini', + 'directory': '/FIO_Test' + } + args = {'options': options} + p = fio.Fio(args, self.ctx) + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') p.setup() mock_ssh.SSH.from_node().execute.return_value = (0, '', '') @@ -263,11 +277,3 @@ class FioTestCase(unittest.TestCase): with open(output) as f: sample_output = f.read() return sample_output - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/storage/test_storagecapacity.py b/yardstick/tests/unit/benchmark/scenarios/storage/test_storagecapacity.py index 095674f72..c1c731b0a 100644 --- a/yardstick/tests/unit/benchmark/scenarios/storage/test_storagecapacity.py +++ b/yardstick/tests/unit/benchmark/scenarios/storage/test_storagecapacity.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. # @@ -99,10 +97,3 @@ class StorageCapacityTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, c.run, self.result) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/storage/test_storperf.py b/yardstick/tests/unit/benchmark/scenarios/storage/test_storperf.py index 52786d7cb..5844746ab 100644 --- a/yardstick/tests/unit/benchmark/scenarios/storage/test_storperf.py +++ b/yardstick/tests/unit/benchmark/scenarios/storage/test_storperf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2016 Huawei Technologies Co.,Ltd. # @@ -233,10 +231,3 @@ class StorPerfTestCase(unittest.TestCase): s = storperf.StorPerf(args, self.ctx) self.assertRaises(AssertionError, s.teardown(), self.result) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/benchmark/scenarios/test_base.py b/yardstick/tests/unit/benchmark/scenarios/test_base.py index a95e6bc86..985338532 100644 --- a/yardstick/tests/unit/benchmark/scenarios/test_base.py +++ b/yardstick/tests/unit/benchmark/scenarios/test_base.py @@ -13,12 +13,11 @@ # License for the specific language governing permissions and limitations # under the License. -import unittest - from yardstick.benchmark.scenarios import base +from yardstick.tests.unit import base as ut_base -class ScenarioTestCase(unittest.TestCase): +class ScenarioTestCase(ut_base.BaseUnitTestCase): def test_get_scenario_type(self): scenario_type = 'dummy scenario' @@ -87,7 +86,7 @@ class ScenarioTestCase(unittest.TestCase): str(exc.exception)) -class IterScenarioClassesTestCase(unittest.TestCase): +class IterScenarioClassesTestCase(ut_base.BaseUnitTestCase): def test_no_scenario_type_defined(self): some_existing_scenario_class_names = [ diff --git a/yardstick/tests/unit/common/banned_modules/__init__.py b/yardstick/tests/unit/common/banned_modules/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/unit/common/banned_modules/__init__.py diff --git a/yardstick/tests/unit/common/banned_modules/banned_module.py b/yardstick/tests/unit/common/banned_modules/banned_module.py new file mode 100644 index 000000000..f57f939d2 --- /dev/null +++ b/yardstick/tests/unit/common/banned_modules/banned_module.py @@ -0,0 +1,17 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class BannedClass(object): + pass diff --git a/yardstick/tests/unit/common/banned_modules/importing_module.py b/yardstick/tests/unit/common/banned_modules/importing_module.py new file mode 100644 index 000000000..fc2542f0c --- /dev/null +++ b/yardstick/tests/unit/common/banned_modules/importing_module.py @@ -0,0 +1,21 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from yardstick.common import import_tools +from yardstick.tests.unit.common.banned_modules import banned_module + + +@import_tools.decorator_banned_modules +class ImportingClass(banned_module.BannedClass): + pass diff --git a/yardstick/tests/unit/common/test_ansible_common.py b/yardstick/tests/unit/common/test_ansible_common.py index 89ea128af..48d8a60c8 100644 --- a/yardstick/tests/unit/common/test_ansible_common.py +++ b/yardstick/tests/unit/common/test_ansible_common.py @@ -17,6 +17,7 @@ from __future__ import absolute_import import os import tempfile +import shutil from collections import defaultdict import mock @@ -99,7 +100,7 @@ class AnsibleNodeTestCase(unittest.TestCase): def test_ansible_node_getattr(self): a = ansible_common.AnsibleNode({"name": "name"}) - self.assertEqual(getattr(a, "nosuch", None), None) + self.assertIsNone(getattr(a, "nosuch", None)) class AnsibleNodeDictTestCase(unittest.TestCase): @@ -145,7 +146,7 @@ class AnsibleNodeDictTestCase(unittest.TestCase): class AnsibleCommonTestCase(unittest.TestCase): def test_get_timeouts(self): - self.assertAlmostEquals(ansible_common.AnsibleCommon.get_timeout(-100), 1200.0) + self.assertAlmostEqual(ansible_common.AnsibleCommon.get_timeout(-100), 1200.0) def test__init__(self): ansible_common.AnsibleCommon({}) @@ -246,3 +247,18 @@ class AnsibleCommonTestCase(unittest.TestCase): a.execute_ansible('', d, ansible_check=True, verbose=True) finally: os.rmdir(d) + + def test_get_sut_info(self): + d = tempfile.mkdtemp() + a = ansible_common.AnsibleCommon({}) + try: + a.get_sut_info(d) + finally: + shutil.rmtree(d) + + def test_get_sut_info_not_exist(self): + a = ansible_common.AnsibleCommon({}) + try: + a.get_sut_info('/hello/world') + except OSError: + pass diff --git a/yardstick/tests/unit/common/test_httpClient.py b/yardstick/tests/unit/common/test_httpClient.py index eb09d1a52..12a8be3a0 100644 --- a/yardstick/tests/unit/common/test_httpClient.py +++ b/yardstick/tests/unit/common/test_httpClient.py @@ -33,11 +33,3 @@ class HttpClientTestCase(unittest.TestCase): url = 'http://localhost:5000/hello' httpClient.HttpClient().get(url) mock_requests.get.assert_called_with(url) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/common/test_import_tools.py b/yardstick/tests/unit/common/test_import_tools.py new file mode 100644 index 000000000..c8fe5fde0 --- /dev/null +++ b/yardstick/tests/unit/common/test_import_tools.py @@ -0,0 +1,46 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +from yardstick.common import exceptions as y_exc +from yardstick.common import import_tools + + +@import_tools.decorator_banned_modules +class DummyClass(object): + pass + + +class DecoratorBannedModule(unittest.TestCase): + + MODULE = 'yardstick.tests.unit.common.banned_modules.banned_module' + + def test_passt(self): + self.assertIsNotNone(DummyClass()) + + def test_banned_module(self): + import_tools.BANNED_MODULES[self.MODULE] = 'Banned module!!' + from yardstick.tests.unit.common.banned_modules import importing_module + self.addCleanup(self._remove_module) + + with self.assertRaises(y_exc.YardstickBannedModuleImported) as exc: + importing_module.ImportingClass() + + msg = ('Module "%s" cannnot be imported. Reason: "Banned module!!"' + % self.MODULE) + self.assertEqual(msg, str(exc.exception)) + + def _remove_module(self): + del import_tools.BANNED_MODULES[self.MODULE] diff --git a/yardstick/tests/unit/common/test_openstack_utils.py b/yardstick/tests/unit/common/test_openstack_utils.py index 8a2f5f95b..c6b0f46b2 100644 --- a/yardstick/tests/unit/common/test_openstack_utils.py +++ b/yardstick/tests/unit/common/test_openstack_utils.py @@ -54,7 +54,7 @@ class GetNetworkIdTestCase(unittest.TestCase): output = openstack_utils.get_network_id(mock_shade_client, 'network_name') - self.assertEqual(None, output) + self.assertIsNone(output) class DeleteNeutronNetTestCase(unittest.TestCase): @@ -83,3 +83,81 @@ class DeleteNeutronNetTestCase(unittest.TestCase): 'network_id') self.assertFalse(output) mock_logger.error.assert_called_once() + + +class CreateNeutronNetTestCase(unittest.TestCase): + + def setUp(self): + self.mock_shade_client = mock.Mock() + self.network_name = 'name' + self.mock_shade_client.create_network = mock.Mock() + + def test_create_neutron_net(self): + _uuid = uuidutils.generate_uuid() + self.mock_shade_client.create_network.return_value = {'id': _uuid} + output = openstack_utils.create_neutron_net(self.mock_shade_client, + self.network_name) + self.assertEqual(_uuid, output) + + @mock.patch.object(openstack_utils, 'log') + def test_create_neutron_net_exception(self, mock_logger): + self.mock_shade_client.create_network.side_effect = ( + exc.OpenStackCloudException('error message')) + + output = openstack_utils.create_neutron_net(self.mock_shade_client, + self.network_name) + mock_logger.error.assert_called_once() + self.assertIsNone(output) + + +class CreateNeutronSubnetTestCase(unittest.TestCase): + + def setUp(self): + self.mock_shade_client = mock.Mock() + self.network_name_or_id = 'name_or_id' + self.mock_shade_client.create_subnet = mock.Mock() + + def test_create_neutron_subnet(self): + _uuid = uuidutils.generate_uuid() + self.mock_shade_client.create_subnet.return_value = {'id': _uuid} + output = openstack_utils.create_neutron_subnet( + self.mock_shade_client, self.network_name_or_id) + self.assertEqual(_uuid, output) + + @mock.patch.object(openstack_utils, 'log') + def test_create_neutron_subnet_exception(self, mock_logger): + self.mock_shade_client.create_subnet.side_effect = ( + exc.OpenStackCloudException('error message')) + + output = openstack_utils.create_neutron_subnet( + self.mock_shade_client, self.network_name_or_id) + mock_logger.error.assert_called_once() + self.assertIsNone(output) + + +class DeleteNeutronRouterTestCase(unittest.TestCase): + + def setUp(self): + self.mock_shade_client = mock.Mock() + self.mock_shade_client.delete_router = mock.Mock() + + def test_delete_neutron_router(self): + self.mock_shade_client.delete_router.return_value = True + output = openstack_utils.delete_neutron_router(self.mock_shade_client, + 'router_id') + self.assertTrue(output) + + def test_delete_neutron_router_fail(self): + self.mock_shade_client.delete_router.return_value = False + output = openstack_utils.delete_neutron_router(self.mock_shade_client, + 'router_id') + self.assertFalse(output) + + @mock.patch.object(openstack_utils, 'log') + def test_delete_neutron_router_exception(self, mock_logger): + self.mock_shade_client.delete_router.side_effect = ( + exc.OpenStackCloudException('error message')) + output = openstack_utils.delete_neutron_router(self.mock_shade_client, + 'router_id') + mock_logger.error.assert_called_once() + self.assertFalse(output) diff --git a/yardstick/tests/unit/common/test_packages.py b/yardstick/tests/unit/common/test_packages.py new file mode 100644 index 000000000..ba59a3015 --- /dev/null +++ b/yardstick/tests/unit/common/test_packages.py @@ -0,0 +1,88 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import mock +from pip import exceptions as pip_exceptions +from pip.operations import freeze +import unittest + +from yardstick.common import packages + + +class PipExecuteActionTestCase(unittest.TestCase): + + def setUp(self): + self._mock_pip_main = mock.patch.object(packages, '_pip_main') + self.mock_pip_main = self._mock_pip_main.start() + self.mock_pip_main.return_value = 0 + self._mock_freeze = mock.patch.object(freeze, 'freeze') + self.mock_freeze = self._mock_freeze.start() + self.addCleanup(self._cleanup) + + def _cleanup(self): + self._mock_pip_main.stop() + self._mock_freeze.stop() + + def test_pip_execute_action(self): + self.assertEqual(0, packages._pip_execute_action('test_package')) + + def test_remove(self): + self.assertEqual(0, packages._pip_execute_action('test_package', + action='uninstall')) + + def test_install(self): + self.assertEqual(0, packages._pip_execute_action( + 'test_package', action='install', target='temp_dir')) + + def test_pip_execute_action_error(self): + self.mock_pip_main.return_value = 1 + self.assertEqual(1, packages._pip_execute_action('test_package')) + + def test_pip_execute_action_exception(self): + self.mock_pip_main.side_effect = pip_exceptions.PipError + self.assertEqual(1, packages._pip_execute_action('test_package')) + + def test_pip_list(self): + pkg_input = [ + 'XStatic-Rickshaw==1.5.0.0', + 'xvfbwrapper==0.2.9', + '-e git+https://git.opnfv.org/yardstick@50773a24afc02c9652b662ecca' + '2fc5621ea6097a#egg=yardstick', + 'zope.interface==4.4.3' + ] + pkg_dict = { + 'XStatic-Rickshaw': '1.5.0.0', + 'xvfbwrapper': '0.2.9', + 'yardstick': '50773a24afc02c9652b662ecca2fc5621ea6097a', + 'zope.interface': '4.4.3' + } + self.mock_freeze.return_value = pkg_input + + pkg_output = packages.pip_list() + for pkg_name, pkg_version in pkg_output.items(): + self.assertEqual(pkg_dict.get(pkg_name), pkg_version) + + def test_pip_list_single_package(self): + pkg_input = [ + 'XStatic-Rickshaw==1.5.0.0', + 'xvfbwrapper==0.2.9', + '-e git+https://git.opnfv.org/yardstick@50773a24afc02c9652b662ecca' + '2fc5621ea6097a#egg=yardstick', + 'zope.interface==4.4.3' + ] + self.mock_freeze.return_value = pkg_input + + pkg_output = packages.pip_list(pkg_name='xvfbwrapper') + self.assertEqual(1, len(pkg_output)) + self.assertEqual(pkg_output.get('xvfbwrapper'), '0.2.9') diff --git a/yardstick/tests/unit/common/test_template_format.py b/yardstick/tests/unit/common/test_template_format.py index 44aa80333..56253efbc 100644 --- a/yardstick/tests/unit/common/test_template_format.py +++ b/yardstick/tests/unit/common/test_template_format.py @@ -45,10 +45,3 @@ class TemplateFormatTestCase(unittest.TestCase): "Resources: {}\n" \ "Outputs: {}" self.assertRaises(ValueError, template_format.parse, yaml2) - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/common/test_utils.py b/yardstick/tests/unit/common/test_utils.py index b4907addc..9540a39e8 100644 --- a/yardstick/tests/unit/common/test_utils.py +++ b/yardstick/tests/unit/common/test_utils.py @@ -20,6 +20,7 @@ import unittest import yardstick from yardstick import ssh +import yardstick.error from yardstick.common import utils from yardstick.common import constants @@ -126,6 +127,63 @@ class CommonUtilTestCase(unittest.TestCase): ("=".join(item) for item in sorted(flattened_data.items()))) self.assertEqual(result, line) + def test_get_key_with_default_negative(self): + with self.assertRaises(KeyError): + utils.get_key_with_default({}, 'key1') + + @mock.patch('yardstick.common.utils.open', create=True) + def test_(self, mock_open): + mock_open.side_effect = IOError + + with self.assertRaises(IOError): + utils.find_relative_file('my/path', 'task/path') + + self.assertEqual(mock_open.call_count, 2) + + @mock.patch('yardstick.common.utils.open', create=True) + def test_open_relative_path(self, mock_open): + mock_open_result = mock_open() + mock_open_call_count = 1 # initial call to get result + + self.assertEqual(utils.open_relative_file('foo', 'bar'), mock_open_result) + + mock_open_call_count += 1 # one more call expected + self.assertEqual(mock_open.call_count, mock_open_call_count) + self.assertIn('foo', mock_open.call_args_list[-1][0][0]) + self.assertNotIn('bar', mock_open.call_args_list[-1][0][0]) + + def open_effect(*args, **kwargs): + if kwargs.get('name', args[0]) == os.path.join('bar', 'foo'): + return mock_open_result + raise IOError(errno.ENOENT, 'not found') + + mock_open.side_effect = open_effect + self.assertEqual(utils.open_relative_file('foo', 'bar'), mock_open_result) + + mock_open_call_count += 2 # two more calls expected + self.assertEqual(mock_open.call_count, mock_open_call_count) + self.assertIn('foo', mock_open.call_args_list[-1][0][0]) + self.assertIn('bar', mock_open.call_args_list[-1][0][0]) + + # test an IOError of type ENOENT + mock_open.side_effect = IOError(errno.ENOENT, 'not found') + with self.assertRaises(IOError): + # the second call still raises + utils.open_relative_file('foo', 'bar') + + mock_open_call_count += 2 # two more calls expected + self.assertEqual(mock_open.call_count, mock_open_call_count) + self.assertIn('foo', mock_open.call_args_list[-1][0][0]) + self.assertIn('bar', mock_open.call_args_list[-1][0][0]) + + # test an IOError other than ENOENT + mock_open.side_effect = IOError(errno.EBUSY, 'busy') + with self.assertRaises(IOError): + utils.open_relative_file('foo', 'bar') + + mock_open_call_count += 1 # one more call expected + self.assertEqual(mock_open.call_count, mock_open_call_count) + class TestMacAddressToHex(unittest.TestCase): @@ -247,8 +305,8 @@ power management: """ socket_map = utils.SocketTopology.parse_cpuinfo(cpuinfo) - assert sorted(socket_map.keys()) == [0] - assert sorted(socket_map[0].keys()) == [2, 3, 4] + self.assertEqual(sorted(socket_map.keys()), [0]) + self.assertEqual(sorted(socket_map[0].keys()), [2, 3, 4]) def test_single_socket_hyperthread(self): cpuinfo = """\ @@ -335,11 +393,11 @@ power management: """ socket_map = utils.SocketTopology.parse_cpuinfo(cpuinfo) - assert sorted(socket_map.keys()) == [0] - assert sorted(socket_map[0].keys()) == [1, 2, 3] - assert sorted(socket_map[0][1]) == [5] - assert sorted(socket_map[0][2]) == [6] - assert sorted(socket_map[0][3]) == [7] + self.assertEqual(sorted(socket_map.keys()), [0]) + self.assertEqual(sorted(socket_map[0].keys()), [1, 2, 3]) + self.assertEqual(sorted(socket_map[0][1]), [5]) + self.assertEqual(sorted(socket_map[0][2]), [6]) + self.assertEqual(sorted(socket_map[0][3]), [7]) def test_dual_socket_hyperthread(self): cpuinfo = """\ @@ -534,15 +592,15 @@ power management: """ socket_map = utils.SocketTopology.parse_cpuinfo(cpuinfo) - assert sorted(socket_map.keys()) == [0, 1] - assert sorted(socket_map[0].keys()) == [0, 1, 2] - assert sorted(socket_map[1].keys()) == [26, 27, 28] - assert sorted(socket_map[0][0]) == [44] - assert sorted(socket_map[0][1]) == [1] - assert sorted(socket_map[0][2]) == [2] - assert sorted(socket_map[1][26]) == [85] - assert sorted(socket_map[1][27]) == [86] - assert sorted(socket_map[1][28]) == [43, 87] + self.assertEqual(sorted(socket_map.keys()), [0, 1]) + self.assertEqual(sorted(socket_map[0].keys()), [0, 1, 2]) + self.assertEqual(sorted(socket_map[1].keys()), [26, 27, 28]) + self.assertEqual(sorted(socket_map[0][0]), [44]) + self.assertEqual(sorted(socket_map[0][1]), [1]) + self.assertEqual(sorted(socket_map[0][2]), [2]) + self.assertEqual(sorted(socket_map[1][26]), [85]) + self.assertEqual(sorted(socket_map[1][27]), [86]) + self.assertEqual(sorted(socket_map[1][28]), [43, 87]) def test_dual_socket_no_hyperthread(self): cpuinfo = """\ @@ -738,11 +796,11 @@ power management: """ socket_map = utils.SocketTopology.parse_cpuinfo(cpuinfo) processors = socket_map.processors() - assert processors == [1, 2, 43, 44, 85, 86, 87] + self.assertEqual(processors, [1, 2, 43, 44, 85, 86, 87]) cores = socket_map.cores() - assert cores == [0, 1, 2, 26, 27, 28] + self.assertEqual(cores, [0, 1, 2, 26, 27, 28]) sockets = socket_map.sockets() - assert sockets == [0, 1] + self.assertEqual(sockets, [0, 1]) class ChangeObjToDictTestCase(unittest.TestCase): @@ -931,9 +989,9 @@ class TestUtils(unittest.TestCase): def test_error_class(self): with self.assertRaises(RuntimeError): - utils.ErrorClass() + yardstick.error.ErrorClass() - error_instance = utils.ErrorClass(test='') + error_instance = yardstick.error.ErrorClass(test='') with self.assertRaises(AttributeError): error_instance.get_name() diff --git a/yardstick/tests/unit/common/test_yaml_loader.py b/yardstick/tests/unit/common/test_yaml_loader.py index 6c2beb422..e621dcbc5 100644 --- a/yardstick/tests/unit/common/test_yaml_loader.py +++ b/yardstick/tests/unit/common/test_yaml_loader.py @@ -12,7 +12,6 @@ # yardstick: this file is copied from python-heatclient and slightly modified -from __future__ import absolute_import import unittest from yardstick.common import yaml_loader @@ -23,10 +22,3 @@ class TemplateFormatTestCase(unittest.TestCase): def test_parse_to_value_exception(self): self.assertEqual(yaml_loader.yaml_load("string"), u"string") - - -def main(): - unittest.main() - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/dispatcher/test_influxdb.py b/yardstick/tests/unit/dispatcher/test_influxdb.py index bca94e385..c844d4bbb 100644 --- a/yardstick/tests/unit/dispatcher/test_influxdb.py +++ b/yardstick/tests/unit/dispatcher/test_influxdb.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others. # @@ -104,11 +102,3 @@ class InfluxdbDispatcherTestCase(unittest.TestCase): mock_time.time.return_value = 1451461248.925574 self.assertEqual(influxdb._get_nano_timestamp(results), '1451461248925574144') - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/orchestrator/test_heat.py b/yardstick/tests/unit/orchestrator/test_heat.py index e0a353812..aae2487aa 100644 --- a/yardstick/tests/unit/orchestrator/test_heat.py +++ b/yardstick/tests/unit/orchestrator/test_heat.py @@ -9,6 +9,7 @@ import tempfile +import munch import mock from oslo_serialization import jsonutils from oslo_utils import uuidutils @@ -40,12 +41,16 @@ class HeatStackTestCase(unittest.TestCase): self._mock_stack_delete = mock.patch.object(self.heatstack._cloud, 'delete_stack') self.mock_stack_delete = self._mock_stack_delete.start() + self._mock_stack_get = mock.patch.object(self.heatstack._cloud, + 'get_stack') + self.mock_stack_get = self._mock_stack_get.start() self.addCleanup(self._cleanup) def _cleanup(self): self._mock_stack_create.stop() self._mock_stack_delete.stop() + self._mock_stack_get.stop() heat._DEPLOYED_STACKS = {} def test_create(self): @@ -101,6 +106,88 @@ class HeatStackTestCase(unittest.TestCase): self.assertFalse(heat._DEPLOYED_STACKS) self.mock_stack_delete.assert_called_once_with(id, wait=True) + def test_get(self): + # make sure shade/get_stack is called with the appropriate vars + self.mock_stack_get.return_value = munch.Munch( + id="my-existing-stack-id", + outputs=[ + { + u'output_value': u'b734d06a-dec7-...', + u'output_key': u'ares.demo-test-port-network_id', + u'description': u'' + }, + {u'output_value': u'b08da78c-2218-...', + u'output_key': u'ares.demo-test-port-subnet_id', + u'description': u'' + }, + {u'output_value': u'10.0.1.0/24', + u'output_key': u'demo-test-subnet-cidr', + u'description': u'' + }, + {u'output_value': u'b08da78c-2218-...', + u'output_key': u'demo-test-subnet', + u'description': u'' + }, + {u'output_value': u'b1a03624-aefc-...', + u'output_key': u'ares.demo', + u'description': u'' + }, + {u'output_value': u'266a8088-c630-...', + u'output_key': u'demo-secgroup', + u'description': u'' + }, + {u'output_value': u'10.0.1.5', + u'output_key': u'ares.demo-test-port', + u'description': u'' + }, + {u'output_value': u'10.0.1.1', + u'output_key': u'demo-test-subnet-gateway_ip', + u'description': u'' + }, + {u'output_value': u'', + u'output_key': u'ares.demo-test-port-device_id', + u'description': u'' + }, + {u'output_value': u'172.24.4.7', + u'output_key': u'ares.demo-fip', + u'description': u'' + }, + {u'output_value': u'fa:16:3e:6c:c3:0f', + u'output_key': u'ares.demo-test-port-mac_address', + u'description': u''} + ] + ) + expected_outputs = { + 'ares.demo-test-port-network_id': 'b734d06a-dec7-...', + 'ares.demo-test-port-subnet_id': 'b08da78c-2218-...', + 'demo-test-subnet-cidr': '10.0.1.0/24', + 'demo-test-subnet': 'b08da78c-2218-...', + 'ares.demo': 'b1a03624-aefc-...', + 'demo-secgroup': '266a8088-c630-...', + 'ares.demo-test-port': '10.0.1.5', + 'demo-test-subnet-gateway_ip': '10.0.1.1', + 'ares.demo-test-port-device_id': '', + 'ares.demo-fip': '172.24.4.7', + 'ares.demo-test-port-mac_address': 'fa:16:3e:6c:c3:0f', + } + + stack_id = "my-existing-stack-id" + self.heatstack.name = "my-existing-stack" + self.heatstack.get() + + self.mock_stack_get.assert_called_once_with(self.heatstack.name) + self.assertEqual(expected_outputs, self.heatstack.outputs) + self.assertEqual(1, len(heat._DEPLOYED_STACKS)) + self.assertEqual(self.heatstack._stack, + heat._DEPLOYED_STACKS[stack_id]) + + def test_get_invalid_name(self): + # No context matching this name exists + self.mock_stack_get.return_value = [] + self.heatstack.name = 'not-a-stack' + self.heatstack.get() + self.assertEqual(0, len(heat._DEPLOYED_STACKS)) + class HeatTemplateTestCase(unittest.TestCase): @@ -160,7 +247,8 @@ class HeatTemplateTestCase(unittest.TestCase): def test__add_resources_to_template_raw(self): test_context = node.NodeContext() - test_context.name = 'foo' + self.addCleanup(test_context._delete_context) + test_context._name = 'foo' test_context.template_file = '/tmp/some-heat-file' test_context.heat_parameters = {'image': 'cirros'} test_context.key_filename = "/tmp/1234" @@ -184,10 +272,18 @@ class HeatTemplateTestCase(unittest.TestCase): heat_template.add_subnet("subnet2", "network2", "cidr2") heat_template.add_router("router1", "gw1", "subnet1") heat_template.add_router_interface("router_if1", "router1", "subnet1") - heat_template.add_port("port1", "network1", "subnet1", "normal") - heat_template.add_port("port2", "network2", "subnet2", "normal", + network1 = mock.MagicMock() + network1.stack_name = "network1" + network1.subnet_stack_name = "subnet1" + network1.vnic_type = "normal" + network2 = mock.MagicMock() + network2.stack_name = "network2" + network2.subnet_stack_name = "subnet2" + network2.vnic_type = "normal" + heat_template.add_port("port1", network1) + heat_template.add_port("port2", network2, sec_group_id="sec_group1", provider="not-sriov") - heat_template.add_port("port3", "network2", "subnet2", "normal", + heat_template.add_port("port3", network2, sec_group_id="sec_group1", provider="sriov") heat_template.add_floating_ip("floating_ip1", "network1", "port1", "router_if1") diff --git a/yardstick/tests/unit/orchestrator/test_kubernetes.py b/yardstick/tests/unit/orchestrator/test_kubernetes.py index 33fa1dca6..f2bc5b0f4 100644 --- a/yardstick/tests/unit/orchestrator/test_kubernetes.py +++ b/yardstick/tests/unit/orchestrator/test_kubernetes.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################## # Copyright (c) 2017 Intel Corporation # @@ -104,11 +102,3 @@ service ssh restart;while true ; do sleep 10000; done'] mock_get_pod_list.return_value.items = [] pods = k8s_template.get_rc_pods() self.assertEqual(pods, []) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/service/__init__.py b/yardstick/tests/unit/service/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/unit/service/__init__.py diff --git a/yardstick/tests/unit/service/test_environment.py b/yardstick/tests/unit/service/test_environment.py new file mode 100644 index 000000000..4af9a3958 --- /dev/null +++ b/yardstick/tests/unit/service/test_environment.py @@ -0,0 +1,49 @@ +############################################################################## +# Copyright (c) 2016 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 +############################################################################## +import unittest + +import mock + +from yardstick.service.environment import Environment +from yardstick.service.environment import AnsibleCommon +from yardstick.common.exceptions import UnsupportedPodFormatError + + +class EnvironmentTestCase(unittest.TestCase): + + def test_get_sut_info(self): + pod_info = { + 'nodes': [ + { + 'name': 'node1', + 'host_name': 'host1', + 'role': 'Controller', + 'ip': '10.1.0.50', + 'user': 'root', + 'passward': 'root' + } + ] + } + + AnsibleCommon.gen_inventory_ini_dict = mock.MagicMock() + AnsibleCommon.get_sut_info = mock.MagicMock(return_value={'node1': {}}) + + env = Environment(pod=pod_info) + env.get_sut_info() + + def test_get_sut_info_pod_str(self): + pod_info = 'nodes' + + env = Environment(pod=pod_info) + with self.assertRaises(UnsupportedPodFormatError): + env.get_sut_info() + + +if __name__ == '__main__': + unittest.main() diff --git a/yardstick/tests/unit/test_cmd/commands/test_env.py b/yardstick/tests/unit/test_cmd/commands/test_env.py index 13c3ed44a..57dacbcd3 100644 --- a/yardstick/tests/unit/test_cmd/commands/test_env.py +++ b/yardstick/tests/unit/test_cmd/commands/test_env.py @@ -21,30 +21,30 @@ class EnvCommandTestCase(unittest.TestCase): def test_do_influxdb(self, check_status_mock, start_async_task_mock): env = EnvCommand() env.do_influxdb({}) - self.assertTrue(start_async_task_mock.called) - self.assertTrue(check_status_mock.called) + start_async_task_mock.assert_called_once() + check_status_mock.assert_called_once() @mock.patch('yardstick.cmd.commands.env.EnvCommand._start_async_task') @mock.patch('yardstick.cmd.commands.env.EnvCommand._check_status') def test_do_grafana(self, check_status_mock, start_async_task_mock): env = EnvCommand() env.do_grafana({}) - self.assertTrue(start_async_task_mock.called) - self.assertTrue(check_status_mock.called) + start_async_task_mock.assert_called_once() + check_status_mock.assert_called_once() @mock.patch('yardstick.cmd.commands.env.EnvCommand._start_async_task') @mock.patch('yardstick.cmd.commands.env.EnvCommand._check_status') def test_do_prepare(self, check_status_mock, start_async_task_mock): env = EnvCommand() env.do_prepare({}) - self.assertTrue(start_async_task_mock.called) - self.assertTrue(check_status_mock.called) + start_async_task_mock.assert_called_once() + check_status_mock.assert_called_once() @mock.patch('yardstick.cmd.commands.env.HttpClient.post') def test_start_async_task(self, post_mock): data = {'action': 'create_grafana'} EnvCommand()._start_async_task(data) - self.assertTrue(post_mock.called) + post_mock.assert_called_once() @mock.patch('yardstick.cmd.commands.env.HttpClient.get') @mock.patch('yardstick.cmd.commands.env.EnvCommand._print_status') @@ -63,11 +63,3 @@ class EnvCommandTestCase(unittest.TestCase): except Exception as e: # pylint: disable=broad-except # NOTE(ralonsoh): try to reduce the scope of this exception. self.assertIsInstance(e, IndexError) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() diff --git a/yardstick/tests/unit/test_cmd/commands/test_testcase.py b/yardstick/tests/unit/test_cmd/commands/test_testcase.py index 7ef157c19..922167614 100644 --- a/yardstick/tests/unit/test_cmd/commands/test_testcase.py +++ b/yardstick/tests/unit/test_cmd/commands/test_testcase.py @@ -18,12 +18,4 @@ class TestcaseCommandsUT(unittest.TestCase): def test_do_list(self, mock_client, mock_print): mock_client.get.return_value = {'result': []} TestcaseCommands().do_list({}) - self.assertTrue(mock_print.called) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() + mock_print.assert_called_once() diff --git a/yardstick/tests/unit/test_cmd/test_NSBperf.py b/yardstick/tests/unit/test_cmd/test_NSBperf.py index 483e82a13..d64b0c551 100644 --- a/yardstick/tests/unit/test_cmd/test_NSBperf.py +++ b/yardstick/tests/unit/test_cmd/test_NSBperf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright (c) 2016-2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -91,17 +89,17 @@ class TestYardstickNSCli(unittest.TestCase): subprocess.check_output = mock.Mock(return_value=0) args = {"vnf": "vpe", "test": "tc_baremetal_rfc2544_ipv4_1flow_1518B.yaml"} - self.assertEqual(None, yardstick_ns_cli.run_test(args, test_path)) + self.assertIsNone(yardstick_ns_cli.run_test(args, test_path)) os.chdir(cur_dir) args = {"vnf": "vpe1"} - self.assertEqual(None, yardstick_ns_cli.run_test(args, test_path)) + self.assertIsNone(yardstick_ns_cli.run_test(args, test_path)) os.chdir(cur_dir) args = {"vnf": "vpe", "test": "tc_baremetal_rfc2544_ipv4_1flow_1518B.yaml."} - self.assertEqual(None, yardstick_ns_cli.run_test(args, test_path)) + self.assertIsNone(yardstick_ns_cli.run_test(args, test_path)) os.chdir(cur_dir) args = [] - self.assertEqual(None, yardstick_ns_cli.run_test(args, test_path)) + self.assertIsNone(yardstick_ns_cli.run_test(args, test_path)) os.chdir(cur_dir) def test_terminate_if_less_options(self): diff --git a/yardstick/tests/unit/test_ssh.py b/yardstick/tests/unit/test_ssh.py index dbaae8c37..f92290070 100644 --- a/yardstick/tests/unit/test_ssh.py +++ b/yardstick/tests/unit/test_ssh.py @@ -21,12 +21,13 @@ import os import socket import unittest from io import StringIO +from itertools import count import mock from oslo_utils import encodeutils from yardstick import ssh -from yardstick.ssh import SSHError +from yardstick.ssh import SSHError, SSHTimeout from yardstick.ssh import SSH from yardstick.ssh import AutoConnectSSH @@ -508,13 +509,45 @@ class SSHRunTestCase(unittest.TestCase): class TestAutoConnectSSH(unittest.TestCase): - def test__connect_with_wait(self): - auto_connect_ssh = AutoConnectSSH('user1', 'host1', wait=True) - auto_connect_ssh._get_client = mock.Mock() - auto_connect_ssh.wait = mock_wait = mock.Mock() + def test__connect_loop(self): + auto_connect_ssh = AutoConnectSSH('user1', 'host1', wait=0) + auto_connect_ssh._get_client = mock__get_client = mock.Mock() auto_connect_ssh._connect() - self.assertEqual(mock_wait.call_count, 1) + self.assertEqual(mock__get_client.call_count, 1) + + def test___init___negative(self): + with self.assertRaises(TypeError): + AutoConnectSSH('user1', 'host1', wait=['wait']) + + with self.assertRaises(ValueError): + AutoConnectSSH('user1', 'host1', wait='wait') + + @mock.patch('yardstick.ssh.time') + def test__connect_loop_ssh_error(self, mock_time): + mock_time.time.side_effect = count() + + auto_connect_ssh = AutoConnectSSH('user1', 'host1', wait=10) + auto_connect_ssh._get_client = mock__get_client = mock.Mock() + mock__get_client.side_effect = SSHError + + with self.assertRaises(SSHTimeout): + auto_connect_ssh._connect() + + self.assertEqual(mock_time.time.call_count, 12) + + def test_get_file_obj(self): + auto_connect_ssh = AutoConnectSSH('user1', 'host1', wait=10) + auto_connect_ssh._get_client = mock__get_client = mock.Mock() + mock_client = mock__get_client() + mock_open_sftp = mock_client.open_sftp() + mock_sftp = mock.Mock() + mock_open_sftp.__enter__ = mock.Mock(return_value=mock_sftp) + mock_open_sftp.__exit__ = mock.Mock() + + auto_connect_ssh.get_file_obj('remote/path', mock.Mock()) + + self.assertEqual(mock_sftp.getfo.call_count, 1) def test__make_dict(self): auto_connect_ssh = AutoConnectSSH('user1', 'host1') @@ -527,7 +560,7 @@ class TestAutoConnectSSH(unittest.TestCase): 'key_filename': None, 'password': None, 'name': None, - 'wait': True, + 'wait': AutoConnectSSH.DEFAULT_WAIT_TIMEOUT, } result = auto_connect_ssh._make_dict() self.assertDictEqual(result, expected) @@ -537,6 +570,13 @@ class TestAutoConnectSSH(unittest.TestCase): self.assertEqual(auto_connect_ssh.get_class(), AutoConnectSSH) + def test_drop_connection(self): + auto_connect_ssh = AutoConnectSSH('user1', 'host1') + self.assertFalse(auto_connect_ssh._client) + auto_connect_ssh._client = True + auto_connect_ssh.drop_connection() + self.assertFalse(auto_connect_ssh._client) + @mock.patch('yardstick.ssh.SCPClient') def test_put(self, mock_scp_client_type): auto_connect_ssh = AutoConnectSSH('user1', 'host1') @@ -562,11 +602,3 @@ class TestAutoConnectSSH(unittest.TestCase): auto_connect_ssh.put_file('a', 'b') self.assertEqual(mock_put_sftp.call_count, 1) - - -def main(): - unittest.main() - - -if __name__ == '__main__': - main() |