Merge "behave_tests: increase nfvbench_test_api timeout"
authorFran�ois-R�gis Menguy <francoisregis.menguy@orange.com>
Fri, 4 Jun 2021 14:09:36 +0000 (14:09 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Fri, 4 Jun 2021 14:09:36 +0000 (14:09 +0000)
15 files changed:
behave_tests/features/quick-test-10kpps.feature [new file with mode: 0644]
docker/Dockerfile
nfvbench/cfg.default.yaml
nfvbench/cleanup.py
nfvbench/credentials.py
nfvbench/nfvbench.py
nfvbenchvm/README.rst
nfvbenchvm/dib/elements/nfvbenchvm/static/etc/rc.d/rc.local.generator
nfvbenchvm/dib/elements/nfvbenchvm/static/etc/rc.d/rc.local.loopvm
nfvbenchvm/dib/elements/nfvbenchvm/static/nfvbench/configure-nfvbench.sh
nfvbenchvm/dib/elements/nfvbenchvm/static/vpp/startup.conf
requirements.txt
test/test_nfvbench.py
xtesting/behaveframework.py [deleted file]
xtesting/testcases.yaml

diff --git a/behave_tests/features/quick-test-10kpps.feature b/behave_tests/features/quick-test-10kpps.feature
new file mode 100644 (file)
index 0000000..d46000c
--- /dev/null
@@ -0,0 +1,13 @@
+@quick-test-10kpps
+Feature: quick-test-10kpps
+
+  @throughput
+  Scenario: Run a 10s test at 10kpps with 64-byte frames and 128 flows
+      Given 10 sec run duration
+      And TRex is restarted
+      And 64 frame size
+      And 128 flow count
+      And 10kpps rate
+      When NFVbench API is ready
+      Then 1 runs are started and waiting for maximum result
+      And push result to database
index 4336261..e851c76 100644 (file)
@@ -40,8 +40,6 @@ RUN apt-get update && apt-get install -y \
        && wget -O nfvbenchvm-$VM_IMAGE_VER.qcow2 http://artifacts.opnfv.org/nfvbench/images/nfvbenchvm_centos-$VM_IMAGE_VER.qcow2 \
        # Override Xtesting testcases.yaml file by NFVbench default one
        && cp xtesting/testcases.yaml /usr/local/lib/python3.8/dist-packages/xtesting/ci/testcases.yaml \
-       # Temporary override waiting for PR approval : https://gerrit.opnfv.org/gerrit/c/functest-xtesting/+/72431
-       && cp xtesting/behaveframework.py /usr/local/lib/python3.8/dist-packages/xtesting/core/behaveframework.py \
        && python3 ./docker/cleanup_generators.py \
        && rm -rf /opt/nfvbench/.git \
        # Symlink for retrocompatibility 4.x
index 8e822e5..c76e738 100644 (file)
 # - availability_zone
 # - hypervisor_hostname
 # - vlans
+# WARNING: Not used if clouds_detail is sets
 openrc_file:
 
+# The OpenStack clouds configuration from clouds.yaml file to use.
+# clouds.yaml file must be in one of the following paths:
+# - ~/.config/openstack
+# - /etc/openstack
+# Note: If running in a container, this path must be valid in the container.
+# The only case where this field can be empty is when measuring a system that does not run
+# OpenStack or when OpenStack APIs are not accessible or OpenStack APis use is not
+# desirable. In that case the EXT service chain must be used.
+#
+# If user is not admin some parameters are mandatory and must be filled with valid values in config file such as :
+# - availability_zone
+# - hypervisor_hostname
+# - vlans
+# If a value is sets, this parameter disable the use of openrc file
+clouds_detail:
+
 # Forwarder to use in nfvbenchvm image. Available options: ['vpp', 'testpmd']
 vm_forwarder: testpmd
 
index 23cdf56..cefdcfa 100644 (file)
@@ -235,7 +235,7 @@ class Cleaner(object):
     """Cleaner for all NFVbench resources."""
 
     def __init__(self, config):
-        cred = credentials.Credentials(config.openrc_file, None, False)
+        cred = credentials.Credentials(config.openrc_file, config.clouds_detail, None, False)
         session = cred.get_session()
         self.neutron_client = nclient.Client('2.0', session=session)
         self.nova_client = Client(2, session=session)
index 4e4985f..a707ba3 100644 (file)
@@ -21,32 +21,40 @@ import getpass
 from keystoneauth1.identity import v2
 from keystoneauth1.identity import v3
 from keystoneauth1 import session
+import openstack
+from keystoneclient.exceptions import HTTPClientError
+
 from .log import LOG
 
 
 class Credentials(object):
 
     def get_session(self):
-        dct = {
-            'username': self.rc_username,
-            'password': self.rc_password,
-            'auth_url': self.rc_auth_url
-        }
-        auth = None
-
-        if self.rc_identity_api_version == 3:
-            dct.update({
-                'project_name': self.rc_project_name,
-                'project_domain_name': self.rc_project_domain_name,
-                'user_domain_name': self.rc_user_domain_name
-            })
-            auth = v3.Password(**dct)
+
+        if self.clouds_detail:
+            connection = openstack.connect(cloud=self.clouds_detail)
+            cred_session = connection.session
         else:
-            dct.update({
-                'tenant_name': self.rc_tenant_name
-            })
-            auth = v2.Password(**dct)
-        return session.Session(auth=auth, verify=self.rc_cacert)
+            dct = {
+                'username': self.rc_username,
+                'password': self.rc_password,
+                'auth_url': self.rc_auth_url
+            }
+
+            if self.rc_identity_api_version == 3:
+                dct.update({
+                    'project_name': self.rc_project_name,
+                    'project_domain_name': self.rc_project_domain_name,
+                    'user_domain_name': self.rc_user_domain_name
+                })
+                auth = v3.Password(**dct)
+            else:
+                dct.update({
+                    'tenant_name': self.rc_tenant_name
+                })
+                auth = v2.Password(**dct)
+            cred_session = session.Session(auth=auth, verify=self.rc_cacert)
+        return cred_session
 
     def __parse_openrc(self, file):
         export_re = re.compile('export OS_([A-Z_]*)="?(.*)')
@@ -91,11 +99,28 @@ class Credentials(object):
                 elif name == "PROJECT_DOMAIN_NAME":
                     self.rc_project_domain_name = value
 
+    # /users URL returns exception (HTTP 403) if user is not admin.
+    # try first without the version in case session already has it in
+    # Return HTTP 200 if user is admin
+    def __user_is_admin(self, url):
+        is_admin = False
+        try:
+            # check if user has admin role in OpenStack project
+            filter = {'service_type': 'identity',
+                      'interface': 'public'}
+            self.get_session().get(url, endpoint_filter=filter)
+            is_admin = True
+        except HTTPClientError as exc:
+            if exc.http_status == 403:
+                LOG.warning(
+                    "User is not admin, no permission to list user roles. Exception: %s", exc)
+        return is_admin
+
     #
     # Read a openrc file and take care of the password
     # The 2 args are passed from the command line and can be None
     #
-    def __init__(self, openrc_file, pwd=None, no_env=False):
+    def __init__(self, openrc_file, clouds_detail, pwd=None, no_env=False):
         self.rc_password = None
         self.rc_username = None
         self.rc_tenant_name = None
@@ -105,8 +130,9 @@ class Credentials(object):
         self.rc_user_domain_name = None
         self.rc_project_domain_name = None
         self.rc_project_name = None
-        self.rc_identity_api_version = 2
+        self.rc_identity_api_version = 3
         self.is_admin = False
+        self.clouds_detail = clouds_detail
         success = True
 
         if openrc_file:
@@ -118,7 +144,7 @@ class Credentials(object):
                     success = False
             else:
                 self.__parse_openrc(openrc_file)
-        elif not no_env:
+        elif not clouds_detail and not no_env:
             # no openrc file passed - we assume the variables have been
             # sourced by the calling shell
             # just check that they are present
@@ -153,34 +179,27 @@ class Credentials(object):
 
 
         # always override with CLI argument if provided
-        if pwd:
-            self.rc_password = pwd
-        # if password not know, check from env variable
-        elif self.rc_auth_url and not self.rc_password and success:
-            if 'OS_PASSWORD' in os.environ and not no_env:
-                self.rc_password = os.environ['OS_PASSWORD']
-            else:
-                # interactively ask for password
-                self.rc_password = getpass.getpass(
-                    'Please enter your OpenStack Password: ')
-        if not self.rc_password:
-            self.rc_password = ""
-
-        # check if user has admin role in OpenStack project
-        filter = {'service_type': 'identity',
-                  'interface': 'public',
-                  'region_name': self.rc_region_name}
+        if not clouds_detail:
+            if pwd:
+                self.rc_password = pwd
+            # if password not know, check from env variable
+            elif self.rc_auth_url and not self.rc_password and success:
+                if 'OS_PASSWORD' in os.environ and not no_env:
+                    self.rc_password = os.environ['OS_PASSWORD']
+                else:
+                    # interactively ask for password
+                    self.rc_password = getpass.getpass(
+                        'Please enter your OpenStack Password: ')
+            if not self.rc_password:
+                self.rc_password = ""
+
+
         try:
             # /users URL returns exception (HTTP 403) if user is not admin.
             # try first without the version in case session already has it in
             # Return HTTP 200 if user is admin
-            self.get_session().get('/users', endpoint_filter=filter)
-            self.is_admin = True
-        except Exception:
-            try:
-                # vX/users URL returns exception (HTTP 403) if user is not admin.
-                self.get_session().get('/v' + str(self.rc_identity_api_version) + '/users',
-                                       endpoint_filter=filter)
-                self.is_admin = True
-            except Exception as e:
-                LOG.warning("User is not admin, no permission to list user roles. Exception: %s", e)
+            self.is_admin = self.__user_is_admin('/users') or self.__user_is_admin(
+                '/v2/users') or self.__user_is_admin('/v3/users')
+        except Exception as e:
+            LOG.warning("Error occurred during Openstack API access. "
+                        "Unable to check user is admin. Exception: %s", e)
index 598247a..0719247 100644 (file)
@@ -60,8 +60,8 @@ class NFVBench(object):
         self.config_plugin = config_plugin
         self.factory = factory
         self.notifier = notifier
-        self.cred = credentials.Credentials(config.openrc_file, None, False) \
-            if config.openrc_file else None
+        self.cred = credentials.Credentials(config.openrc_file, config.clouds_detail, None, False) \
+            if config.openrc_file or config.clouds_detail else None
         self.chain_runner = None
         self.specs = Specs()
         self.specs.set_openstack_spec(openstack_spec)
@@ -96,8 +96,10 @@ class NFVBench(object):
 
             # check that an empty openrc file (no OpenStack) is only allowed
             # with EXT chain
-            if not self.config.openrc_file and self.config.service_chain != ChainType.EXT:
-                raise Exception("openrc_file in the configuration is required for PVP/PVVP chains")
+            if (not self.config.openrc_file and not self.config.clouds_detail) and \
+                    self.config.service_chain != ChainType.EXT:
+                raise Exception("openrc_file or clouds_detail in the configuration is required"
+                                " for PVP/PVVP chains")
 
             self.specs.set_run_spec(self.config_plugin.get_run_spec(self.config,
                                                                     self.specs.openstack))
index 0274c75..dad9f46 100644 (file)
@@ -95,6 +95,29 @@ Hardcoded Username and Password
 GENERATOR IMAGE INSTANCE AND CONFIG
 ===================================
 
+Pre-requisites
+--------------
+To use openstack APIs, NFVbench generator VM will use `clouds.yaml` file as openstack configuration.
+The OpenStack clouds configuration from clouds.yaml file to use.
+clouds.yaml file must be in one of the following paths:
+- ~/.config/openstack
+- /etc/openstack
+
+Example of `clouds.yaml`:
+
+.. code-block:: yaml
+
+    clouds:
+      devstack:
+        auth:
+          auth_url: http://192.168.122.10:35357/
+          project_name: demo
+          username: demo
+          password: 0penstack
+        region_name: RegionOne
+
+.. note:: Add `CLOUD_DETAIL` property with the accurate value for your openstack configuration (`devstack` in the above example) in ``/etc/nfvbenchvm.conf``
+
 Interface Requirements
 ----------------------
 The instance must be launched using OpenStack with 2 network interfaces for dataplane traffic (using SR-IOV function) and 1 management interface to control nfvbench.
@@ -135,6 +158,7 @@ Template of a genarator profile using CPU pinning:
               pci: "{{PCI_ADDRESS_2}}"
               switch:
           intf_speed:
+
 .. note:: `CORE_THREADS` value is determined automatically based on the cores available on the VM starting from 2 to last worker core available.
 
 Auto-configuration
@@ -155,6 +179,7 @@ Example of configuration:
     LOOPBACK_INTF_MAC2=FA:16:3E:10:DA:10
     E2E_INTF_MAC1=FA:16:3E:B0:E2:43
     E2E_INTF_MAC2=FA:16:3E:D3:6A:FC
+
 .. note:: `ACTION` parameter is not mandatory but will permit to start NFVbench with the accurate ports (loopback or e2e).
 .. note:: Set of MAC parameters cannot be used in parallel as only one NFVbench/TRex process is running.
 .. note:: Switching from `loopback` to `e2e` action can be done manually using `/nfvbench/start-nfvbench.sh <action>` with the accurate keyword for `action` parameter. This script will restart NFVbench with the good set of MAC.
@@ -185,6 +210,7 @@ Using pre-created direct-physical ports on openstack, mac addresses value are on
     INTF_MGMT_CIDR=172.20.56.228/2
     INTF_MGMT_IP_GW=172.20.56.225
     DNS_SERVERS=8.8.8.8,dns.server.com
+
 .. note:: A management interface is required to automatically find the virtual interface to use according to the MAC address provided (see `INTF_MAC_MGMT` parameter).
 .. note:: NFVbench VM will call openstack API through the management interface to retrieve mac address for these ports
 .. note:: If openstack API required a host name resolution, add the parameter DNS_SERVERS to add IP or DNS server names (multiple servers can be added separated by a `,`)
index 0746fd6..633403c 100644 (file)
@@ -4,7 +4,6 @@ touch /var/lock/subsys/local
 
 # Waiting for cloud-init to generate $NFVBENCH_CONF, retry 60 seconds
 NFVBENCH_CONF=/etc/nfvbenchvm.conf
-OPENRC=/etc/nfvbench/openrc
 retry=30
 until [ $retry -eq 0 ]; do
     if [ -f $NFVBENCH_CONF ]; then break; fi
@@ -20,10 +19,6 @@ echo "Generating configurations for NFVbench and TRex..."
 eval $(cat $NFVBENCH_CONF)
 touch /nfvbench_configured.flag
 
-if [ -f $OPENRC ]; then
-    source $OPENRC
-fi
-
 # Add DNS entry
 if [ $DNS_SERVERS ]; then
     IFS="," read -a dns <<< $DNS_SERVERS
@@ -80,8 +75,8 @@ get_eth_port() {
 if [ $INTF_MGMT_CIDR ] && [ $INTF_MGMT_IP_GW ]; then
     if [ $INTF_MAC_MGMT ]; then
         ETH_PORT=$(get_eth_port $INTF_MAC_MGMT)
-    elif [ -f $OPENRC ] && [ "$PORT_MGMT_NAME" ]; then
-        $INTF_MAC_MGMT=$(openstack port list | grep $PORT_MGMT_NAME | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
+    elif [ "$CLOUD_DETAIL" ] && [ "$PORT_MGMT_NAME" ]; then
+        $INTF_MAC_MGMT=$(openstack --os-cloud $CLOUD_DETAIL port list | grep $PORT_MGMT_NAME | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
         ETH_PORT=$(get_eth_port $INTF_MAC_MGMT)
     else
         ETH_PORT=""
index bc14902..ecc8b05 100644 (file)
@@ -167,10 +167,11 @@ fi
 if [ $PCI_ADDRESS_1 ] && [ $PCI_ADDRESS_2 ]; then
     logger "NFVBENCHVM: Using pci $PCI_ADDRESS_1 ($INTF_MAC1)"
     logger "NFVBENCHVM: Using pci $PCI_ADDRESS_2 ($INTF_MAC2)"
+    # active uio_pci_generic driver
+    modprobe uio_pci_generic
     # Configure the forwarder
     if [ "$FORWARDER" == "testpmd" ]; then
         echo "Configuring testpmd..."
-        modprobe uio_pci_generic
         mkdir /dpdk
         echo "set promisc all off" > /dpdk/testpmd_cmd.txt
         # Binding ports to DPDK VFIO or UIO
index 5ec584b..3bf1d8d 100644 (file)
@@ -6,15 +6,10 @@ NFVBENCH_CONF=/etc/nfvbenchvm.conf
 E2E_CFG=/etc/nfvbench/e2e.cfg
 LOOPBACK_CFG=/etc/nfvbench/loopback.cfg
 NFVBENCH_CFG=/etc/nfvbench/nfvbench.cfg
-OPENRC=/etc/nfvbench/openrc
 
 # Parse and obtain all configurations
 eval $(cat $NFVBENCH_CONF)
 
-if [ -f $OPENRC ]; then
-    source $OPENRC
-fi
-
 # WE assume there are at least 2 cores available for the VM
 CPU_CORES=$(grep -c ^processor /proc/cpuinfo)
 
@@ -88,21 +83,21 @@ get_interfaces_mac_values(){
     # Set dynamically interfaces mac values, if VM is spawn with SRIOV PF ports
     # and openstack API are accessible
     if [ -z "$LOOPBACK_INTF_MAC1" ] && [ -z "$LOOPBACK_INTF_MAC2" ]; then
-        if [ -f $OPENRC ] && [ "$LOOPBACK_PORT_NAME1" ] && [ "$LOOPBACK_PORT_NAME2" ]; then
-            LOOPBACK_INTF_MAC1=$(openstack port list | grep $LOOPBACK_PORT_NAME1 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
-            LOOPBACK_INTF_MAC2=$(openstack port list | grep $LOOPBACK_PORT_NAME2 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
+        if [ "$CLOUD_DETAIL" ] && [ "$LOOPBACK_PORT_NAME1" ] && [ "$LOOPBACK_PORT_NAME2" ]; then
+            LOOPBACK_INTF_MAC1=$(openstack --os-cloud $CLOUD_DETAIL port list | grep $LOOPBACK_PORT_NAME1 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
+            LOOPBACK_INTF_MAC2=$(openstack --os-cloud $CLOUD_DETAIL port list | grep $LOOPBACK_PORT_NAME2 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
         fi
     fi
     if [ -z "$E2E_INTF_MAC1" ] && [ -z "$E2E_INTF_MAC2" ]; then
-        if [ -f $OPENRC ] && [ "$E2E_PORT_NAME1" ] && [ "$E2E_PORT_NAME2" ]; then
-            E2E_INTF_MAC1=$(openstack port list | grep $E2E_PORT_NAME1 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
-            E2E_INTF_MAC2=$(openstack port list | grep $E2E_PORT_NAME2 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
+        if [ "$CLOUD_DETAIL" ] && [ "$E2E_PORT_NAME1" ] && [ "$E2E_PORT_NAME2" ]; then
+            E2E_INTF_MAC1=$(openstack --os-cloud $CLOUD_DETAIL port list | grep $E2E_PORT_NAME1 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
+            E2E_INTF_MAC2=$(openstack --os-cloud $CLOUD_DETAIL port list | grep $E2E_PORT_NAME2 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
         fi
     fi
     if [ -z "$INTF_MAC1" ] && [ -z "$INTF_MAC2" ]; then
-        if [ -f $OPENRC ] && [ "$PORT_NAME1" ] && [ "$PORT_NAME2" ]; then
-            INTF_MAC1=$(openstack port list | grep $PORT_NAME1 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
-            INTF_MAC2=$(openstack port list | grep $PORT_NAME2 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
+        if [ "$CLOUD_DETAIL" ] && [ "$PORT_NAME1" ] && [ "$PORT_NAME2" ]; then
+            INTF_MAC1=$(openstack --os-cloud $CLOUD_DETAIL port list | grep $PORT_NAME1 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
+            INTF_MAC2=$(openstack --os-cloud $CLOUD_DETAIL port list | grep $PORT_NAME2 | grep -o -Ei '([a-fA-F0-9:]{17}|[a-fA-F0-9]{12}$)' | head -1)
         fi
     fi
 }
index d174299..874f6cb 100644 (file)
@@ -19,7 +19,7 @@ dpdk {
   socket-mem 1024
   dev {{PCI_ADDRESS_1}}
   dev {{PCI_ADDRESS_2}}
-  uio-driver igb_uio
+  uio-driver uio_pci_generic
   num-mbufs {{NUM_MBUFS}}
 }
 
index 7c74119..a333380 100644 (file)
@@ -22,7 +22,7 @@ tabulate>=0.7.5
 flask>=0.12
 fluent-logger>=0.5.3
 netaddr>=0.7.19
-xtesting>=0.87.0
+xtesting>=0.92.0
 hdrhistogram>=0.8.0
 behave>=1.2.6
 retry>=0.9.2
\ No newline at end of file
index e53a586..360e3bd 100644 (file)
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 #
+import openstack
+from keystoneauth1.exceptions import HTTPClientError
 from mock import patch
 import pytest
 
@@ -139,13 +141,41 @@ def test_load_from_rate():
 # =========================================================================
 
 def test_no_credentials():
-    cred = Credentials('/completely/wrong/path/openrc', None, False)
-    if cred.rc_auth_url:
-        # shouldn't get valid data unless user set environment variables
+    with patch.object(openstack, 'connect') as mock:
+        cred = Credentials('/completely/wrong/path/openrc', None, None, False)
+        if cred.rc_auth_url:
+            # shouldn't get valid data unless user set environment variables
+            assert False
+        else:
+            assert True
+    mock.assert_not_called()
+
+
+def test_clouds_file_credentials():
+    with patch.object(openstack, 'connect') as mock:
+        Credentials(None, 'openstack', None, False)
+    mock.assert_called_once()
+
+
+@patch('nfvbench.nfvbench.credentials')
+def test_is_not_admin(mock_session):
+    mock_session.Session.return_value.get.return_value.raiseError.side_effect = HTTPClientError
+    cred = Credentials(None, 'openstack', None, False)
+    if cred.is_admin:
         assert False
     else:
         assert True
 
+
+def test_is_admin():
+    with patch.object(openstack, 'connect'):
+        cred = Credentials(None, 'openstack', None, False)
+        if cred.is_admin:
+            assert True
+        else:
+            assert False
+
+
 def test_ip_block():
     ipb = IpBlock('10.0.0.0', '0.0.0.1', 256)
     assert ipb.get_ip() == '10.0.0.0'
diff --git a/xtesting/behaveframework.py b/xtesting/behaveframework.py
deleted file mode 100644 (file)
index 651240d..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2021 Orange
-#
-#    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.
-#
-
-"""Define classes required to run any Behave test suites."""
-
-from __future__ import division
-
-import logging
-import os
-import time
-
-import json
-import six
-
-from behave.__main__ import main as behave_main
-
-from xtesting.core import testcase
-
-__author__ = "Deepak Chandella <deepak.chandella@orange.com>"
-
-
-class BehaveFramework(testcase.TestCase):
-    """BehaveFramework runner."""
-    # pylint: disable=too-many-instance-attributes
-
-    __logger = logging.getLogger(__name__)
-    dir_results = "/var/lib/xtesting/results"
-
-    def __init__(self, **kwargs):
-        super().__init__(**kwargs)
-        self.json_file = os.path.join(self.res_dir, 'output.json')
-        self.total_tests = 0
-        self.pass_tests = 0
-        self.fail_tests = 0
-        self.skip_tests = 0
-        self.response = None
-
-    def parse_results(self):
-        """Parse output.json and get the details in it."""
-        with open(self.json_file) as stream_:
-            self.response = json.load(stream_)
-            if self.response:
-                self.total_tests = len(self.response)
-            for item in self.response:
-                if item['status'] == 'passed':
-                    self.pass_tests += 1
-                elif item['status'] == 'failed':
-                    self.fail_tests += 1
-                elif item['status'] == 'skipped':
-                    self.skip_tests += 1
-            self.result = 100 * (
-                self.pass_tests / self.total_tests)
-            self.details = {}
-            self.details['total_tests'] = self.total_tests
-            self.details['pass_tests'] = self.pass_tests
-            self.details['fail_tests'] = self.fail_tests
-            self.details['skip_tests'] = self.skip_tests
-            self.details['tests'] = self.response
-
-    def run(self, **kwargs):
-        """Run the BehaveFramework feature files
-
-        Here are the steps:
-           * create the output directories if required,
-           * run behave features with parameters
-           * get the results in output.json,
-
-        Args:
-            kwargs: Arbitrary keyword arguments.
-
-        Returns:
-            EX_OK if all suites ran well.
-            EX_RUN_ERROR otherwise.
-        """
-        try:
-            suites = kwargs["suites"]
-            tags = kwargs.get("tags", [])
-            console = kwargs["console"] if "console" in kwargs else False
-        except KeyError:
-            self.__logger.exception("Mandatory args were not passed")
-            return self.EX_RUN_ERROR
-        if not os.path.exists(self.res_dir):
-            try:
-                os.makedirs(self.res_dir)
-            except Exception:  # pylint: disable=broad-except
-                self.__logger.exception("Cannot create %s", self.res_dir)
-                return self.EX_RUN_ERROR
-        config = ['--tags=' + ','.join(tags),
-                  '--junit', '--junit-directory={}'.format(self.res_dir),
-                  '--format=json', '--outfile={}'.format(self.json_file)]
-        if six.PY3:
-            html_file = os.path.join(self.res_dir, 'output.html')
-            config += ['--format=behave_html_formatter:HTMLFormatter',
-                       '--outfile={}'.format(html_file)]
-        if console:
-            config += ['--format=pretty',
-                       '--outfile=-']
-        for feature in suites:
-            config.append(feature)
-        self.start_time = time.time()
-        behave_main(config)
-        self.stop_time = time.time()
-
-        try:
-            self.parse_results()
-            self.__logger.info("Results were successfully parsed")
-        except Exception:  # pylint: disable=broad-except
-            self.__logger.exception("Cannot parse results")
-            return self.EX_RUN_ERROR
-        return self.EX_OK
index bb4a521..03579b7 100644 (file)
@@ -60,8 +60,29 @@ tiers:
                         console:
                             - true
     -
-        name: nfvbench-demo
+        name: quick-test-10kpps
         order: 3
+        description: 'Quick nfvbench test at low packet rate'
+        testcases:
+            -
+                case_name: quick-test-10kpps
+                project_name: nfvbench
+                criteria: 100
+                blocking: true
+                clean_flag: false
+                description: ''
+                run:
+                    name: 'nfvbench_behaveframework'
+                    args:
+                        suites:
+                            - /opt/nfvbench/behave_tests/features/quick-test-10kpps.feature
+                        tags:
+                            - quick-test-10kpps
+                        console:
+                            - true
+    -
+        name: nfvbench-demo
+        order: 4
         description: 'Data Plane Performance Testing'
         testcases:
             -