diff options
44 files changed, 1581 insertions, 1131 deletions
diff --git a/ansible/install-inventory.ini b/ansible/install-inventory.ini new file mode 100644 index 000000000..6aa9905bd --- /dev/null +++ b/ansible/install-inventory.ini @@ -0,0 +1,30 @@ +# the group of systems on which to install yardstick +# by default just localhost +[jumphost] +#yardstickvm1 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=local +localhost ansible_connection=local + +# section below is only due backward compatibility. +# it will be removed later +[yardstick:children] +jumphost + +[yardstick-standalone] +#yardstickvm2 ansible_host=192.168.2.51 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=ssh +# uncomment hosts below if you would to test yardstick-standalone/sriov scenarios +#yardstick-standalone-node ansible_host=192.168.1.2 +#yardstick-standalone-node-2 ansible_host=192.168.1.3 + +[yardstick-baremetal] +#yardstickvm3 ansible_host=192.168.2.52 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=ssh +# hostname ansible_host=192.168.1.2 + +[all:vars] +arch_amd64=amd64 +arch_arm64=arm64 +inst_mode_container=container +inst_mode_baremetal=baremetal +ubuntu_archive={"amd64": "http://archive.ubuntu.com/ubuntu/", "arm64": "http://ports.ubuntu.com/ubuntu-ports/"} +# uncomment credentials below for yardstick-standalone +#ansible_user=root +#ansible_pass=root diff --git a/ansible/install.yaml b/ansible/install.yaml new file mode 100644 index 000000000..d1745798c --- /dev/null +++ b/ansible/install.yaml @@ -0,0 +1,99 @@ +# 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. +--- +- hosts: jumphost + become: yes + vars: + installation_mode: "{{ INSTALLATION_MODE | default('baremetal') }}" + yardstick_dir: "{{ YARDSTICK_DIR | default('/home/opnfv/repos/yardstick') }}" + virtual_environment: "{{ VIRTUAL_ENVIRONMENT | default(False) }}" + nsb_dir: "{{ NSB_DIR | default('/opt/nsb_bin/') }}" + + pre_tasks: + + - name: Create NSB binaries directory, accesible to any user + file: + path: "{{ nsb_dir }}" + state: directory + owner: root + mode: 0777 + + roles: + - add_repos_jumphost + - install_dependencies_jumphost + - install_yardstick + - configure_uwsgi + - configure_nginx + - download_trex + - install_trex + - configure_rabbitmq + + post_tasks: + + - service: + name: nginx + state: restarted + when: installation_mode != inst_mode_container + + - shell: uwsgi -i /etc/yardstick/yardstick.ini + when: installation_mode != inst_mode_container + +- name: Prepare baremetal and standalone server(s) + hosts: yardstick-baremetal,yardstick-standalone + become: yes + vars: + YARD_IMG_ARCH: "{{ arch_amd64 }}" + environment: + proxy_env: + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + ftp_proxy: "{{ lookup('env', 'ftp_proxy') }}" + no_proxy: "{{ lookup('env', 'no_proxy') }}" + + roles: + - add_custom_repos + - role: set_package_installer_proxy + when: proxy_env is defined and proxy_env + # can't update grub in chroot/docker + - enable_hugepages_on_boot + # needed for collectd plugins + - increase_open_file_limits + - install_image_dependencies + - role: download_dpdk + # dpdk_version: "17.02" + - install_dpdk + - download_trex + - install_trex + - download_civetweb + - install_civetweb + - download_samplevnfs + - role: install_samplevnf + vnf_name: PROX + - role: install_samplevnf + vnf_name: UDP_Replay + - role: install_samplevnf + vnf_name: ACL + - role: install_samplevnf + vnf_name: FW + - role: install_samplevnf + vnf_name: CGNATP + # build shared DPDK for collectd only, required DPDK downloaded already + - install_dpdk_shared + - install_rabbitmq + - download_intel_cmt_cat + - install_intel_cmt_cat + - download_pmu_tools + - install_pmu_tools + - download_collectd + - install_collectd diff --git a/ansible/nsb_setup.yml b/ansible/nsb_setup.yml index 56e591afe..a00d991d2 100644 --- a/ansible/nsb_setup.yml +++ b/ansible/nsb_setup.yml @@ -22,7 +22,7 @@ environment: "{{ proxy_env }}" roles: - - install_dependencies + - install_dependencies_jumphost - docker - name: "handle all openstack stuff when: openrc_file is defined" diff --git a/ansible/roles/add_repos_jumphost/tasks/Debian.yml b/ansible/roles/add_repos_jumphost/tasks/Debian.yml new file mode 100644 index 000000000..0b67c6691 --- /dev/null +++ b/ansible/roles/add_repos_jumphost/tasks/Debian.yml @@ -0,0 +1,82 @@ +# 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. +--- +# Arguments needed: arch_arm64, arch_amd64, ubuntu_archive + +- name: Set the repositories architecture name + set_fact: + arch: "{{ arch_arm64 if ansible_architecture == 'aarch64' else arch_amd64 }}" + extra_arch: "{{ arch_amd64 if ansible_architecture == 'aarch64' else arch_arm64 }}" + +- name: Define the repositories names + set_fact: + repo: "{{ ubuntu_archive[arch] }}" + extra_repo: "{{ ubuntu_archive[extra_arch] }}" + +- name: Add architecture to the default repository list + replace: + path: "{{ sources_list_file }}" + regexp: '(^deb\s+)([^\[].*)$' + replace: 'deb [arch={{ arch }}] \2' + +- name: Remove support for source repositories + replace: + path: "{{ sources_list_file }}" + regexp: "^deb-src " + replace: "# deb-src " + +- name: Add extra architecture + apt: + dpkg_options: "add-architecture {{ extra_arch }}" + +- name: Define the default release version + copy: + dest: "{{ default_distro_file }}" + content: 'APT::Default-Release "{{ ansible_distribution_release }}";' + +- name: Remove extra repository file + file: + path: "{{ repo_file }}" + state: absent + ignore_errors: yes + +- name: Add extra repository file + file: + path: "{{ repo_file }}" + state: touch + +- name: Add the repository for qemu_static_user/xenial + blockinfile: + path: "{{ repo_file }}" + marker: "MARKER" + content: | + deb [arch={{ arch }}] {{ repo }} xenial-updates universe + when: ansible_distribution_release != "xenial" + +- name: Add extra architecture repositories if installing in container + blockinfile: + path: "{{ repo_file }}" + marker: "MARKER" + content: | + deb [arch={{ extra_arch }}] {{ extra_repo }} {{ ansible_distribution_release }} main universe multiverse restricted + deb [arch={{ extra_arch }}] {{ extra_repo }} {{ ansible_distribution_release }}-updates main universe multiverse restricted + deb [arch={{ extra_arch }}] {{ extra_repo }} {{ ansible_distribution_release }}-security main universe multiverse restricted + deb [arch={{ extra_arch }}] {{ extra_repo }} {{ ansible_distribution_release }}-proposed main universe multiverse restricted + when: installation_mode == "container" + +- name: Remove the marker + lineinfile: + dest: "{{ repo_file }}" + state: absent + regexp: "MARKER" diff --git a/ansible/install_dependencies.yml b/ansible/roles/add_repos_jumphost/tasks/main.yml index 1c7d20170..f50fd9f0d 100644 --- a/ansible/install_dependencies.yml +++ b/ansible/roles/add_repos_jumphost/tasks/main.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Intel Corporation. +# 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. @@ -12,8 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. --- -- name: install yardstick dependencies - hosts: all - - roles: - - install_dependencies +- include: "{{ ansible_os_family }}.yml" + when: ansible_os_family == "Debian" diff --git a/ansible/roles/add_repos_jumphost/vars/main.yml b/ansible/roles/add_repos_jumphost/vars/main.yml new file mode 100644 index 000000000..30e444711 --- /dev/null +++ b/ansible/roles/add_repos_jumphost/vars/main.yml @@ -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. +--- +repo_file: "/etc/apt/sources.list.d/yardstick.list" +sources_list_file: "/etc/apt/sources.list" +default_distro_file: "/etc/apt/apt.conf.d/default-distro" diff --git a/ansible/roles/configure_gui/tasks/main.yml b/ansible/roles/configure_gui/tasks/main.yml new file mode 100644 index 000000000..846a9cb47 --- /dev/null +++ b/ansible/roles/configure_gui/tasks/main.yml @@ -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. +--- +- name: Define variables + set_fact: + gui_dir: "{{ yardstick_dir }}/gui/" + +- name: Run gui.sh + shell: + cmd: /bin/bash gui.sh + chdir: "{{ gui_dir }}" + +- name: Create nginx/yardstick directory + file: + path: /etc/nginx/yardstick + state: directory + recurse: yes + +- name: Move dist to /etc/nginx/yardstick/gui + shell: + cmd: mv dist /etc/nginx/yardstick/gui + chdir: "{{ gui_dir }}" diff --git a/ansible/roles/configure_nginx/tasks/main.yml b/ansible/roles/configure_nginx/tasks/main.yml new file mode 100644 index 000000000..e0f7f75bb --- /dev/null +++ b/ansible/roles/configure_nginx/tasks/main.yml @@ -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. +--- +- name: Define variables + set_fact: + socket_file: "{{ socket_file|default('/var/run/yardstick.sock') }}" + +- name: Make sure conf.d directory exists + file: + path: /etc/nginx/conf.d + state: directory + +- name: Create the nginx config file + template: + src: yardstick.conf.j2 + dest: "/etc/nginx/conf.d/yardstick.conf" + +- name: Configure ports if RedHat OS + shell: | + semanage port -m -t http_port_t -p tcp 5000 + semanage port -m -t http_port_t -p udp 5000 + when: ansible_os_family == "RedHat" diff --git a/ansible/roles/configure_nginx/templates/yardstick.conf.j2 b/ansible/roles/configure_nginx/templates/yardstick.conf.j2 new file mode 100644 index 000000000..484096cec --- /dev/null +++ b/ansible/roles/configure_nginx/templates/yardstick.conf.j2 @@ -0,0 +1,18 @@ +server { + listen 5000; + server_name localhost; + index index.htm index.html; + location / { + include uwsgi_params; + client_max_body_size 2000m; + uwsgi_pass unix://{{ socket_file }}; + } + + location /gui/ { + alias /etc/nginx/yardstick/gui/; + } + + location /report/ { + alias /tmp/; + } +} diff --git a/ansible/roles/configure_rabbitmq/tasks/main.yml b/ansible/roles/configure_rabbitmq/tasks/main.yml new file mode 100644 index 000000000..3ad60c1ea --- /dev/null +++ b/ansible/roles/configure_rabbitmq/tasks/main.yml @@ -0,0 +1,30 @@ +# 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. +--- +- name: Restart rabbitmq + service: + name: rabbitmq-server + state: restarted + +- name: rabbitmqctl start_app + shell: rabbitmqctl start_app + +- name: Configure rabbitmq + rabbitmq_user: + user: yardstick + password: yardstick + configure_priv: .* + read_priv: .* + write_priv: .* + state: present diff --git a/ansible/roles/configure_uwsgi/tasks/main.yml b/ansible/roles/configure_uwsgi/tasks/main.yml new file mode 100644 index 000000000..6a2244657 --- /dev/null +++ b/ansible/roles/configure_uwsgi/tasks/main.yml @@ -0,0 +1,45 @@ +# 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. +--- +- name: Define variables + set_fact: + config_dir: "/etc/yardstick/" + log_dir: "/var/log/yardstick/" + socket_file: "/var/run/yardstick.sock" + +- name: Create UWSGI config directory + file: + path: "/etc/yardstick" + state: directory + owner: root + mode: 0755 + +- name: Create API log directory + file: + path: "{{ log_dir }}" + state: directory + owner: root + mode: 0777 + +- name: Create the socket for communicating + file: + path: "{{ socket_file }}" + state: touch + owner: root + mode: 0644 + +- name: Create the UWSGI config file + template: + src: yardstick.ini.j2 + dest: "{{ config_dir }}yardstick.ini" diff --git a/ansible/roles/configure_uwsgi/templates/yardstick.ini.j2 b/ansible/roles/configure_uwsgi/templates/yardstick.ini.j2 new file mode 100644 index 000000000..c049daf84 --- /dev/null +++ b/ansible/roles/configure_uwsgi/templates/yardstick.ini.j2 @@ -0,0 +1,18 @@ +[uwsgi] +master = true +debug = true +chdir = {{ yardstick_dir }}api +module = server +plugins = python +processes = 10 +threads = 5 +async = true +max-requests = 5000 +chmod-socket = 666 +callable = app_wrapper +enable-threads = true +close-on-exec = 1 +daemonize = {{ log_dir }}uwsgi.log +socket = {{ socket_file }} +{# If virtual environment, we need to add: + virtualenv = <virtual_env> #}
\ No newline at end of file diff --git a/ansible/roles/download_trex/tasks/main.yml b/ansible/roles/download_trex/tasks/main.yml index baa964fd8..9df67d939 100644 --- a/ansible/roles/download_trex/tasks/main.yml +++ b/ansible/roles/download_trex/tasks/main.yml @@ -12,6 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. --- +- name: make sure trex_dest exists + file: + path: "{{ trex_dest }}" + state: directory + - name: fetch Trex get_url: url: "{{ trex_url }}" diff --git a/ansible/roles/install_dependencies_jumphost/tasks/Debian.yml b/ansible/roles/install_dependencies_jumphost/tasks/Debian.yml new file mode 100755 index 000000000..9baf7e59e --- /dev/null +++ b/ansible/roles/install_dependencies_jumphost/tasks/Debian.yml @@ -0,0 +1,76 @@ +# Copyright (c) 2017 Intel Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +--- +- name: Update repositories + apt: + update_cache: yes + +- name: Install core packages + action: "{{ ansible_pkg_mgr }} name={{ item }} state=present" + with_items: + - wget + - curl + - screen + - procps + - socat + - sshpass + - sudo + - vim + - libffi-dev + - libfuse-dev + - libssl-dev + - libxft-dev + - libxml2-dev + - libxss-dev + - libxslt-dev + - libxslt1-dev + - libzmq-dev + - qemu-user-static + - qemu-utils + - kpartx + - python + - python-setuptools + - python-dev + - python-pip + - python-libvirt + - python-virtualenv + - bridge-utils + - ebtables + - openssl + - ccze + - nginx-full + - uwsgi + - uwsgi-plugin-python + - supervisor + - lsof + - nodejs + - npm + - rabbitmq-server + +- name: Install libc6:arm64 package + action: "{{ ansible_pkg_mgr }} name={{ item }} state=present" + with_items: + - libc6:arm64 + when: + - arch is defined + - arch != arch_arm64 + - installation_mode == inst_mode_container + +- name: Remove dependencies that are no longer required + apt: + update_cache: yes + +- name: Remove useless packages from the cache + apt: + autoclean: yes diff --git a/ansible/roles/install_dependencies/tasks/RedHat.yml b/ansible/roles/install_dependencies_jumphost/tasks/RedHat.yml index a5d4d0b15..85eb1156a 100644 --- a/ansible/roles/install_dependencies/tasks/RedHat.yml +++ b/ansible/roles/install_dependencies_jumphost/tasks/RedHat.yml @@ -42,5 +42,13 @@ - python-setuptools - libffi-devel - python-devel - - kpartx - + - nodejs + - npm + - gcc + - lsof + - procps + - bridge-utils + - ebtables + - openssl + - python-virtualenv + - ccze diff --git a/ansible/roles/install_dependencies/tasks/Debian.yml b/ansible/roles/install_dependencies_jumphost/tasks/Suse.yml index bba6fb13c..af53c9cd5 100755..100644 --- a/ansible/roles/install_dependencies/tasks/Debian.yml +++ b/ansible/roles/install_dependencies_jumphost/tasks/Suse.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Intel Corporation. +# 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. @@ -12,39 +12,38 @@ # See the License for the specific language governing permissions and # limitations under the License. --- +- name: Install EPEL if needed + action: "{{ ansible_pkg_mgr }} name=epel-release state=present" + when: ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux'] + - name: Install core packages action: "{{ ansible_pkg_mgr }} name={{ item }} state=present" with_items: - - python-minimal + - deltarpm - wget + - expect - curl - screen - - procps - git - socat - sshpass - - libxslt1-dev - - libffi-dev - - libfuse-dev - qemu-kvm - - qemu-user-static - - qemu-utils - kpartx - - libvirt0 - - python-libvirt + - libxslt-devel + - libffi-devel + - openssl-devel + - nginx + - uwsgi + - python-setuptools + - libffi-devel + - python-devel + - nodejs + - npm + - gcc + - lsof + - procps - bridge-utils - ebtables - openssl - - libssl-dev - - python-dev - python-virtualenv - ccze - - libxml2-dev - - libxslt-dev - - libzmq-dev - - nginx-full - - uwsgi - - uwsgi-plugin-python - - supervisor - - python-setuptools - - lsof diff --git a/ansible/roles/install_dependencies/tasks/main.yml b/ansible/roles/install_dependencies_jumphost/tasks/main.yml index 27660c3ca..27660c3ca 100644 --- a/ansible/roles/install_dependencies/tasks/main.yml +++ b/ansible/roles/install_dependencies_jumphost/tasks/main.yml diff --git a/ansible/roles/install_yardstick/tasks/main.yml b/ansible/roles/install_yardstick/tasks/main.yml new file mode 100644 index 000000000..ee1b83756 --- /dev/null +++ b/ansible/roles/install_yardstick/tasks/main.yml @@ -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. +--- +# Arguments needed: map_min_addr_file, yardstick_dir + +- name: Define variables + set_fact: + map_min_addr_file: "/etc/sysctl.d/mmap_min_addr.conf" + +- name: Remove the kernel minimum virtual address restriction that a process is allowed to mmap + copy: + dest: "{{ map_min_addr_file }}" + content: "vm.mmap_min_addr = 0\n" + +- name: Config git SSL + git_config: + name: http.sslVerify + scope: global + value: False + +# There is a bug with the easy install ansible module in suse linux. +# Until this is fixed the shell command must be used +- name: Install pip + shell: easy_install -U pip +# easy_install: +# name: pip +# state: latest + +- name: install yardstick without virtual environment + include_tasks: regular_install.yml + when: virtual_environment == False + +- name: install yardstick with virtual environment + include_tasks: virtual_install.yml + when: virtual_environment == True diff --git a/ansible/roles/install_yardstick/tasks/regular_install.yml b/ansible/roles/install_yardstick/tasks/regular_install.yml new file mode 100644 index 000000000..cd0e86fb9 --- /dev/null +++ b/ansible/roles/install_yardstick/tasks/regular_install.yml @@ -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. +--- +- name: Install Yardstick requirements + pip: + requirements: "{{ yardstick_dir }}/requirements.txt" + +- name: Install Yardstick code + pip: + name: "." + extra_args: -e + chdir: "{{ yardstick_dir }}/" diff --git a/ansible/roles/install_yardstick/tasks/virtual_install.yml b/ansible/roles/install_yardstick/tasks/virtual_install.yml new file mode 100644 index 000000000..8545acbcb --- /dev/null +++ b/ansible/roles/install_yardstick/tasks/virtual_install.yml @@ -0,0 +1,25 @@ +# 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. +--- +- name: Install Yardstick requirements + pip: + requirements: "{{ yardstick_dir }}/requirements.txt" + virtualenv: "{{ yardstick_dir }}/virtualenv" + +- name: Install Yardstick code + pip: + name: "{{ yardstick_dir }}/." + extra_args: -e + virtualenv: "{{ yardstick_dir }}/virtualenv" + diff --git a/ansible/yardstick-install-inventory.ini b/ansible/yardstick-install-inventory.ini deleted file mode 100644 index e276076cc..000000000 --- a/ansible/yardstick-install-inventory.ini +++ /dev/null @@ -1,20 +0,0 @@ -# the group of systems on which to install yardstick -# by default just localhost -[jumphost] -localhost ansible_connection=local - -# section below is only due backward compatibility. -# it will be removed later -[yardstick:children] -jumphost - -[yardstick-standalone] -# uncomment hosts below if you would to test yardstick-standalone/sriov scenarios -#yardstick-standalone-node ansible_host=192.168.1.2 -#yardstick-standalone-node-2 ansible_host=192.168.1.2 - -[all:vars] -# incomment credentials below for yardstick-standalone -#ansible_user=root -#ansible_pass=root - diff --git a/docker/Dockerfile b/docker/Dockerfile index 95ec1857e..2467329c4 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,32 +20,35 @@ ENV REPOS_DIR="/home/opnfv/repos" \ # Set work directory # Yardstick repo -ENV YARDSTICK_REPO_DIR="${REPOS_DIR}/yardstick" \ +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 iputils-ping && apt-get -y autoremove && apt-get clean RUN easy_install -U setuptools==30.0.0 -RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 python-openstackclient==3.11.0 python-heatclient==1.11.0 +RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 python-openstackclient==3.11.0 python-heatclient==1.11.0 ansible==2.4.2 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 -b $BRANCH https://gerrit.opnfv.org/gerrit/yardstick ${YARDSTICK_REPO_DIR} +RUN mkdir ${YARDSTICK_REPO_DIR} +COPY ./ ${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} -RUN ${YARDSTICK_REPO_DIR}/install.sh +RUN ansible-playbook -vvv -e INSTALLATION_MODE="container" ${YARDSTICK_REPO_DIR}/ansible/install.yaml + RUN ${YARDSTICK_REPO_DIR}/docker/supervisor.sh RUN echo "daemon off;" >> /etc/nginx/nginx.conf - # nginx=5000, rabbitmq=5672 EXPOSE 5000 5672 ADD http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img ${IMAGE_DIR} ADD http://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-amd64-disk1.img ${IMAGE_DIR} -COPY ./exec_tests.sh /usr/local/bin/ +COPY ./docker/exec_tests.sh /usr/local/bin/ ENV NSB_DIR="/opt/nsb_bin" ENV PYTHONPATH="${PYTHONPATH}:${NSB_DIR}/trex_client:${NSB_DIR}/trex_client/stl" diff --git a/install.sh b/install.sh index 04985f48a..74929345d 100755 --- a/install.sh +++ b/install.sh @@ -119,4 +119,4 @@ tar xvf ${NSB_DIR}/trex_client.tar.gz -C ${NSB_DIR} rm -f ${NSB_DIR}/trex_client.tar.gz service nginx restart -uwsgi -i /etc/yardstick/yardstick.ini +uwsgi -i /etc/yardstick/yardstick.ini
\ No newline at end of file diff --git a/nsb_setup.sh b/nsb_setup.sh index 50fc017d1..d68263a06 100755 --- a/nsb_setup.sh +++ b/nsb_setup.sh @@ -71,4 +71,4 @@ cd ${ANSIBLE_SCRIPTS} &&\ ansible-playbook \ -e img_property="nsb" \ -e YARD_IMG_ARCH='amd64' ${extra_args}\ - -i yardstick-install-inventory.ini nsb_setup.yml + -i install-inventory.ini nsb_setup.yml diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index 0640d2c78..3d8907bb5 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -7,9 +7,6 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import -from __future__ import print_function - import collections import logging import os diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py index 4f7ef60d5..4d7c4f9be 100644 --- a/yardstick/benchmark/scenarios/networking/vnf_generic.py +++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py @@ -136,7 +136,7 @@ class NetworkServiceTestCase(scenario_base.Scenario): def _get_duration(self): options = self.scenario_cfg.get('options', {}) return options.get('duration', - tprofile_base.TrafficProfile.DEFAULT_DURATION) + tprofile_base.TrafficProfileConfig.DEFAULT_DURATION) def _fill_traffic_profile(self): tprofile = self._get_traffic_profile() diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py index 869db469b..f9fe0e336 100644 --- a/yardstick/common/utils.py +++ b/yardstick/common/utils.py @@ -422,13 +422,18 @@ class ErrorClass(object): class Timer(object): - def __init__(self, timeout=None): + def __init__(self, timeout=None, raise_exception=True): super(Timer, self).__init__() self.start = self.delta = None self._timeout = int(timeout) if timeout else None + self._timeout_flag = False + self._raise_exception = raise_exception def _timeout_handler(self, *args): - raise exceptions.TimerTimeout(timeout=self._timeout) + self._timeout_flag = True + if self._raise_exception: + raise exceptions.TimerTimeout(timeout=self._timeout) + self.__exit__() def __enter__(self): self.start = datetime.datetime.now() @@ -445,6 +450,23 @@ class Timer(object): def __getattr__(self, item): return getattr(self.delta, item) + def __iter__(self): + self._raise_exception = False + return self.__enter__() + + def next(self): # pragma: no cover + # NOTE(ralonsoh): Python 2 support. + if not self._timeout_flag: + return datetime.datetime.now() + raise StopIteration() + + def __next__(self): # pragma: no cover + # NOTE(ralonsoh): Python 3 support. + return self.next() + + def __del__(self): # pragma: no cover + signal.alarm(0) + def read_meminfo(ssh_client): """Read "/proc/meminfo" file and parse all keys and values""" diff --git a/yardstick/network_services/traffic_profile/base.py b/yardstick/network_services/traffic_profile/base.py index 4c3b29754..f4b5b178c 100644 --- a/yardstick/network_services/traffic_profile/base.py +++ b/yardstick/network_services/traffic_profile/base.py @@ -21,16 +21,21 @@ class TrafficProfileConfig(object): This object will parse and validate the traffic profile information. """ + + DEFAULT_SCHEMA = 'nsb:traffic_profile:0.1' + DEFAULT_FRAME_RATE = 100 + DEFAULT_DURATION = 30 + def __init__(self, tp_config): - self.schema = tp_config.get('schema', 'nsb:traffic_profile:0.1') + self.schema = tp_config.get('schema', self.DEFAULT_SCHEMA) self.name = tp_config.get('name') self.description = tp_config.get('description') tprofile = tp_config['traffic_profile'] self.traffic_type = tprofile.get('traffic_type') - self.frame_rate = tprofile.get('frame_rate') + self.frame_rate = tprofile.get('frame_rate', self.DEFAULT_FRAME_RATE) self.test_precision = tprofile.get('test_precision') self.packet_sizes = tprofile.get('packet_sizes') - self.duration = tprofile.get('duration') + self.duration = tprofile.get('duration', self.DEFAULT_DURATION) self.lower_bound = tprofile.get('lower_bound') self.upper_bound = tprofile.get('upper_bound') self.step_interval = tprofile.get('step_interval') @@ -43,7 +48,6 @@ class TrafficProfile(object): """ UPLINK = "uplink" DOWNLINK = "downlink" - DEFAULT_DURATION = 30 @staticmethod def get(tp_config): diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py index 73806f958..e105c2f55 100644 --- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py +++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py @@ -95,7 +95,6 @@ class IXIARFC2544Profile(TrexProfile): if not profile_data: continue self.profile_data = profile_data - self.get_streams(self.profile_data) self.full_profile.update({vld_id: self.profile_data}) for intf in intfs: yield traffic_generator.vnfd_helper.port_num(intf) diff --git a/yardstick/network_services/traffic_profile/rfc2544.py b/yardstick/network_services/traffic_profile/rfc2544.py index 83020c85c..c24e2f65a 100644 --- a/yardstick/network_services/traffic_profile/rfc2544.py +++ b/yardstick/network_services/traffic_profile/rfc2544.py @@ -11,190 +11,288 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -""" RFC2544 Throughput implemenation """ -from __future__ import absolute_import -from __future__ import division import logging -from trex_stl_lib.trex_stl_client import STLStream -from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats -from trex_stl_lib.trex_stl_streams import STLTXCont +from trex_stl_lib import api as Pkt +from trex_stl_lib import trex_stl_client +from trex_stl_lib import trex_stl_packet_builder_scapy +from trex_stl_lib import trex_stl_streams + +from yardstick.network_services.traffic_profile import trex_traffic_profile -from yardstick.network_services.traffic_profile.trex_traffic_profile \ - import TrexProfile LOGGING = logging.getLogger(__name__) +SRC_PORT = 'sport' +DST_PORT = 'dport' + + +class PortPgIDMap(object): + """Port and pg_id mapping class + + "pg_id" is the identification STL library gives to each stream. In the + RFC2544Profile class, the traffic has a STLProfile per port, which contains + one or several streams, one per packet size defined in the IMIX test case + description. + + Example of port <-> pg_id map: + self._port_pg_id_map = { + 0: [1, 2, 3, 4], + 1: [5, 6, 7, 8] + } + """ + + def __init__(self): + self._pg_id = 0 + self._last_port = None + self._port_pg_id_map = {} + + def add_port(self, port): + self._last_port = port + self._port_pg_id_map[port] = [] + + def get_pg_ids(self, port): + return self._port_pg_id_map.get(port) + + def increase_pg_id(self, port=None): + port = self._last_port if not port else port + if port is None: + return + pg_id_list = self._port_pg_id_map.get(port) + if not pg_id_list: + self.add_port(port) + pg_id_list = self._port_pg_id_map[port] + self._pg_id += 1 + pg_id_list.append(self._pg_id) + return self._pg_id -class RFC2544Profile(TrexProfile): - """ This class handles rfc2544 implemenation. """ +class RFC2544Profile(trex_traffic_profile.TrexProfile): + """TRex RFC2544 traffic profile""" + + TOLERANCE_LIMIT = 0.05 def __init__(self, traffic_generator): super(RFC2544Profile, self).__init__(traffic_generator) self.generator = None - self.max_rate = None - self.min_rate = None - self.ports = None - self.rate = 100 - self.drop_percent_at_max_tx = None - self.throughput_max = None + self.rate = self.config.frame_rate + self.max_rate = self.config.frame_rate + self.min_rate = 0 + self.drop_percent_max = 0 def register_generator(self, generator): self.generator = generator - def execute_traffic(self, traffic_generator=None): - """ Generate the stream and run traffic on the given ports """ + def stop_traffic(self, traffic_generator=None): + """"Stop traffic injection, reset counters and remove streams""" if traffic_generator is not None and self.generator is None: self.generator = traffic_generator - if self.ports is not None: - return + self.generator.client.stop() + self.generator.client.reset() + self.generator.client.remove_all_streams() + + def execute_traffic(self, traffic_generator=None): + """Generate the stream and run traffic on the given ports + + :param traffic_generator: (TrexTrafficGenRFC) traffic generator + :return ports: (list of int) indexes of ports + port_pg_id: (dict) port indexes and pg_id [1] map + [1] https://trex-tgn.cisco.com/trex/doc/cp_stl_docs/api/ + profile_code.html#stlstream-modes + """ + if traffic_generator is not None and self.generator is None: + self.generator = traffic_generator - self.ports = [] + port_pg_id = PortPgIDMap() + ports = [] for vld_id, intfs in sorted(self.generator.networks.items()): profile_data = self.params.get(vld_id) - # no profile for this port if not profile_data: continue - # correlated traffic doesn't use public traffic? - if vld_id.startswith(self.DOWNLINK) and \ - self.generator.rfc2544_helper.correlated_traffic: + if (vld_id.startswith(self.DOWNLINK) and + self.generator.rfc2544_helper.correlated_traffic): continue for intf in intfs: - port = self.generator.port_num(intf) - self.ports.append(port) - self.generator.client.add_streams(self.get_streams(profile_data), ports=port) - - self.max_rate = self.rate - self.min_rate = 0 - self.generator.client.start(ports=self.ports, mult=self.get_multiplier(), - duration=30, force=True) - self.drop_percent_at_max_tx = 0 - self.throughput_max = 0 - - def get_multiplier(self): - """ Get the rate at which next iteration to run """ - self.rate = round((self.max_rate + self.min_rate) / 2.0, 2) - multiplier = round(self.rate / self.pps, 2) - return str(multiplier) - - def get_drop_percentage(self, generator=None): - """ Calculate the drop percentage and run the traffic """ - if generator is None: - generator = self.generator - run_duration = self.generator.RUN_DURATION - samples = self.generator.generate_samples(self.ports) - - in_packets = sum([value['in_packets'] for value in samples.values()]) - out_packets = sum([value['out_packets'] for value in samples.values()]) - - packet_drop = abs(out_packets - in_packets) - drop_percent = 100.0 - try: - drop_percent = round((packet_drop / float(out_packets)) * 100, 5) - except ZeroDivisionError: - LOGGING.info('No traffic is flowing') + port_num = int(self.generator.port_num(intf)) + ports.append(port_num) + port_pg_id.add_port(port_num) + profile = self._create_profile(profile_data, + self.rate, port_pg_id) + self.generator.client.add_streams(profile, ports=[port_num]) + + self.generator.client.start(ports=ports, + duration=self.config.duration, + force=True) + return ports, port_pg_id + + def _create_profile(self, profile_data, rate, port_pg_id): + """Create a STL profile (list of streams) for a port""" + streams = [] + for packet_name in profile_data: + imix = (profile_data[packet_name]. + get('outer_l2', {}).get('framesize')) + imix_data = self._create_imix_data(imix) + self._create_vm(profile_data[packet_name]) + _streams = self._create_streams(imix_data, rate, port_pg_id) + streams.extend(_streams) + return trex_stl_streams.STLProfile(streams) + + def _create_imix_data(self, imix): + """Generate the IMIX distribution for a STL profile + + The input information is the framesize dictionary in a test case + traffic profile definition. E.g.: + downlink_0: + ipv4: + id: 2 + outer_l2: + framesize: + 64B: 10 + 128B: 20 + ... + + This function normalizes the sum of framesize weights to 100 and + returns a dictionary of frame sizes in bytes and weight in percentage. + E.g.: + imix_count = {64: 25, 128: 75} + + :param imix: (dict) IMIX size and weight + """ + imix_count = {} + if not imix: + return imix_count + + imix_count = {size.upper().replace('B', ''): int(weight) + for size, weight in imix.items()} + imix_sum = sum(imix_count.values()) + if imix_sum <= 0: + imix_count = {64: 100} + imix_sum = 100 + + weight_normalize = float(imix_sum) / 100 + return {size: float(weight) / weight_normalize + for size, weight in imix_count.items()} + + def _create_vm(self, packet_definition): + """Create the STL Raw instructions""" + self.ether_packet = Pkt.Ether() + self.ip_packet = Pkt.IP() + self.ip6_packet = None + self.udp_packet = Pkt.UDP() + self.udp[DST_PORT] = 'UDP.dport' + self.udp[SRC_PORT] = 'UDP.sport' + self.qinq = False + self.vm_flow_vars = [] + outer_l2 = packet_definition.get('outer_l2') + outer_l3v4 = packet_definition.get('outer_l3v4') + outer_l3v6 = packet_definition.get('outer_l3v6') + outer_l4 = packet_definition.get('outer_l4') + if outer_l2: + self._set_outer_l2_fields(outer_l2) + if outer_l3v4: + self._set_outer_l3v4_fields(outer_l3v4) + if outer_l3v6: + self._set_outer_l3v6_fields(outer_l3v6) + if outer_l4: + self._set_outer_l4_fields(outer_l4) + self.trex_vm = trex_stl_packet_builder_scapy.STLScVmRaw( + self.vm_flow_vars) + + def _create_single_packet(self, size=64): + size -= 4 + ether_packet = self.ether_packet + ip_packet = self.ip6_packet if self.ip6_packet else self.ip_packet + udp_packet = self.udp_packet + if self.qinq: + qinq_packet = self.qinq_packet + base_pkt = ether_packet / qinq_packet / ip_packet / udp_packet + else: + base_pkt = ether_packet / ip_packet / udp_packet + pad = max(0, size - len(base_pkt)) * 'x' + return trex_stl_packet_builder_scapy.STLPktBuilder( + pkt=base_pkt / pad, vm=self.trex_vm) + + def _create_streams(self, imix_data, rate, port_pg_id): + """Create a list of streams per packet size + + The STL TX mode speed of the generated streams will depend on the frame + weight and the frame rate. Both the frame weight and the total frame + rate are normalized to 100. The STL TX mode speed, defined in + percentage, is the combitation of both percentages. E.g.: + frame weight = 100 + rate = 90 + --> STLTXmode percentage = 10 (%) + + frame weight = 80 + rate = 50 + --> STLTXmode percentage = 40 (%) + + :param imix_data: (dict) IMIX size and weight + :param rate: (float) normalized [0..100] total weight + :param pg_id: (PortPgIDMap) port / pg_id (list) map + """ + streams = [] + for size, weight in ((int(size), float(weight)) for (size, weight) + in imix_data.items() if float(weight) > 0): + packet = self._create_single_packet(size) + pg_id = port_pg_id.increase_pg_id() + stl_flow = trex_stl_streams.STLFlowLatencyStats(pg_id=pg_id) + mode = trex_stl_streams.STLTXCont(percentage=weight * rate / 100) + streams.append(trex_stl_client.STLStream( + packet=packet, flow_stats=stl_flow, mode=mode)) + return streams + + def get_drop_percentage(self, samples, tol_low, tol_high, + correlated_traffic): + """Calculate the drop percentage and run the traffic""" + tx_rate_fps = 0 + rx_rate_fps = 0 + for sample in samples: + tx_rate_fps += sum( + port['tx_throughput_fps'] for port in sample.values()) + rx_rate_fps += sum( + port['rx_throughput_fps'] for port in sample.values()) + tx_rate_fps = round(float(tx_rate_fps) / len(samples), 2) + rx_rate_fps = round(float(rx_rate_fps) / len(samples), 2) # TODO(esm): RFC2544 doesn't tolerate packet loss, why do we? - tolerance_low = generator.rfc2544_helper.tolerance_low - tolerance_high = generator.rfc2544_helper.tolerance_high - - tx_rate = out_packets / run_duration - rx_rate = in_packets / run_duration - - throughput_max = self.throughput_max - drop_percent_at_max_tx = self.drop_percent_at_max_tx + out_packets = sum(port['out_packets'] for port in samples[-1].values()) + in_packets = sum(port['in_packets'] for port in samples[-1].values()) + drop_percent = 100.0 - if self.drop_percent_at_max_tx is None: - self.rate = tx_rate - self.first_run = False + # https://tools.ietf.org/html/rfc2544#section-26.3 + if out_packets: + drop_percent = round( + (float(abs(out_packets - in_packets)) / out_packets) * 100, 5) - if drop_percent > tolerance_high: - # TODO(esm): why don't we discard results that are out of tolerance? + tol_high = tol_high if tol_high > self.TOLERANCE_LIMIT else tol_high + tol_low = tol_low if tol_low > self.TOLERANCE_LIMIT else tol_low + if drop_percent > tol_high: self.max_rate = self.rate - if throughput_max == 0: - throughput_max = rx_rate - drop_percent_at_max_tx = drop_percent - - elif drop_percent >= tolerance_low: - # TODO(esm): why do we update the samples dict in this case - # and not update our tracking values? - throughput_max = rx_rate - drop_percent_at_max_tx = drop_percent - - elif drop_percent >= self.drop_percent_at_max_tx: - # TODO(esm): why don't we discard results that are out of tolerance? + elif drop_percent < tol_low: self.min_rate = self.rate - self.drop_percent_at_max_tx = drop_percent_at_max_tx = drop_percent - self.throughput_max = throughput_max = rx_rate + # else: + # NOTE(ralonsoh): the test should finish here + # pass + last_rate = self.rate + self.rate = round(float(self.max_rate + self.min_rate) / 2.0, 5) - else: - # TODO(esm): why don't we discard results that are out of tolerance? - self.min_rate = self.rate + throughput = rx_rate_fps * 2 if correlated_traffic else rx_rate_fps - generator.clear_client_stats(self.ports) - generator.start_client(self.ports, mult=self.get_multiplier(), - duration=run_duration, force=True) + if drop_percent > self.drop_percent_max: + self.drop_percent_max = drop_percent - # if correlated traffic update the Throughput - if generator.rfc2544_helper.correlated_traffic: - throughput_max *= 2 + latency = {port_num: value['latency'] + for port_num, value in samples[-1].items()} - samples.update({ - 'TxThroughput': tx_rate, - 'RxThroughput': rx_rate, + output = { + 'TxThroughput': tx_rate_fps, + 'RxThroughput': rx_rate_fps, 'CurrentDropPercentage': drop_percent, - 'Throughput': throughput_max, - 'DropPercentage': drop_percent_at_max_tx, - }) - - return samples - - def execute_latency(self, generator=None, samples=None): - if generator is not None and self.generator is None: - self.generator = generator - - if samples is None: - samples = self.generator.generate_samples() - - self.pps, multiplier = self.calculate_pps(samples) - self.ports = [] - self.pg_id = self.params['traffic_profile'].get('pg_id', 1) - for vld_id, intfs in sorted(self.generator.networks.items()): - profile_data = self.params.get(vld_id) - if not profile_data: - continue - # correlated traffic doesn't use public traffic? - if vld_id.startswith(self.DOWNLINK) and \ - self.generator.rfc2544_helper.correlated_traffic: - continue - for intf in intfs: - port = self.generator.port_num(intf) - self.ports.append(port) - self.generator.client.add_streams(self.get_streams(profile_data), ports=port) - - self.generator.start_client(ports=self.ports, mult=str(multiplier), - duration=120, force=True) - self.first_run = False - - def calculate_pps(self, samples): - pps = round(samples['Throughput'] / 2, 2) - multiplier = round(self.rate / self.pps, 2) - return pps, multiplier - - def create_single_stream(self, packet_size, pps, isg=0): - packet = self._create_single_packet(packet_size) - if pps: - stl_mode = STLTXCont(pps=pps) - else: - stl_mode = STLTXCont(pps=self.pps) - if self.pg_id: - LOGGING.debug("pg_id: %s", self.pg_id) - stl_flow_stats = STLFlowLatencyStats(pg_id=self.pg_id) - stream = STLStream(isg=isg, packet=packet, mode=stl_mode, - flow_stats=stl_flow_stats) - self.pg_id += 1 - else: - stream = STLStream(isg=isg, packet=packet, mode=stl_mode) - return stream + 'Throughput': throughput, + 'DropPercentage': self.drop_percent_max, + 'Rate': last_rate, + 'Latency': latency + } + return output diff --git a/yardstick/network_services/traffic_profile/trex_traffic_profile.py b/yardstick/network_services/traffic_profile/trex_traffic_profile.py index f5e3923d5..ed0355fa5 100644 --- a/yardstick/network_services/traffic_profile/trex_traffic_profile.py +++ b/yardstick/network_services/traffic_profile/trex_traffic_profile.py @@ -19,21 +19,16 @@ from random import SystemRandom import ipaddress import six - -from yardstick.common import exceptions as y_exc -from yardstick.network_services.traffic_profile import base -from trex_stl_lib.trex_stl_client import STLStream -from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats -from trex_stl_lib.trex_stl_streams import STLTXCont -from trex_stl_lib.trex_stl_streams import STLProfile from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmWrFlowVar from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFlowVarRepeatableRandom from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFlowVar -from trex_stl_lib.trex_stl_packet_builder_scapy import STLPktBuilder -from trex_stl_lib.trex_stl_packet_builder_scapy import STLScVmRaw from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFixIpv4 from trex_stl_lib import api as Pkt +from yardstick.common import exceptions as y_exc +from yardstick.network_services.traffic_profile import base + + SRC = 'src' DST = 'dst' ETHERNET = 'Ethernet' @@ -342,115 +337,6 @@ class TrexProfile(base.TrafficProfile): if 'dstport' in outer_l4: self._set_proto_addr(UDP, DST_PORT, outer_l4['dstport'], outer_l4['count']) - def generate_imix_data(self, packet_definition): - """ generate packet size for a given traffic profile """ - imix_count = {} - imix_data = {} - if not packet_definition: - return imix_count - imix = packet_definition.get('framesize') - if imix: - for size in imix: - data = imix[size] - imix_data[int(size[:-1])] = int(data) - imix_sum = sum(imix_data.values()) - if imix_sum > 100: - raise SystemExit("Error in IMIX data") - elif imix_sum < 100: - imix_data[64] = imix_data.get(64, 0) + (100 - imix_sum) - - avg_size = 0.0 - for size in imix_data: - count = int(imix_data[size]) - if count: - avg_size += round(size * count / 100, 2) - pps = round(self.pps * count / 100, 0) - imix_count[size] = pps - self.rate = round(1342177280 / avg_size, 0) * 2 - logging.debug("Imax: %s rate: %s", imix_count, self.rate) - return imix_count - - def get_streams(self, profile_data): - """ generate trex stream - :param profile_data: - :type profile_data: - """ - self.streams = [] - self.pps = self.params['traffic_profile'].get('frame_rate', 100) - for packet_name in profile_data: - outer_l2 = profile_data[packet_name].get('outer_l2') - imix_data = self.generate_imix_data(outer_l2) - if not imix_data: - imix_data = {64: self.pps} - self.generate_vm(profile_data[packet_name]) - for size in imix_data: - self._generate_streams(size, imix_data[size]) - self._generate_profile() - return self.profile - - def generate_vm(self, packet_definition): - """ generate trex vm with flows setup """ - self.ether_packet = Pkt.Ether() - self.ip_packet = Pkt.IP() - self.ip6_packet = None - self.udp_packet = Pkt.UDP() - self.udp[DST_PORT] = 'UDP.dport' - self.udp[SRC_PORT] = 'UDP.sport' - self.qinq = False - self.vm_flow_vars = [] - outer_l2 = packet_definition.get('outer_l2', None) - outer_l3v4 = packet_definition.get('outer_l3v4', None) - outer_l3v6 = packet_definition.get('outer_l3v6', None) - outer_l4 = packet_definition.get('outer_l4', None) - if outer_l2: - self._set_outer_l2_fields(outer_l2) - if outer_l3v4: - self._set_outer_l3v4_fields(outer_l3v4) - if outer_l3v6: - self._set_outer_l3v6_fields(outer_l3v6) - if outer_l4: - self._set_outer_l4_fields(outer_l4) - self.trex_vm = STLScVmRaw(self.vm_flow_vars) - - def generate_packets(self): - """ generate packets from trex TG """ - base_pkt = self.base_pkt - size = self.fsize - 4 - pad = max(0, size - len(base_pkt)) * 'x' - self.packets = [STLPktBuilder(pkt=base_pkt / pad, - vm=vm) for vm in self.vms] - - def _create_single_packet(self, size=64): - size = size - 4 - ether_packet = self.ether_packet - ip_packet = self.ip6_packet if self.ip6_packet else self.ip_packet - udp_packet = self.udp_packet - if self.qinq: - qinq_packet = self.qinq_packet - base_pkt = ether_packet / qinq_packet / ip_packet / udp_packet - else: - base_pkt = ether_packet / ip_packet / udp_packet - pad = max(0, size - len(base_pkt)) * 'x' - packet = STLPktBuilder(pkt=base_pkt / pad, vm=self.trex_vm) - return packet - - def _create_single_stream(self, packet_size, pps, isg=0): - packet = self._create_single_packet(packet_size) - if self.pg_id: - self.pg_id += 1 - stl_flow = STLFlowLatencyStats(pg_id=self.pg_id) - stream = STLStream(isg=isg, packet=packet, mode=STLTXCont(pps=pps), - flow_stats=stl_flow) - else: - stream = STLStream(isg=isg, packet=packet, mode=STLTXCont(pps=pps)) - return stream - - def _generate_streams(self, packet_size, pps): - self.streams.append(self._create_single_stream(packet_size, pps)) - - def _generate_profile(self): - self.profile = STLProfile(self.streams) - @classmethod def _count_ip(cls, start_ip, end_ip): start = ipaddress.ip_address(six.u(start_ip)) diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py index 02927295c..9ff2e7d1a 100644 --- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py @@ -11,20 +11,17 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -""" Base class implementation for generic vnf implementation """ -from collections import Mapping import logging from multiprocessing import Queue, Value, Process import os import posixpath import re +import six import subprocess import time -import six - from trex_stl_lib.trex_stl_client import LoggerApi from trex_stl_lib.trex_stl_client import STLClient from trex_stl_lib.trex_stl_exceptions import STLError @@ -388,39 +385,14 @@ class ClientResourceHelper(ResourceHelper): LOG.error('TRex client not connected') return {} - def generate_samples(self, ports, key=None, default=None): - # needs to be used ports - last_result = self.get_stats(ports) - key_value = last_result.get(key, default) - - if not isinstance(last_result, Mapping): # added for mock unit test - self._terminated.value = 1 - return {} - - samples = {} - # recalculate port for interface and see if it matches ports provided - for intf in self.vnfd_helper.interfaces: - name = intf["name"] - port = self.vnfd_helper.port_num(name) - if port in ports: - xe_value = last_result.get(port, {}) - samples[name] = { - "rx_throughput_fps": float(xe_value.get("rx_pps", 0.0)), - "tx_throughput_fps": float(xe_value.get("tx_pps", 0.0)), - "rx_throughput_mbps": float(xe_value.get("rx_bps", 0.0)), - "tx_throughput_mbps": float(xe_value.get("tx_bps", 0.0)), - "in_packets": int(xe_value.get("ipackets", 0)), - "out_packets": int(xe_value.get("opackets", 0)), - } - if key: - samples[name][key] = key_value - return samples + def _get_samples(self, ports, port_pg_id=False): + raise NotImplementedError() def _run_traffic_once(self, traffic_profile): traffic_profile.execute_traffic(self) self.client_started.value = 1 time.sleep(self.RUN_DURATION) - samples = self.generate_samples(traffic_profile.ports) + samples = self._get_samples(traffic_profile.ports) time.sleep(self.QUEUE_WAIT_TIME) self._queue.put(samples) diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py index 4e9f4bdc1..07cec6745 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py @@ -11,74 +11,45 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -""" Trex traffic generation definitions which implements rfc2544 """ -from __future__ import absolute_import -from __future__ import print_function -import time import logging -from collections import Mapping - -from yardstick.network_services.vnf_generic.vnf.tg_trex import TrexTrafficGen -from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper -from yardstick.network_services.vnf_generic.vnf.tg_trex import TrexResourceHelper - -LOGGING = logging.getLogger(__name__) +import time +from yardstick.common import utils +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.vnf_generic.vnf import tg_trex -class TrexRfc2544ResourceHelper(Rfc2544ResourceHelper): - def is_done(self): - return self.latency and self.iteration.value > 10 +LOGGING = logging.getLogger(__name__) -class TrexRfcResourceHelper(TrexResourceHelper): +class TrexRfcResourceHelper(tg_trex.TrexResourceHelper): - LATENCY_TIME_SLEEP = 120 - RUN_DURATION = 30 - WAIT_TIME = 3 + SAMPLING_PERIOD = 2 + TRANSIENT_PERIOD = 10 - def __init__(self, setup_helper, rfc_helper_type=None): + def __init__(self, setup_helper): super(TrexRfcResourceHelper, self).__init__(setup_helper) - - if rfc_helper_type is None: - rfc_helper_type = TrexRfc2544ResourceHelper - - self.rfc2544_helper = rfc_helper_type(self.scenario_helper) + self.rfc2544_helper = sample_vnf.Rfc2544ResourceHelper( + self.scenario_helper) def _run_traffic_once(self, traffic_profile): - if self._terminated.value: - return - - traffic_profile.execute_traffic(self) self.client_started.value = 1 - time.sleep(self.RUN_DURATION) - self.client.stop(traffic_profile.ports) - time.sleep(self.WAIT_TIME) - samples = traffic_profile.get_drop_percentage(self) - self._queue.put(samples) - - if not self.rfc2544_helper.is_done(): - return - - self.client.stop(traffic_profile.ports) - self.client.reset(ports=traffic_profile.ports) - self.client.remove_all_streams(traffic_profile.ports) - traffic_profile.execute_traffic_latency(samples=samples) - multiplier = traffic_profile.calculate_pps(samples)[1] - for _ in range(5): - time.sleep(self.LATENCY_TIME_SLEEP) - self.client.stop(traffic_profile.ports) - time.sleep(self.WAIT_TIME) - last_res = self.client.get_stats(traffic_profile.ports) - if not isinstance(last_res, Mapping): - self._terminated.value = 1 - continue - self.generate_samples(traffic_profile.ports, 'latency', {}) - self._queue.put(samples) - self.client.start(mult=str(multiplier), - ports=traffic_profile.ports, - duration=120, force=True) + ports, port_pg_id = traffic_profile.execute_traffic(self) + + samples = [] + timeout = int(traffic_profile.config.duration) - self.TRANSIENT_PERIOD + time.sleep(self.TRANSIENT_PERIOD) + for _ in utils.Timer(timeout=timeout): + samples.append(self._get_samples(ports, port_pg_id=port_pg_id)) + time.sleep(self.SAMPLING_PERIOD) + + traffic_profile.stop_traffic(self) + output = traffic_profile.get_drop_percentage( + samples, self.rfc2544_helper.tolerance_low, + self.rfc2544_helper.tolerance_high, + self.rfc2544_helper.correlated_traffic) + self._queue.put(output) def start_client(self, ports, mult=None, duration=None, force=True): self.client.start(ports=ports, mult=mult, duration=duration, force=force) @@ -86,12 +57,8 @@ class TrexRfcResourceHelper(TrexResourceHelper): def clear_client_stats(self, ports): self.client.clear_stats(ports=ports) - def collect_kpi(self): - self.rfc2544_helper.iteration.value += 1 - return super(TrexRfcResourceHelper, self).collect_kpi() - -class TrexTrafficGenRFC(TrexTrafficGen): +class TrexTrafficGenRFC(tg_trex.TrexTrafficGen): """ This class handles mapping traffic profile and generating traffic for rfc2544 testcase. diff --git a/yardstick/network_services/vnf_generic/vnf/tg_trex.py b/yardstick/network_services/vnf_generic/vnf/tg_trex.py index 0084a124c..80b42e22d 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_trex.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_trex.py @@ -13,7 +13,6 @@ # limitations under the License. """ Trex acts as traffic generation and vnf definitions based on IETS Spec """ -from __future__ import absolute_import import logging import os @@ -25,6 +24,7 @@ from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTraff from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper + LOG = logging.getLogger(__name__) @@ -165,6 +165,30 @@ class TrexResourceHelper(ClientResourceHelper): cmd = "sudo fuser -n tcp %s %s -k > /dev/null 2>&1" self.ssh_helper.execute(cmd % (self.SYNC_PORT, self.ASYNC_PORT)) + def _get_samples(self, ports, port_pg_id=None): + stats = self.get_stats(ports) + samples = {} + for pname in (intf['name'] for intf in self.vnfd_helper.interfaces): + port_num = self.vnfd_helper.port_num(pname) + port_stats = stats.get(port_num, {}) + samples[pname] = { + 'rx_throughput_fps': float(port_stats.get('rx_pps', 0.0)), + 'tx_throughput_fps': float(port_stats.get('tx_pps', 0.0)), + 'rx_throughput_bps': float(port_stats.get('rx_bps', 0.0)), + 'tx_throughput_bps': float(port_stats.get('tx_bps', 0.0)), + 'in_packets': int(port_stats.get('ipackets', 0)), + 'out_packets': int(port_stats.get('opackets', 0)), + } + + pg_id_list = port_pg_id.get_pg_ids(port_num) + samples[pname]['latency'] = {} + for pg_id in pg_id_list: + latency_global = stats.get('latency', {}) + pg_latency = latency_global.get(pg_id, {}).get('latency') + samples[pname]['latency'][pg_id] = pg_latency + + return samples + class TrexTrafficGen(SampleVNFTrafficGen): """ diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py index 3d6fe183c..5ed199a6c 100644 --- a/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py +++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py @@ -422,7 +422,7 @@ class OvsDeployTestCase(unittest.TestCase): def setUp(self): self._mock_ssh = mock.patch.object(ssh, 'SSH') - self.mock_ssh = self._mock_ssh .start() + self.mock_ssh = self._mock_ssh.start() self.ovs_deploy = model.OvsDeploy(self.mock_ssh, '/tmp/dpdk-devbind.py', self.OVS_DETAILS) @@ -493,5 +493,5 @@ class OvsDeployTestCase(unittest.TestCase): 'ovs_version': ovs_version, 'dpdk_version': dpdk_version, 'proxy': 'test_proxy'}) - mock_execute.assert_called_with(cmd) - mock_env_get.assert_called_with('http_proxy', '') + mock_execute.assert_called_once_with(cmd) + mock_env_get.assert_has_calls([mock.call('http_proxy', '')]) diff --git a/yardstick/tests/unit/benchmark/contexts/test_heat.py b/yardstick/tests/unit/benchmark/contexts/test_heat.py index d05b912f9..749f731c0 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_heat.py +++ b/yardstick/tests/unit/benchmark/contexts/test_heat.py @@ -225,7 +225,7 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase): self.assertRaises(y_exc.HeatTemplateError, self.test_context.deploy) - mock_path_exists.assert_called_once() + mock_path_exists.assert_called() mock_resources_template.assert_called_once() @mock.patch.object(os.path, 'exists', return_value=False) @@ -250,7 +250,7 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase): 'yardstick/resources/files/yardstick_key-', self.test_context._name_task_id]) mock_genkeys.assert_called_once_with(key_filename) - mock_path_exists.assert_called() + mock_path_exists.assert_any_call(key_filename) @mock.patch.object(heat, 'HeatTemplate') @mock.patch.object(os.path, 'exists', return_value=False) @@ -276,7 +276,7 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase): '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_path_exists.assert_any_call(key_filename) @mock.patch.object(heat, 'HeatTemplate') @mock.patch.object(os.path, 'exists', return_value=False) @@ -292,7 +292,6 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase): 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) @@ -330,7 +329,7 @@ class HeatContextTestCase(ut_base.BaseUnitTestCase): '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_path_exists.assert_any_call(key_filename) mock_call_gen_keys = mock.call.gen_keys(key_filename) mock_call_add_resources = ( diff --git a/yardstick/tests/unit/common/test_utils.py b/yardstick/tests/unit/common/test_utils.py index 5fd91c87f..6247afd18 100644 --- a/yardstick/tests/unit/common/test_utils.py +++ b/yardstick/tests/unit/common/test_utils.py @@ -24,9 +24,10 @@ from yardstick import ssh from yardstick.common import constants from yardstick.common import utils from yardstick.common import exceptions +from yardstick.tests.unit import base as ut_base -class IterSubclassesTestCase(unittest.TestCase): +class IterSubclassesTestCase(ut_base.BaseUnitTestCase): # Disclaimer: this class is a modified copy from # rally/tests/unit/common/plugin/test_discover.py # Copyright 2015: Mirantis Inc. @@ -47,7 +48,7 @@ class IterSubclassesTestCase(unittest.TestCase): self.assertEqual([B, C, D], list(utils.itersubclasses(A))) -class ImportModulesFromPackageTestCase(unittest.TestCase): +class ImportModulesFromPackageTestCase(ut_base.BaseUnitTestCase): @mock.patch('yardstick.common.utils.os.walk') def test_import_modules_from_package_no_mod(self, mock_walk): @@ -72,7 +73,7 @@ class ImportModulesFromPackageTestCase(unittest.TestCase): mock_import_module.assert_called_once_with('bar.baz') -class GetParaFromYaml(unittest.TestCase): +class GetParaFromYaml(ut_base.BaseUnitTestCase): @mock.patch('yardstick.common.utils.os.environ.get') def test_get_param_para_not_found(self, get_env): @@ -96,7 +97,7 @@ class GetParaFromYaml(unittest.TestCase): return file_path -class CommonUtilTestCase(unittest.TestCase): +class CommonUtilTestCase(ut_base.BaseUnitTestCase): def setUp(self): self.data = { @@ -186,14 +187,14 @@ class CommonUtilTestCase(unittest.TestCase): self.assertEqual(mock_open.call_count, mock_open_call_count) -class TestMacAddressToHex(unittest.TestCase): +class TestMacAddressToHex(ut_base.BaseUnitTestCase): def test_mac_address_to_hex_list(self): self.assertEqual(utils.mac_address_to_hex_list("ea:3e:e1:9a:99:e8"), ['0xea', '0x3e', '0xe1', '0x9a', '0x99', '0xe8']) -class TranslateToStrTestCase(unittest.TestCase): +class TranslateToStrTestCase(ut_base.BaseUnitTestCase): def test_translate_to_str_unicode(self): input_str = u'hello' @@ -219,7 +220,7 @@ class TranslateToStrTestCase(unittest.TestCase): self.assertIs(input_value, result) -class TestParseCpuInfo(unittest.TestCase): +class TestParseCpuInfo(ut_base.BaseUnitTestCase): def test_single_socket_no_hyperthread(self): cpuinfo = """\ @@ -804,7 +805,7 @@ power management: self.assertEqual(sockets, [0, 1]) -class ChangeObjToDictTestCase(unittest.TestCase): +class ChangeObjToDictTestCase(ut_base.BaseUnitTestCase): def test_change_obj_to_dict(self): class A(object): @@ -817,7 +818,7 @@ class ChangeObjToDictTestCase(unittest.TestCase): self.assertEqual(obj_r, obj_s) -class SetDictValueTestCase(unittest.TestCase): +class SetDictValueTestCase(ut_base.BaseUnitTestCase): def test_set_dict_value(self): input_dic = { @@ -827,7 +828,7 @@ class SetDictValueTestCase(unittest.TestCase): self.assertEqual(output_dic.get('welcome', {}).get('to'), 'yardstick') -class RemoveFileTestCase(unittest.TestCase): +class RemoveFileTestCase(ut_base.BaseUnitTestCase): def test_remove_file(self): try: @@ -837,7 +838,83 @@ class RemoveFileTestCase(unittest.TestCase): self.assertTrue(isinstance(e, OSError)) -class TestUtils(unittest.TestCase): +class ParseIniFileTestCase(ut_base.BaseUnitTestCase): + + def setUp(self): + self._mock_config_parser_type = mock.patch.object(configparser, + 'ConfigParser') + self.mock_config_parser_type = self._mock_config_parser_type.start() + self.addCleanup(self._stop_mocks) + + def _stop_mocks(self): + self._mock_config_parser_type.stop() + + def test_parse_ini_file(self): + defaults = {'default1': 'value1', + 'default2': 'value2'} + s1 = {'key1': 'value11', + 'key2': 'value22'} + s2 = {'key1': 'value123', + 'key2': 'value234'} + + mock_config_parser = mock.Mock() + self.mock_config_parser_type.return_value = mock_config_parser + mock_config_parser.read.return_value = True + mock_config_parser.sections.return_value = ['s1', 's2'] + mock_config_parser.items.side_effect = iter([ + defaults.items(), + s1.items(), + s2.items(), + ]) + + expected = {'DEFAULT': defaults, + 's1': s1, + 's2': s2} + result = utils.parse_ini_file('my_path') + self.assertDictEqual(expected, result) + + @mock.patch.object(utils, 'logger') + def test_parse_ini_file_missing_section_header(self, *args): + mock_config_parser = mock.Mock() + self.mock_config_parser_type.return_value = mock_config_parser + mock_config_parser.read.side_effect = ( + configparser.MissingSectionHeaderError( + mock.Mock(), 321, mock.Mock())) + + with self.assertRaises(configparser.MissingSectionHeaderError): + utils.parse_ini_file('my_path') + + def test_parse_ini_file_no_file(self): + mock_config_parser = mock.Mock() + self.mock_config_parser_type.return_value = mock_config_parser + mock_config_parser.read.return_value = False + with self.assertRaises(RuntimeError): + utils.parse_ini_file('my_path') + + def test_parse_ini_file_no_default_section_header(self): + s1 = {'key1': 'value11', + 'key2': 'value22'} + s2 = {'key1': 'value123', + 'key2': 'value234'} + + mock_config_parser = mock.Mock() + self.mock_config_parser_type.return_value = mock_config_parser + mock_config_parser.read.return_value = True + mock_config_parser.sections.return_value = ['s1', 's2'] + mock_config_parser.items.side_effect = iter([ + configparser.NoSectionError(mock.Mock()), + s1.items(), + s2.items(), + ]) + + expected = {'DEFAULT': {}, + 's1': s1, + 's2': s2} + result = utils.parse_ini_file('my_path') + self.assertDictEqual(expected, result) + + +class TestUtils(ut_base.BaseUnitTestCase): @mock.patch('yardstick.common.utils.os.makedirs') def test_makedirs(self, *_): @@ -992,7 +1069,7 @@ class TestUtils(unittest.TestCase): utils.validate_non_string_sequence(1, raise_exc=RuntimeError) -class TestUtilsIpAddrMethods(unittest.TestCase): +class TestUtilsIpAddrMethods(ut_base.BaseUnitTestCase): GOOD_IP_V4_ADDRESS_STR_LIST = [ u'0.0.0.0', @@ -1119,7 +1196,7 @@ class TestUtilsIpAddrMethods(unittest.TestCase): self.assertEqual(utils.ip_to_hex(value), value) -class SafeDecodeUtf8TestCase(unittest.TestCase): +class SafeDecodeUtf8TestCase(ut_base.BaseUnitTestCase): @unittest.skipIf(six.PY2, 'This test should only be launched with Python 3.x') @@ -1130,7 +1207,7 @@ class SafeDecodeUtf8TestCase(unittest.TestCase): self.assertEqual('this is a byte array', out) -class ReadMeminfoTestCase(unittest.TestCase): +class ReadMeminfoTestCase(ut_base.BaseUnitTestCase): MEMINFO = (b'MemTotal: 65860500 kB\n' b'MemFree: 28690900 kB\n' @@ -1156,7 +1233,7 @@ class ReadMeminfoTestCase(unittest.TestCase): self.assertEqual(self.MEMINFO_DICT, output) -class TimerTestCase(unittest.TestCase): +class TimerTestCase(ut_base.BaseUnitTestCase): def test__getattr(self): with utils.Timer() as timer: @@ -1174,8 +1251,19 @@ class TimerTestCase(unittest.TestCase): with utils.Timer(timeout=1): time.sleep(2) + def test__enter_with_timeout_no_exception(self): + with utils.Timer(timeout=1, raise_exception=False): + time.sleep(2) + + def test__iter(self): + iterations = [] + for i in utils.Timer(timeout=2): + iterations.append(i) + time.sleep(1.1) + self.assertEqual(2, len(iterations)) + -class WaitUntilTrueTestCase(unittest.TestCase): +class WaitUntilTrueTestCase(ut_base.BaseUnitTestCase): def test_no_timeout(self): self.assertIsNone(utils.wait_until_true(lambda: True, diff --git a/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py b/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py index 45efb829e..e66e7fbb8 100644 --- a/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py +++ b/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py @@ -143,8 +143,6 @@ 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() @@ -153,7 +151,6 @@ class TestMultiPortConfig(unittest.TestCase): def _cleanup(self): self._mock_open.stop() - self._mock_os.stop() self._mock_config_parser.stop() def test_validate_ip_and_prefixlen(self): @@ -185,7 +182,8 @@ class TestMultiPortConfig(unittest.TestCase): samplevnf_helper.MultiPortConfig.validate_ip_and_prefixlen( '::1', '129') - def test___init__(self): + @mock.patch.object(os.path, 'isfile', return_value=False) + def test___init__(self, *args): topology_file = mock.Mock() config_tpl = mock.Mock() tmp_file = mock.Mock() @@ -193,8 +191,6 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf = samplevnf_helper.MultiPortConfig( topology_file, config_tpl, tmp_file, vnfd_mock) self.assertEqual(0, opnfv_vnf.swq) - 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) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_base.py b/yardstick/tests/unit/network_services/traffic_profile/test_base.py index cf4888d82..55276af58 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_base.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_base.py @@ -77,6 +77,12 @@ class TestDummyProfile(unittest.TestCase): class TrafficProfileConfigTestCase(unittest.TestCase): def test__init(self): - tp_config = {'traffic_profile': {'duration': 15}} + tp_config = {'traffic_profile': {'packet_sizes': {'64B': 100}}} tp_config_obj = base.TrafficProfileConfig(tp_config) - self.assertEqual(15, tp_config_obj.duration) + self.assertEqual({'64B': 100}, tp_config_obj.packet_sizes) + self.assertEqual(base.TrafficProfileConfig.DEFAULT_SCHEMA, + tp_config_obj.schema) + self.assertEqual(base.TrafficProfileConfig.DEFAULT_FRAME_RATE, + tp_config_obj.frame_rate) + self.assertEqual(base.TrafficProfileConfig.DEFAULT_DURATION, + tp_config_obj.duration) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py index 2684e0ba1..0cf93f9ae 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py @@ -11,33 +11,26 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# -import unittest import mock -from yardstick.tests import STL_MOCKS - +from trex_stl_lib import api as Pkt +from trex_stl_lib import trex_stl_client +from trex_stl_lib import trex_stl_packet_builder_scapy +from trex_stl_lib import trex_stl_streams -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() +from yardstick.network_services.traffic_profile import rfc2544 +from yardstick.tests.unit import base -if stl_patch: - from yardstick.network_services.traffic_profile.trex_traffic_profile \ - import TrexProfile - from yardstick.network_services.traffic_profile.rfc2544 import \ - RFC2544Profile - -class TestRFC2544Profile(unittest.TestCase): +class TestRFC2544Profile(base.BaseUnitTestCase): TRAFFIC_PROFILE = { "schema": "isb:traffic_profile:0.1", "name": "fixed", "description": "Fixed traffic profile to run UDP traffic", "traffic_profile": { "traffic_type": "FixedTraffic", - "frame_rate": 100, # pps + "frame_rate": 100, "flow_number": 10, "frame_size": 64}} @@ -45,233 +38,251 @@ class TestRFC2544Profile(unittest.TestCase): 'name': 'rfc2544', 'traffic_profile': {'traffic_type': 'RFC2544Profile', 'frame_rate': 100}, - 'downlink_0': {'ipv4': - {'outer_l2': {'framesize': - {'64B': '100', '1518B': '0', - '128B': '0', '1400B': '0', - '256B': '0', '373b': '0', - '570B': '0'}}, - 'outer_l3v4': {'dstip4': '1.1.1.1-1.15.255.255', - 'proto': 'udp', - 'srcip4': '90.90.1.1-90.105.255.255', - 'dscp': 0, 'ttl': 32, 'count': 1}, - 'outer_l4': {'srcport': '2001', - 'dsrport': '1234', 'count': 1}}}, - 'uplink_0': {'ipv4': - {'outer_l2': {'framesize': - {'64B': '100', '1518B': '0', - '128B': '0', '1400B': '0', - '256B': '0', '373b': '0', - '570B': '0'}}, - 'outer_l3v4': {'dstip4': '9.9.1.1-90.105.255.255', - 'proto': 'udp', - 'srcip4': '1.1.1.1-1.15.255.255', - 'dscp': 0, 'ttl': 32, 'count': 1}, - 'outer_l4': {'dstport': '2001', - 'srcport': '1234', 'count': 1}}}, + 'downlink_0': + {'ipv4': + {'outer_l2': + {'framesize': + {'64B': '100', '1518B': '0', + '128B': '0', '1400B': '0', + '256B': '0', '373b': '0', + '570B': '0'}}, + 'outer_l3v4': + {'dstip4': '1.1.1.1-1.15.255.255', + 'proto': 'udp', + 'srcip4': '90.90.1.1-90.105.255.255', + 'dscp': 0, 'ttl': 32, 'count': 1}, + 'outer_l4': + {'srcport': '2001', + 'dsrport': '1234', 'count': 1}}}, + 'uplink_0': + {'ipv4': + {'outer_l2': + {'framesize': + {'64B': '100', '1518B': '0', + '128B': '0', '1400B': '0', + '256B': '0', '373b': '0', + '570B': '0'}}, + 'outer_l3v4': + {'dstip4': '9.9.1.1-90.105.255.255', + 'proto': 'udp', + 'srcip4': '1.1.1.1-1.15.255.255', + 'dscp': 0, 'ttl': 32, 'count': 1}, + 'outer_l4': + {'dstport': '2001', + 'srcport': '1234', 'count': 1}}}, 'schema': 'isb:traffic_profile:0.1'} def test___init__(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - self.assertIsNotNone(r_f_c2544_profile.rate) + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + self.assertEqual(rfc2544_profile.max_rate, rfc2544_profile.rate) + self.assertEqual(0, rfc2544_profile.min_rate) - def test_execute(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client.return_value = True - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - r_f_c2544_profile.first_run = True - self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator)) + def test_stop_traffic(self): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + mock_generator = mock.Mock() + rfc2544_profile.stop_traffic(traffic_generator=mock_generator) + mock_generator.client.stop.assert_called_once() + mock_generator.client.reset.assert_called_once() + mock_generator.client.remove_all_streams.assert_called_once() - def test_get_drop_percentage(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client.return_value = True + def test_execute_traffic(self): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + mock_generator = mock.Mock() + mock_generator.networks = { + 'downlink_0': ['xe0', 'xe1'], + 'uplink_0': ['xe2', 'xe3'], + 'downlink_1': []} + mock_generator.port_num.side_effect = [10, 20, 30, 40] + mock_generator.rfc2544_helper.correlated_traffic = False + rfc2544_profile.params = { + 'downlink_0': 'profile1', + 'uplink_0': 'profile2'} - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - r_f_c2544_profile.register_generator(traffic_generator) - self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator)) + with mock.patch.object(rfc2544_profile, '_create_profile') as \ + mock_create_profile: + rfc2544_profile.execute_traffic(traffic_generator=mock_generator) + mock_create_profile.assert_has_calls([ + mock.call('profile1', rfc2544_profile.rate, mock.ANY), + mock.call('profile1', rfc2544_profile.rate, mock.ANY), + mock.call('profile2', rfc2544_profile.rate, mock.ANY), + mock.call('profile2', rfc2544_profile.rate, mock.ANY)]) + mock_generator.client.add_streams.assert_has_calls([ + mock.call(mock.ANY, ports=[10]), + mock.call(mock.ANY, ports=[20]), + mock.call(mock.ANY, ports=[30]), + mock.call(mock.ANY, ports=[40])]) + mock_generator.client.start(ports=[10, 20, 30, 40], + duration=rfc2544_profile.config.duration, + force=True) - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = { - "rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "in_packets": 1000, - "out_packets": 1000, - } + @mock.patch.object(trex_stl_streams, 'STLProfile') + def test__create_profile(self, mock_stl_profile): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + port_pg_id = mock.ANY + profile_data = {'packetid_1': {'outer_l2': {'framesize': 'imix_info'}}} + rate = 100 + with mock.patch.object(rfc2544_profile, '_create_imix_data') as \ + mock_create_imix, \ + mock.patch.object(rfc2544_profile, '_create_vm') as \ + mock_create_vm, \ + mock.patch.object(rfc2544_profile, '_create_streams') as \ + mock_create_streams: + mock_create_imix.return_value = 'imix_data' + mock_create_streams.return_value = ['stream1'] + rfc2544_profile._create_profile(profile_data, rate, port_pg_id) - expected = { - 'DropPercentage': 0.0, - 'RxThroughput': 100 / 3.0, - 'TxThroughput': 100 / 3.0, - 'CurrentDropPercentage': 0.0, - 'Throughput': 66.66666666666667, - 'xe0': { - 'tx_throughput_fps': 20, - 'in_packets': 1000, - 'out_packets': 1000, - 'rx_throughput_mbps': 10, - 'tx_throughput_mbps': 10, - 'rx_throughput_fps': 20, - }, - } - traffic_generator.generate_samples.return_value = samples - traffic_generator.RUN_DURATION = 30 - traffic_generator.rfc2544_helper.tolerance_low = 0.0001 - traffic_generator.rfc2544_helper.tolerance_high = 0.0001 - result = r_f_c2544_profile.get_drop_percentage(traffic_generator) - self.assertDictEqual(result, expected) + mock_create_imix.assert_called_once_with('imix_info') + mock_create_vm.assert_called_once_with( + {'outer_l2': {'framesize': 'imix_info'}}) + mock_create_streams.assert_called_once_with('imix_data', 100, + port_pg_id) + mock_stl_profile.assert_called_once_with(['stream1']) - def test_get_drop_percentage_update(self): - traffic_generator = mock.Mock(autospec=RFC2544Profile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client = mock.Mock(return_value=True) + def test__create_imix_data(self): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + data = {'64B': 50, '128B': 50} + self.assertEqual({'64': 50.0, '128': 50.0}, + rfc2544_profile._create_imix_data(data)) + data = {'64B': 1, '128b': 3} + self.assertEqual({'64': 25.0, '128': 75.0}, + rfc2544_profile._create_imix_data(data)) + data = {} + self.assertEqual({}, rfc2544_profile._create_imix_data(data)) - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - r_f_c2544_profile.register_generator(traffic_generator) - self.assertIsNone(r_f_c2544_profile.execute_traffic()) + def test__create_vm(self): + packet = {'outer_l2': 'l2_definition'} + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + with mock.patch.object(rfc2544_profile, '_set_outer_l2_fields') as \ + mock_l2_fileds: + rfc2544_profile._create_vm(packet) + mock_l2_fileds.assert_called_once_with('l2_definition') - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = { - "rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "in_packets": 1000, - "out_packets": 1002, - } - expected = { - 'DropPercentage': 0.1996, - 'RxThroughput': 33.333333333333336, - 'TxThroughput': 33.4, - 'CurrentDropPercentage': 0.1996, - 'Throughput': 66.66666666666667, - 'xe0': { - 'tx_throughput_fps': 20, - 'in_packets': 1000, - 'out_packets': 1002, - 'rx_throughput_mbps': 10, - 'tx_throughput_mbps': 10, - 'rx_throughput_fps': 20, - }, - } - traffic_generator.generate_samples = mock.MagicMock( - return_value=samples) - traffic_generator.RUN_DURATION = 30 - traffic_generator.rfc2544_helper.tolerance_low = 0.0001 - traffic_generator.rfc2544_helper.tolerance_high = 0.0001 - result = r_f_c2544_profile.get_drop_percentage(traffic_generator) - self.assertDictEqual(expected, result) + @mock.patch.object(trex_stl_packet_builder_scapy, 'STLPktBuilder', + return_value='packet') + def test__create_single_packet(self, mock_pktbuilder): + size = 128 + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + rfc2544_profile.ether_packet = Pkt.Eth() + rfc2544_profile.ip_packet = Pkt.IP() + rfc2544_profile.udp_packet = Pkt.UDP() + rfc2544_profile.trex_vm = 'trex_vm' + base_pkt = (rfc2544_profile.ether_packet / rfc2544_profile.ip_packet / + rfc2544_profile.udp_packet) + pad = (size - len(base_pkt)) * 'x' + output = rfc2544_profile._create_single_packet(size=size) + mock_pktbuilder.assert_called_once_with(pkt=base_pkt / pad, + vm='trex_vm') + self.assertEqual(output, 'packet') - def test_get_drop_percentage_div_zero(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client = \ - mock.Mock(return_value=True) - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - self.assertIsNone( - r_f_c2544_profile.execute_traffic(traffic_generator)) - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = {"rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "in_packets": 1000, - "out_packets": 0} - r_f_c2544_profile.throughput_max = 0 - expected = { - 'DropPercentage': 100.0, 'RxThroughput': 100 / 3.0, - 'TxThroughput': 0.0, 'CurrentDropPercentage': 100.0, - 'Throughput': 66.66666666666667, - 'xe0': { - 'tx_throughput_fps': 20, 'in_packets': 1000, - 'out_packets': 0, 'rx_throughput_mbps': 10, - 'tx_throughput_mbps': 10, 'rx_throughput_fps': 20 - } - } - traffic_generator.generate_samples = mock.Mock(return_value=samples) - traffic_generator.RUN_DURATION = 30 - traffic_generator.rfc2544_helper.tolerance_low = 0.0001 - traffic_generator.rfc2544_helper.tolerance_high = 0.0001 - self.assertDictEqual(expected, - r_f_c2544_profile.get_drop_percentage(traffic_generator)) + @mock.patch.object(trex_stl_packet_builder_scapy, 'STLPktBuilder', + return_value='packet') + def test__create_single_packet_qinq(self, mock_pktbuilder): + size = 128 + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + rfc2544_profile.ether_packet = Pkt.Eth() + rfc2544_profile.ip_packet = Pkt.IP() + rfc2544_profile.udp_packet = Pkt.UDP() + rfc2544_profile.trex_vm = 'trex_vm' + rfc2544_profile.qinq = True + rfc2544_profile.qinq_packet = Pkt.Dot1Q(vlan=1) / Pkt.Dot1Q(vlan=2) + base_pkt = (rfc2544_profile.ether_packet / + rfc2544_profile.qinq_packet / rfc2544_profile.ip_packet / + rfc2544_profile.udp_packet) + pad = (size - len(base_pkt)) * 'x' + output = rfc2544_profile._create_single_packet(size=size) + mock_pktbuilder.assert_called_once_with(pkt=base_pkt / pad, + vm='trex_vm') + self.assertEqual(output, 'packet') + + @mock.patch.object(trex_stl_streams, 'STLFlowLatencyStats') + @mock.patch.object(trex_stl_streams, 'STLTXCont') + @mock.patch.object(trex_stl_client, 'STLStream') + def test__create_streams(self, mock_stream, mock_txcont, mock_latency): + imix_data = {'64': 25, '512': 75} + rate = 35 + port_pg_id = rfc2544.PortPgIDMap() + port_pg_id.add_port(10) + mock_stream.side_effect = ['stream1', 'stream2'] + mock_txcont.side_effect = ['txcont1', 'txcont2'] + mock_latency.side_effect = ['latency1', 'latency2'] + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + with mock.patch.object(rfc2544_profile, '_create_single_packet'): + output = rfc2544_profile._create_streams(imix_data, rate, + port_pg_id) + self.assertEqual(['stream1', 'stream2'], output) + mock_latency.assert_has_calls([ + mock.call(pg_id=1), mock.call(pg_id=2)]) + mock_txcont.assert_has_calls([ + mock.call(percentage=float(25 * 35) / 100), + mock.call(percentage=float(75 * 35) / 100)], any_order=True) + + def test_get_drop_percentage(self): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + samples = [ + {'xe1': {'tx_throughput_fps': 100, + 'rx_throughput_fps': 101, + 'out_packets': 2000, + 'in_packets': 2010}, + 'xe2': {'tx_throughput_fps': 200, + 'rx_throughput_fps': 201, + 'out_packets': 4000, + 'in_packets': 4010}}, + {'xe1': {'tx_throughput_fps': 106, + 'rx_throughput_fps': 108, + 'out_packets': 2031, + 'in_packets': 2040, + 'latency': 'Latency1'}, + 'xe2': {'tx_throughput_fps': 203, + 'rx_throughput_fps': 215, + 'out_packets': 4025, + 'in_packets': 4040, + 'latency': 'Latency2'}} + ] + output = rfc2544_profile.get_drop_percentage(samples, 0, 0, False) + expected = {'DropPercentage': 0.3963, + 'Latency': {'xe1': 'Latency1', 'xe2': 'Latency2'}, + 'RxThroughput': 312.5, + 'TxThroughput': 304.5, + 'CurrentDropPercentage': 0.3963, + 'Rate': 100, + 'Throughput': 312.5} + self.assertEqual(expected, output) - def test_get_multiplier(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.max_rate = 100 - r_f_c2544_profile.min_rate = 100 - self.assertEqual("1.0", r_f_c2544_profile.get_multiplier()) - def test_calculate_pps(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.rate = 100 - r_f_c2544_profile.pps = 100 - samples = {'Throughput': 4549093.33} - self.assertEqual((2274546.67, 1.0), - r_f_c2544_profile.calculate_pps(samples)) +class PortPgIDMapTestCase(base.BaseUnitTestCase): - def test_create_single_stream(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile._create_single_packet = mock.MagicMock() - r_f_c2544_profile.pg_id = 1 - self.assertIsNotNone( - r_f_c2544_profile.create_single_stream(64, 2274546.67)) + def test_add_port(self): + port_pg_id_map = rfc2544.PortPgIDMap() + port_pg_id_map.add_port(10) + self.assertEqual(10, port_pg_id_map._last_port) + self.assertEqual([], port_pg_id_map._port_pg_id_map[10]) - def test_create_single_stream_no_pg_id(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile._create_single_packet = mock.MagicMock() - r_f_c2544_profile.pg_id = 0 - self.assertIsNotNone( - r_f_c2544_profile.create_single_stream(64, 2274546.67)) + def test_get_pg_ids(self): + port_pg_id_map = rfc2544.PortPgIDMap() + port_pg_id_map.add_port(10) + port_pg_id_map.increase_pg_id() + port_pg_id_map.increase_pg_id() + port_pg_id_map.add_port(20) + port_pg_id_map.increase_pg_id() + self.assertEqual([1, 2], port_pg_id_map.get_pg_ids(10)) + self.assertEqual([3], port_pg_id_map.get_pg_ids(20)) - def test_execute_latency(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "private_0": ["xe0"], - "public_0": ["xe1"], - } - traffic_generator.client = \ - mock.Mock(return_value=True) - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - r_f_c2544_profile.first_run = True - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = {"rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "in_packets": 1000, - "out_packets": 0} + def test_increase_pg_id_no_port(self): + port_pg_id_map = rfc2544.PortPgIDMap() + self.assertIsNone(port_pg_id_map.increase_pg_id()) - samples['Throughput'] = 4549093.33 - r_f_c2544_profile.calculate_pps = mock.Mock(return_value=[2274546.67, - 1.0]) + def test_increase_pg_id_last_port(self): + port_pg_id_map = rfc2544.PortPgIDMap() + port_pg_id_map.add_port(10) + self.assertEqual(1, port_pg_id_map.increase_pg_id()) + self.assertEqual([1], port_pg_id_map.get_pg_ids(10)) + self.assertEqual(10, port_pg_id_map._last_port) - self.assertIsNone(r_f_c2544_profile.execute_latency(traffic_generator, - samples)) + def test_increase_pg_id(self): + port_pg_id_map = rfc2544.PortPgIDMap() + port_pg_id_map.add_port(10) + port_pg_id_map.increase_pg_id() + self.assertEqual(2, port_pg_id_map.increase_pg_id(port=20)) + self.assertEqual([1], port_pg_id_map.get_pg_ids(10)) + self.assertEqual([2], port_pg_id_map.get_pg_ids(20)) + self.assertEqual(20, port_pg_id_map._last_port) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py b/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py index bc83224d5..628e85459 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py @@ -14,29 +14,12 @@ import ipaddress -import mock import six import unittest -from yardstick.tests import STL_MOCKS from yardstick.common import exceptions as y_exc - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.traffic_profile.base import TrafficProfile - from yardstick.network_services.traffic_profile.trex_traffic_profile import TrexProfile - from yardstick.network_services.traffic_profile.trex_traffic_profile import SRC - from yardstick.network_services.traffic_profile.trex_traffic_profile import DST - from yardstick.network_services.traffic_profile.trex_traffic_profile import ETHERNET - from yardstick.network_services.traffic_profile.trex_traffic_profile import IP - from yardstick.network_services.traffic_profile.trex_traffic_profile import IPv6 - from yardstick.network_services.traffic_profile.trex_traffic_profile import UDP - from yardstick.network_services.traffic_profile.trex_traffic_profile import SRC_PORT - from yardstick.network_services.traffic_profile.trex_traffic_profile import DST_PORT - from yardstick.network_services.traffic_profile.trex_traffic_profile import TYPE_OF_SERVICE +from yardstick.network_services.traffic_profile import base as tp_base +from yardstick.network_services.traffic_profile import trex_traffic_profile class TestTrexProfile(unittest.TestCase): @@ -59,7 +42,7 @@ class TestTrexProfile(unittest.TestCase): 'name': 'rfc2544', 'traffic_profile': {'traffic_type': 'RFC2544Profile', 'frame_rate': 100}, - TrafficProfile.DOWNLINK: { + tp_base.TrafficProfile.DOWNLINK: { 'ipv4': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', '128B': '0', @@ -77,7 +60,7 @@ class TestTrexProfile(unittest.TestCase): 'outer_l4': {'srcport': '2001', 'dsrport': '1234', 'count': 1}}}, - TrafficProfile.UPLINK: { + tp_base.TrafficProfile.UPLINK: { 'ipv4': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', @@ -99,7 +82,7 @@ class TestTrexProfile(unittest.TestCase): 'name': 'rfc2544', 'traffic_profile': {'traffic_type': 'RFC2544Profile', 'frame_rate': 100}, - TrafficProfile.DOWNLINK: { + tp_base.TrafficProfile.DOWNLINK: { 'ipv6': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', '128B': '0', '1400B': '0', @@ -118,7 +101,7 @@ class TestTrexProfile(unittest.TestCase): 'outer_l4': {'srcport': '2001', 'dsrport': '1234', 'count': 1}}}, - TrafficProfile.UPLINK: { + tp_base.TrafficProfile.UPLINK: { 'ipv6': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', '128B': '0', '1400B': '0', @@ -139,66 +122,56 @@ class TestTrexProfile(unittest.TestCase): 'count': 1}}}, 'schema': 'isb:traffic_profile:0.1'} - def setUp(self): - self.trex_profile = TrexProfile(self.PROFILE) - def test___init__(self): - self.assertEqual(self.trex_profile.pps, 100) + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + self.assertEqual(trex_profile.pps, 100) def test_qinq(self): + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) qinq = {"S-VLAN": {"id": 128, "priority": 0, "cfi": 0}, "C-VLAN": {"id": 512, "priority": 0, "cfi": 0}} - self.assertIsNone(self.trex_profile.set_qinq(qinq)) + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + self.assertIsNone(trex_profile.set_qinq(qinq)) qinq = {"S-VLAN": {"id": "128-130", "priority": 0, "cfi": 0}, "C-VLAN": {"id": "512-515", "priority": 0, "cfi": 0}} - self.assertIsNone(self.trex_profile.set_qinq(qinq)) + self.assertIsNone(trex_profile.set_qinq(qinq)) def test__set_outer_l2_fields(self): + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) qinq = {"S-VLAN": {"id": 128, "priority": 0, "cfi": 0}, "C-VLAN": {"id": 512, "priority": 0, "cfi": 0}} - outer_l2 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l2'] + outer_l2 = self.PROFILE[ + tp_base.TrafficProfile.UPLINK]['ipv4']['outer_l2'] outer_l2['QinQ'] = qinq - self.assertIsNone(self.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): - outer_l3v4 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l3v4'] + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + outer_l3v4 = self.PROFILE[ + tp_base.TrafficProfile.UPLINK]['ipv4']['outer_l3v4'] outer_l3v4['proto'] = 'tcp' - self.assertIsNone(self.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): - outer_l3v6 = self.PROFILE_v6[TrafficProfile.UPLINK]['ipv6']['outer_l3v4'] + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + outer_l3v6 = self.PROFILE_v6[ + tp_base.TrafficProfile.UPLINK]['ipv6']['outer_l3v4'] outer_l3v6['proto'] = 'tcp' outer_l3v6['tc'] = 1 outer_l3v6['hlim'] = 10 - self.assertIsNone(self.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): - outer_l4 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l4'] - self.assertIsNone(self.trex_profile._set_outer_l4_fields(outer_l4)) - - def test_get_streams(self): - profile_data = self.PROFILE[TrafficProfile.UPLINK] - self.assertIsNotNone(self.trex_profile.get_streams(profile_data)) - self.trex_profile.pg_id = 1 - self.assertIsNotNone(self.trex_profile.get_streams(profile_data)) - self.trex_profile.params = self.PROFILE_v6 - self.trex_profile.profile_data = self.PROFILE_v6[TrafficProfile.UPLINK] - self.assertIsNotNone(self.trex_profile.get_streams(profile_data)) - self.trex_profile.pg_id = 1 - self.assertIsNotNone(self.trex_profile.get_streams(profile_data)) - - def test_generate_packets(self): - self.trex_profile.fsize = 10 - self.trex_profile.base_pkt = [10] - self.assertIsNone(self.trex_profile.generate_packets()) - - def test_generate_imix_data_error(self): - self.assertEqual({}, self.trex_profile.generate_imix_data(False)) + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + outer_l4 = self.PROFILE[ + tp_base.TrafficProfile.UPLINK]['ipv4']['outer_l4'] + self.assertIsNone(trex_profile._set_outer_l4_fields(outer_l4)) def test__count_ip_ipv4(self): - start, end, count = TrexProfile._count_ip('1.1.1.1', '1.2.3.4') + start, end, count = trex_traffic_profile.TrexProfile._count_ip( + '1.1.1.1', '1.2.3.4') self.assertEqual('1.1.1.1', str(start)) self.assertEqual('1.2.3.4', str(end)) diff = (int(ipaddress.IPv4Address(six.u('1.2.3.4'))) - @@ -208,7 +181,8 @@ class TestTrexProfile(unittest.TestCase): def test__count_ip_ipv6(self): start_ip = '0064:ff9b:0:0:0:0:9810:6414' end_ip = '0064:ff9b:0:0:0:0:9810:6420' - start, end, count = TrexProfile._count_ip(start_ip, end_ip) + start, end, count = trex_traffic_profile.TrexProfile._count_ip( + start_ip, end_ip) self.assertEqual(0x98106414, start) self.assertEqual(0x98106420, end) self.assertEqual(0x98106420 - 0x98106414, count) @@ -217,10 +191,10 @@ class TestTrexProfile(unittest.TestCase): start_ip = '0064:ff9b:0:0:0:0:9810:6420' end_ip = '0064:ff9b:0:0:0:0:9810:6414' with self.assertRaises(y_exc.IPv6RangeError): - TrexProfile._count_ip(start_ip, end_ip) + trex_traffic_profile.TrexProfile._count_ip(start_ip, end_ip) def test__dscp_range_action_partial_actual_count_zero(self): - traffic_profile = TrexProfile(self.PROFILE) + traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE) dscp_partial = traffic_profile._dscp_range_action_partial() flow_vars_initial_length = len(traffic_profile.vm_flow_vars) @@ -228,7 +202,7 @@ class TestTrexProfile(unittest.TestCase): self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2) def test__dscp_range_action_partial_count_greater_than_actual(self): - traffic_profile = TrexProfile(self.PROFILE) + traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE) dscp_partial = traffic_profile._dscp_range_action_partial() flow_vars_initial_length = len(traffic_profile.vm_flow_vars) @@ -236,7 +210,7 @@ class TestTrexProfile(unittest.TestCase): self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2) def test__udp_range_action_partial_actual_count_zero(self): - traffic_profile = TrexProfile(self.PROFILE) + traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE) traffic_profile.udp['field1'] = 'value1' udp_partial = traffic_profile._udp_range_action_partial('field1') @@ -245,46 +219,59 @@ class TestTrexProfile(unittest.TestCase): self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2) def test__udp_range_action_partial_count_greater_than_actual(self): - traffic_profile = TrexProfile(self.PROFILE) + traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE) traffic_profile.udp['field1'] = 'value1' - udp_partial = traffic_profile._udp_range_action_partial('field1', 'not_used_count') - + udp_partial = traffic_profile._udp_range_action_partial( + 'field1', 'not_used_count') flow_vars_initial_length = len(traffic_profile.vm_flow_vars) udp_partial('1', '10', '100') self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2) def test__general_single_action_partial(self): - self.trex_profile._general_single_action_partial(ETHERNET)(SRC)( + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + trex_profile._general_single_action_partial( + trex_traffic_profile.ETHERNET)(trex_traffic_profile.SRC)( self.EXAMPLE_ETHERNET_ADDR) self.assertEqual(self.EXAMPLE_ETHERNET_ADDR, - self.trex_profile.ether_packet.src) + trex_profile.ether_packet.src) - self.trex_profile._general_single_action_partial(IP)(DST)( - self.EXAMPLE_IP_ADDR) - self.assertEqual(self.EXAMPLE_IP_ADDR, self.trex_profile.ip_packet.dst) + trex_profile._general_single_action_partial(trex_traffic_profile.IP)( + trex_traffic_profile.DST)(self.EXAMPLE_IP_ADDR) + self.assertEqual(self.EXAMPLE_IP_ADDR, trex_profile.ip_packet.dst) - self.trex_profile._general_single_action_partial(IPv6)(DST)( - self.EXAMPLE_IPv6_ADDR) - self.assertEqual(self.EXAMPLE_IPv6_ADDR, - self.trex_profile.ip6_packet.dst) + trex_profile._general_single_action_partial(trex_traffic_profile.IPv6)( + trex_traffic_profile.DST)(self.EXAMPLE_IPv6_ADDR) + self.assertEqual(self.EXAMPLE_IPv6_ADDR, trex_profile.ip6_packet.dst) - self.trex_profile._general_single_action_partial(UDP)(SRC_PORT)(5060) - self.assertEqual(5060, self.trex_profile.udp_packet.sport) + trex_profile._general_single_action_partial(trex_traffic_profile.UDP)( + trex_traffic_profile.SRC_PORT)(5060) + self.assertEqual(5060, trex_profile.udp_packet.sport) - self.trex_profile._general_single_action_partial( - IP)(TYPE_OF_SERVICE)(0) - self.assertEqual(0, self.trex_profile.ip_packet.tos) + trex_profile._general_single_action_partial(trex_traffic_profile.IP)( + trex_traffic_profile.TYPE_OF_SERVICE)(0) + self.assertEqual(0, trex_profile.ip_packet.tos) def test__set_proto_addr(self): + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + ether_range = "00:00:00:00:00:01-00:00:00:00:00:02" ip_range = "1.1.1.2-1.1.1.10" ipv6_range = '0064:ff9b:0:0:0:0:9810:6414-0064:ff9b:0:0:0:0:9810:6420' - self.trex_profile._set_proto_addr(ETHERNET, SRC, ether_range) - self.trex_profile._set_proto_addr(ETHERNET, DST, ether_range) - self.trex_profile._set_proto_addr(IP, SRC, ip_range) - self.trex_profile._set_proto_addr(IP, DST, ip_range) - self.trex_profile._set_proto_addr(IPv6, SRC, ipv6_range) - self.trex_profile._set_proto_addr(IPv6, DST, ipv6_range) - self.trex_profile._set_proto_addr(UDP, SRC_PORT, '5060-5090') - self.trex_profile._set_proto_addr(UDP, DST_PORT, '5060') + trex_profile._set_proto_addr(trex_traffic_profile.ETHERNET, + trex_traffic_profile.SRC, ether_range) + trex_profile._set_proto_addr(trex_traffic_profile.ETHERNET, + trex_traffic_profile.DST, ether_range) + trex_profile._set_proto_addr(trex_traffic_profile.IP, + trex_traffic_profile.SRC, ip_range) + trex_profile._set_proto_addr(trex_traffic_profile.IP, + trex_traffic_profile.DST, ip_range) + trex_profile._set_proto_addr(trex_traffic_profile.IPv6, + trex_traffic_profile.SRC, ipv6_range) + trex_profile._set_proto_addr(trex_traffic_profile.IPv6, + trex_traffic_profile.DST, ipv6_range) + trex_profile._set_proto_addr(trex_traffic_profile.UDP, + trex_traffic_profile.SRC_PORT, + '5060-5090') + trex_profile._set_proto_addr(trex_traffic_profile.UDP, + trex_traffic_profile.DST_PORT, '5060') diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py index 01d79303c..45e06689b 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# from copy import deepcopy @@ -19,37 +18,29 @@ import unittest import mock import six -from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh -from yardstick.tests import STL_MOCKS from yardstick.benchmark.contexts.base import Context from yardstick.common import exceptions as y_exceptions from yardstick.common import utils from yardstick.network_services.nfvi.resource import ResourceProfile from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper - - -class MockError(BaseException): +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFDeployHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import ResourceHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SetupEnvHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen +from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper +from yardstick.tests.unit.network_services.vnf_generic.vnf import test_base + + +class MockError(Exception): pass -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf import sample_vnf - from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFDeployHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import ResourceHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import SetupEnvHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF - from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen - from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper - - class TestVnfSshHelper(unittest.TestCase): VNFD_0 = { @@ -1003,176 +994,39 @@ class TestClientResourceHelper(unittest.TestCase): } @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.LOG') - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.STLError', - new_callable=lambda: MockError) - def test_get_stats_not_connected(self, mock_state_error, *args): + @mock.patch.object(sample_vnf, 'STLError', new_callable=lambda: MockError) + def test_get_stats_not_connected(self, mock_stl_error, *args): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) - client_resource_helper.client = mock.MagicMock() - client_resource_helper.client.get_stats.side_effect = mock_state_error + client_resource_helper.client = mock.Mock() + client_resource_helper.client.get_stats.side_effect = mock_stl_error self.assertEqual(client_resource_helper.get_stats(), {}) self.assertEqual(client_resource_helper.client.get_stats.call_count, 1) - def test_generate_samples(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - ssh_helper = mock.Mock() - scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - client_resource_helper = ClientResourceHelper(dpdk_setup_helper) - client_resource_helper.client = mock.MagicMock() - client_resource_helper.client.get_stats.return_value = { - 0: { - 'rx_pps': 5.5, - 'tx_pps': 4.9, - 'rx_bps': 234.78, - 'tx_bps': 243.11, - 'ipackets': 34251, - 'opackets': 52342, - }, - 1: { - 'tx_pps': 5.9, - 'rx_bps': 434.78, - 'opackets': 48791, - }, - } - - expected = { - 'xe0': { - "rx_throughput_fps": 5.5, - "tx_throughput_fps": 4.9, - "rx_throughput_mbps": 234.78, - "tx_throughput_mbps": 243.11, - "in_packets": 34251, - "out_packets": 52342, - }, - 'xe1': { - "rx_throughput_fps": 0.0, - "tx_throughput_fps": 5.9, - "rx_throughput_mbps": 434.78, - "tx_throughput_mbps": 0.0, - "in_packets": 0, - "out_packets": 48791, - }, - } - ports = vnfd_helper.port_nums(vnfd_helper.port_pairs.all_ports) - result = client_resource_helper.generate_samples(ports) - self.assertDictEqual(result, expected) - - def test_generate_samples_with_key(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - ssh_helper = mock.Mock() - scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - client_resource_helper = ClientResourceHelper(dpdk_setup_helper) - client_resource_helper.client = mock.MagicMock() - client_resource_helper.client.get_stats.return_value = { - 'key_name': 'key_value', - 0: { - 'rx_pps': 5.5, - 'tx_pps': 4.9, - 'rx_bps': 234.78, - 'tx_bps': 243.11, - 'ipackets': 34251, - 'opackets': 52342, - }, - 1: { - 'tx_pps': 5.9, - 'rx_bps': 434.78, - 'opackets': 48791, - }, - } - - expected = { - 'xe0': { - 'key_name': 'key_value', - "rx_throughput_fps": 5.5, - "tx_throughput_fps": 4.9, - "rx_throughput_mbps": 234.78, - "tx_throughput_mbps": 243.11, - "in_packets": 34251, - "out_packets": 52342, - }, - 'xe1': { - 'key_name': 'key_value', - "rx_throughput_fps": 0.0, - "tx_throughput_fps": 5.9, - "rx_throughput_mbps": 434.78, - "tx_throughput_mbps": 0.0, - "in_packets": 0, - "out_packets": 48791, - }, - } - ports = vnfd_helper.port_nums(vnfd_helper.port_pairs.all_ports) - result = client_resource_helper.generate_samples(ports, 'key_name') - self.assertDictEqual(result, expected) - - def test_generate_samples_with_key_and_default(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - ssh_helper = mock.Mock() - scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - client_resource_helper = ClientResourceHelper(dpdk_setup_helper) - client_resource_helper.client = mock.MagicMock() - client_resource_helper.client.get_stats.return_value = { - 0: { - 'rx_pps': 5.5, - 'tx_pps': 4.9, - 'rx_bps': 234.78, - 'tx_bps': 243.11, - 'ipackets': 34251, - 'opackets': 52342, - }, - 1: { - 'tx_pps': 5.9, - 'rx_bps': 434.78, - 'opackets': 48791, - }, - } - - expected = { - 'xe0': { - 'key_name': 'default', - "rx_throughput_fps": 5.5, - "tx_throughput_fps": 4.9, - "rx_throughput_mbps": 234.78, - "tx_throughput_mbps": 243.11, - "in_packets": 34251, - "out_packets": 52342, - }, - 'xe1': { - 'key_name': 'default', - "rx_throughput_fps": 0.0, - "tx_throughput_fps": 5.9, - "rx_throughput_mbps": 434.78, - "tx_throughput_mbps": 0.0, - "in_packets": 0, - "out_packets": 48791, - }, - } - ports = vnfd_helper.port_nums(vnfd_helper.port_pairs.all_ports) - result = client_resource_helper.generate_samples(ports, 'key_name', 'default') - self.assertDictEqual(result, expected) - def test_clear_stats(self): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client_resource_helper.client = mock.Mock() self.assertIsNone(client_resource_helper.clear_stats()) - self.assertEqual(client_resource_helper.client.clear_stats.call_count, 1) + self.assertEqual( + client_resource_helper.client.clear_stats.call_count, 1) def test_clear_stats_of_ports(self): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client_resource_helper.client = mock.Mock() @@ -1183,7 +1037,8 @@ class TestClientResourceHelper(unittest.TestCase): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client_resource_helper.client = mock.Mock() @@ -1194,7 +1049,8 @@ class TestClientResourceHelper(unittest.TestCase): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client_resource_helper.client = mock.Mock() @@ -1221,17 +1077,15 @@ class TestClientResourceHelper(unittest.TestCase): self.assertDictEqual(result, expected) @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time') - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.LOG') - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.STLError', - new_callable=lambda: MockError) - def test__connect_with_failures(self, mock_error, *args): + @mock.patch.object(sample_vnf, 'STLError') + def test__connect_with_failures(self, mock_stl_error, *args): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client = mock.MagicMock() - client.connect.side_effect = mock_error + client.connect.side_effect = mock_stl_error(msg='msg') self.assertIs(client_resource_helper._connect(client), client) @@ -1680,7 +1534,7 @@ class TestSampleVnf(unittest.TestCase): @mock.patch("yardstick.ssh.SSH") def test_instantiate(self, ssh): - mock_ssh(ssh) + test_base.mock_ssh(ssh) nodes = { 'vnf1': 'name1', @@ -1780,7 +1634,7 @@ class TestSampleVnf(unittest.TestCase): @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") @mock.patch("yardstick.ssh.SSH") def test_wait_for_instantiate_empty_queue(self, ssh, *args): - mock_ssh(ssh, exec_result=(1, "", "")) + test_base.mock_ssh(ssh, exec_result=(1, "", "")) queue_size_list = [ 0, diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py index 8b1b8a39c..a463fa0de 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py @@ -11,44 +11,39 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# - -import unittest -import mock - -from yardstick.tests import STL_MOCKS -SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' +from __future__ import absolute_import -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.tg_rfc2544_trex import TrexTrafficGenRFC, \ - TrexRfcResourceHelper - from yardstick.network_services.vnf_generic.vnf import tg_rfc2544_trex - from yardstick.network_services.traffic_profile.base import TrafficProfile - from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base \ - import FileAbsPath, mock_ssh +import mock +import unittest -MODULE_PATH = FileAbsPath(__file__) -get_file_abspath = MODULE_PATH.get_path +from yardstick.network_services.traffic_profile import base as tp_base +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.vnf_generic.vnf import tg_rfc2544_trex class TestTrexRfcResouceHelper(unittest.TestCase): - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.MultiPortConfig') - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_trex.time") - @mock.patch(SSH_HELPER) - def test__run_traffic_once(self, ssh, *_): - mock_ssh(ssh) + def test__run_traffic_once(self): + mock_setup_helper = mock.Mock() + mock_traffic_profile = mock.Mock() + mock_traffic_profile.config.duration = 3 + mock_traffic_profile.execute_traffic.return_value = ('fake_ports', + 'port_pg_id_map') + mock_traffic_profile.get_drop_percentage.return_value = 'percentage' + rfc_rh = tg_rfc2544_trex.TrexRfcResourceHelper(mock_setup_helper) + rfc_rh.TRANSIENT_PERIOD = 0 + rfc_rh.rfc2544_helper = mock.Mock() + + with mock.patch.object(rfc_rh, '_get_samples') as mock_get_samples: + rfc_rh._run_traffic_once(mock_traffic_profile) - mock_traffic_profile = mock.MagicMock(autospec=TrafficProfile, - **{'get_drop_percentage.return_value': {}}) - sut = TrexRfcResourceHelper(mock.MagicMock(), mock.MagicMock()) - sut.client = mock.MagicMock() - sut._run_traffic_once(mock_traffic_profile) + mock_traffic_profile.execute_traffic.assert_called_once_with(rfc_rh) + mock_traffic_profile.stop_traffic.assert_called_once_with(rfc_rh) + mock_traffic_profile.stop_traffic.assert_called_once() + mock_get_samples.assert_has_calls([ + mock.call('fake_ports', port_pg_id='port_pg_id_map'), + mock.call('fake_ports', port_pg_id='port_pg_id_map')]) class TestTrexTrafficGenRFC(unittest.TestCase): @@ -219,33 +214,24 @@ class TestTrexTrafficGenRFC(unittest.TestCase): 'schema': 'yardstick:task:0.1', } - @mock.patch(SSH_HELPER) - def test___init__(self, ssh): - mock_ssh(ssh) - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - self.assertIsNotNone(trex_traffic_gen.resource_helper._terminated.value) - - @mock.patch(SSH_HELPER) - def test_collect_kpi(self, ssh): - mock_ssh(ssh) - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - self.assertEqual(trex_traffic_gen.collect_kpi(), {}) + def setUp(self): + self._mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper') + self.mock_ssh_helper = self._mock_ssh_helper.start() + self.addCleanup(self._stop_mocks) - @mock.patch(SSH_HELPER) - def test_listen_traffic(self, ssh): - mock_ssh(ssh) - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - self.assertIsNone(trex_traffic_gen.listen_traffic({})) + def _stop_mocks(self): + self._mock_ssh_helper.stop() - @mock.patch(SSH_HELPER) - def test_instantiate(self, ssh): - mock_ssh(ssh) + def test___init__(self): + trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC('vnf1', self.VNFD_0) + self.assertIsNotNone(trex_traffic_gen.resource_helper._terminated.value) - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + def test_instantiate(self): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) + trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC('vnf1', self.VNFD_0) trex_traffic_gen._start_server = mock.Mock(return_value=0) trex_traffic_gen.resource_helper = mock.MagicMock() trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() @@ -274,15 +260,12 @@ class TestTrexTrafficGenRFC(unittest.TestCase): scenario_cfg.update({"nodes": ["tg_1", "vnf_1"]}) self.assertIsNone(trex_traffic_gen.instantiate(scenario_cfg, {})) - @mock.patch(SSH_HELPER) - def test_instantiate_error(self, ssh): - mock_ssh(ssh, exec_result=(1, "", "")) - - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + def test_instantiate_error(self): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) + trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC('vnf1', self.VNFD_0) trex_traffic_gen.resource_helper = mock.MagicMock() trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() scenario_cfg = { @@ -310,29 +293,3 @@ class TestTrexTrafficGenRFC(unittest.TestCase): }, } trex_traffic_gen.instantiate(scenario_cfg, {}) - - @mock.patch(SSH_HELPER) - def test__start_server(self, ssh): - mock_ssh(ssh) - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - trex_traffic_gen.resource_helper = mock.MagicMock() - self.assertIsNone(trex_traffic_gen._start_server()) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_trex.time") - @mock.patch(SSH_HELPER) - def test__generate_trex_cfg(self, ssh, _): - mock_ssh(ssh) - - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - trex_traffic_gen.ssh_helper = mock.MagicMock() - trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() - self.assertIsNone(trex_traffic_gen.resource_helper.generate_cfg()) - - def test_terminate(self): - with mock.patch(SSH_HELPER) as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - trex_traffic_gen.resource_helper = mock.MagicMock() - self.assertIsNone(trex_traffic_gen.terminate()) diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py index aae3d468f..4f8742477 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py @@ -11,31 +11,23 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# import copy import mock import unittest -from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh -from yardstick.tests import STL_MOCKS +from yardstick.network_services.traffic_profile import base as tp_base +from yardstick.network_services.traffic_profile import rfc2544 +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.vnf_generic.vnf import tg_trex -SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' NAME = 'vnf_1' -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.tg_trex import \ - TrexTrafficGen, TrexResourceHelper - from yardstick.network_services.traffic_profile.base import TrafficProfile - class TestTrexTrafficGen(unittest.TestCase): + VNFD = {'vnfd:vnfd-catalog': {'vnfd': [{'short-name': 'VpeVnf', @@ -168,7 +160,7 @@ class TestTrexTrafficGen(unittest.TestCase): "interfaces": { "xe0": { "local_iface_name": "ens786f0", - "vld_id": TrafficProfile.UPLINK, + "vld_id": tp_base.TrafficProfile.UPLINK, "netmask": "255.255.255.0", "vpci": "0000:05:00.0", "local_ip": "152.16.100.19", @@ -180,7 +172,7 @@ class TestTrexTrafficGen(unittest.TestCase): }, "xe1": { "local_iface_name": "ens786f1", - "vld_id": TrafficProfile.DOWNLINK, + "vld_id": tp_base.TrafficProfile.DOWNLINK, "netmask": "255.255.255.0", "vpci": "0000:05:00.1", "local_ip": "152.16.40.19", @@ -236,7 +228,7 @@ class TestTrexTrafficGen(unittest.TestCase): "interfaces": { "xe0": { "local_iface_name": "ens513f0", - "vld_id": TrafficProfile.DOWNLINK, + "vld_id": tp_base.TrafficProfile.DOWNLINK, "netmask": "255.255.255.0", "vpci": "0000:02:00.0", "local_ip": "152.16.40.20", @@ -270,7 +262,7 @@ class TestTrexTrafficGen(unittest.TestCase): "interfaces": { "xe0": { "local_iface_name": "ens785f0", - "vld_id": TrafficProfile.UPLINK, + "vld_id": tp_base.TrafficProfile.UPLINK, "netmask": "255.255.255.0", "vpci": "0000:05:00.0", "local_ip": "152.16.100.20", @@ -297,36 +289,35 @@ class TestTrexTrafficGen(unittest.TestCase): } } - @mock.patch(SSH_HELPER) - def test___init__(self, ssh): - mock_ssh(ssh) + def setUp(self): + self._mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper') + self.mock_ssh_helper = self._mock_ssh_helper.start() + self.addCleanup(self._stop_mocks) + + def _stop_mocks(self): + self._mock_ssh_helper.stop() + + def test___init__(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) - self.assertIsInstance( - trex_traffic_gen.resource_helper, TrexResourceHelper) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) + self.assertIsInstance(trex_traffic_gen.resource_helper, + tg_trex.TrexResourceHelper) - @mock.patch(SSH_HELPER) - def test_collect_kpi(self, ssh): - mock_ssh(ssh) + def test_collect_kpi(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) trex_traffic_gen.resource_helper._queue.put({}) result = trex_traffic_gen.collect_kpi() self.assertEqual({}, result) - @mock.patch(SSH_HELPER) - def test_listen_traffic(self, ssh): - mock_ssh(ssh) + def test_listen_traffic(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) self.assertIsNone(trex_traffic_gen.listen_traffic({})) - @mock.patch(SSH_HELPER) - def test_instantiate(self, ssh): - mock_ssh(ssh) - + def test_instantiate(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) trex_traffic_gen._start_server = mock.Mock(return_value=0) trex_traffic_gen._tg_process = mock.MagicMock() trex_traffic_gen._tg_process.start = mock.Mock() @@ -335,16 +326,12 @@ class TestTrexTrafficGen(unittest.TestCase): trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() + self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG, + self.CONTEXT_CFG)) - self.assertIsNone(trex_traffic_gen.instantiate( - self.SCENARIO_CFG, self.CONTEXT_CFG)) - - @mock.patch(SSH_HELPER) - def test_instantiate_error(self, ssh): - mock_ssh(ssh, exec_result=(1, "", "")) - + def test_instantiate_error(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) trex_traffic_gen._start_server = mock.Mock(return_value=0) trex_traffic_gen._tg_process = mock.MagicMock() trex_traffic_gen._tg_process.start = mock.Mock() @@ -352,62 +339,53 @@ class TestTrexTrafficGen(unittest.TestCase): trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() - self.assertIsNone(trex_traffic_gen.instantiate( - self.SCENARIO_CFG, self.CONTEXT_CFG)) + self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG, + self.CONTEXT_CFG)) - @mock.patch(SSH_HELPER) - def test__start_server(self, ssh): - mock_ssh(ssh) + def test__start_server(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() trex_traffic_gen.scenario_helper.scenario_cfg = {} self.assertIsNone(trex_traffic_gen._start_server()) - @mock.patch(SSH_HELPER) - def test__start_server_multiple_queues(self, ssh): - mock_ssh(ssh) + def test__start_server_multiple_queues(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() trex_traffic_gen.scenario_helper.scenario_cfg = { "options": {NAME: {"queues_per_port": 2}}} self.assertIsNone(trex_traffic_gen._start_server()) - @mock.patch(SSH_HELPER) - def test__traffic_runner(self, ssh): - mock_ssh(ssh) - - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + def test__traffic_runner(self): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.execute_traffic.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - self.sut = TrexTrafficGen(NAME, vnfd) + self.sut = tg_trex.TrexTrafficGen(NAME, vnfd) self.sut.ssh_helper = mock.Mock() self.sut.ssh_helper.run = mock.Mock() - self.sut._connect_client = mock.Mock(autospec=STLClient) + self.sut._connect_client = mock.Mock() self.sut._connect_client.get_stats = mock.Mock(return_value="0") self.sut.resource_helper.RUN_DURATION = 0 self.sut.resource_helper.QUEUE_WAIT_TIME = 0 - # must generate cfg before we can run traffic so Trex port mapping is created + # must generate cfg before we can run traffic so Trex port mapping is + # created self.sut.resource_helper.generate_cfg() - self.sut._traffic_runner(mock_traffic_profile) + with mock.patch.object(self.sut.resource_helper, 'run_traffic'): + self.sut._traffic_runner(mock_traffic_profile) - @mock.patch(SSH_HELPER) - def test__generate_trex_cfg(self, ssh): - mock_ssh(ssh) + def test__generate_trex_cfg(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() self.assertIsNone(trex_traffic_gen.resource_helper.generate_cfg()) - @mock.patch(SSH_HELPER) - def test_build_ports_reversed_pci_ordering(self, ssh): - mock_ssh(ssh) + def test_build_ports_reversed_pci_ordering(self): vnfd = copy.deepcopy(self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]) vnfd['vdu'][0]['external-interface'] = [ {'virtual-interface': @@ -442,26 +420,24 @@ class TestTrexTrafficGen(unittest.TestCase): 'local_mac': '00:00:00:00:00:01'}, 'vnfd-connection-point-ref': 'xe1', 'name': 'xe1'}] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.generate_cfg() trex_traffic_gen.resource_helper._build_ports() - self.assertEqual( - sorted(trex_traffic_gen.resource_helper.all_ports), [0, 1]) + self.assertEqual(sorted(trex_traffic_gen.resource_helper.all_ports), + [0, 1]) # there is a gap in ordering - self.assertEqual(dict(trex_traffic_gen.resource_helper.dpdk_to_trex_port_map), - {0: 0, 2: 1}) - - @mock.patch(SSH_HELPER) - def test_run_traffic(self, ssh): - mock_ssh(ssh) + self.assertEqual( + {0: 0, 2: 1}, + dict(trex_traffic_gen.resource_helper.dpdk_to_trex_port_map)) - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + def test_run_traffic(self): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - self.sut = TrexTrafficGen(NAME, vnfd) + self.sut = tg_trex.TrexTrafficGen(NAME, vnfd) self.sut.ssh_helper = mock.Mock() self.sut.ssh_helper.run = mock.Mock() self.sut._traffic_runner = mock.Mock(return_value=0) @@ -470,20 +446,60 @@ class TestTrexTrafficGen(unittest.TestCase): self.sut._traffic_process.terminate() self.assertIsNotNone(result) - @mock.patch(SSH_HELPER) - def test_terminate(self, ssh): - mock_ssh(ssh) + def test_terminate(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() self.assertIsNone(trex_traffic_gen.terminate()) - @mock.patch(SSH_HELPER) - def test__connect_client(self, ssh): - mock_ssh(ssh) + def test__connect_client(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) - client = mock.Mock(autospec=STLClient) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd) + client = mock.Mock() client.connect = mock.Mock(return_value=0) self.assertIsNotNone(trex_traffic_gen.resource_helper._connect(client)) + + +class TrexResourceHelperTestCase(unittest.TestCase): + + def test__get_samples(self): + mock_setup_helper = mock.Mock() + trex_rh = tg_trex.TrexResourceHelper(mock_setup_helper) + trex_rh.vnfd_helper.interfaces = [ + {'name': 'interface1'}, + {'name': 'interface2'}] + stats = { + 10: {'rx_pps': 5, 'ipackets': 200}, + 20: {'rx_pps': 10, 'ipackets': 300}, + 'latency': {1: {'latency': 'latency_port_10_pg_id_1'}, + 2: {'latency': 'latency_port_10_pg_id_2'}, + 3: {'latency': 'latency_port_20_pg_id_3'}, + 4: {'latency': 'latency_port_20_pg_id_4'}} + } + port_pg_id = rfc2544.PortPgIDMap() + port_pg_id.add_port(10) + port_pg_id.increase_pg_id() + port_pg_id.increase_pg_id() + port_pg_id.add_port(20) + port_pg_id.increase_pg_id() + port_pg_id.increase_pg_id() + + with mock.patch.object(trex_rh, 'get_stats') as mock_get_stats, \ + mock.patch.object(trex_rh.vnfd_helper, 'port_num') as \ + mock_port_num: + mock_get_stats.return_value = stats + mock_port_num.side_effect = [10, 20] + output = trex_rh._get_samples([10, 20], port_pg_id=port_pg_id) + + interface = output['interface1'] + self.assertEqual(5.0, interface['rx_throughput_fps']) + self.assertEqual(200, interface['in_packets']) + self.assertEqual('latency_port_10_pg_id_1', interface['latency'][1]) + self.assertEqual('latency_port_10_pg_id_2', interface['latency'][2]) + + interface = output['interface2'] + self.assertEqual(10.0, interface['rx_throughput_fps']) + self.assertEqual(300, interface['in_packets']) + self.assertEqual('latency_port_20_pg_id_3', interface['latency'][3]) + self.assertEqual('latency_port_20_pg_id_4', interface['latency'][4]) |