summaryrefslogtreecommitdiffstats
path: root/testcases/testcase.py
diff options
context:
space:
mode:
Diffstat (limited to 'testcases/testcase.py')
-rw-r--r--testcases/testcase.py208
1 files changed, 142 insertions, 66 deletions
diff --git a/testcases/testcase.py b/testcases/testcase.py
index 0effce75..5f5c9358 100644
--- a/testcases/testcase.py
+++ b/testcases/testcase.py
@@ -27,6 +27,7 @@ from core.loader import Loader
from core.results.results_constants import ResultsConstants
from tools import tasks
from tools import hugepages
+from tools import functions
from tools.pkt_gen.trafficgen.trafficgenhelper import TRAFFIC_DEFAULTS
from conf import settings as S
from conf import get_test_param
@@ -36,7 +37,7 @@ class TestCase(object):
In this basic form runs RFC2544 throughput test
"""
- def __init__(self, cfg, results_dir):
+ def __init__(self, cfg):
"""Pull out fields from test config
:param cfg: A dictionary of string-value pairs describing the test
@@ -44,6 +45,7 @@ class TestCase(object):
values.
:param results_dir: Where the csv formatted results are written.
"""
+ self._testcase_start_time = time.time()
self._hugepages_mounted = False
self._traffic_ctl = None
self._vnf_ctl = None
@@ -52,6 +54,27 @@ class TestCase(object):
self._loadgen = None
self._output_file = None
self._tc_results = None
+ self.guest_loopback = []
+ self._settings_original = {}
+ self._settings_paths_modified = False
+ self._testcast_run_time = None
+
+ self._update_settings('VSWITCH', cfg.get('vSwitch', S.getValue('VSWITCH')))
+ self._update_settings('VNF', cfg.get('VNF', S.getValue('VNF')))
+ self._update_settings('TRAFFICGEN', cfg.get('Trafficgen', S.getValue('TRAFFICGEN')))
+ self._update_settings('TEST_PARAMS', cfg.get('Parameters', S.getValue('TEST_PARAMS')))
+
+ # update global settings
+ guest_loopback = get_test_param('guest_loopback', None)
+ if guest_loopback:
+ self._update_settings('GUEST_LOOPBACK', [guest_loopback for dummy in S.getValue('GUEST_LOOPBACK')])
+
+ if 'VSWITCH' in self._settings_original or 'VNF' in self._settings_original:
+ self._settings_original.update({
+ 'RTE_SDK' : S.getValue('RTE_SDK'),
+ 'OVS_DIR' : S.getValue('OVS_DIR'),
+ })
+ functions.settings_update_paths()
# set test parameters; CLI options take precedence to testcase settings
self._logger = logging.getLogger(__name__)
@@ -61,6 +84,10 @@ class TestCase(object):
bidirectional = cfg.get('biDirectional', TRAFFIC_DEFAULTS['bidir'])
bidirectional = get_test_param('bidirectional', bidirectional)
+ if not isinstance(bidirectional, str):
+ raise TypeError(
+ 'Bi-dir value must be of type string in testcase configuration')
+ bidirectional = bidirectional.title() # Keep things consistent
traffic_type = cfg.get('Traffic Type', TRAFFIC_DEFAULTS['traffic_type'])
traffic_type = get_test_param('traffic_type', traffic_type)
@@ -82,18 +109,11 @@ class TestCase(object):
self._tunnel_type = get_test_param('tunnel_type',
self._tunnel_type)
-
# identify guest loopback method, so it can be added into reports
- self.guest_loopback = []
- if self.deployment in ['pvp', 'pvvp']:
- guest_loopback = get_test_param('guest_loopback', None)
- if guest_loopback:
- self.guest_loopback.append(guest_loopback)
- else:
- if self.deployment == 'pvp':
- self.guest_loopback.append(S.getValue('GUEST_LOOPBACK')[0])
- else:
- self.guest_loopback = S.getValue('GUEST_LOOPBACK').copy()
+ if self.deployment == 'pvp':
+ self.guest_loopback.append(S.getValue('GUEST_LOOPBACK')[0])
+ else:
+ self.guest_loopback = S.getValue('GUEST_LOOPBACK').copy()
# read configuration of streams; CLI parameter takes precedence to
# testcase definition
@@ -114,7 +134,7 @@ class TestCase(object):
if self._frame_mod:
self._frame_mod = self._frame_mod.lower()
- self._results_dir = results_dir
+ self._results_dir = S.getValue('RESULTS_PATH')
# set traffic details, so they can be passed to vswitch and traffic ctls
self._traffic = copy.deepcopy(TRAFFIC_DEFAULTS)
@@ -127,27 +147,17 @@ class TestCase(object):
'pre_installed_flows' : pre_installed_flows,
'frame_rate': int(framerate)})
+ # Packet Forwarding mode
+ self._vswitch_none = 'none' == S.getValue('VSWITCH').strip().lower()
+
# OVS Vanilla requires guest VM MAC address and IPs to work
if 'linux_bridge' in self.guest_loopback:
- self._traffic['l2'].update({'srcmac': S.getValue('GUEST_NET2_MAC')[0],
- 'dstmac': S.getValue('GUEST_NET1_MAC')[0]})
+ self._traffic['l2'].update({'srcmac': S.getValue('VANILLA_TGEN_PORT1_MAC'),
+ 'dstmac': S.getValue('VANILLA_TGEN_PORT2_MAC')})
self._traffic['l3'].update({'srcip': S.getValue('VANILLA_TGEN_PORT1_IP'),
'dstip': S.getValue('VANILLA_TGEN_PORT2_IP')})
- # Packet Forwarding mode
- self._vswitch_none = 'none' == S.getValue('VSWITCH').strip().lower()
-
- def run_initialize(self):
- """ Prepare test execution environment
- """
- self._logger.debug(self.name)
-
- # mount hugepages if needed
- self._mount_hugepages()
-
- # copy sources of l2 forwarding tools into VM shared dir if needed
- self._copy_fwd_tools_for_guest()
-
+ # trafficgen configuration required for tests of tunneling protocols
if self.deployment == "op2p":
self._traffic['l2'].update({'srcmac':
S.getValue('TRAFFICGEN_PORT1_MAC'),
@@ -163,7 +173,24 @@ class TestCase(object):
self._traffic['l2'] = S.getValue(self._tunnel_type.upper() + '_FRAME_L2')
self._traffic['l3'] = S.getValue(self._tunnel_type.upper() + '_FRAME_L3')
self._traffic['l4'] = S.getValue(self._tunnel_type.upper() + '_FRAME_L4')
+ elif S.getValue('NICS')[0]['type'] == 'vf' or S.getValue('NICS')[1]['type'] == 'vf':
+ mac1 = S.getValue('NICS')[0]['mac']
+ mac2 = S.getValue('NICS')[1]['mac']
+ if mac1 and mac2:
+ self._traffic['l2'].update({'srcmac': mac2, 'dstmac': mac1})
+ else:
+ self._logger.debug("MAC addresses can not be read")
+ def run_initialize(self):
+ """ Prepare test execution environment
+ """
+ self._logger.debug(self.name)
+
+ # mount hugepages if needed
+ self._mount_hugepages()
+
+ # copy sources of l2 forwarding tools into VM shared dir if needed
+ self._copy_fwd_tools_for_all_guests()
self._logger.debug("Controllers:")
loader = Loader()
@@ -177,6 +204,7 @@ class TestCase(object):
if self._vswitch_none:
self._vswitch_ctl = component_factory.create_pktfwd(
+ self.deployment,
loader.get_pktfwd_class())
else:
self._vswitch_ctl = component_factory.create_vswitch(
@@ -203,6 +231,29 @@ class TestCase(object):
# umount hugepages if mounted
self._umount_hugepages()
+ # restore original settings
+ S.load_from_dict(self._settings_original)
+
+ # cleanup any namespaces created
+ if os.path.isdir('/tmp/namespaces'):
+ import tools.namespace
+ namespace_list = os.listdir('/tmp/namespaces')
+ if len(namespace_list):
+ self._logger.info('Cleaning up namespaces')
+ for name in namespace_list:
+ tools.namespace.delete_namespace(name)
+ os.rmdir('/tmp/namespaces')
+ # cleanup any veth ports created
+ if os.path.isdir('/tmp/veth'):
+ import tools.veth
+ veth_list = os.listdir('/tmp/veth')
+ if len(veth_list):
+ self._logger.info('Cleaning up veth ports')
+ for eth in veth_list:
+ port1, port2 = eth.split('-')
+ tools.veth.del_veth_port(port1, port2)
+ os.rmdir('/tmp/veth')
+
def run_report(self):
""" Report test results
"""
@@ -214,7 +265,7 @@ class TestCase(object):
self._traffic_ctl.print_results()
self._tc_results = self._append_results(self._traffic_ctl.get_results())
- TestCase._write_result_to_file(self._tc_results, self._output_file)
+ TestCase.write_result_to_file(self._tc_results, self._output_file)
def run(self):
"""Run the test
@@ -255,9 +306,25 @@ class TestCase(object):
# tear down test execution environment and log results
self.run_finalize()
+ self._testcase_run_time = time.strftime("%H:%M:%S",
+ time.gmtime(time.time() - self._testcase_start_time))
+ logging.info("Testcase execution time: " + self._testcase_run_time)
# report test results
self.run_report()
+ def _update_settings(self, param, value):
+ """ Check value of given configuration parameter
+ In case that new value is different, then testcase
+ specific settings is updated and original value stored
+
+ :param param: Name of parameter inside settings
+ :param value: Disired parameter value
+ """
+ orig_value = S.getValue(param)
+ if orig_value != value:
+ self._settings_original[param] = orig_value
+ S.setValue(param, value)
+
def _append_results(self, results):
"""
Method appends mandatory Test Case results to list of dictionaries.
@@ -271,52 +338,60 @@ class TestCase(object):
item[ResultsConstants.ID] = self.name
item[ResultsConstants.DEPLOYMENT] = self.deployment
item[ResultsConstants.TRAFFIC_TYPE] = self._traffic['l3']['proto']
+ item[ResultsConstants.TEST_RUN_TIME] = self._testcase_run_time
if self._traffic['multistream']:
item[ResultsConstants.SCAL_STREAM_COUNT] = self._traffic['multistream']
item[ResultsConstants.SCAL_STREAM_TYPE] = self._traffic['stream_type']
item[ResultsConstants.SCAL_PRE_INSTALLED_FLOWS] = self._traffic['pre_installed_flows']
- if len(self.guest_loopback):
+ if self.deployment in ['pvp', 'pvvp'] and len(self.guest_loopback):
item[ResultsConstants.GUEST_LOOPBACK] = ' '.join(self.guest_loopback)
if self._tunnel_type:
item[ResultsConstants.TUNNEL_TYPE] = self._tunnel_type
return results
- def _copy_fwd_tools_for_guest(self):
- """Copy dpdk and l2fwd code to GUEST_SHARE_DIR[s] for use by guests.
+ def _copy_fwd_tools_for_all_guests(self):
+ """Copy dpdk and l2fwd code to GUEST_SHARE_DIR[s] based on selected deployment.
"""
- counter = 0
- # method is executed only for pvp and pvvp, so let's count number of 'v'
- while counter < self.deployment.count('v'):
- guest_dir = S.getValue('GUEST_SHARE_DIR')[counter]
-
- # remove shared dir if it exists to avoid issues with file consistency
- if os.path.exists(guest_dir):
- tasks.run_task(['rm', '-f', '-r', guest_dir], self._logger,
- 'Removing content of shared directory...', True)
-
- # directory to share files between host and guest
- os.makedirs(guest_dir)
-
- # copy sources into shared dir only if neccessary
- if 'testpmd' in self.guest_loopback or 'l2fwd' in self.guest_loopback:
- try:
- tasks.run_task(['rsync', '-a', '-r', '-l', r'--exclude="\.git"',
- os.path.join(S.getValue('RTE_SDK'), ''),
- os.path.join(guest_dir, 'DPDK')],
- self._logger,
- 'Copying DPDK to shared directory...',
- True)
- tasks.run_task(['rsync', '-a', '-r', '-l',
- os.path.join(S.getValue('ROOT_DIR'), 'src/l2fwd/'),
- os.path.join(guest_dir, 'l2fwd')],
- self._logger,
- 'Copying l2fwd to shared directory...',
- True)
- except subprocess.CalledProcessError:
- self._logger.error('Unable to copy DPDK and l2fwd to shared directory')
-
+ # data are copied only for pvp and pvvp, so let's count number of 'v'
+ counter = 1
+ while counter <= self.deployment.count('v'):
+ self._copy_fwd_tools_for_guest(counter)
counter += 1
+ def _copy_fwd_tools_for_guest(self, index):
+ """Copy dpdk and l2fwd code to GUEST_SHARE_DIR of VM
+
+ :param index: Index of VM starting from 1 (i.e. 1st VM has index 1)
+ """
+ guest_dir = S.getValue('GUEST_SHARE_DIR')[index-1]
+
+ # remove shared dir if it exists to avoid issues with file consistency
+ if os.path.exists(guest_dir):
+ tasks.run_task(['rm', '-f', '-r', guest_dir], self._logger,
+ 'Removing content of shared directory...', True)
+
+ # directory to share files between host and guest
+ os.makedirs(guest_dir)
+
+ # copy sources into shared dir only if neccessary
+ if 'testpmd' in self.guest_loopback or 'l2fwd' in self.guest_loopback:
+ try:
+ tasks.run_task(['rsync', '-a', '-r', '-l', r'--exclude="\.git"',
+ os.path.join(S.getValue('RTE_SDK_USER'), ''),
+ os.path.join(guest_dir, 'DPDK')],
+ self._logger,
+ 'Copying DPDK to shared directory...',
+ True)
+ tasks.run_task(['rsync', '-a', '-r', '-l',
+ os.path.join(S.getValue('ROOT_DIR'), 'src/l2fwd/'),
+ os.path.join(guest_dir, 'l2fwd')],
+ self._logger,
+ 'Copying l2fwd to shared directory...',
+ True)
+ except subprocess.CalledProcessError:
+ self._logger.error('Unable to copy DPDK and l2fwd to shared directory')
+
+
def _mount_hugepages(self):
"""Mount hugepages if usage of DPDK or Qemu is detected
"""
@@ -324,7 +399,8 @@ class TestCase(object):
if not self._hugepages_mounted and \
(self.deployment.count('v') or \
S.getValue('VSWITCH').lower().count('dpdk') or \
- self._vswitch_none):
+ self._vswitch_none or \
+ self.test and 'vnf' in [step[0][0:3] for step in self.test]):
hugepages.mount_hugepages()
self._hugepages_mounted = True
@@ -336,7 +412,7 @@ class TestCase(object):
self._hugepages_mounted = False
@staticmethod
- def _write_result_to_file(results, output):
+ def write_result_to_file(results, output):
"""Write list of dictionaries to a CSV file.
Each element on list will create separate row in output file.