From bdcbbd8c7f35d6b0bebf996a8d64379cf29ebc5d Mon Sep 17 00:00:00 2001 From: Orest Voznyy Date: Sat, 28 Jul 2018 19:05:06 +0300 Subject: Add TclClients for Spirent Landslide TG Add class "LandslideTclClient" which holds TCL calls wrappers for operations on the LandSlide TG. It also introduces several new parameters in - test case YAML file structure: * session_profile: YAML file holding a template of Landslide test session for specific vEPC test scenario * dmf: test case options member holding traffic flow specific parameters for designated test scenario, that override ones in traffic_profile YAML file * test_cases: test case options member holding parameters specific to designated vEPC test case, overriding those in session_profile template file - pod YAML file structure: * tas_manager: holds parameters used to connect to Spirent Landslide TAS * config: list of entries describing Landslide test servers access, their network interfaces configuration, information of vEPC elements emulated by specific test server Class "LandslideProfile" implements access to traffic profile template from "LandslideResourceHelper" class. JIRA: YARDSTICK-1356 Change-Id: Ia6428072b1e72025be17c94e5141bd23f7993247 Signed-off-by: Orest Voznyy Signed-off-by: Emma Foley Signed-off-by: Orest Voznyy --- etc/yardstick/yardstick.conf.sample | 2 + yardstick/common/exceptions.py | 6 + .../network_services/traffic_profile/__init__.py | 1 + .../traffic_profile/landslide_profile.py | 47 ++ yardstick/network_services/utils.py | 3 + .../vnf_generic/vnf/tg_landslide.py | 521 +++++++++++++++ .../traffic_profile/test_landslide_profile.py | 136 ++++ .../vnf_generic/vnf/test_tg_landslide.py | 722 +++++++++++++++++++++ 8 files changed, 1438 insertions(+) create mode 100644 yardstick/network_services/traffic_profile/landslide_profile.py create mode 100644 yardstick/network_services/vnf_generic/vnf/tg_landslide.py create mode 100644 yardstick/tests/unit/network_services/traffic_profile/test_landslide_profile.py create mode 100644 yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py diff --git a/etc/yardstick/yardstick.conf.sample b/etc/yardstick/yardstick.conf.sample index 5675cc3bd..ccfa86d5c 100644 --- a/etc/yardstick/yardstick.conf.sample +++ b/etc/yardstick/yardstick.conf.sample @@ -32,3 +32,5 @@ password = root trex_path=/opt/nsb_bin/trex/scripts bin_path=/opt/nsb_bin trex_client_lib=/opt/nsb_bin/trex_client/stl +# Path to 32-bit Java installation, for Spirent Landslide TG API +jre_path_i386=/usr/lib/jvm/java-8-openjdk-i386/jre diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index 10c1f3f27..4a4006ae4 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -420,3 +420,9 @@ class InvalidMacAddress(YardstickException): class ValueCheckError(YardstickException): message = 'Constraint "%(value1)s %(operator)s %(value2)s" does not hold' + + +class LandslideTclException(RuntimeError): + def __init__(self, message): + self._message = message + super(LandslideTclException, self).__init__(message) diff --git a/yardstick/network_services/traffic_profile/__init__.py b/yardstick/network_services/traffic_profile/__init__.py index a1b26a24d..91d8a665f 100644 --- a/yardstick/network_services/traffic_profile/__init__.py +++ b/yardstick/network_services/traffic_profile/__init__.py @@ -28,6 +28,7 @@ def register_modules(): 'yardstick.network_services.traffic_profile.prox_ramp', 'yardstick.network_services.traffic_profile.rfc2544', 'yardstick.network_services.traffic_profile.pktgen', + 'yardstick.network_services.traffic_profile.landslide_profile', ] for module in modules: diff --git a/yardstick/network_services/traffic_profile/landslide_profile.py b/yardstick/network_services/traffic_profile/landslide_profile.py new file mode 100644 index 000000000..f79226fb4 --- /dev/null +++ b/yardstick/network_services/traffic_profile/landslide_profile.py @@ -0,0 +1,47 @@ +# 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. +""" Spirent Landslide traffic profile definitions """ + +from yardstick.network_services.traffic_profile import base + + +class LandslideProfile(base.TrafficProfile): + """ + This traffic profile handles attributes of Landslide data stream + """ + + def __init__(self, tp_config): + super(LandslideProfile, self).__init__(tp_config) + + # for backward compatibility support dict and list of dicts + if isinstance(tp_config["dmf_config"], dict): + self.dmf_config = [tp_config["dmf_config"]] + else: + self.dmf_config = tp_config["dmf_config"] + + def execute(self, traffic_generator): + pass + + def update_dmf(self, options): + if 'dmf' in options: + if isinstance(options['dmf'], dict): + _dmfs = [options['dmf']] + else: + _dmfs = options['dmf'] + + for index, _dmf in enumerate(_dmfs): + try: + self.dmf_config[index].update(_dmf) + except IndexError: + pass diff --git a/yardstick/network_services/utils.py b/yardstick/network_services/utils.py index 4b987fafe..9c64fecde 100644 --- a/yardstick/network_services/utils.py +++ b/yardstick/network_services/utils.py @@ -36,6 +36,9 @@ OPTS = [ cfg.StrOpt('trex_client_lib', default=os.path.join(NSB_ROOT, 'trex_client/stl'), help='trex python library path.'), + cfg.StrOpt('jre_path_i386', + default='', + help='path to installation of 32-bit Java 1.7+.'), ] CONF.register_opts(OPTS, group="nsb") diff --git a/yardstick/network_services/vnf_generic/vnf/tg_landslide.py b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py new file mode 100644 index 000000000..3bb849c52 --- /dev/null +++ b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py @@ -0,0 +1,521 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from yardstick.common import exceptions +from yardstick.common import utils as common_utils +from yardstick.network_services import utils as net_serv_utils +from yardstick.network_services.vnf_generic.vnf import sample_vnf + +try: + from lsapi import LsApi +except ImportError: + LsApi = common_utils.ErrorClass + +LOG = logging.getLogger(__name__) + + +class LandslideResourceHelper(sample_vnf.ClientResourceHelper): + """Landslide TG helper class""" + + REST_STATUS_CODES = {'OK': 200, 'CREATED': 201, 'NO CHANGE': 409} + REST_API_CODES = {'NOT MODIFIED': 500810} + + def __init__(self, setup_helper): + super(LandslideResourceHelper, self).__init__(setup_helper) + self._result = {} + self.vnfd_helper = setup_helper.vnfd_helper + self.scenario_helper = setup_helper.scenario_helper + + # TCL session initialization + self._tcl = LandslideTclClient(LsTclHandler(), self) + + def terminate(self): + raise NotImplementedError() + + def collect_kpi(self): + raise NotImplementedError() + + +class LandslideTclClient(object): + """Landslide TG TCL client class""" + + DEFAULT_TEST_NODE = { + 'ethStatsEnabled': True, + 'forcedEthInterface': '', + 'innerVlanId': 0, + 'ip': '', + 'mac': '', + 'mtu': 1500, + 'nextHop': '', + 'numLinksOrNodes': 1, + 'numVlan': 1, + 'phy': '', + 'uniqueVlanAddr': False, + 'vlanDynamic': 0, + 'vlanId': 0, + 'vlanUserPriority': 0, + 'vlanTagType': 0 + } + + TEST_NODE_CMD = \ + 'ls::create -TestNode-{} -under $p_ -Type "eth"' \ + ' -Phy "{phy}" -Ip "{ip}" -NumLinksOrNodes {numLinksOrNodes}' \ + ' -NextHop "{nextHop}" -Mac "{mac}" -MTU {mtu} ' \ + ' -ForcedEthInterface "{forcedEthInterface}"' \ + ' -EthStatsEnabled {ethStatsEnabled}' \ + ' -VlanId {vlanId} -VlanUserPriority {vlanUserPriority}' \ + ' -NumVlan {numVlan} -UniqueVlanAddr {uniqueVlanAddr}' \ + ';' + + def __init__(self, tcl_handler, ts_context): + self.tcl_server_ip = None + self._user = None + self._library_id = None + self._basic_library_id = None + self._tcl = tcl_handler + self._ts_context = ts_context + self.ts_ids = set() + + # Test types names expected in session profile, test case and pod files + self._tc_types = {"SGW_Nodal", "SGW_Node", "MME_Nodal", "PGW_Node", + "PCRF_Node"} + + self._class_param_config_handler = { + "Array": self._configure_array_param, + "TestNode": self._configure_test_node_param, + "Sut": self._configure_sut_param, + "Dmf": self._configure_dmf_param + } + + def connect(self, tcl_server_ip, username, password): + """ Connect to TCL server with username and password + + :param tcl_server_ip: TCL server IP address + :type tcl_server_ip: str + :param username: existing username on TCL server + :type username: str + :param password: password related to username on TCL server + :type password: str + """ + LOG.info("connect: server='%s' user='%s'", tcl_server_ip, username) + res = self._tcl.execute( + "ls::login {} {} {}".format(tcl_server_ip, username, password)) + if 'java0x' not in res: # handle assignment reflects login success + raise exceptions.LandslideTclException( + "connect: login failed ='{}'.".format(res)) + self._library_id = self._tcl.execute( + "ls::get [ls::query LibraryInfo -userLibraryName {}] -Id".format( + username)) + self._basic_library_id = self._get_library_id('Basic') + self.tcl_server_ip = tcl_server_ip + self._user = username + LOG.debug("connect: user='%s' me='%s' basic='%s'", self._user, + self._library_id, + self._basic_library_id) + + def disconnect(self): + """ Disconnect from TCL server. Drop TCL connection configuration """ + LOG.info("disconnect: server='%s' user='%s'", + self.tcl_server_ip, self._user) + self._tcl.execute("ls::logout") + self.tcl_server_ip = None + self._user = None + self._library_id = None + self._basic_library_id = None + + def _add_test_server(self, name, ip): + try: + # Check if test server exists with name equal to _ts_name + ts_id = int(self.resolve_test_server_name(name)) + except ValueError: + # Such test server does not exist. Attempt to create it + ts_id = self._tcl.execute( + 'ls::perform AddTs -Name "{}" -Ip "{}"'.format(name, ip)) + try: + int(ts_id) + except ValueError: + # Failed to create test server, e.g. limit reached + raise RuntimeError( + 'Failed to create test server: "{}". {}'.format(name, + ts_id)) + return ts_id + + def _update_license(self, name): + """ Setup/update test server license + + :param name: test server name + :type name: str + """ + # Retrieve current TsInfo configuration, result stored in handle "ts" + self._tcl.execute( + 'set ts [ls::retrieve TsInfo -Name "{}"]'.format(name)) + + # Set license ID, if it differs from current one, update test server + _curr_lic_id = self._tcl.execute('ls::get $ts -RequestedLicense') + if _curr_lic_id != self._ts_context.license_data['lic_id']: + self._tcl.execute('ls::config $ts -RequestedLicense {}'.format( + self._ts_context.license_data['lic_id'])) + self._tcl.execute('ls::perform ModifyTs $ts') + + def _set_thread_model(self, name, thread_model): + # Retrieve test server configuration, store it in handle "tsc" + _cfguser_password = self._ts_context.vnfd_helper['mgmt-interface'][ + 'cfguser_password'] + self._tcl.execute( + 'set tsc [ls::perform RetrieveTsConfiguration ' + '-name "{}" {}]'.format(name, _cfguser_password)) + # Configure ThreadModel, if it differs from current one + thread_model_map = {'Legacy': 'V0', + 'Max': 'V1', + 'Fireball': 'V1_FB3'} + _model = thread_model_map[thread_model] + _curr_model = self._tcl.execute('ls::get $tsc -ThreadModel') + if _curr_model != _model: + self._tcl.execute( + 'ls::config $tsc -ThreadModel "{}"'.format(_model)) + self._tcl.execute( + 'ls::perform ApplyTsConfiguration $tsc {}'.format( + _cfguser_password)) + + def create_test_server(self, test_server): + _ts_thread_model = test_server.get('thread_model') + _ts_name = test_server['name'] + + ts_id = self._add_test_server(_ts_name, test_server['ip']) + + self._update_license(_ts_name) + + # Skip below code modifying thread_model if it is not defined + if _ts_thread_model: + self._set_thread_model(_ts_name, _ts_thread_model) + + return ts_id + + def create_test_session(self, test_session): + """ Create, configure and save Landslide test session object. + + :param test_session: Landslide TestSession object + :type test_session: dict + """ + LOG.info("create_test_session: name='%s'", test_session['name']) + self._tcl.execute('set test_ [ls::create TestSession]') + self._tcl.execute('ls::config $test_ -Library {} -Name "{}"'.format( + self._library_id, test_session['name'])) + self._tcl.execute('ls::config $test_ -Description "{}"'.format( + test_session['description'])) + if 'keywords' in test_session: + self._tcl.execute('ls::config $test_ -Keywords "{}"'.format( + test_session['keywords'])) + if 'duration' in test_session: + self._tcl.execute('ls::config $test_ -Duration "{}"'.format( + test_session['duration'])) + if 'iterations' in test_session: + self._tcl.execute('ls::config $test_ -Iterations "{}"'.format( + test_session['iterations'])) + if 'reservePorts' in test_session: + if test_session['reservePorts']: + self._tcl.execute('ls::config $test_ -Reserve Ports') + + if 'reservations' in test_session: + for _reservation in test_session['reservations']: + self._configure_reservation(_reservation) + + if 'reportOptions' in test_session: + self._configure_report_options(test_session['reportOptions']) + + for _index, _group in enumerate(test_session['tsGroups']): + self._configure_ts_group(_group, _index) + + self._save_test_session() + + def create_dmf(self, dmf): + """ Create, configure and save Landslide Data Message Flow object. + + :param dmf: Landslide Data Message Flow object + :type: dmf: dict + """ + self._tcl.execute('set dmf_ [ls::create Dmf]') + _lib_id = self._get_library_id(dmf['dmf']['library']) + self._tcl.execute('ls::config $dmf_ -Library {} -Name "{}"'.format( + _lib_id, + dmf['dmf']['name'])) + for _param_key in dmf: + if _param_key == 'dmf': + continue + _param_value = dmf[_param_key] + if isinstance(_param_value, dict): + # Configure complex parameter + _tcl_cmd = 'ls::config $dmf_' + for _sub_param_key in _param_value: + _sub_param_value = _param_value[_sub_param_key] + if isinstance(_sub_param_value, str): + _tcl_cmd += ' -{} "{}"'.format(_sub_param_key, + _sub_param_value) + else: + _tcl_cmd += ' -{} {}'.format(_sub_param_key, + _sub_param_value) + + self._tcl.execute(_tcl_cmd) + else: + # Configure simple parameter + if isinstance(_param_value, str): + self._tcl.execute( + 'ls::config $dmf_ -{} "{}"'.format(_param_key, + _param_value)) + else: + self._tcl.execute( + 'ls::config $dmf_ -{} {}'.format(_param_key, + _param_value)) + self._save_dmf() + + def configure_dmf(self, dmf): + # Use create to reconfigure and overwrite existing dmf + self.create_dmf(dmf) + + def delete_dmf(self, dmf): + raise NotImplementedError + + def _save_dmf(self): + # Call 'Validate' to set default values for missing parameters + res = self._tcl.execute('ls::perform Validate -Dmf $dmf_') + if res == 'Invalid': + res = self._tcl.execute('ls::get $dmf_ -ErrorsAndWarnings') + LOG.error("_save_dmf: %s", res) + raise exceptions.LandslideTclException("_save_dmf: {}".format(res)) + else: + res = self._tcl.execute('ls::save $dmf_ -overwrite') + LOG.debug("_save_dmf: result (%s)", res) + + def _configure_report_options(self, options): + for _option_key in options: + _option_value = options[_option_key] + if _option_key == 'format': + _format = 0 + if _option_value == 'CSV': + _format = 1 + self._tcl.execute( + 'ls::config $test_.ReportOptions -Format {} ' + '-Ts -3 -Tc -3'.format(_format)) + else: + self._tcl.execute( + 'ls::config $test_.ReportOptions -{} {}'.format( + _option_key, + _option_value)) + + def _configure_ts_group(self, ts_group, ts_group_index): + try: + _ts_id = int(self.resolve_test_server_name(ts_group['tsId'])) + except ValueError: + raise RuntimeError('Test server name "{}" does not exist.'.format( + ts_group['tsId'])) + if _ts_id not in self.ts_ids: + self._tcl.execute( + 'set tss_ [ls::create TsGroup -under $test_ -tsId {} ]'.format( + _ts_id)) + self.ts_ids.add(_ts_id) + for _case in ts_group.get('testCases', []): + self._configure_tc_type(_case, ts_group_index) + + self._configure_preresolved_arp(ts_group.get('preResolvedArpAddress')) + + def _configure_tc_type(self, tc, ts_group_index): + if tc['type'] not in self._tc_types: + raise RuntimeError('Test type {} not supported.'.format( + tc['type'])) + tc['type'] = tc['type'].replace('_', ' ') + res = self._tcl.execute( + 'set tc_ [ls::retrieve testcase -libraryId {0} "{1}"]'.format( + self._basic_library_id, tc['type'])) + if 'Invalid' in res: + raise RuntimeError('Test type {} not found in "Basic" ' + 'library.'.format(tc['type'])) + self._tcl.execute( + 'ls::config $test_.TsGroup({}) -children-Tc $tc_'.format( + ts_group_index)) + self._tcl.execute('ls::config $tc_ -Library {0} -Name "{1}"'.format( + self._basic_library_id, tc['name'])) + self._tcl.execute( + 'ls::config $tc_ -Description "{}"'.format(tc['type'])) + self._tcl.execute( + 'ls::config $tc_ -Keywords "GTP LTE {}"'.format(tc['type'])) + if 'linked' in tc: + self._tcl.execute( + 'ls::config $tc_ -Linked {}'.format(tc['linked'])) + if 'AssociatedPhys' in tc: + self._tcl.execute('ls::config $tc_ -AssociatedPhys "{}"'.format( + tc['AssociatedPhys'])) + if 'parameters' in tc: + self._configure_parameters(tc['parameters']) + + def _configure_parameters(self, params): + self._tcl.execute('set p_ [ls::get $tc_ -children-Parameters(0)]') + for _param_key in sorted(params): + _param_value = params[_param_key] + if isinstance(_param_value, dict): + # Configure complex parameter + if _param_value['class'] in self._class_param_config_handler: + self._class_param_config_handler[_param_value['class']]( + _param_key, + _param_value) + else: + # Configure simple parameter + self._tcl.execute( + 'ls::create {} -under $p_ -Value "{}"'.format( + _param_key, + _param_value)) + + def _configure_array_param(self, name, params): + self._tcl.execute('ls::create -Array-{} -under $p_ ;'.format(name)) + for param in params['array']: + self._tcl.execute( + 'ls::create ArrayItem -under $p_.{} -Value "{}"'.format(name, + param)) + + def _configure_test_node_param(self, name, params): + _params = self.DEFAULT_TEST_NODE + _params.update(params) + + # TCL command expects lower case 'true' or 'false' + _params['ethStatsEnabled'] = str(_params['ethStatsEnabled']).lower() + _params['uniqueVlanAddr'] = str(_params['uniqueVlanAddr']).lower() + + cmd = self.TEST_NODE_CMD.format(name, **_params) + self._tcl.execute(cmd) + + def _configure_sut_param(self, name, params): + self._tcl.execute( + 'ls::create -Sut-{} -under $p_ -Name "{}";'.format(name, + params['name'])) + + def _configure_dmf_param(self, name, params): + self._tcl.execute('ls::create -Dmf-{} -under $p_ ;'.format(name)) + + for _flow_index, _flow in enumerate(params['mainflows']): + _lib_id = self._get_library_id(_flow['library']) + self._tcl.execute( + 'ls::perform AddDmfMainflow $p_.Dmf {} "{}"'.format( + _lib_id, + _flow['name'])) + + if not params.get('instanceGroups'): + return + + _instance_group = params['instanceGroups'][_flow_index] + + # Traffic Mixer parameters handling + for _key in ['mixType', 'rate']: + if _key in _instance_group: + self._tcl.execute( + 'ls::config $p_.Dmf.InstanceGroup({}) -{} {}'.format( + _flow_index, _key, _instance_group[_key])) + + # Assignments parameters handling + for _row_id, _row in enumerate(_instance_group.get('rows', [])): + self._tcl.execute( + 'ls::config $p_.Dmf.InstanceGroup({}).Row({}) -Node {} ' + '-OverridePort {} -ClientPort {} -Context {} -Role {} ' + '-PreferredTransport {} -RatingGroup {} ' + '-ServiceID {}'.format( + _flow_index, _row_id, _row['node'], + _row['overridePort'], _row['clientPort'], + _row['context'], _row['role'], _row['transport'], + _row['ratingGroup'], _row['serviceId'])) + + def _configure_reservation(self, reservation): + _ts_id = self.resolve_test_server_name(reservation['tsId']) + self._tcl.execute( + 'set reservation_ [ls::create Reservation -under $test_]') + self._tcl.execute( + 'ls::config $reservation_ -TsIndex {} -TsId {} ' + '-TsName "{}"'.format(reservation['tsIndex'], + _ts_id, + reservation['tsName'])) + for _subnet in reservation['phySubnets']: + self._tcl.execute( + 'set physubnet_ [ls::create PhySubnet -under $reservation_]') + self._tcl.execute( + 'ls::config $physubnet_ -Name "{}" -Base "{}" -Mask "{}" ' + '-NumIps {}'.format(_subnet['name'], _subnet['base'], + _subnet['mask'], _subnet['numIps'])) + + def _configure_preresolved_arp(self, pre_resolved_arp): + if not pre_resolved_arp: # Pre-resolved ARP configuration not found + return + for _entry in pre_resolved_arp: + # TsGroup handle name should correspond in _configure_ts_group() + self._tcl.execute( + 'ls::create PreResolvedArpAddress -under $tss_ ' + '-StartingAddress "{StartingAddress}" ' + '-NumNodes {NumNodes}'.format(**_entry)) + + def delete_test_session(self, test_session): + raise NotImplementedError + + def _save_test_session(self): + # Call 'Validate' to set default values for missing parameters + res = self._tcl.execute('ls::perform Validate -TestSession $test_') + if res == 'Invalid': + res = self._tcl.execute('ls::get $test_ -ErrorsAndWarnings') + raise exceptions.LandslideTclException( + "_save_test_session: {}".format(res)) + else: + res = self._tcl.execute('ls::save $test_ -overwrite') + LOG.debug("_save_test_session: result (%s)", res) + + def _get_library_id(self, library): + _library_id = self._tcl.execute( + "ls::get [ls::query LibraryInfo -systemLibraryName {}] -Id".format( + library)) + try: + int(_library_id) + return _library_id + except ValueError: + pass + + _library_id = self._tcl.execute( + "ls::get [ls::query LibraryInfo -userLibraryName {}] -Id".format( + library)) + try: + int(_library_id) + except ValueError: + LOG.error("_get_library_id: library='%s' not found.", library) + raise exceptions.LandslideTclException( + "_get_library_id: library='{}' not found.".format( + library)) + + return _library_id + + def resolve_test_server_name(self, ts_name): + return self._tcl.execute("ls::query TsId {}".format(ts_name)) + + +class LsTclHandler(object): + """Landslide TCL Handler class""" + + LS_OK = "ls_ok" + JRE_PATH = net_serv_utils.get_nsb_option('jre_path_i386') + + def __init__(self): + self.tcl_cmds = {} + self._ls = LsApi(jre_path=self.JRE_PATH) + self._ls.tcl( + "ls::config ApiOptions -NoReturnSuccessResponseString '{}'".format( + self.LS_OK)) + + def execute(self, command): + res = self._ls.tcl(command) + self.tcl_cmds[command] = res + return res diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_landslide_profile.py b/yardstick/tests/unit/network_services/traffic_profile/test_landslide_profile.py new file mode 100644 index 000000000..afd550029 --- /dev/null +++ b/yardstick/tests/unit/network_services/traffic_profile/test_landslide_profile.py @@ -0,0 +1,136 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import copy +import unittest + +from yardstick.network_services.traffic_profile import landslide_profile + +TP_CONFIG = { + 'schema': "nsb:traffic_profile:0.1", + 'name': 'LandslideProfile', + 'description': 'Spirent Landslide traffic profile (Data Message Flow)', + 'traffic_profile': { + 'traffic_type': 'LandslideProfile' + }, + 'dmf_config': { + 'dmf': { + 'library': 'test', + 'name': 'Fireball UDP', + 'description': "Basic data flow using UDP/IP (Fireball DMF)", + 'keywords': 'UDP ', + 'dataProtocol': 'fb_udp', + 'burstCount': 1, + 'clientPort': { + 'clientPort': 2002, + 'isClientPortRange': 'false' + }, + 'serverPort': 2003, + 'connection': { + 'initiatingSide': 'Client', + 'disconnectSide': 'Client', + 'underlyingProtocol': 'none', + 'persistentConnection': 'false' + }, + 'protocolId': 0, + 'persistentConnection': 'false', + 'transactionRate': 8.0, + 'transactions': { + 'totalTransactions': 0, + 'retries': 0, + 'dataResponseTime': 60000, + 'packetSize': 64 + }, + 'segment': { + 'segmentSize': 64000, + 'maxSegmentSize': 0 + }, + 'size': { + 'sizeDistribution': 'Fixed', + 'sizeDeviation': 10 + }, + 'interval': { + 'intervalDistribution': 'Fixed', + 'intervalDeviation': 10 + }, + 'ipHeader': { + 'typeOfService': 0, + 'timeToLive': 64 + }, + 'tcpConnection': { + 'force3Way': 'false', + 'fixedRetryTime': 0, + 'maxPacketsToForceAck': 0 + }, + 'tcp': { + 'windowSize': 32768, + 'windowScaling': -1, + 'disableFinAckWait': 'false' + }, + 'disconnectType': 'FIN', + 'slowStart': 'false', + 'connectOnly': 'false', + 'vtag': { + 'VTagMask': '0x0', + 'VTagValue': '0x0' + }, + 'sctpPayloadProtocolId': 0, + 'billingIncludeSyn': 'true', + 'billingIncludeSubflow': 'true', + 'billingRecordPerTransaction': 'false', + 'tcpPush': 'false', + 'hostDataExpansionRatio': 1 + } + } +} +DMF_OPTIONS = { + 'dmf': { + 'transactionRate': 5, + 'packetSize': 512, + 'burstCount': 1 + } +} + + +class TestLandslideProfile(unittest.TestCase): + + def test___init__(self): + ls_traffic_profile = landslide_profile.LandslideProfile(TP_CONFIG) + self.assertListEqual([TP_CONFIG["dmf_config"]], + ls_traffic_profile.dmf_config) + + def test___init__config_not_a_dict(self): + _tp_config = copy.deepcopy(TP_CONFIG) + _tp_config['dmf_config'] = [_tp_config['dmf_config']] + ls_traffic_profile = landslide_profile.LandslideProfile(_tp_config) + self.assertListEqual(_tp_config['dmf_config'], + ls_traffic_profile.dmf_config) + + def test_execute(self): + ls_traffic_profile = landslide_profile.LandslideProfile(TP_CONFIG) + self.assertIsNone(ls_traffic_profile.execute(None)) + + def test_update_dmf_options_dict(self): + ls_traffic_profile = landslide_profile.LandslideProfile(TP_CONFIG) + ls_traffic_profile.update_dmf(DMF_OPTIONS) + self.assertDictContainsSubset(DMF_OPTIONS['dmf'], + ls_traffic_profile.dmf_config[0]) + + def test_update_dmf_options_list(self): + ls_traffic_profile = landslide_profile.LandslideProfile(TP_CONFIG) + _dmf_options = copy.deepcopy(DMF_OPTIONS) + _dmf_options['dmf'] = [_dmf_options['dmf']] + ls_traffic_profile.update_dmf(_dmf_options) + self.assertTrue(all([x in ls_traffic_profile.dmf_config[0] + for x in DMF_OPTIONS['dmf']])) diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py new file mode 100644 index 000000000..178ec5dab --- /dev/null +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py @@ -0,0 +1,722 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import mock +import unittest + +from yardstick.common import exceptions +from yardstick.network_services.vnf_generic.vnf import tg_landslide + +NAME = "tg__0" + +EXAMPLE_URL = 'http://example.com/' +TCL_SUCCESS_RESPONSE = 'ls_ok' + +TEST_SERVERS = [ + {'ip': '192.168.122.101', + 'phySubnets': [ + {'mask': '/24', + 'base': '10.42.32.100', + 'numIps': 20, + 'name': 'eth1'} + ], + 'role': 'SGW_Node', + 'name': 'TestServer_1'}, + {'ip': '192.168.122.102', + 'phySubnets': [ + {'mask': '/24', + 'base': '10.42.32.1', + 'numIps': 100, + 'name': 'eth1' + }, + {'mask': '/24', + 'base': '10.42.33.1', + 'numIps': 100, + 'name': 'eth2'} + ], + 'preResolvedArpAddress': [ + {'NumNodes': 1, + 'StartingAddress': '10.42.33.5'} + ], + 'role': 'SGW_Nodal', + 'name': 'TestServer_2', + 'thread_model': 'Fireball' + } +] + +TS1_SUTS = [ + {'name': 'SGW - C TestNode', + 'role': 'SgwControlAddr', + 'managementIp': '12.0.1.1', + 'ip': '10.42.32.100', + 'phy': 'eth5', + 'nextHop': '10.42.32.5' + }, + {'name': 'SGW - U TestNode', + 'role': 'SgwUserAddr', + 'managementIp': '12.0.1.2', + 'ip': '10.42.32.101', + 'phy': 'eth5', + 'nextHop': '10.42.32.5' + } +] + +TS2_SUTS = [ + {'name': 'eNodeB TestNode', + 'role': 'EnbUserAddr', + 'managementIp': '12.0.2.1', + 'ip': '10.42.32.2', + 'phy': 'eth5', + 'nextHop': '10.42.32.5' + }, + {'name': 'MME TestNode', + 'role': 'MmeControlAddr', + 'managementIp': '12.0.3.1', + 'ip': '10.42.32.1', + 'phy': 'eth5', + 'nextHop': '10.42.32.5' + }, + {'name': 'NetHost TestNode', + 'role': 'NetworkHostAddrLocal', + 'managementIp': '12.0.4.1', + 'ip': '10.42.33.1', + 'phy': 'eth5', + 'nextHop': '10.42.32.5' + }, + {'name': 'PGW TestNode', + 'role': 'PgwV4Sut', + 'managementIp': '12.0.5.1', + 'ip': '10.42.32.105', + 'phy': 'eth5', + 'nextHop': '10.42.32.5' + }, + {'name': 'SGW - C SUT', + 'role': 'SgwSut', + 'managementIp': '12.0.6.1', + 'ip': '10.42.32.100' + }, + {'name': 'SGW - U SUT', + 'role': 'SgwUserSut', + 'managementIp': '12.0.6.2', + 'ip': '10.42.32.101'} +] + +VNFD = { + 'vnfd:vnfd-catalog': { + 'vnfd': [{ + 'short-name': 'landslide', + 'vdu': [{ + 'description': 'AB client interface details', + 'name': 'abclient-baremetal', + 'id': 'abclient-baremetal', + 'external-interface': []}], + 'description': 'Spirent Landslide traffic generator', + 'config': [{'test_server': TEST_SERVERS[0], 'suts': TS1_SUTS}, + {'test_server': TEST_SERVERS[1], 'suts': TS2_SUTS}], + 'mgmt-interface': { + 'vdu-id': 'landslide-tas', + 'user': 'user', + 'password': 'user', + 'super-user': 'super-user', + 'super-user-password': 'super-user-password', + 'cfguser_password': 'cfguser_password', + 'license': 48, + 'proto': 'http', + 'ip': '1.1.1.1'}, + 'benchmark': { + 'kpi': [ + 'tx_throughput_mbps', + 'rx_throughput_mbps', + 'in_packets', + 'out_packets', + 'activation_rate_sessps', + 'deactivation_rate_sessps']}, + 'id': 'LandslideTrafficGen', + 'name': 'LandslideTrafficGen'}]}} + +TAS_INFO = VNFD['vnfd:vnfd-catalog']['vnfd'][0]['mgmt-interface'] + +DMF_CFG = { + "dmf": { + "library": "test", + "name": "Basic UDP" + }, + "clientPort": { + "clientPort": 2002, + "isClientPortRange": "false" + }, + "dataProtocol": "udp", + "serverPort": 2003 +} + +SESSION_PROFILE = { + 'keywords': '', + 'duration': 60, + 'iterations': 1, + 'description': 'UE default bearer creation test case', + 'name': 'default_bearer_capacity', + 'reportOptions': {'Format': '1'}, + "reservePorts": "true", + "reservations": [ + {"tsId": 4, + "tsIndex": 0, + "tsName": TEST_SERVERS[0]['name'], + "phySubnets": [ + {"base": "10.42.32.100", "mask": "/24", "name": "eth5", + "numIps": 20}, + {"base": "10.42.33.100", "mask": "/24", "name": "eth6", + "numIps": 20} + ]}, + {"tsId": 2, + "tsIndex": 1, + "tsName": "TestServer_2", + "phySubnets": [ + {"base": "10.42.32.1", "mask": "/24", "name": "eth5", + "numIps": 100}, + {"base": "10.42.33.1", "mask": "/24", "name": "eth6", + "numIps": 100} + ]} + ], + 'tsGroups': [ + { + 'testCases': [{ + 'type': 'SGW_Node', + 'name': '', + 'linked': False, + 'AssociatedPhys': '', + 'parameters': { + 'SgiPtpTunnelEn': 'false', + 'Gtp2Imsi': '505024101215074', + 'Sessions': '100000', + 'S5Protocol': 'GTPv2', + 'TrafficMtu': '1500', + 'Gtp2Version': '13.6.0', + 'BearerV4AddrPool': '1.0.0.1', + 'Gtp2Imei': '50502410121507', + 'PgwNodeEn': 'true', + 'DedicatedsPerDefaultBearer': '0', + 'DefaultBearers': '1', + 'SgwUserAddr': { + 'numLinksOrNodes': 1, + 'phy': 'eth1', + 'forcedEthInterface': '', + 'ip': 'SGW_USER_IP', + 'class': 'TestNode', + 'ethStatsEnabled': False, + 'mtu': 1500 + }, + 'SgwControlAddr': { + 'numLinksOrNodes': 1, + 'phy': 'eth1', + 'forcedEthInterface': '', + 'ip': 'SGW_CONTROL_IP', + 'class': 'TestNode', + 'ethStatsEnabled': False, + 'mtu': 1500, + 'nextHop': 'SGW_CONTROL_NEXT_HOP' + }, + 'BearerAddrPool': '2001::1', + 'TestType': 'SGW-NODE' + } + }], + 'tsId': TEST_SERVERS[0]['name']}, + { + 'testCases': [{ + 'type': 'SGW_Nodal', + 'name': '', + 'parameters': { + 'DataTraffic': 'Continuous', + 'TrafficStartType': 'When All Sessions Established', + 'NetworkHost': 'Local', + 'Gtp2Imsi': '505024101215074', + 'Dmf': { + 'mainflows': [ + { + 'name': 'Basic UDP', + 'library': 'test' + } + ], + 'class': 'Dmf', + 'instanceGroups': [ + { + 'startPaused': False, + 'rate': 0, + 'mainflowIdx': 0, + 'mixType': '' + } + ] + }, + 'S5Protocol': 'GTPv2', + 'DataUserCfgFileEn': 'false', + 'PgwUserSutEn': 'false', + 'MmeControlAddr': { + 'numLinksOrNodes': 1, + 'phy': 'eth1', + 'forcedEthInterface': '', + 'ip': 'MME_CONTROL_IP', + 'class': 'TestNode', + 'ethStatsEnabled': False, + 'mtu': 1500 + }, + 'SgwUserSut': { + 'class': 'Sut', + 'name': 'SGW_USER_NAME' + }, + 'TestActivity': 'Capacity Test', + 'NetworkHostAddrLocal': { + 'numLinksOrNodes': 1, + 'phy': 'eth2', + 'forcedEthInterface': '', + 'ip': 'NET_HOST_IP', + 'class': 'TestNode', + 'ethStatsEnabled': False, + 'mtu': 1500 + }, + 'DedicatedsPerDefaultBearer': '0', + 'DisconnectRate': '1000.0', + 'Sessions': '100000', + 'SgwSut': { + 'class': 'Sut', + 'name': 'SGW_CONTROL_NAME' + }, + 'TrafficMtu': '1500', + 'Gtp2Version': '13.6.0', + 'Gtp2Imei': '50502410121507', + 'PgwNodeEn': 'false', + 'StartRate': '1000.0', + 'PgwV4Sut': { + 'class': 'Sut', + 'name': 'PGW_SUT_NAME' + }, + 'DefaultBearers': '1', + 'EnbUserAddr': { + 'numLinksOrNodes': 1, + 'phy': 'eth1', + 'forcedEthInterface': '', + 'ip': 'ENB_USER_IP', + 'class': 'TestNode', + 'ethStatsEnabled': False, + 'mtu': 1500 + }, + 'TestType': 'SGW-NODAL' + } + }], + 'tsId': TEST_SERVERS[1]['name'] + } + ] +} + + +class TestLandslideResourceHelper(unittest.TestCase): + TEST_TERMINATED = 1 + SUCCESS_RECORD_ID = 11 + + TEST_RESULTS_DATA = { + "interval": 0, + "elapsedTime": 138, + "actualTime": 1521548057296, + "iteration": 1, + "tabs": { + "Test Summary": { + "Start Time": "Tue Mar 20 07:11:55 CDT 2018", + "Attempted Dedicated Bearer Session Connects": "0", + "Attempted Dedicated Bearer Session Disconnects": "0", + "Actual Dedicated Bearer Session Connects": "0", + "Actual Dedicated Bearer Session Disconnects": "0", + "Dedicated Bearer Sessions Pending": "0", + "Dedicated Bearer Sessions Established": "0" + }}} + + def setUp(self): + self.mock_lsapi = mock.patch.object(tg_landslide, 'LsApi') + self.mock_lsapi.start() + + mock_env_helper = mock.Mock() + self.res_helper = tg_landslide.LandslideResourceHelper(mock_env_helper) + self.res_helper._url = EXAMPLE_URL + + self.addCleanup(self._cleanup) + + def _cleanup(self): + self.mock_lsapi.stop() + self.res_helper._url = None + + def test___init__(self, *args): + self.assertIsInstance(self.res_helper, + tg_landslide.LandslideResourceHelper) + self.assertEqual({}, self.res_helper._result) + + def test_terminate(self): + self.assertRaises(NotImplementedError, self.res_helper.terminate) + + def test_collect_kpi_test_running(self): + self.assertRaises(NotImplementedError, self.res_helper.collect_kpi) + + +class TestLandslideTclClient(unittest.TestCase): + def setUp(self): + self.mock_tcl_handler = mock.Mock(spec=tg_landslide.LsTclHandler) + self.ls_res_helper = mock.Mock( + spec=tg_landslide.LandslideResourceHelper) + self.ls_tcl_client = tg_landslide.LandslideTclClient( + self.mock_tcl_handler, + self.ls_res_helper) + + def test___init__(self, *args): + self.ls_tcl_client = tg_landslide.LandslideTclClient( + self.mock_tcl_handler, + self.ls_res_helper) + self.assertIsNone(self.ls_tcl_client.tcl_server_ip) + self.assertIsNone(self.ls_tcl_client._user) + self.assertIsNone(self.ls_tcl_client._library_id) + self.assertIsNone(self.ls_tcl_client._basic_library_id) + self.assertEqual(set(), self.ls_tcl_client.ts_ids) + self.assertIsInstance(self.ls_tcl_client._tc_types, set) + self.assertIsNotNone(self.ls_tcl_client._tc_types) + + def test_connect_login_success(self, *args): + lib_id = '123' + exec_responses = ['java0x2', lib_id, lib_id] + auth = ('user', 'password') + self.mock_tcl_handler.execute.side_effect = exec_responses + self.ls_tcl_client.connect(TAS_INFO['ip'], *auth) + self.assertEqual(lib_id, self.ls_tcl_client._library_id) + self.assertEqual(lib_id, self.ls_tcl_client._basic_library_id) + self.assertEqual(TAS_INFO['ip'], self.ls_tcl_client.tcl_server_ip) + self.assertEqual(auth[0], self.ls_tcl_client._user) + self.assertEqual(len(exec_responses), + self.mock_tcl_handler.execute.call_count) + + def test_connect_login_failed(self, *args): + exec_responses = ['Login failed'] + auth = ('user', 'password') + self.mock_tcl_handler.execute.side_effect = exec_responses + self.assertRaises(exceptions.LandslideTclException, + self.ls_tcl_client.connect, + TAS_INFO['ip'], + *auth) + self.assertIsNone(self.ls_tcl_client._library_id) + self.assertIsNone(self.ls_tcl_client._basic_library_id) + self.assertIsNone(self.ls_tcl_client.tcl_server_ip) + self.assertIsNone(self.ls_tcl_client._user) + self.assertEqual(len(exec_responses), + self.mock_tcl_handler.execute.call_count) + + def test_disconnect(self, *args): + self.ls_tcl_client.disconnect() + self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + self.assertIsNone(self.ls_tcl_client.tcl_server_ip) + self.assertIsNone(self.ls_tcl_client._user) + self.assertIsNone(self.ls_tcl_client._library_id) + self.assertIsNone(self.ls_tcl_client._basic_library_id) + + def test_create_test_server(self, *args): + return_value = '2' + self.ls_tcl_client._ts_context.vnfd_helper = \ + VNFD['vnfd:vnfd-catalog']['vnfd'][0] + self.ls_tcl_client._ts_context.license_data = {'lic_id': return_value} + self.mock_tcl_handler.execute.return_value = return_value + self.ls_tcl_client._set_thread_model = mock.Mock() + res = self.ls_tcl_client.create_test_server(TEST_SERVERS[1]) + self.assertEqual(3, self.mock_tcl_handler.execute.call_count) + self.ls_tcl_client._set_thread_model.assert_called_once_with( + TEST_SERVERS[1]['name'], + TEST_SERVERS[1]['thread_model']) + self.assertEqual(int(return_value), res) + + def test_create_test_server_fail_limit_reach(self, *args): + self.mock_tcl_handler.execute.side_effect = ['TS not found', + 'Add failed'] + self.assertRaises(RuntimeError, + self.ls_tcl_client.create_test_server, + TEST_SERVERS[0]) + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + + def test__add_test_server(self): + ts_id = '2' + self.mock_tcl_handler.execute.side_effect = ['TS not found', ts_id] + self.assertEqual(ts_id, + self.ls_tcl_client._add_test_server('name', 'ip')) + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + + def test__add_test_server_failed(self): + self.mock_tcl_handler.execute.side_effect = ['TS not found', + 'Add failed'] + self.assertRaises(RuntimeError, self.ls_tcl_client._add_test_server, + 'name', 'ip') + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + + def test__update_license(self): + curr_lic_id = '111' + new_lic_id = '222' + exec_resp = ['java0x4', + curr_lic_id, + TCL_SUCCESS_RESPONSE, + TCL_SUCCESS_RESPONSE] + self.ls_tcl_client._ts_context.license_data = {'lic_id': new_lic_id} + self.mock_tcl_handler.execute.side_effect = exec_resp + self.ls_tcl_client._update_license('name') + self.assertEqual(len(exec_resp), + self.mock_tcl_handler.execute.call_count) + + def test__update_license_same_as_current(self): + curr_lic_id = '111' + new_lic_id = '111' + exec_resp = ['java0x4', curr_lic_id] + self.ls_tcl_client._ts_context.license_data = {'lic_id': new_lic_id} + self.mock_tcl_handler.execute.side_effect = exec_resp + self.ls_tcl_client._update_license('name') + self.assertEqual(len(exec_resp), + self.mock_tcl_handler.execute.call_count) + + def test__set_thread_model_update_needed(self): + self.ls_tcl_client._ts_context.vnfd_helper = { + 'mgmt-interface': { + 'cfguser_password': 'cfguser_password' + } + } + exec_resp = ['java0x4', 'V0', '', ''] + self.mock_tcl_handler.execute.side_effect = exec_resp + self.ls_tcl_client._set_thread_model('name', 'Fireball') + self.assertEqual(len(exec_resp), + self.mock_tcl_handler.execute.call_count) + + def test__set_thread_model_no_update_needed(self): + self.ls_tcl_client._ts_context.vnfd_helper = { + 'mgmt-interface': { + 'cfguser_password': 'cfguser_password' + } + } + exec_resp = ['java0x4', 'V0'] + self.mock_tcl_handler.execute.side_effect = exec_resp + self.ls_tcl_client._set_thread_model('name', 'Legacy') + self.assertEqual(len(exec_resp), + self.mock_tcl_handler.execute.call_count) + + @mock.patch.object(tg_landslide.LandslideTclClient, + 'resolve_test_server_name', return_value='2') + def test_create_test_session(self, *args): + self.ls_tcl_client._save_test_session = mock.Mock() + self.ls_tcl_client._configure_ts_group = mock.Mock() + self.ls_tcl_client.create_test_session(SESSION_PROFILE) + self.assertEqual(20, self.mock_tcl_handler.execute.call_count) + + def test_create_dmf(self): + self.mock_tcl_handler.execute.return_value = '2' + self.ls_tcl_client._save_dmf = mock.Mock() + self.ls_tcl_client.create_dmf(DMF_CFG) + self.assertEqual(6, self.mock_tcl_handler.execute.call_count) + + def test_configure_dmf(self): + self.mock_tcl_handler.execute.return_value = '2' + self.ls_tcl_client._save_dmf = mock.Mock() + self.ls_tcl_client.configure_dmf(DMF_CFG) + self.assertEqual(6, self.mock_tcl_handler.execute.call_count) + + def test_delete_dmf(self): + self.assertRaises(NotImplementedError, + self.ls_tcl_client.delete_dmf, + DMF_CFG) + + def test__save_dmf_valid(self): + exec_resp = [TCL_SUCCESS_RESPONSE, TCL_SUCCESS_RESPONSE] + self.mock_tcl_handler.execute.side_effect = exec_resp + self.ls_tcl_client._save_dmf() + self.assertEqual(len(exec_resp), + self.mock_tcl_handler.execute.call_count) + + def test__save_dmf_invalid(self): + exec_resp = ['Invalid', 'List of errors and warnings'] + self.mock_tcl_handler.execute.side_effect = exec_resp + self.assertRaises(exceptions.LandslideTclException, + self.ls_tcl_client._save_dmf) + self.assertEqual(len(exec_resp), + self.mock_tcl_handler.execute.call_count) + + def test__configure_report_options(self): + _options = {'format': 'CSV', 'PerInterval': False} + self.ls_tcl_client._configure_report_options(_options) + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + + def test___configure_ts_group(self, *args): + self.ls_tcl_client._configure_tc_type = mock.Mock() + self.ls_tcl_client._configure_preresolved_arp = mock.Mock() + self.ls_tcl_client.resolve_test_server_name = mock.Mock( + return_value='2') + self.ls_tcl_client._configure_ts_group( + SESSION_PROFILE['tsGroups'][0], 0) + self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + + def test___configure_ts_group_resolve_ts_fail(self, *args): + self.ls_tcl_client._configure_tc_type = mock.Mock() + self.ls_tcl_client._configure_preresolved_arp = mock.Mock() + self.ls_tcl_client.resolve_test_server_name = mock.Mock( + return_value='TS Not Found') + self.assertRaises(RuntimeError, self.ls_tcl_client._configure_ts_group, + SESSION_PROFILE['tsGroups'][0], 0) + self.assertEqual(0, self.mock_tcl_handler.execute.call_count) + + def test__configure_tc_type(self): + _tc = SESSION_PROFILE['tsGroups'][0]['testCases'][0] + self.mock_tcl_handler.execute.return_value = TCL_SUCCESS_RESPONSE + self.ls_tcl_client._configure_parameters = mock.Mock() + self.ls_tcl_client._configure_tc_type(_tc, 0) + self.assertEqual(7, self.mock_tcl_handler.execute.call_count) + + def test__configure_tc_type_wrong_type(self): + _tc = SESSION_PROFILE['tsGroups'][0]['testCases'][0] + _tc['type'] = 'not_supported' + self.ls_tcl_client._configure_parameters = mock.Mock() + self.assertRaises(RuntimeError, + self.ls_tcl_client._configure_tc_type, + _tc, 0) + + def test__configure_tc_type_not_found_basic_lib(self): + _tc = SESSION_PROFILE['tsGroups'][0]['testCases'][0] + self.ls_tcl_client._configure_parameters = mock.Mock() + self.mock_tcl_handler.execute.return_value = 'Invalid' + self.assertRaises(RuntimeError, + self.ls_tcl_client._configure_tc_type, + _tc, 0) + self.assertEqual(0, self.mock_tcl_handler.execute.call_count) + + def test__configure_parameters(self): + _params = SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters'] + self.ls_tcl_client._configure_parameters(_params) + self.assertEqual(16, self.mock_tcl_handler.execute.call_count) + + def test__configure_array_param(self): + _array = {"class": "Array", + "array": ["0"]} + self.ls_tcl_client._configure_array_param('name', _array) + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + + def test__configure_test_node_param(self): + _params = SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters'] + self.ls_tcl_client._configure_test_node_param('SgwUserAddr', + _params['SgwUserAddr']) + self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + + def test__configure_sut_param(self): + _params = {'name': 'name'} + self.ls_tcl_client._configure_sut_param('name', _params) + self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + + def test__configure_dmf_param(self): + _params = {"mainflows": [{"library": '111', + "name": "Basic UDP"}], + "instanceGroups": [{ + "mainflowIdx": 0, + "mixType": "", + "rate": 0.0, + "rows": [{ + "clientPort": 0, + "context": 0, + "node": 0, + "overridePort": False, + "ratingGroup": 0, + "role": 0, + "serviceId": 0, + "transport": "Any"}] + }]} + self.ls_tcl_client._get_library_id = mock.Mock(return_value='111') + res = self.ls_tcl_client._configure_dmf_param('name', _params) + self.assertEqual(5, self.mock_tcl_handler.execute.call_count) + self.assertIsNone(res) + + def test__configure_dmf_param_no_instance_groups(self): + _params = {"mainflows": [{"library": '111', + "name": "Basic UDP"}]} + self.ls_tcl_client._get_library_id = mock.Mock(return_value='111') + res = self.ls_tcl_client._configure_dmf_param('name', _params) + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.assertIsNone(res) + + def test__configure_reservation(self): + _reservation = SESSION_PROFILE['reservations'][0] + self.ls_tcl_client.resolve_test_server_name = mock.Mock( + return_value='2') + res = self.ls_tcl_client._configure_reservation(_reservation) + self.assertIsNone(res) + self.assertEqual(6, self.mock_tcl_handler.execute.call_count) + + def test__configure_preresolved_arp(self): + _arp = [{'StartingAddress': '10.81.1.10', + 'NumNodes': 1}] + res = self.ls_tcl_client._configure_preresolved_arp(_arp) + self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + self.assertIsNone(res) + + def test__configure_preresolved_arp_none(self): + res = self.ls_tcl_client._configure_preresolved_arp(None) + self.assertIsNone(res) + + def test_delete_test_session(self): + self.assertRaises(NotImplementedError, + self.ls_tcl_client.delete_test_session, {}) + + def test__save_test_session(self): + self.mock_tcl_handler.execute.side_effect = [TCL_SUCCESS_RESPONSE, + TCL_SUCCESS_RESPONSE] + res = self.ls_tcl_client._save_test_session() + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.assertIsNone(res) + + def test__save_test_session_invalid(self): + self.mock_tcl_handler.execute.side_effect = ['Invalid', 'Errors'] + self.assertRaises(exceptions.LandslideTclException, + self.ls_tcl_client._save_test_session) + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + + def test__get_library_id_system_lib(self): + self.mock_tcl_handler.execute.side_effect = ['111'] + res = self.ls_tcl_client._get_library_id('name') + self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + self.assertEqual('111', res) + + def test__get_library_id_user_lib(self): + self.mock_tcl_handler.execute.side_effect = ['Not found', '222'] + res = self.ls_tcl_client._get_library_id('name') + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.assertEqual('222', res) + + def test__get_library_id_exception(self): + self.mock_tcl_handler.execute.side_effect = ['Not found', 'Not found'] + self.assertRaises(exceptions.LandslideTclException, + self.ls_tcl_client._get_library_id, + 'name') + self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + + +class TestLsTclHandler(unittest.TestCase): + + def setUp(self): + self.mock_lsapi = mock.patch.object(tg_landslide, 'LsApi') + self.mock_lsapi.start() + + self.addCleanup(self._cleanup) + + def _cleanup(self): + self.mock_lsapi.stop() + + def test___init__(self, *args): + self.ls_tcl_handler = tg_landslide.LsTclHandler() + self.assertEqual({}, self.ls_tcl_handler.tcl_cmds) + self.ls_tcl_handler._ls.tcl.assert_called_once() + + def test_execute(self, *args): + self.ls_tcl_handler = tg_landslide.LsTclHandler() + self.ls_tcl_handler.execute('command') + self.assertIn('command', self.ls_tcl_handler.tcl_cmds) -- cgit 1.2.3-korg From dea3a485f5f196d7ee18ccc0c64a35ab5560385f Mon Sep 17 00:00:00 2001 From: Emma Foley Date: Thu, 30 Aug 2018 13:19:36 +0100 Subject: Added Landslide Resource Helper implementation Class "LandslideResourceHelper" provides API for operations needed - to configure Landslide test session - manage test session execution (start/stop/abort) - collect measurements during test run This helper class API is responsible to for configure Landslide test runs: - create test user - create test servers (for emulation of specific vEPC blocks) - create SUTs (actual tested VNFs performing specific vEPC roles) - create test session (contains actual test cases) - create DMFs (pre-defined traffic flows in traffic profile) - operate traffic run execution (start, stop, abort) - monitor test run status - collect KPIs on TG side Some of these features use Landslide REST API. Other ones use Landslide TCL API. JIRA: YARDSTICK-1356 Change-Id: I8fc8a7d85301121da465d054b8d38ae09a541c36 Signed-off-by: Orest Voznyy Signed-off-by: Emma Foley Signed-off-by: Orest Voznyy --- yardstick/common/exceptions.py | 6 + .../vnf_generic/vnf/tg_landslide.py | 516 ++++++++++++++- .../vnf_generic/vnf/test_tg_landslide.py | 734 ++++++++++++++++++++- 3 files changed, 1218 insertions(+), 38 deletions(-) diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index 4a4006ae4..539e0fec3 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -422,6 +422,12 @@ class ValueCheckError(YardstickException): message = 'Constraint "%(value1)s %(operator)s %(value2)s" does not hold' +class RestApiError(RuntimeError): + def __init__(self, message): + self._message = message + super(RestApiError, self).__init__(message) + + class LandslideTclException(RuntimeError): def __init__(self, message): self._message = message diff --git a/yardstick/network_services/vnf_generic/vnf/tg_landslide.py b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py index 3bb849c52..0ccffeeb1 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_landslide.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py @@ -13,6 +13,10 @@ # limitations under the License. import logging +import requests +import six +import time +from collections import Mapping from yardstick.common import exceptions from yardstick.common import utils as common_utils @@ -39,14 +43,515 @@ class LandslideResourceHelper(sample_vnf.ClientResourceHelper): self.vnfd_helper = setup_helper.vnfd_helper self.scenario_helper = setup_helper.scenario_helper + # TAS Manager config initialization + self._url = None + self._user_id = None + self.session = None + self.license_data = {} + # TCL session initialization self._tcl = LandslideTclClient(LsTclHandler(), self) + self.session = requests.Session() + self.running_tests_uri = 'runningTests' + self.test_session_uri = 'testSessions' + self.test_serv_uri = 'testServers' + self.suts_uri = 'suts' + self.users_uri = 'users' + self.user_lib_uri = None + self.run_id = None + + def abort_running_tests(self, timeout=60, delay=5): + """ Abort running test sessions, if any """ + _start_time = time.time() + while time.time() < _start_time + timeout: + run_tests_states = {x['id']: x['testStateOrStep'] + for x in self.get_running_tests()} + if not set(run_tests_states.values()).difference( + {'COMPLETE', 'COMPLETE_ERROR'}): + break + else: + [self.stop_running_tests(running_test_id=_id, force=True) + for _id, _state in run_tests_states.items() + if 'COMPLETE' not in _state] + time.sleep(delay) + else: + raise RuntimeError( + 'Some test runs not stopped during {} seconds'.format(timeout)) + + def _build_url(self, resource, action=None): + """ Build URL string + + :param resource: REST API resource name + :type resource: str + :param action: actions name and value + :type action: dict('name': , 'value': ) + :returns str: REST API resource name with optional action info + """ + # Action is optional and accepted only in presence of resource param + if action and not resource: + raise ValueError("Resource name not provided") + # Concatenate actions + _action = ''.join(['?{}={}'.format(k, v) for k, v in + action.items()]) if action else '' + + return ''.join([self._url, resource, _action]) + + def get_response_params(self, method, resource, params=None): + """ Retrieve params from JSON response of specific resource URL + + :param method: one of supported REST API methods + :type method: str + :param resource: URI, requested resource name + :type resource: str + :param params: attributes to be found in JSON response + :type params: list(str) + """ + _res = [] + params = params if params else [] + response = self.exec_rest_request(method, resource) + # Get substring between last slash sign and question mark (if any) + url_last_part = resource.rsplit('/', 1)[-1].rsplit('?', 1)[0] + _response_json = response.json() + # Expect dict(), if URL last part and top dict key don't match + # Else, if they match, expect list() + k, v = list(_response_json.items())[0] + if k != url_last_part: + v = [v] # v: list(dict(str: str)) + # Extract params, or whole list of dicts (without top level key) + for x in v: + _res.append({param: x[param] for param in params} if params else x) + return _res + + def _create_user(self, auth, level=1): + """ Create new user + + :param auth: data to create user account on REST server + :type auth: dict + :param level: Landslide user permissions level + :type level: int + :returns int: user id + """ + # Set expiration date in two years since account creation date + _exp_date = time.strftime( + '{}/%m/%d %H:%M %Z'.format(time.gmtime().tm_year + 2)) + _username = auth['user'] + _fields = {"contactInformation": "", "expiresOn": _exp_date, + "fullName": "Test User", + "isActive": "true", "level": level, + "password": auth['password'], + "username": _username} + _response = self.exec_rest_request('post', self.users_uri, + json_data=_fields, raise_exc=False) + _resp_json = _response.json() + if _response.status_code == self.REST_STATUS_CODES['CREATED']: + # New user created + _id = _resp_json['id'] + LOG.info("New user created: username='%s', id='%s'", _username, + _id) + elif _resp_json.get('apiCode') == self.REST_API_CODES['NOT MODIFIED']: + # User already exists + LOG.info("Account '%s' already exists.", _username) + # Get user id + _id = self._modify_user(_username, {"isActive": "true"})['id'] + else: + raise exceptions.RestApiError( + 'Error during new user "{}" creation'.format(_username)) + return _id + + def _modify_user(self, username, fields): + """ Modify information about existing user + + :param username: user name of account to be modified + :type username: str + :param fields: data to modify user account on REST server + :type fields: dict + :returns dict: user info + """ + _response = self.exec_rest_request('post', self.users_uri, + action={'username': username}, + json_data=fields, raise_exc=False) + if _response.status_code == self.REST_STATUS_CODES['OK']: + _response = _response.json() + else: + raise exceptions.RestApiError( + 'Error during user "{}" data update: {}'.format( + username, + _response.status_code)) + LOG.info("User account '%s' modified: '%s'", username, _response) + return _response + + def _delete_user(self, username): + """ Delete user account + + :param username: username field + :type username: str + :returns bool: True if succeeded + """ + self.exec_rest_request('delete', self.users_uri, + action={'username': username}) + + def _get_users(self, username=None): + """ Get user records from REST server + + :param username: username field + :type username: None|str + :returns list(dict): empty list, or user record, or list of all users + """ + _response = self.get_response_params('get', self.users_uri) + _res = [u for u in _response if + u['username'] == username] if username else _response + return _res + + def exec_rest_request(self, method, resource, action=None, json_data=None, + logs=True, raise_exc=True): + """ Execute REST API request, return response object + + :param method: one of supported requests ('post', 'get', 'delete') + :type method: str + :param resource: URL of resource + :type resource: str + :param action: data used to provide URI located after question mark + :type action: dict + :param json_data: mandatory only for 'post' method + :type json_data: dict + :param logs: debug logs display flag + :type raise_exc: bool + :param raise_exc: if True, raise exception on REST API call error + :returns requests.Response(): REST API call response object + """ + json_data = json_data if json_data else {} + action = action if action else {} + _method = method.upper() + method = method.lower() + if method not in ('post', 'get', 'delete'): + raise ValueError("Method '{}' not supported".format(_method)) + + if method == 'post' and not action: + if not (json_data and isinstance(json_data, Mapping)): + raise ValueError( + 'JSON data missing in {} request'.format(_method)) + + r = getattr(self.session, method)(self._build_url(resource, action), + json=json_data) + if raise_exc and not r.ok: + msg = 'Failed to "{}" resource "{}". Reason: "{}"'.format( + method, self._build_url(resource, action), r.reason) + raise exceptions.RestApiError(msg) + + if logs: + LOG.debug("RC: %s | Request: %s | URL: %s", r.status_code, method, + r.request.url) + LOG.debug("Response: %s", r.json()) + return r + + def connect(self): + """Connect to RESTful server using test user account""" + tas_info = self.vnfd_helper['mgmt-interface'] + # Supported REST Server ports: HTTP - 8080, HTTPS - 8181 + _port = '8080' if tas_info['proto'] == 'http' else '8181' + tas_info.update({'port': _port}) + self._url = '{proto}://{ip}:{port}/api/'.format(**tas_info) + self.session.headers.update({'Accept': 'application/json', + 'Content-type': 'application/json'}) + # Login with super user to create test user + self.session.auth = ( + tas_info['super-user'], tas_info['super-user-password']) + LOG.info("Connect using superuser: server='%s'", self._url) + auth = {x: tas_info[x] for x in ('user', 'password')} + self._user_id = self._create_user(auth) + # Login with test user + self.session.auth = auth['user'], auth['password'] + # Test user validity + self.exec_rest_request('get', '') + + self.user_lib_uri = 'libraries/{{}}/{}'.format(self.test_session_uri) + LOG.info("Login with test user: server='%s'", self._url) + # Read existing license + self.license_data['lic_id'] = tas_info['license'] + + # Tcl client init + self._tcl.connect(tas_info['ip'], *self.session.auth) + + return self.session + + def disconnect(self): + self.session = None + self._tcl.disconnect() + def terminate(self): - raise NotImplementedError() + self._terminated.value = 1 + + def create_dmf(self, dmf): + if isinstance(dmf, list): + for _dmf in dmf: + self._tcl.create_dmf(_dmf) + else: + self._tcl.create_dmf(dmf) + + def delete_dmf(self, dmf): + if isinstance(dmf, list): + for _dmf in dmf: + self._tcl.delete_dmf(_dmf) + else: + self._tcl.delete_dmf(dmf) + + def create_suts(self, suts): + # Keep only supported keys in suts object + for _sut in suts: + sut_entry = {k: v for k, v in _sut.items() + if k not in {'phy', 'nextHop', 'role'}} + _response = self.exec_rest_request( + 'post', self.suts_uri, json_data=sut_entry, + logs=False, raise_exc=False) + if _response.status_code != self.REST_STATUS_CODES['CREATED']: + LOG.info(_response.reason) # Failed to create + _name = sut_entry.pop('name') + # Modify existing SUT + self.configure_sut(sut_name=_name, json_data=sut_entry) + else: + LOG.info("SUT created: %s", sut_entry) + + def get_suts(self, suts_id=None): + if suts_id: + _suts = self.exec_rest_request( + 'get', '{}/{}'.format(self.suts_uri, suts_id)).json() + else: + _suts = self.get_response_params('get', self.suts_uri) + + return _suts + + def configure_sut(self, sut_name, json_data): + """ Modify information of specific SUTs + + :param sut_name: name of existing SUT + :type sut_name: str + :param json_data: SUT settings + :type json_data: dict() + """ + LOG.info("Modifying SUT information...") + _response = self.exec_rest_request('post', + self.suts_uri, + action={'name': sut_name}, + json_data=json_data, + raise_exc=False) + if _response.status_code not in {self.REST_STATUS_CODES[x] for x in + {'OK', 'NO CHANGE'}}: + raise exceptions.RestApiError(_response.reason) + + LOG.info("Modified SUT: %s", sut_name) + + def delete_suts(self, suts_ids=None): + if not suts_ids: + _curr_suts = self.get_response_params('get', self.suts_uri) + suts_ids = [x['id'] for x in _curr_suts] + LOG.info("Deleting SUTs with following IDs: %s", suts_ids) + for _id in suts_ids: + self.exec_rest_request('delete', + '{}/{}'.format(self.suts_uri, _id)) + LOG.info("\tDone for SUT id: %s", _id) + + def _check_test_servers_state(self, test_servers_ids=None, delay=10, + timeout=300): + LOG.info("Waiting for related test servers state change to READY...") + # Wait on state change + _start_time = time.time() + while time.time() - _start_time < timeout: + ts_ids_not_ready = {x['id'] for x in + self.get_test_servers(test_servers_ids) + if x['state'] != 'READY'} + if ts_ids_not_ready == set(): + break + time.sleep(delay) + else: + raise RuntimeError( + 'Test servers not in READY state after {} seconds.'.format( + timeout)) + + def create_test_servers(self, test_servers): + """ Create test servers + + :param test_servers: input data for test servers creation + mandatory fields: managementIp + optional fields: name + :type test_servers: list(dict) + """ + _ts_ids = [] + for _ts in test_servers: + _msg = 'Created test server "%(name)s"' + _ts_ids.append(self._tcl.create_test_server(_ts)) + if _ts.get('thread_model'): + _msg += ' in mode: "%(thread_model)s"' + LOG.info(_msg, _ts) + + self._check_test_servers_state(_ts_ids) + + def get_test_servers(self, test_server_ids=None): + if not test_server_ids: # Get all test servers info + _test_servers = self.exec_rest_request( + 'get', self.test_serv_uri).json()[self.test_serv_uri] + LOG.info("Current test servers configuration: %s", _test_servers) + return _test_servers + + _test_servers = [] + for _id in test_server_ids: + _test_servers.append(self.exec_rest_request( + 'get', '{}/{}'.format(self.test_serv_uri, _id)).json()) + LOG.info("Current test servers configuration: %s", _test_servers) + return _test_servers + + def configure_test_servers(self, action, json_data=None, + test_server_ids=None): + if not test_server_ids: + test_server_ids = [x['id'] for x in self.get_test_servers()] + elif isinstance(test_server_ids, int): + test_server_ids = [test_server_ids] + for _id in test_server_ids: + self.exec_rest_request('post', + '{}/{}'.format(self.test_serv_uri, _id), + action=action, json_data=json_data) + LOG.info("Test server (id: %s) configuration done: %s", _id, + action) + return test_server_ids + + def delete_test_servers(self, test_servers_ids=None): + # Delete test servers + for _ts in self.get_test_servers(test_servers_ids): + self.exec_rest_request('delete', '{}/{}'.format(self.test_serv_uri, + _ts['id'])) + LOG.info("Deleted test server: %s", _ts['name']) + + def create_test_session(self, test_session): + # Use tcl client to create session + test_session['library'] = self._user_id + LOG.debug("Creating session='%s'", test_session['name']) + self._tcl.create_test_session(test_session) + + def get_test_session(self, test_session_name=None): + if test_session_name: + uri = 'libraries/{}/{}/{}'.format(self._user_id, + self.test_session_uri, + test_session_name) + else: + uri = self.user_lib_uri.format(self._user_id) + _test_sessions = self.exec_rest_request('get', uri).json() + return _test_sessions + + def configure_test_session(self, template_name, test_session): + # Override specified test session parameters + LOG.info('Update test session parameters: %s', test_session['name']) + test_session.update({'library': self._user_id}) + return self.exec_rest_request( + method='post', + action={'action': 'overrideAndSaveAs'}, + json_data=test_session, + resource='{}/{}'.format(self.user_lib_uri.format(self._user_id), + template_name)) + + def delete_test_session(self, test_session): + return self.exec_rest_request('delete', '{}/{}'.format( + self.user_lib_uri.format(self._user_id), test_session)) + + def create_running_tests(self, test_session_name): + r = self.exec_rest_request('post', + self.running_tests_uri, + json_data={'library': self._user_id, + 'name': test_session_name}) + if r.status_code != self.REST_STATUS_CODES['CREATED']: + raise exceptions.RestApiError('Failed to start test session.') + self.run_id = r.json()['id'] + + def get_running_tests(self, running_test_id=None): + """Get JSON structure of specified running test entity + + :param running_test_id: ID of created running test entity + :type running_test_id: int + :returns list: running tests entity + """ + if not running_test_id: + running_test_id = '' + _res_name = '{}/{}'.format(self.running_tests_uri, running_test_id) + _res = self.exec_rest_request('get', _res_name, logs=False).json() + # If no run_id specified, skip top level key in response dict. + # Else return JSON as list + return _res.get('runningTests', [_res]) + + def delete_running_tests(self, running_test_id=None): + if not running_test_id: + running_test_id = '' + _res_name = '{}/{}'.format(self.running_tests_uri, running_test_id) + self.get_response_params('delete', _res_name) + LOG.info("Deleted running test with id: %s", running_test_id) + + def _running_tests_action(self, running_test_id, action, json_data=None): + if not json_data: + json_data = {} + # Supported actions: + # 'stop', 'abort', 'continue', 'update', 'sendTcCommand', 'sendOdc' + _res_name = '{}/{}'.format(self.running_tests_uri, running_test_id) + self.exec_rest_request('post', _res_name, {'action': action}, + json_data) + LOG.debug("Executed action: '%s' on running test id: %s", action, + running_test_id) + + def stop_running_tests(self, running_test_id, json_data=None, force=False): + _action = 'abort' if force else 'stop' + self._running_tests_action(running_test_id, _action, + json_data=json_data) + LOG.info('Performed action: "%s" to test run with id: %s', _action, + running_test_id) + + def check_running_test_state(self, run_id): + r = self.exec_rest_request('get', + '{}/{}'.format(self.running_tests_uri, + run_id)) + return r.json().get("testStateOrStep") + + def get_running_tests_results(self, run_id): + _res = self.exec_rest_request( + 'get', + '{}/{}/{}'.format(self.running_tests_uri, + run_id, + 'measurements')).json() + return _res + + def _write_results(self, results): + # Avoid None value at test session start + _elapsed_time = results['elapsedTime'] if results['elapsedTime'] else 0 + + _res_tabs = results.get('tabs') + # Avoid parsing 'tab' dict key initially (missing or empty) + if not _res_tabs: + return + + # Flatten nested dict holding Landslide KPIs of current test run + flat_kpis_dict = {} + for _tab, _kpis in six.iteritems(_res_tabs): + for _kpi, _value in six.iteritems(_kpis): + # Combine table name and KPI name using delimiter "::" + _key = '::'.join([_tab, _kpi]) + try: + # Cast value from str to float + # Remove comma and/or measure units, e.g. "us" + flat_kpis_dict[_key] = float( + _value.split(' ')[0].replace(',', '')) + except ValueError: # E.g. if KPI represents datetime + pass + LOG.info("Polling test results of test run id: %s. Elapsed time: %s " + "seconds", self.run_id, _elapsed_time) + return flat_kpis_dict def collect_kpi(self): - raise NotImplementedError() + if 'COMPLETE' in self.check_running_test_state(self.run_id): + self._result.update({'done': True}) + return self._result + _res = self.get_running_tests_results(self.run_id) + _kpis = self._write_results(_res) + if _kpis: + _kpis.update({'run_id': int(self.run_id)}) + _kpis.update({'iteration': _res['iteration']}) + self._result.update(_kpis) + return self._result class LandslideTclClient(object): @@ -470,10 +975,11 @@ class LandslideTclClient(object): if res == 'Invalid': res = self._tcl.execute('ls::get $test_ -ErrorsAndWarnings') raise exceptions.LandslideTclException( - "_save_test_session: {}".format(res)) + "Test session validation failed. Server response: {}".format( + res)) else: - res = self._tcl.execute('ls::save $test_ -overwrite') - LOG.debug("_save_test_session: result (%s)", res) + self._tcl.execute('ls::save $test_ -overwrite') + LOG.debug("Test session saved successfully.") def _get_library_id(self, library): _library_id = self._tcl.execute( diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py index 178ec5dab..9f0e69b60 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py @@ -13,7 +13,10 @@ # limitations under the License. # +import copy import mock +import requests +import time import unittest from yardstick.common import exceptions @@ -167,7 +170,7 @@ SESSION_PROFILE = { 'iterations': 1, 'description': 'UE default bearer creation test case', 'name': 'default_bearer_capacity', - 'reportOptions': {'Format': '1'}, + 'reportOptions': {'format': 'CSV'}, "reservePorts": "true", "reservations": [ {"tsId": 4, @@ -181,7 +184,7 @@ SESSION_PROFILE = { ]}, {"tsId": 2, "tsIndex": 1, - "tsName": "TestServer_2", + "tsName": TEST_SERVERS[1]['name'], "phySubnets": [ {"base": "10.42.32.1", "mask": "/24", "name": "eth5", "numIps": 100}, @@ -320,8 +323,85 @@ SESSION_PROFILE = { class TestLandslideResourceHelper(unittest.TestCase): - TEST_TERMINATED = 1 + PROTO_PORT = 8080 + EXAMPLE_URL = ''.join([TAS_INFO['proto'], '://', TAS_INFO['ip'], ':', + str(PROTO_PORT), '/api/']) + SUCCESS_CREATED_CODE = 201 + SUCCESS_OK_CODE = 200 + INVALID_REST_CODE = '400' + NOT_MODIFIED_CODE = 500810 + ERROR_CODE = 500800 SUCCESS_RECORD_ID = 11 + EXPIRE_DATE = '2020/01/01 12:00 FLE Standard Time' + TEST_USER = 'test' + TEST_TERMINATED = 1 + AUTH_DATA = {'user': TAS_INFO['user'], 'password': TAS_INFO['password']} + TEST_SESSION_NAME = 'default_bearer_capacity' + + USERS_DATA = { + "users": [{ + "url": ''.join([EXAMPLE_URL, 'users/', str(SUCCESS_RECORD_ID)]), + "id": SUCCESS_RECORD_ID, + "level": 1, + "username": TEST_USER + }] + } + + CREATE_USER_DATA = {'username': TAS_INFO['user'], + 'expiresOn': EXPIRE_DATE, + 'level': 1, + 'contactInformation': '', + 'fullName': 'Test User', + 'password': TAS_INFO['password'], + 'isActive': 'true'} + + SUTS_DATA = { + "suts": [ + { + "url": ''.join([EXAMPLE_URL, 'suts/', str(SUCCESS_RECORD_ID)]), + "id": SUCCESS_RECORD_ID, + "name": "10.41.32.1" + }]} + + TEST_SERVERS_DATA = { + "testServers": [ + { + "url": ''.join([EXAMPLE_URL, "testServers/1"]), + "id": 1, + "name": TEST_SERVERS[0]['name'], + "state": "READY", + "version": "16.4.0.10" + }, + { + "url": ''.join([EXAMPLE_URL, "testServers/2"]), + "id": 2, + "name": TEST_SERVERS[1]['name'], + "state": "READY", + "version": "16.4.0.10" + } + + ] + } + + RUN_ID = 3 + + RUNNING_TESTS_DATA = { + "runningTests": [{ + "url": ''.join([EXAMPLE_URL, "runningTests/{}".format(RUN_ID)]), + "measurementsUrl": ''.join( + [EXAMPLE_URL, + "runningTests/{}/measurements".format(RUN_ID)]), + "criteriaUrl": ''.join( + [EXAMPLE_URL, + "runningTests/{}/criteria".format(RUN_ID)]), + "noteToUser": "", + "id": RUN_ID, + "library": SUCCESS_RECORD_ID, + "name": "default_bearer_capacity", + "user": TEST_USER, + "criteriaStatus": "NA", + "testStateOrStep": "COMPLETE" + }]} TEST_RESULTS_DATA = { "interval": 0, @@ -331,12 +411,11 @@ class TestLandslideResourceHelper(unittest.TestCase): "tabs": { "Test Summary": { "Start Time": "Tue Mar 20 07:11:55 CDT 2018", - "Attempted Dedicated Bearer Session Connects": "0", - "Attempted Dedicated Bearer Session Disconnects": "0", - "Actual Dedicated Bearer Session Connects": "0", - "Actual Dedicated Bearer Session Disconnects": "0", - "Dedicated Bearer Sessions Pending": "0", - "Dedicated Bearer Sessions Established": "0" + "Actual Dedicated Bearer Session Connects": "100", + "Actual Dedicated Bearer Session Disconnects": "100", + "Actual Disconnect Rate(Sessions / Second)(P - I)": "164.804", + "Average Session Disconnect Time(P - I)": "5.024 s", + "Total Data Sent + Received Packets / Sec(P - I)": "1,452.294" }}} def setUp(self): @@ -357,12 +436,590 @@ class TestLandslideResourceHelper(unittest.TestCase): self.assertIsInstance(self.res_helper, tg_landslide.LandslideResourceHelper) self.assertEqual({}, self.res_helper._result) + self.assertIsNone(self.res_helper.run_id) + + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'stop_running_tests') + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'get_running_tests') + def test_abort_running_tests_no_running_tests(self, mock_get_tests, + mock_stop_tests, *args): + tests_data = [{'id': self.SUCCESS_RECORD_ID, + 'testStateOrStep': 'COMPLETE'}] + mock_get_tests.return_value = tests_data + self.assertIsNone(self.res_helper.abort_running_tests()) + mock_stop_tests.assert_not_called() + + @mock.patch.object(time, 'sleep') + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'stop_running_tests') + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'get_running_tests') + def test_abort_running_tests(self, mock_get_tests, mock_stop_tests, *args): + test_states_seq = iter(['RUNNING', 'COMPLETE']) + + def configure_mock(*args): + return [{'id': self.SUCCESS_RECORD_ID, + 'testStateOrStep': next(test_states_seq)}] + + mock_get_tests.side_effect = configure_mock + self.assertIsNone(self.res_helper.abort_running_tests()) + mock_stop_tests.assert_called_once_with( + running_test_id=self.SUCCESS_RECORD_ID, + force=True) + self.assertEqual(2, mock_get_tests.call_count) + + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'stop_running_tests') + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'get_running_tests') + def test_abort_running_tests_error(self, mock_get_tests, mock_stop_tests, + *args): + tests_data = {'id': self.SUCCESS_RECORD_ID, + 'testStateOrStep': 'RUNNING'} + mock_get_tests.return_value = [tests_data] + with self.assertRaises(RuntimeError): + self.res_helper.abort_running_tests(timeout=1, delay=1) + mock_stop_tests.assert_called_with( + running_test_id=self.SUCCESS_RECORD_ID, + force=True) + + def test__build_url(self, *args): + resource = 'users' + action = {'action': 'userCreate'} + expected_url = ''.join([EXAMPLE_URL, 'users?action=userCreate']) + self.assertEqual(expected_url, + self.res_helper._build_url(resource, action)) + + def test__build_url_error(self, *args): + resource = '' + action = {'action': 'userCreate'} + + with self.assertRaises(ValueError): + self.res_helper._build_url(resource, action) + + def test_get_response_params(self, *args): + method = 'get' + resource = 'users' + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.USERS_DATA} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + resp = self.res_helper.get_response_params(method, resource) + self.assertTrue(resp) + + @mock.patch.object(tg_landslide.LandslideResourceHelper, '_get_users') + @mock.patch.object(time, 'time') + def test__create_user(self, mock_time, mock_get_users, *args): + mock_time.strftime.return_value = self.EXPIRE_DATE + post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE, + 'json.return_value': {'id': self.SUCCESS_RECORD_ID}} + mock_session = mock.Mock(spec=requests.Session) + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + self.assertEqual(self.SUCCESS_RECORD_ID, + self.res_helper._create_user(self.AUTH_DATA)) + mock_get_users.assert_not_called() + + @mock.patch.object(tg_landslide.LandslideResourceHelper, '_modify_user') + @mock.patch.object(time, 'time') + def test__create_user_username_exists(self, mock_time, mock_modify_user, + *args): + mock_time.strftime.return_value = self.EXPIRE_DATE + mock_modify_user.return_value = {'id': self.SUCCESS_RECORD_ID, + 'result': 'No changes requested'} + post_resp_data = { + 'status_code': self.ERROR_CODE, + 'json.return_value': {'id': self.SUCCESS_OK_CODE, + 'apiCode': self.NOT_MODIFIED_CODE}} + mock_session = mock.Mock(spec=requests.Session) + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + res = self.res_helper._create_user(self.AUTH_DATA) + mock_modify_user.assert_called_once_with(TAS_INFO['user'], + {'isActive': 'true'}) + self.assertEqual(self.SUCCESS_RECORD_ID, res) + + @mock.patch.object(time, 'time') + def test__create_user_error(self, mock_time, *args): + mock_time.strftime.return_value = self.EXPIRE_DATE + mock_session = mock.Mock(spec=requests.Session) + post_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': {'apiCode': self.ERROR_CODE}} + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + with self.assertRaises(exceptions.RestApiError): + self.res_helper._create_user(self.AUTH_DATA) + + def test__modify_user(self, *args): + post_data = {'username': 'test_user'} + mock_session = mock.Mock(spec=requests.Session) + post_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': {'id': self.SUCCESS_RECORD_ID}} + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + res = self.res_helper._modify_user(username=self.TEST_USER, + fields=post_data) + self.assertEqual(self.SUCCESS_RECORD_ID, res['id']) + + def test__modify_user_rest_resp_fail(self, *args): + post_data = {'non-existing-key': ''} + mock_session = mock.Mock(spec=requests.Session) + mock_session.post.ok = False + self.res_helper.session = mock_session + self.assertRaises(exceptions.RestApiError, + self.res_helper._modify_user, + username=self.TEST_USER, fields=post_data) + mock_session.post.assert_called_once() + + def test__delete_user(self, *args): + mock_session = mock.Mock(spec=requests.Session) + self.res_helper.session = mock_session + self.assertIsNone(self.res_helper._delete_user( + username=self.TEST_USER)) + + def test__get_users(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.USERS_DATA} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + self.assertEqual(self.USERS_DATA['users'], + self.res_helper._get_users()) + + def test_exec_rest_request(self, *args): + resource = 'testServers' + action = {'action': 'modify'} + expected_url = ''.join([EXAMPLE_URL, 'testServers?action=modify']) + post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE, + 'json.return_value': {'id': self.SUCCESS_RECORD_ID}} + mock_session = mock.Mock(spec=requests.Session) + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + self.res_helper.exec_rest_request('post', resource, action) + self.res_helper.session.post.assert_called_once_with(expected_url, + json={}) + + def test_exec_rest_request_unsupported_method_error(self, *args): + resource = 'testServers' + action = {'action': 'modify'} + with self.assertRaises(ValueError): + self.res_helper.exec_rest_request('patch', resource, action) + + def test_exec_rest_request_missed_action_arg(self, *args): + resource = 'testServers' + with self.assertRaises(ValueError): + self.res_helper.exec_rest_request('post', resource) + + def test_exec_rest_request_raise_exc(self): + resource = 'users' + action = {'action': 'modify'} + post_resp_data = {'status_code': self.ERROR_CODE, + 'json.return_value': { + 'status_code': self.ERROR_CODE}} + mock_session = mock.Mock(spec=requests.Session) + mock_session.post.return_value.configure_mock(**post_resp_data) + self.assertRaises(exceptions.RestApiError, + self.res_helper.exec_rest_request, + 'post', resource, action, raise_exc=True) + + @mock.patch.object(time, 'time') + def test_connect(self, mock_time, *args): + vnfd = VNFD['vnfd:vnfd-catalog']['vnfd'][0] + mock_time.strftime.return_value = self.EXPIRE_DATE + self.res_helper.vnfd_helper = vnfd + + self.res_helper._tcl = mock.Mock() + post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE, + 'json.return_value': {'id': self.SUCCESS_RECORD_ID}} + mock_session = mock.Mock(spec=requests.Session, headers={}) + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + self.assertIsInstance(self.res_helper.connect(), requests.Session) + self.res_helper._tcl.connect.assert_called_once_with( + TAS_INFO['ip'], + TAS_INFO['user'], + TAS_INFO['password']) + + def test_disconnect(self, *args): + self.res_helper._tcl = mock.Mock() + self.assertIsNone(self.res_helper.disconnect()) + self.assertIsNone(self.res_helper.session) + self.res_helper._tcl.disconnect.assert_called_once() + + def test_terminate(self, *args): + self.assertIsNone(self.res_helper.terminate()) + self.assertEqual(self.TEST_TERMINATED, + self.res_helper._terminated.value) + + def test_create_dmf(self, *args): + self.res_helper._tcl = mock.Mock() + self.assertIsNone(self.res_helper.create_dmf(DMF_CFG)) + self.res_helper._tcl.create_dmf.assert_called_once_with(DMF_CFG) + + def test_create_dmf_as_list(self, *args): + self.res_helper._tcl = mock.Mock() + self.assertIsNone(self.res_helper.create_dmf([DMF_CFG])) + self.res_helper._tcl.create_dmf.assert_called_once_with(DMF_CFG) + + def test_delete_dmf(self, *args): + self.res_helper._tcl = mock.Mock() + self.assertIsNone(self.res_helper.delete_dmf(DMF_CFG)) + self.res_helper._tcl.delete_dmf.assert_called_once_with(DMF_CFG) + + def test_delete_dmf_as_list(self, *args): + self.res_helper._tcl = mock.Mock() + self.assertIsNone(self.res_helper.delete_dmf([DMF_CFG])) + self.res_helper._tcl.delete_dmf.assert_called_once_with(DMF_CFG) + + @mock.patch.object(tg_landslide.LandslideResourceHelper, 'configure_sut') + def test_create_suts(self, mock_configure_sut, *args): + mock_session = mock.Mock(spec=requests.Session) + post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE} + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + self.assertIsNone(self.res_helper.create_suts(TS1_SUTS)) + mock_configure_sut.assert_not_called() + + @mock.patch.object(tg_landslide.LandslideResourceHelper, 'configure_sut') + def test_create_suts_sut_exists(self, mock_configure_sut, *args): + sut_name = 'test_sut' + suts = [ + {'name': sut_name, + 'role': 'SgwControlAddr', + 'managementIp': '12.0.1.1', + 'ip': '10.42.32.100' + } + ] + mock_session = mock.Mock(spec=requests.Session) + post_resp_data = {'status_code': self.NOT_MODIFIED_CODE} + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + self.assertIsNone(self.res_helper.create_suts(suts)) + mock_configure_sut.assert_called_once_with( + sut_name=sut_name, + json_data={k: v for k, v in suts[0].items() + if k not in {'phy', 'nextHop', 'role', 'name'}}) + + def test_get_suts(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.SUTS_DATA} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + self.assertIsInstance(self.res_helper.get_suts(), list) + + def test_get_suts_single_id(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.SUTS_DATA['suts'][0]} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + self.assertIsInstance(self.res_helper.get_suts(suts_id=2), dict) + + def test_configure_sut(self, *args): + post_data = {'managementIp': '2.2.2.2'} + mock_session = mock.Mock(spec=requests.Session) + post_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': {'id': self.SUCCESS_RECORD_ID}} + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + self.assertIsNone(self.res_helper.configure_sut('test_name', + post_data)) + mock_session.post.assert_called_once() + + def test_configure_sut_error(self, *args): + post_data = {'managementIp': '2.2.2.2'} + mock_session = mock.Mock(spec=requests.Session) + post_resp_data = {'status_code': self.NOT_MODIFIED_CODE} + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + with self.assertRaises(exceptions.RestApiError): + self.res_helper.configure_sut('test_name', post_data) + + def test_delete_suts(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.SUTS_DATA} + delete_resp_data = {'status_code': self.SUCCESS_OK_CODE} + mock_session.get.return_value.configure_mock(**get_resp_data) + mock_session.delete.return_value.configure_mock(**delete_resp_data) + self.res_helper.session = mock_session + self.assertIsNone(self.res_helper.delete_suts()) + mock_session.delete.assert_called_once() + + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'get_test_servers') + def test__check_test_servers_state(self, mock_get_test_servers, *args): + mock_get_test_servers.return_value = \ + self.TEST_SERVERS_DATA['testServers'] + self.res_helper._check_test_servers_state() + mock_get_test_servers.assert_called_once() + + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'get_test_servers') + def test__check_test_servers_state_server_not_ready( + self, mock_get_test_servers, *args): + test_servers_not_ready = [ + { + "url": ''.join([EXAMPLE_URL, "testServers/1"]), + "id": 1, + "name": "TestServer_1", + "state": "NOT_READY", + "version": "16.4.0.10" + } + ] + + mock_get_test_servers.return_value = test_servers_not_ready + with self.assertRaises(RuntimeError): + self.res_helper._check_test_servers_state(timeout=1, delay=0) + + @mock.patch.object(tg_landslide.LandslideResourceHelper, + '_check_test_servers_state') + def test_create_test_servers(self, mock_check_ts_state, *args): + test_servers_ids = [ + ts['id'] for ts in self.TEST_SERVERS_DATA['testServers']] + + self.res_helper.license_data['lic_id'] = TAS_INFO['license'] + self.res_helper._tcl.create_test_server = mock.Mock() + self.res_helper._tcl.create_test_server.side_effect = test_servers_ids + self.assertIsNone(self.res_helper.create_test_servers(TEST_SERVERS)) + mock_check_ts_state.assert_called_once_with(test_servers_ids) + + @mock.patch.object(tg_landslide.LandslideTclClient, + 'resolve_test_server_name') + @mock.patch.object(tg_landslide.LsTclHandler, 'execute') + def test_create_test_servers_error(self, mock_execute, + mock_resolve_ts_name, *args): + self.res_helper.license_data['lic_id'] = TAS_INFO['license'] + # Return message for case test server wasn't created + mock_execute.return_value = 'TS not found' + # Return message for case test server name wasn't resolved + mock_resolve_ts_name.return_value = 'TS not found' + with self.assertRaises(RuntimeError): + self.res_helper.create_test_servers(TEST_SERVERS) + + def test_get_test_servers(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.TEST_SERVERS_DATA} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + res = self.res_helper.get_test_servers() + self.assertEqual(self.TEST_SERVERS_DATA['testServers'], res) + + def test_get_test_servers_by_id(self, *args): + mock_session = mock.Mock(spec=requests.Session) + + _ts = self.TEST_SERVERS_DATA['testServers'][0] + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': _ts} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + res = self.res_helper.get_test_servers(test_server_ids=[_ts['id']]) + self.assertEqual([_ts], res) + + def test_configure_test_servers(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.TEST_SERVERS_DATA} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + res = self.res_helper.configure_test_servers( + action={'action': 'recycle'}) + self.assertEqual( + {x['id'] for x in self.TEST_SERVERS_DATA['testServers']}, + set(res)) + self.assertEqual(len(self.TEST_SERVERS_DATA['testServers']), + mock_session.post.call_count) + + def test_delete_test_servers(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.TEST_SERVERS_DATA} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + self.assertIsNone(self.res_helper.delete_test_servers()) + self.assertEqual(len(self.TEST_SERVERS_DATA['testServers']), + mock_session.delete.call_count) - def test_terminate(self): - self.assertRaises(NotImplementedError, self.res_helper.terminate) + def test_create_test_session(self, *args): + self.res_helper._user_id = self.SUCCESS_RECORD_ID + self.res_helper._tcl = mock.Mock() + test_session = {'name': 'test'} + self.assertIsNone(self.res_helper.create_test_session(test_session)) + self.res_helper._tcl.create_test_session.assert_called_once_with( + {'name': 'test', 'library': self.SUCCESS_RECORD_ID}) + + @mock.patch.object(tg_landslide.LandslideTclClient, + 'resolve_test_server_name', + return_value='Not Found') + def test_create_test_session_ts_name_not_found(self, *args): + self.res_helper._user_id = self.SUCCESS_RECORD_ID + test_session = { + 'duration': 60, + 'description': 'UE default bearer creation test case', + 'name': 'default_bearer_capacity', + 'tsGroups': [{'testCases': [{'type': 'SGW_Node', + 'name': ''}], + 'tsId': 'TestServer_3'}] + } + with self.assertRaises(RuntimeError): + self.res_helper.create_test_session(test_session) + + def test_get_test_session(self, *args): + test_session = {"name": self.TEST_SESSION_NAME} + self.res_helper._user_id = self.SUCCESS_RECORD_ID + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': test_session} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + res = self.res_helper.get_test_session(self.TEST_SESSION_NAME) + self.assertEqual(test_session, res) + + def test_configure_test_session(self, *args): + test_session = {'name': self.TEST_SESSION_NAME} + self.res_helper._user_id = self.SUCCESS_RECORD_ID + self.res_helper.user_lib_uri = 'libraries/{{}}/{}'.format( + self.res_helper.test_session_uri) + mock_session = mock.Mock(spec=requests.Session) + self.res_helper.session = mock_session + res = self.res_helper.configure_test_session(self.TEST_SESSION_NAME, + test_session) + self.assertIsNotNone(res) + mock_session.post.assert_called_once() + + def test_delete_test_session(self, *args): + self.res_helper._user_id = self.SUCCESS_RECORD_ID + self.res_helper.user_lib_uri = 'libraries/{{}}/{}'.format( + self.res_helper.test_session_uri) + mock_session = mock.Mock(spec=requests.Session) + self.res_helper.session = mock_session + res = self.res_helper.delete_test_session(self.TEST_SESSION_NAME) + self.assertIsNotNone(res) + mock_session.delete.assert_called_once() + + def test_create_running_tests(self, *args): + self.res_helper._user_id = self.SUCCESS_RECORD_ID + test_session = {'id': self.SUCCESS_RECORD_ID} + mock_session = mock.Mock(spec=requests.Session) + post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE, + 'json.return_value': test_session} + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + self.res_helper.create_running_tests(self.TEST_SESSION_NAME) + self.assertEqual(self.SUCCESS_RECORD_ID, self.res_helper.run_id) + + def test_create_running_tests_error(self, *args): + self.res_helper._user_id = self.SUCCESS_RECORD_ID + mock_session = mock.Mock(spec=requests.Session) + post_resp_data = {'status_code': self.NOT_MODIFIED_CODE} + mock_session.post.return_value.configure_mock(**post_resp_data) + self.res_helper.session = mock_session + with self.assertRaises(exceptions.RestApiError): + self.res_helper.create_running_tests(self.TEST_SESSION_NAME) + + def test_get_running_tests(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.RUNNING_TESTS_DATA} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + res = self.res_helper.get_running_tests() + self.assertEqual(self.RUNNING_TESTS_DATA['runningTests'], res) + + def test_delete_running_tests(self, *args): + mock_session = mock.Mock(spec=requests.Session) + delete_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.RUNNING_TESTS_DATA} + mock_session.delete.return_value.configure_mock(**delete_resp_data) + self.res_helper.session = mock_session + self.assertIsNone(self.res_helper.delete_running_tests()) + + def test__running_tests_action(self, *args): + action = 'abort' + mock_session = mock.Mock(spec=requests.Session) + self.res_helper.session = mock_session + res = self.res_helper._running_tests_action(self.SUCCESS_RECORD_ID, + action) + self.assertIsNone(res) - def test_collect_kpi_test_running(self): - self.assertRaises(NotImplementedError, self.res_helper.collect_kpi) + @mock.patch.object(tg_landslide.LandslideResourceHelper, + '_running_tests_action') + def test_stop_running_tests(self, mock_tests_action, *args): + res = self.res_helper.stop_running_tests(self.SUCCESS_RECORD_ID) + self.assertIsNone(res) + mock_tests_action.assert_called_once() + + def test_check_running_test_state(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = { + 'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.RUNNING_TESTS_DATA["runningTests"][0]} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + res = self.res_helper.check_running_test_state(self.SUCCESS_RECORD_ID) + self.assertEqual( + self.RUNNING_TESTS_DATA["runningTests"][0]['testStateOrStep'], + res) + + def test_get_running_tests_results(self, *args): + mock_session = mock.Mock(spec=requests.Session) + get_resp_data = {'status_code': self.SUCCESS_OK_CODE, + 'json.return_value': self.TEST_RESULTS_DATA} + mock_session.get.return_value.configure_mock(**get_resp_data) + self.res_helper.session = mock_session + res = self.res_helper.get_running_tests_results( + self.SUCCESS_RECORD_ID) + self.assertEqual(self.TEST_RESULTS_DATA, res) + + def test__write_results(self, *args): + self.maxDiff = None + res = self.res_helper._write_results(self.TEST_RESULTS_DATA) + exp_res = { + "Test Summary::Actual Dedicated Bearer Session Connects": 100.0, + "Test Summary::Actual Dedicated Bearer Session Disconnects": 100.0, + "Test Summary::Actual Disconnect Rate(Sessions / Second)(P - I)": 164.804, + "Test Summary::Average Session Disconnect Time(P - I)": 5.024, + "Test Summary::Total Data Sent + Received Packets / Sec(P - I)": 1452.294 + } + self.assertEqual(exp_res, res) + + def test__write_results_no_tabs(self, *args): + _res_data = copy.deepcopy(self.TEST_RESULTS_DATA) + del _res_data['tabs'] + # Return None if tabs not found in test results dict + self.assertIsNone(self.res_helper._write_results(_res_data)) + + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'check_running_test_state') + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'get_running_tests_results') + def test_collect_kpi_test_running(self, mock_tests_results, + mock_tests_state, *args): + self.res_helper.run_id = self.SUCCESS_RECORD_ID + mock_tests_state.return_value = 'RUNNING' + mock_tests_results.return_value = self.TEST_RESULTS_DATA + res = self.res_helper.collect_kpi() + self.assertNotIn('done', res) + mock_tests_state.assert_called_once_with(self.res_helper.run_id) + mock_tests_results.assert_called_once_with(self.res_helper.run_id) + + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'check_running_test_state') + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'get_running_tests_results') + def test_collect_kpi_test_completed(self, mock_tests_results, + mock_tests_state, *args): + self.res_helper.run_id = self.SUCCESS_RECORD_ID + mock_tests_state.return_value = 'COMPLETE' + res = self.res_helper.collect_kpi() + self.assertIsNotNone(res) + mock_tests_state.assert_called_once_with(self.res_helper.run_id) + mock_tests_results.assert_not_called() + self.assertDictContainsSubset({'done': True}, res) class TestLandslideTclClient(unittest.TestCase): @@ -416,7 +1073,7 @@ class TestLandslideTclClient(unittest.TestCase): def test_disconnect(self, *args): self.ls_tcl_client.disconnect() - self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_called_once() self.assertIsNone(self.ls_tcl_client.tcl_server_ip) self.assertIsNone(self.ls_tcl_client._user) self.assertIsNone(self.ls_tcl_client._library_id) @@ -508,9 +1165,10 @@ class TestLandslideTclClient(unittest.TestCase): @mock.patch.object(tg_landslide.LandslideTclClient, 'resolve_test_server_name', return_value='2') def test_create_test_session(self, *args): + _session_profile = copy.deepcopy(SESSION_PROFILE) self.ls_tcl_client._save_test_session = mock.Mock() self.ls_tcl_client._configure_ts_group = mock.Mock() - self.ls_tcl_client.create_test_session(SESSION_PROFILE) + self.ls_tcl_client.create_test_session(_session_profile) self.assertEqual(20, self.mock_tcl_handler.execute.call_count) def test_create_dmf(self): @@ -546,37 +1204,46 @@ class TestLandslideTclClient(unittest.TestCase): self.mock_tcl_handler.execute.call_count) def test__configure_report_options(self): - _options = {'format': 'CSV', 'PerInterval': False} + _options = {'format': 'CSV', 'PerInterval': 'false'} self.ls_tcl_client._configure_report_options(_options) self.assertEqual(2, self.mock_tcl_handler.execute.call_count) def test___configure_ts_group(self, *args): + _ts_group = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]) self.ls_tcl_client._configure_tc_type = mock.Mock() self.ls_tcl_client._configure_preresolved_arp = mock.Mock() self.ls_tcl_client.resolve_test_server_name = mock.Mock( return_value='2') - self.ls_tcl_client._configure_ts_group( - SESSION_PROFILE['tsGroups'][0], 0) - self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + self.ls_tcl_client._configure_ts_group(_ts_group, 0) + self.mock_tcl_handler.execute.assert_called_once() def test___configure_ts_group_resolve_ts_fail(self, *args): + _ts_group = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]) self.ls_tcl_client._configure_tc_type = mock.Mock() self.ls_tcl_client._configure_preresolved_arp = mock.Mock() self.ls_tcl_client.resolve_test_server_name = mock.Mock( return_value='TS Not Found') self.assertRaises(RuntimeError, self.ls_tcl_client._configure_ts_group, - SESSION_PROFILE['tsGroups'][0], 0) - self.assertEqual(0, self.mock_tcl_handler.execute.call_count) + _ts_group, 0) + self.mock_tcl_handler.execute.assert_not_called() def test__configure_tc_type(self): - _tc = SESSION_PROFILE['tsGroups'][0]['testCases'][0] + _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0]) self.mock_tcl_handler.execute.return_value = TCL_SUCCESS_RESPONSE self.ls_tcl_client._configure_parameters = mock.Mock() self.ls_tcl_client._configure_tc_type(_tc, 0) self.assertEqual(7, self.mock_tcl_handler.execute.call_count) + def test__configure_tc_type_optional_param_omitted(self): + _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0]) + del _tc['linked'] + self.mock_tcl_handler.execute.return_value = TCL_SUCCESS_RESPONSE + self.ls_tcl_client._configure_parameters = mock.Mock() + self.ls_tcl_client._configure_tc_type(_tc, 0) + self.assertEqual(6, self.mock_tcl_handler.execute.call_count) + def test__configure_tc_type_wrong_type(self): - _tc = SESSION_PROFILE['tsGroups'][0]['testCases'][0] + _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0]) _tc['type'] = 'not_supported' self.ls_tcl_client._configure_parameters = mock.Mock() self.assertRaises(RuntimeError, @@ -584,16 +1251,16 @@ class TestLandslideTclClient(unittest.TestCase): _tc, 0) def test__configure_tc_type_not_found_basic_lib(self): - _tc = SESSION_PROFILE['tsGroups'][0]['testCases'][0] + _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0]) self.ls_tcl_client._configure_parameters = mock.Mock() self.mock_tcl_handler.execute.return_value = 'Invalid' self.assertRaises(RuntimeError, self.ls_tcl_client._configure_tc_type, _tc, 0) - self.assertEqual(0, self.mock_tcl_handler.execute.call_count) def test__configure_parameters(self): - _params = SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters'] + _params = copy.deepcopy( + SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters']) self.ls_tcl_client._configure_parameters(_params) self.assertEqual(16, self.mock_tcl_handler.execute.call_count) @@ -604,15 +1271,16 @@ class TestLandslideTclClient(unittest.TestCase): self.assertEqual(2, self.mock_tcl_handler.execute.call_count) def test__configure_test_node_param(self): - _params = SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters'] + _params = copy.deepcopy( + SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters']) self.ls_tcl_client._configure_test_node_param('SgwUserAddr', _params['SgwUserAddr']) - self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_called_once() def test__configure_sut_param(self): _params = {'name': 'name'} self.ls_tcl_client._configure_sut_param('name', _params) - self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_called_once() def test__configure_dmf_param(self): _params = {"mainflows": [{"library": '111', @@ -645,7 +1313,7 @@ class TestLandslideTclClient(unittest.TestCase): self.assertIsNone(res) def test__configure_reservation(self): - _reservation = SESSION_PROFILE['reservations'][0] + _reservation = copy.deepcopy(SESSION_PROFILE['reservations'][0]) self.ls_tcl_client.resolve_test_server_name = mock.Mock( return_value='2') res = self.ls_tcl_client._configure_reservation(_reservation) @@ -656,7 +1324,7 @@ class TestLandslideTclClient(unittest.TestCase): _arp = [{'StartingAddress': '10.81.1.10', 'NumNodes': 1}] res = self.ls_tcl_client._configure_preresolved_arp(_arp) - self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_called_once() self.assertIsNone(res) def test__configure_preresolved_arp_none(self): @@ -681,9 +1349,9 @@ class TestLandslideTclClient(unittest.TestCase): self.assertEqual(2, self.mock_tcl_handler.execute.call_count) def test__get_library_id_system_lib(self): - self.mock_tcl_handler.execute.side_effect = ['111'] + self.mock_tcl_handler.execute.return_value = '111' res = self.ls_tcl_client._get_library_id('name') - self.assertEqual(1, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_called_once() self.assertEqual('111', res) def test__get_library_id_user_lib(self): -- cgit 1.2.3-korg From 4bcfaec22bd4c9ece155986ed2c0bd91262afd8e Mon Sep 17 00:00:00 2001 From: Emma Foley Date: Thu, 30 Aug 2018 13:54:57 +0100 Subject: Add Spirent Landslide TG API New TG class "LandslideTrafficGen" represents an interface to use Spirent Landslide API to configure and execute vEPC test cases on hardware/software Spirent environment. For that purpose this class and its helper classes use Spirent Landslide REST API calls and Landslide TCL API calls via library module lsapi.py. Change-Id: Ib6560d5cd2483c6c9f5c95568345ac39bfebbd4d Signed-off-by: Emma Foley Signed-off-by: Orest Voznyy --- .../vnf_generic/vnf/tg_landslide.py | 182 ++++++++- .../vnf_generic/vnf/test_tg_landslide.py | 405 +++++++++++++++++++-- 2 files changed, 547 insertions(+), 40 deletions(-) diff --git a/yardstick/network_services/vnf_generic/vnf/tg_landslide.py b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py index 0ccffeeb1..d4222c136 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_landslide.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py @@ -12,14 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. +import collections import logging import requests import six import time -from collections import Mapping from yardstick.common import exceptions from yardstick.common import utils as common_utils +from yardstick.common import yaml_loader from yardstick.network_services import utils as net_serv_utils from yardstick.network_services.vnf_generic.vnf import sample_vnf @@ -31,6 +32,181 @@ except ImportError: LOG = logging.getLogger(__name__) +class LandslideTrafficGen(sample_vnf.SampleVNFTrafficGen): + APP_NAME = 'LandslideTG' + + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): + if resource_helper_type is None: + resource_helper_type = LandslideResourceHelper + super(LandslideTrafficGen, self).__init__(name, vnfd, task_id, + setup_env_helper_type, + resource_helper_type) + + self.bin_path = net_serv_utils.get_nsb_option('bin_path') + self.name = name + self.runs_traffic = True + self.traffic_finished = False + self.session_profile = None + + def listen_traffic(self, traffic_profile): + pass + + def terminate(self): + self.resource_helper.disconnect() + + def instantiate(self, scenario_cfg, context_cfg): + super(LandslideTrafficGen, self).instantiate(scenario_cfg, context_cfg) + self.resource_helper.connect() + + # Create test servers + test_servers = [x['test_server'] for x in self.vnfd_helper['config']] + self.resource_helper.create_test_servers(test_servers) + + # Create SUTs + [self.resource_helper.create_suts(x['suts']) for x in + self.vnfd_helper['config']] + + # Fill in test session based on session profile and test case options + self._load_session_profile() + + def run_traffic(self, traffic_profile): + self.resource_helper.abort_running_tests() + # Update DMF profile with related test case options + traffic_profile.update_dmf(self.scenario_helper.all_options) + # Create DMF in test user library + self.resource_helper.create_dmf(traffic_profile.dmf_config) + # Create/update test session in test user library + self.resource_helper.create_test_session(self.session_profile) + # Start test session + self.resource_helper.create_running_tests(self.session_profile['name']) + + def collect_kpi(self): + return self.resource_helper.collect_kpi() + + def wait_for_instantiate(self): + pass + + @staticmethod + def _update_session_suts(suts, testcase): + """ Create SUT entry. Update related EPC block in session profile. """ + for sut in suts: + # Update session profile EPC element with SUT info from pod file + tc_role = testcase['parameters'].get(sut['role']) + if tc_role: + _param = {} + if tc_role['class'] == 'Sut': + _param['name'] = sut['name'] + elif tc_role['class'] == 'TestNode': + _param.update({x: sut[x] for x in {'ip', 'phy', 'nextHop'} + if x in sut and sut[x]}) + testcase['parameters'][sut['role']].update(_param) + else: + LOG.info('Unexpected SUT role in pod file: "%s".', sut['role']) + return testcase + + def _update_session_test_servers(self, test_server, _tsgroup_index): + """ Update tsId, reservations, pre-resolved ARP in session profile """ + # Update test server name + test_groups = self.session_profile['tsGroups'] + test_groups[_tsgroup_index]['tsId'] = test_server['name'] + + # Update preResolvedArpAddress + arp_key = 'preResolvedArpAddress' + _preresolved_arp = test_server.get(arp_key) # list of dicts + if _preresolved_arp: + test_groups[_tsgroup_index][arp_key] = _preresolved_arp + + # Update reservations + if 'phySubnets' in test_server: + reservation = {'tsId': test_server['name'], + 'tsIndex': _tsgroup_index, + 'tsName': test_server['name'], + 'phySubnets': test_server['phySubnets']} + if 'reservations' in self.session_profile: + self.session_profile['reservations'].append(reservation) + else: + self.session_profile['reservePorts'] = 'true' + self.session_profile['reservations'] = [reservation] + + @staticmethod + def _update_session_tc_params(tc_options, testcase): + for _param_key in tc_options: + if _param_key == 'AssociatedPhys': + testcase[_param_key] = tc_options[_param_key] + continue + testcase['parameters'][_param_key] = tc_options[_param_key] + return testcase + + def _load_session_profile(self): + + with common_utils.open_relative_file( + self.scenario_helper.scenario_cfg['session_profile'], + self.scenario_helper.task_path) as stream: + self.session_profile = yaml_loader.yaml_load(stream) + + # Raise exception if number of entries differs in following files, + _config_files = ['pod file', 'session_profile file', 'test_case file'] + # Count testcases number in all tsGroups of session profile + session_tests_num = [xx for x in self.session_profile['tsGroups'] + for xx in x['testCases']] + # Create a set containing number of list elements in each structure + _config_files_blocks_num = [ + len(x) for x in + (self.vnfd_helper['config'], # test_servers and suts info + session_tests_num, + self.scenario_helper.all_options['test_cases'])] # test case file + + if len(set(_config_files_blocks_num)) != 1: + raise RuntimeError('Unequal number of elements. {}'.format( + dict(six.moves.zip_longest(_config_files, + _config_files_blocks_num)))) + + ts_names = set() + _tsgroup_idx = -1 + _testcase_idx = 0 + + # Iterate over data structures to overwrite session profile defaults + # _config: single list element holding test servers and SUTs info + # _tc_options: single test case parameters + for _config, tc_options in zip( + self.vnfd_helper['config'], # test servers and SUTS + self.scenario_helper.all_options['test_cases']): # testcase + + _ts_config = _config['test_server'] + + # Calculate test group/test case indexes based on test server name + if _ts_config['name'] in ts_names: + _testcase_idx += 1 + else: + _tsgroup_idx += 1 + _testcase_idx = 0 + + _testcase = \ + self.session_profile['tsGroups'][_tsgroup_idx]['testCases'][ + _testcase_idx] + + if _testcase['type'] != _ts_config['role']: + raise RuntimeError( + 'Test type mismatch in TC#{} of test server {}'.format( + _testcase_idx, _ts_config['name'])) + + # Fill session profile with test servers parameters + if _ts_config['name'] not in ts_names: + self._update_session_test_servers(_ts_config, _tsgroup_idx) + ts_names.add(_ts_config['name']) + + # Fill session profile with suts parameters + self.session_profile['tsGroups'][_tsgroup_idx]['testCases'][ + _testcase_idx].update( + self._update_session_suts(_config['suts'], _testcase)) + + # Update test case parameters + self.session_profile['tsGroups'][_tsgroup_idx]['testCases'][ + _testcase_idx].update( + self._update_session_tc_params(tc_options, _testcase)) + + class LandslideResourceHelper(sample_vnf.ClientResourceHelper): """Landslide TG helper class""" @@ -228,7 +404,7 @@ class LandslideResourceHelper(sample_vnf.ClientResourceHelper): raise ValueError("Method '{}' not supported".format(_method)) if method == 'post' and not action: - if not (json_data and isinstance(json_data, Mapping)): + if not (json_data and isinstance(json_data, collections.Mapping)): raise ValueError( 'JSON data missing in {} request'.format(_method)) @@ -731,7 +907,7 @@ class LandslideTclClient(object): self._tcl.execute('ls::config $test_ -Iterations "{}"'.format( test_session['iterations'])) if 'reservePorts' in test_session: - if test_session['reservePorts']: + if test_session['reservePorts'] == 'true': self._tcl.execute('ls::config $test_ -Reserve Ports') if 'reservations' in test_session: diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py index 9f0e69b60..d47061c6e 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py @@ -11,17 +11,24 @@ # 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 requests import time import unittest +import uuid +from yardstick.benchmark.contexts import base as ctx_base from yardstick.common import exceptions +from yardstick.common import utils as common_utils +from yardstick.common import yaml_loader +from yardstick.network_services import utils as net_serv_utils +from yardstick.network_services.traffic_profile import landslide_profile +from yardstick.network_services.vnf_generic.vnf import sample_vnf from yardstick.network_services.vnf_generic.vnf import tg_landslide + NAME = "tg__0" EXAMPLE_URL = 'http://example.com/' @@ -164,6 +171,16 @@ DMF_CFG = { "serverPort": 2003 } +RESERVATIONS = [ + {'tsName': TEST_SERVERS[0]['name'], + 'phySubnets': TEST_SERVERS[0]['phySubnets'], + 'tsId': TEST_SERVERS[0]['name'], + 'tsIndex': 0}, + {'tsName': TEST_SERVERS[1]['name'], + 'phySubnets': TEST_SERVERS[1]['phySubnets'], + 'tsId': TEST_SERVERS[1]['name'], + 'tsIndex': 1}] + SESSION_PROFILE = { 'keywords': '', 'duration': 60, @@ -171,33 +188,13 @@ SESSION_PROFILE = { 'description': 'UE default bearer creation test case', 'name': 'default_bearer_capacity', 'reportOptions': {'format': 'CSV'}, - "reservePorts": "true", - "reservations": [ - {"tsId": 4, - "tsIndex": 0, - "tsName": TEST_SERVERS[0]['name'], - "phySubnets": [ - {"base": "10.42.32.100", "mask": "/24", "name": "eth5", - "numIps": 20}, - {"base": "10.42.33.100", "mask": "/24", "name": "eth6", - "numIps": 20} - ]}, - {"tsId": 2, - "tsIndex": 1, - "tsName": TEST_SERVERS[1]['name'], - "phySubnets": [ - {"base": "10.42.32.1", "mask": "/24", "name": "eth5", - "numIps": 100}, - {"base": "10.42.33.1", "mask": "/24", "name": "eth6", - "numIps": 100} - ]} - ], + 'reservePorts': 'false', 'tsGroups': [ { 'testCases': [{ 'type': 'SGW_Node', 'name': '', - 'linked': False, + 'linked': "false", 'AssociatedPhys': '', 'parameters': { 'SgiPtpTunnelEn': 'false', @@ -217,7 +214,7 @@ SESSION_PROFILE = { 'forcedEthInterface': '', 'ip': 'SGW_USER_IP', 'class': 'TestNode', - 'ethStatsEnabled': False, + 'ethStatsEnabled': "false", 'mtu': 1500 }, 'SgwControlAddr': { @@ -226,7 +223,7 @@ SESSION_PROFILE = { 'forcedEthInterface': '', 'ip': 'SGW_CONTROL_IP', 'class': 'TestNode', - 'ethStatsEnabled': False, + 'ethStatsEnabled': "false", 'mtu': 1500, 'nextHop': 'SGW_CONTROL_NEXT_HOP' }, @@ -254,7 +251,7 @@ SESSION_PROFILE = { 'class': 'Dmf', 'instanceGroups': [ { - 'startPaused': False, + 'startPaused': "false", 'rate': 0, 'mainflowIdx': 0, 'mixType': '' @@ -270,7 +267,7 @@ SESSION_PROFILE = { 'forcedEthInterface': '', 'ip': 'MME_CONTROL_IP', 'class': 'TestNode', - 'ethStatsEnabled': False, + 'ethStatsEnabled': "false", 'mtu': 1500 }, 'SgwUserSut': { @@ -284,7 +281,7 @@ SESSION_PROFILE = { 'forcedEthInterface': '', 'ip': 'NET_HOST_IP', 'class': 'TestNode', - 'ethStatsEnabled': False, + 'ethStatsEnabled': "false", 'mtu': 1500 }, 'DedicatedsPerDefaultBearer': '0', @@ -310,7 +307,7 @@ SESSION_PROFILE = { 'forcedEthInterface': '', 'ip': 'ENB_USER_IP', 'class': 'TestNode', - 'ethStatsEnabled': False, + 'ethStatsEnabled': "false", 'mtu': 1500 }, 'TestType': 'SGW-NODAL' @@ -322,7 +319,340 @@ SESSION_PROFILE = { } +class TestLandslideTrafficGen(unittest.TestCase): + SCENARIO_CFG = { + 'session_profile': '/traffic_profiles/landslide/' + 'landslide_session_default_bearer.yaml', + 'task_path': '', + 'runner': { + 'type': 'Iteration', + 'iterations': 1 + }, + 'nodes': { + 'tg__0': 'tg__0.traffic_gen', + 'vnf__0': 'vnf__0.vnf_epc' + }, + 'topology': 'landslide_tg_topology.yaml', + 'type': 'NSPerf', + 'traffic_profile': '../../traffic_profiles/landslide/' + 'landslide_dmf_udp.yaml', + 'options': { + 'test_cases': [ + { + 'BearerAddrPool': '2002::2', + 'type': 'SGW_Node', + 'BearerV4AddrPool': '2.0.0.2', + 'Sessions': '90000' + }, + { + 'StartRate': '900.0', + 'type': 'SGW_Nodal', + 'DisconnectRate': '900.0', + 'Sessions': '90000' + } + ], + 'dmf': + { + 'transactionRate': 1000, + 'packetSize': 512 + } + } + } + + CONTEXT_CFG = { + 'contexts': [ + { + 'type': 'Node', + 'name': 'traffic_gen', + 'file': '/etc/yardstick/nodes/pod_landslide.yaml' + }, + { + 'type': 'Node', + 'name': 'vnf_epc', + 'file': '/etc/yardstick/nodes/pod_vepc_sut.yaml' + } + ] + } + + TRAFFIC_PROFILE = { + "schema": "nsb:traffic_profile:0.1", + "name": "LandslideProfile", + "description": "Spirent Landslide traffic profile", + "traffic_profile": { + "traffic_type": "LandslideProfile" + }, + "dmf_config": { + "dmf": { + "library": "test", + "name": "Basic UDP" + }, + "description": "Basic data flow using UDP/IP", + "keywords": "UDP", + "dataProtocol": "udp" + } + } + + SUCCESS_CREATED_CODE = 201 + SUCCESS_OK_CODE = 200 + SUCCESS_RECORD_ID = 5 + TEST_USER_ID = 11 + + def setUp(self): + self._id = uuid.uuid1().int + + self.mock_lsapi = mock.patch.object(tg_landslide, 'LsApi') + self.mock_lsapi.start() + + self.mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper') + self.mock_ssh_helper.start() + self.vnfd = VNFD['vnfd:vnfd-catalog']['vnfd'][0] + self.ls_tg = tg_landslide.LandslideTrafficGen( + NAME, self.vnfd, self._id) + self.session_profile = copy.deepcopy(SESSION_PROFILE) + self.ls_tg.session_profile = self.session_profile + + self.addCleanup(self._cleanup) + + def _cleanup(self): + self.mock_lsapi.stop() + self.mock_ssh_helper.stop() + + @mock.patch.object(net_serv_utils, 'get_nsb_option') + def test___init__(self, mock_get_nsb_option, *args): + _path_to_nsb = 'path/to/nsb' + mock_get_nsb_option.return_value = _path_to_nsb + ls_tg = tg_landslide.LandslideTrafficGen(NAME, self.vnfd, self._id) + self.assertIsInstance(ls_tg.resource_helper, + tg_landslide.LandslideResourceHelper) + mock_get_nsb_option.assert_called_once_with('bin_path') + self.assertEqual(_path_to_nsb, ls_tg.bin_path) + self.assertEqual(NAME, ls_tg.name) + self.assertTrue(ls_tg.runs_traffic) + self.assertFalse(ls_tg.traffic_finished) + self.assertIsNone(ls_tg.session_profile) + + def test_listen_traffic(self): + _traffic_profile = {} + self.assertIsNone(self.ls_tg.listen_traffic(_traffic_profile)) + + def test_terminate(self, *args): + self.ls_tg.resource_helper._tcl = mock.Mock() + self.assertIsNone(self.ls_tg.terminate()) + self.ls_tg.resource_helper._tcl.disconnect.assert_called_once() + + @mock.patch.object(ctx_base.Context, 'get_context_from_server', + return_value='fake_context') + def test_instantiate(self, *args): + self.ls_tg._tg_process = mock.Mock() + self.ls_tg._tg_process.start = mock.Mock() + self.ls_tg.resource_helper.connect = mock.Mock() + self.ls_tg.resource_helper.create_test_servers = mock.Mock() + self.ls_tg.resource_helper.create_suts = mock.Mock() + self.ls_tg._load_session_profile = mock.Mock() + self.assertIsNone(self.ls_tg.instantiate(self.SCENARIO_CFG, + self.CONTEXT_CFG)) + self.ls_tg.resource_helper.connect.assert_called_once() + self.ls_tg.resource_helper.create_test_servers.assert_called_once() + _suts_blocks_num = len([item['suts'] for item in self.vnfd['config']]) + self.assertEqual(_suts_blocks_num, + self.ls_tg.resource_helper.create_suts.call_count) + self.ls_tg._load_session_profile.assert_called_once() + + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'get_running_tests') + def test_run_traffic(self, mock_get_tests, *args): + self.ls_tg.resource_helper._url = EXAMPLE_URL + self.ls_tg.scenario_helper.scenario_cfg = self.SCENARIO_CFG + mock_traffic_profile = mock.Mock( + spec=landslide_profile.LandslideProfile) + mock_traffic_profile.dmf_config = {'keywords': 'UDP', + 'dataProtocol': 'udp'} + mock_traffic_profile.params = self.TRAFFIC_PROFILE + self.ls_tg.resource_helper._user_id = self.TEST_USER_ID + mock_get_tests.return_value = [{'id': self.SUCCESS_RECORD_ID, + 'testStateOrStep': 'COMPLETE'}] + mock_post = mock.Mock() + mock_post.status_code = self.SUCCESS_CREATED_CODE + mock_post.json.return_value = {'id': self.SUCCESS_RECORD_ID} + mock_session = mock.Mock(spec=requests.Session) + mock_session.post.return_value = mock_post + self.ls_tg.resource_helper.session = mock_session + self.ls_tg.resource_helper._tcl = mock.Mock() + _tcl = self.ls_tg.resource_helper._tcl + self.assertIsNone(self.ls_tg.run_traffic(mock_traffic_profile)) + self.assertEqual(self.SUCCESS_RECORD_ID, + self.ls_tg.resource_helper.run_id) + mock_traffic_profile.update_dmf.assert_called_with( + self.ls_tg.scenario_helper.all_options) + _tcl.create_dmf.assert_called_with(mock_traffic_profile.dmf_config) + _tcl.create_test_session.assert_called_with(self.session_profile) + + @mock.patch.object(tg_landslide.LandslideResourceHelper, + 'check_running_test_state') + def test_collect_kpi(self, mock_check_running_test_state, *args): + self.ls_tg.resource_helper.run_id = self.SUCCESS_RECORD_ID + mock_check_running_test_state.return_value = 'COMPLETE' + self.assertEqual({'done': True}, self.ls_tg.collect_kpi()) + mock_check_running_test_state.assert_called_once() + + def test_wait_for_instantiate(self): + self.assertIsNone(self.ls_tg.wait_for_instantiate()) + self.ls_tg.wait_for_instantiate() + + def test__update_session_suts_no_tc_role(self, *args): + _suts = [{'role': 'epc_role'}] + _testcase = {'parameters': {'diff_epc_role': {'class': 'Sut'}}} + res = self.ls_tg._update_session_suts(_suts, _testcase) + self.assertEqual(_testcase, res) + + def test__update_session_suts(self, *args): + + def get_testnode_param(role, key, session_prof): + """ Get value by key from the deep nested dict to avoid calls like: + e.g. session_prof['tsGroups'][0]['testCases'][1]['parameters'][key] + """ + for group in session_prof['tsGroups']: + for tc in group['testCases']: + tc_params = tc['parameters'] + if tc_params.get(role): + return tc_params[role][key] + + def get_sut_param(role, key, suts): + """ Search list of dicts for one with specific role. + Return the value of related dict by key. Expect key presence. + """ + for sut in suts: + if sut.get('role') == role: + return sut[key] + + # TestNode to verify + testnode_role = 'SgwControlAddr' + # SUT to verify + sut_role = 'SgwUserSut' + + config_suts = [config['suts'] for config in self.vnfd['config']] + session_tcs = [_tc for _ts_group in self.ls_tg.session_profile['tsGroups'] + for _tc in _ts_group['testCases']] + for suts, tc in zip(config_suts, session_tcs): + self.assertEqual(tc, self.ls_tg._update_session_suts(suts, tc)) + + # Verify TestNode class objects keys were updated + for _key in {'ip', 'phy', 'nextHop'}: + self.assertEqual( + get_testnode_param(testnode_role, _key, self.ls_tg.session_profile), + get_sut_param(testnode_role, _key, TS1_SUTS)) + # Verify Sut class objects name was updated + self.assertEqual( + get_testnode_param(sut_role, 'name', self.ls_tg.session_profile), + get_sut_param(sut_role, 'name', TS2_SUTS)) + + def test__update_session_test_servers(self, *args): + for ts_index, ts in enumerate(TEST_SERVERS): + self.assertIsNone( + self.ls_tg._update_session_test_servers(ts, ts_index)) + # Verify preResolvedArpAddress key was added + self.assertTrue(any( + _item.get('preResolvedArpAddress') + for _item in self.ls_tg.session_profile['tsGroups'])) + # Verify reservations key was added to session profile + self.assertEqual(RESERVATIONS, + self.ls_tg.session_profile.get('reservations')) + self.assertEqual('true', + self.ls_tg.session_profile.get('reservePorts')) + + def test__update_session_tc_params_assoc_phys(self): + _tc_options = {'AssociatedPhys': 'eth1'} + _testcase = {} + _testcase_orig = copy.deepcopy(_testcase) + res = self.ls_tg._update_session_tc_params(_tc_options, _testcase) + self.assertNotEqual(_testcase_orig, res) + self.assertEqual(_tc_options, _testcase) + + def test__update_session_tc_params(self, *args): + + def get_session_tc_param_value(param, tc_type, session_prof): + """ Get param value from the deep nested dict to avoid calls like: + session_prof['tsGroups'][0]['testCases'][0]['parameters'][key] + """ + for test_group in session_prof['tsGroups']: + session_tc = test_group['testCases'][0] + if session_tc['type'] == tc_type: + return session_tc['parameters'].get(param) + + session_tcs = [_tc for _ts_group in self.ls_tg.session_profile['tsGroups'] + for _tc in _ts_group['testCases']] + scenario_tcs = [_tc for _tc in + self.SCENARIO_CFG['options']['test_cases']] + for tc_options, tc in zip(scenario_tcs, session_tcs): + self.assertEqual( + tc, + self.ls_tg._update_session_tc_params(tc_options, tc)) + + # Verify that each test case parameter was updated + # Params been compared are deeply nested. Using loops to ease access. + for _tc in self.SCENARIO_CFG['options']['test_cases']: + for _key, _val in _tc.items(): + if _key != 'type': + self.assertEqual( + _val, + get_session_tc_param_value(_key, _tc.get('type'), + self.ls_tg.session_profile)) + + @mock.patch.object(common_utils, 'open_relative_file') + @mock.patch.object(yaml_loader, 'yaml_load') + @mock.patch.object(tg_landslide.LandslideTrafficGen, + '_update_session_test_servers') + @mock.patch.object(tg_landslide.LandslideTrafficGen, + '_update_session_suts') + @mock.patch.object(tg_landslide.LandslideTrafficGen, + '_update_session_tc_params') + def test__load_session_profile(self, mock_upd_ses_tc_params, + mock_upd_ses_suts, mock_upd_ses_ts, + mock_yaml_load, *args): + self.ls_tg.scenario_helper.scenario_cfg = self.SCENARIO_CFG + mock_yaml_load.return_value = SESSION_PROFILE + self.assertIsNone(self.ls_tg._load_session_profile()) + self.assertIsNotNone(self.ls_tg.session_profile) + # Number of blocks in configuration files + # Number of test servers, suts and tc params blocks should be equal + _config_files_blocks_num = len([item['test_server'] + for item in self.vnfd['config']]) + self.assertEqual(_config_files_blocks_num, + mock_upd_ses_ts.call_count) + self.assertEqual(_config_files_blocks_num, + mock_upd_ses_suts.call_count) + self.assertEqual(_config_files_blocks_num, + mock_upd_ses_tc_params.call_count) + + @mock.patch.object(common_utils, 'open_relative_file') + @mock.patch.object(yaml_loader, 'yaml_load') + def test__load_session_profile_unequal_num_of_cfg_blocks( + self, mock_yaml_load, *args): + vnfd = copy.deepcopy(VNFD['vnfd:vnfd-catalog']['vnfd'][0]) + ls_traffic_gen = tg_landslide.LandslideTrafficGen(NAME, vnfd, self._id) + ls_traffic_gen.scenario_helper.scenario_cfg = self.SCENARIO_CFG + mock_yaml_load.return_value = SESSION_PROFILE + # Delete test_servers item from pod file to make it not valid + ls_traffic_gen.vnfd_helper['config'].pop() + with self.assertRaises(RuntimeError): + ls_traffic_gen._load_session_profile() + + @mock.patch.object(common_utils, 'open_relative_file') + @mock.patch.object(yaml_loader, 'yaml_load') + def test__load_session_profile_test_type_mismatch(self, mock_yaml_load, + *args): + vnfd = copy.deepcopy(VNFD['vnfd:vnfd-catalog']['vnfd'][0]) + # Swap test servers data in pod file + vnfd['config'] = list(reversed(vnfd['config'])) + ls_tg = tg_landslide.LandslideTrafficGen(NAME, vnfd, self._id) + ls_tg.scenario_helper.scenario_cfg = self.SCENARIO_CFG + mock_yaml_load.return_value = SESSION_PROFILE + with self.assertRaises(RuntimeError): + ls_tg._load_session_profile() + + class TestLandslideResourceHelper(unittest.TestCase): + PROTO_PORT = 8080 EXAMPLE_URL = ''.join([TAS_INFO['proto'], '://', TAS_INFO['ip'], ':', str(PROTO_PORT), '/api/']) @@ -829,8 +1159,8 @@ class TestLandslideResourceHelper(unittest.TestCase): res = self.res_helper.configure_test_servers( action={'action': 'recycle'}) self.assertEqual( - {x['id'] for x in self.TEST_SERVERS_DATA['testServers']}, - set(res)) + [x['id'] for x in self.TEST_SERVERS_DATA['testServers']], + res) self.assertEqual(len(self.TEST_SERVERS_DATA['testServers']), mock_session.post.call_count) @@ -844,7 +1174,7 @@ class TestLandslideResourceHelper(unittest.TestCase): self.assertEqual(len(self.TEST_SERVERS_DATA['testServers']), mock_session.delete.call_count) - def test_create_test_session(self, *args): + def test_create_test_session_res_helper(self, *args): self.res_helper._user_id = self.SUCCESS_RECORD_ID self.res_helper._tcl = mock.Mock() test_session = {'name': 'test'} @@ -976,7 +1306,6 @@ class TestLandslideResourceHelper(unittest.TestCase): self.assertEqual(self.TEST_RESULTS_DATA, res) def test__write_results(self, *args): - self.maxDiff = None res = self.res_helper._write_results(self.TEST_RESULTS_DATA) exp_res = { "Test Summary::Actual Dedicated Bearer Session Connects": 100.0, @@ -1166,10 +1495,11 @@ class TestLandslideTclClient(unittest.TestCase): 'resolve_test_server_name', return_value='2') def test_create_test_session(self, *args): _session_profile = copy.deepcopy(SESSION_PROFILE) + _session_profile['reservations'] = RESERVATIONS self.ls_tcl_client._save_test_session = mock.Mock() self.ls_tcl_client._configure_ts_group = mock.Mock() self.ls_tcl_client.create_test_session(_session_profile) - self.assertEqual(20, self.mock_tcl_handler.execute.call_count) + self.assertEqual(17, self.mock_tcl_handler.execute.call_count) def test_create_dmf(self): self.mock_tcl_handler.execute.return_value = '2' @@ -1293,7 +1623,7 @@ class TestLandslideTclClient(unittest.TestCase): "clientPort": 0, "context": 0, "node": 0, - "overridePort": False, + "overridePort": "false", "ratingGroup": 0, "role": 0, "serviceId": 0, @@ -1313,12 +1643,12 @@ class TestLandslideTclClient(unittest.TestCase): self.assertIsNone(res) def test__configure_reservation(self): - _reservation = copy.deepcopy(SESSION_PROFILE['reservations'][0]) + _reservation = copy.deepcopy(RESERVATIONS[0]) self.ls_tcl_client.resolve_test_server_name = mock.Mock( return_value='2') res = self.ls_tcl_client._configure_reservation(_reservation) self.assertIsNone(res) - self.assertEqual(6, self.mock_tcl_handler.execute.call_count) + self.assertEqual(4, self.mock_tcl_handler.execute.call_count) def test__configure_preresolved_arp(self): _arp = [{'StartingAddress': '10.81.1.10', @@ -1330,6 +1660,7 @@ class TestLandslideTclClient(unittest.TestCase): def test__configure_preresolved_arp_none(self): res = self.ls_tcl_client._configure_preresolved_arp(None) self.assertIsNone(res) + self.mock_tcl_handler.execute.assert_not_called() def test_delete_test_session(self): self.assertRaises(NotImplementedError, -- cgit 1.2.3-korg From cb110cf04a54307dbc617e5f9a7ffaa5020cf10a Mon Sep 17 00:00:00 2001 From: Emma Foley Date: Thu, 6 Sep 2018 18:26:55 +0100 Subject: Update LSResourceHelper unittests New unit tests have been added to make sure the right commands are sent to Spirent LS. This helps to ensure that the correct commands are sent to Spirent, so that potentially breaking changes can be flagged. JIRA: YARDSTICK-1356 Change-Id: I23f452355afcec2705da7d4665a34b178e2ba729 Signed-off-by: Emma Foley --- .../vnf_generic/vnf/tg_landslide.py | 2 +- .../vnf_generic/vnf/test_tg_landslide.py | 210 ++++++++++++++++++++- 2 files changed, 201 insertions(+), 11 deletions(-) diff --git a/yardstick/network_services/vnf_generic/vnf/tg_landslide.py b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py index d4222c136..a146b72ca 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_landslide.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py @@ -754,7 +754,7 @@ class LandslideTclClient(object): TEST_NODE_CMD = \ 'ls::create -TestNode-{} -under $p_ -Type "eth"' \ ' -Phy "{phy}" -Ip "{ip}" -NumLinksOrNodes {numLinksOrNodes}' \ - ' -NextHop "{nextHop}" -Mac "{mac}" -MTU {mtu} ' \ + ' -NextHop "{nextHop}" -Mac "{mac}" -MTU {mtu}' \ ' -ForcedEthInterface "{forcedEthInterface}"' \ ' -EthStatsEnabled {ethStatsEnabled}' \ ' -VlanId {vlanId} -VlanUserPriority {vlanUserPriority}' \ diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py index d47061c6e..53439972a 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py @@ -609,8 +609,9 @@ class TestLandslideTrafficGen(unittest.TestCase): def test__load_session_profile(self, mock_upd_ses_tc_params, mock_upd_ses_suts, mock_upd_ses_ts, mock_yaml_load, *args): - self.ls_tg.scenario_helper.scenario_cfg = self.SCENARIO_CFG - mock_yaml_load.return_value = SESSION_PROFILE + self.ls_tg.scenario_helper.scenario_cfg = \ + copy.deepcopy(self.SCENARIO_CFG) + mock_yaml_load.return_value = copy.deepcopy(SESSION_PROFILE) self.assertIsNone(self.ls_tg._load_session_profile()) self.assertIsNotNone(self.ls_tg.session_profile) # Number of blocks in configuration files @@ -631,7 +632,7 @@ class TestLandslideTrafficGen(unittest.TestCase): vnfd = copy.deepcopy(VNFD['vnfd:vnfd-catalog']['vnfd'][0]) ls_traffic_gen = tg_landslide.LandslideTrafficGen(NAME, vnfd, self._id) ls_traffic_gen.scenario_helper.scenario_cfg = self.SCENARIO_CFG - mock_yaml_load.return_value = SESSION_PROFILE + mock_yaml_load.return_value = copy.deepcopy(SESSION_PROFILE) # Delete test_servers item from pod file to make it not valid ls_traffic_gen.vnfd_helper['config'].pop() with self.assertRaises(RuntimeError): @@ -1384,6 +1385,10 @@ class TestLandslideTclClient(unittest.TestCase): self.assertEqual(auth[0], self.ls_tcl_client._user) self.assertEqual(len(exec_responses), self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call("ls::login 1.1.1.1 user password"), + mock.call("ls::get [ls::query LibraryInfo -userLibraryName user] -Id"), + ]) def test_connect_login_failed(self, *args): exec_responses = ['Login failed'] @@ -1399,10 +1404,12 @@ class TestLandslideTclClient(unittest.TestCase): self.assertIsNone(self.ls_tcl_client._user) self.assertEqual(len(exec_responses), self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_called_with( + "ls::login 1.1.1.1 user password") def test_disconnect(self, *args): self.ls_tcl_client.disconnect() - self.mock_tcl_handler.execute.assert_called_once() + self.mock_tcl_handler.execute.assert_called_once_with("ls::logout") self.assertIsNone(self.ls_tcl_client.tcl_server_ip) self.assertIsNone(self.ls_tcl_client._user) self.assertIsNone(self.ls_tcl_client._library_id) @@ -1417,6 +1424,11 @@ class TestLandslideTclClient(unittest.TestCase): self.ls_tcl_client._set_thread_model = mock.Mock() res = self.ls_tcl_client.create_test_server(TEST_SERVERS[1]) self.assertEqual(3, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::query TsId TestServer_2'), + mock.call('set ts [ls::retrieve TsInfo -Name "TestServer_2"]'), + mock.call('ls::get $ts -RequestedLicense'), + ]) self.ls_tcl_client._set_thread_model.assert_called_once_with( TEST_SERVERS[1]['name'], TEST_SERVERS[1]['thread_model']) @@ -1429,6 +1441,11 @@ class TestLandslideTclClient(unittest.TestCase): self.ls_tcl_client.create_test_server, TEST_SERVERS[0]) self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::query TsId TestServer_1'), + mock.call('ls::perform AddTs -Name "TestServer_1" ' + '-Ip "192.168.122.101"'), + ]) def test__add_test_server(self): ts_id = '2' @@ -1436,6 +1453,10 @@ class TestLandslideTclClient(unittest.TestCase): self.assertEqual(ts_id, self.ls_tcl_client._add_test_server('name', 'ip')) self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::query TsId name'), + mock.call('ls::perform AddTs -Name "name" -Ip "ip"'), + ]) def test__add_test_server_failed(self): self.mock_tcl_handler.execute.side_effect = ['TS not found', @@ -1443,6 +1464,10 @@ class TestLandslideTclClient(unittest.TestCase): self.assertRaises(RuntimeError, self.ls_tcl_client._add_test_server, 'name', 'ip') self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::query TsId name'), + mock.call('ls::perform AddTs -Name "name" -Ip "ip"'), + ]) def test__update_license(self): curr_lic_id = '111' @@ -1457,6 +1482,13 @@ class TestLandslideTclClient(unittest.TestCase): self.assertEqual(len(exec_resp), self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('set ts [ls::retrieve TsInfo -Name "name"]'), + mock.call('ls::get $ts -RequestedLicense'), + mock.call('ls::config $ts -RequestedLicense 222'), + mock.call('ls::perform ModifyTs $ts'), + ]) + def test__update_license_same_as_current(self): curr_lic_id = '111' new_lic_id = '111' @@ -1466,6 +1498,10 @@ class TestLandslideTclClient(unittest.TestCase): self.ls_tcl_client._update_license('name') self.assertEqual(len(exec_resp), self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('set ts [ls::retrieve TsInfo -Name "name"]'), + mock.call('ls::get $ts -RequestedLicense'), + ]) def test__set_thread_model_update_needed(self): self.ls_tcl_client._ts_context.vnfd_helper = { @@ -1478,6 +1514,13 @@ class TestLandslideTclClient(unittest.TestCase): self.ls_tcl_client._set_thread_model('name', 'Fireball') self.assertEqual(len(exec_resp), self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('set tsc [ls::perform RetrieveTsConfiguration ' + '-name "name" cfguser_password]'), + mock.call('ls::get $tsc -ThreadModel'), + mock.call('ls::config $tsc -ThreadModel "V1_FB3"'), + mock.call('ls::perform ApplyTsConfiguration $tsc cfguser_password'), + ]) def test__set_thread_model_no_update_needed(self): self.ls_tcl_client._ts_context.vnfd_helper = { @@ -1490,28 +1533,103 @@ class TestLandslideTclClient(unittest.TestCase): self.ls_tcl_client._set_thread_model('name', 'Legacy') self.assertEqual(len(exec_resp), self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('set tsc [ls::perform RetrieveTsConfiguration ' + '-name "name" cfguser_password]'), + mock.call('ls::get $tsc -ThreadModel'), + ]) @mock.patch.object(tg_landslide.LandslideTclClient, - 'resolve_test_server_name', return_value='2') + 'resolve_test_server_name', side_effect=['4', '2']) def test_create_test_session(self, *args): _session_profile = copy.deepcopy(SESSION_PROFILE) _session_profile['reservations'] = RESERVATIONS self.ls_tcl_client._save_test_session = mock.Mock() self.ls_tcl_client._configure_ts_group = mock.Mock() + self.ls_tcl_client._library_id = 42 self.ls_tcl_client.create_test_session(_session_profile) self.assertEqual(17, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('set test_ [ls::create TestSession]'), + mock.call('ls::config $test_ -Library 42 ' + '-Name "default_bearer_capacity"'), + mock.call('ls::config $test_ -Description ' \ + '"UE default bearer creation test case"'), + mock.call('ls::config $test_ -Keywords ""'), + mock.call('ls::config $test_ -Duration "60"'), + mock.call('ls::config $test_ -Iterations "1"'), + # _configure_reservation + mock.call('set reservation_ [ls::create Reservation -under $test_]'), + mock.call('ls::config $reservation_ -TsIndex 0 ' + '-TsId 4 -TsName "TestServer_1"'), + mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'), + mock.call('ls::config $physubnet_ -Name "eth1" -Base "10.42.32.100" ' + '-Mask "/24" -NumIps 20'), + # _configure_reservation + mock.call('set reservation_ [ls::create Reservation -under $test_]'), + mock.call('ls::config $reservation_ -TsIndex 1 ' + '-TsId 2 -TsName "TestServer_2"'), + mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'), + mock.call('ls::config $physubnet_ -Name "eth1" -Base "10.42.32.1" ' + '-Mask "/24" -NumIps 100'), + mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'), + mock.call('ls::config $physubnet_ -Name "eth2" -Base "10.42.33.1" ' + '-Mask "/24" -NumIps 100'), + # _configure_report_options + mock.call('ls::config $test_.ReportOptions -Format 1 -Ts -3 -Tc -3'), + ]) def test_create_dmf(self): self.mock_tcl_handler.execute.return_value = '2' self.ls_tcl_client._save_dmf = mock.Mock() - self.ls_tcl_client.create_dmf(DMF_CFG) + self.ls_tcl_client.create_dmf(copy.deepcopy(DMF_CFG)) self.assertEqual(6, self.mock_tcl_handler.execute.call_count) + # This is needed because the dictionary is unordered and the arguments + # can come in either order + call1 = mock.call( + 'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"') + call2 = mock.call( + 'ls::config $dmf_ -isClientPortRange "false" -clientPort 2002') + self.assertTrue( + call1 in self.mock_tcl_handler.execute.mock_calls or + call2 in self.mock_tcl_handler.execute.mock_calls) + + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('set dmf_ [ls::create Dmf]'), + mock.call( + 'ls::get [ls::query LibraryInfo -systemLibraryName test] -Id'), + mock.call('ls::config $dmf_ -Library 2 -Name "Basic UDP"'), + mock.call('ls::config $dmf_ -dataProtocol "udp"'), + # mock.call( + # 'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"'), + mock.call('ls::config $dmf_ -serverPort 2003'), + ], any_order=True) def test_configure_dmf(self): self.mock_tcl_handler.execute.return_value = '2' self.ls_tcl_client._save_dmf = mock.Mock() self.ls_tcl_client.configure_dmf(DMF_CFG) self.assertEqual(6, self.mock_tcl_handler.execute.call_count) + # This is need because the dictionary is unordered and the arguments + # can come in either order + call1 = mock.call( + 'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"') + call2 = mock.call( + 'ls::config $dmf_ -isClientPortRange "false" -clientPort 2002') + self.assertTrue( + call1 in self.mock_tcl_handler.execute.mock_calls or + call2 in self.mock_tcl_handler.execute.mock_calls) + + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('set dmf_ [ls::create Dmf]'), + mock.call( + 'ls::get [ls::query LibraryInfo -systemLibraryName test] -Id'), + mock.call('ls::config $dmf_ -Library 2 -Name "Basic UDP"'), + mock.call('ls::config $dmf_ -dataProtocol "udp"'), + # mock.call( + # 'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"'), + mock.call('ls::config $dmf_ -serverPort 2003'), + ], any_order=True) def test_delete_dmf(self): self.assertRaises(NotImplementedError, @@ -1524,6 +1642,10 @@ class TestLandslideTclClient(unittest.TestCase): self.ls_tcl_client._save_dmf() self.assertEqual(len(exec_resp), self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::perform Validate -Dmf $dmf_'), + mock.call('ls::save $dmf_ -overwrite'), + ]) def test__save_dmf_invalid(self): exec_resp = ['Invalid', 'List of errors and warnings'] @@ -1532,11 +1654,20 @@ class TestLandslideTclClient(unittest.TestCase): self.ls_tcl_client._save_dmf) self.assertEqual(len(exec_resp), self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::perform Validate -Dmf $dmf_'), + mock.call('ls::get $dmf_ -ErrorsAndWarnings'), + ]) def test__configure_report_options(self): _options = {'format': 'CSV', 'PerInterval': 'false'} self.ls_tcl_client._configure_report_options(_options) self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::config $test_.ReportOptions -Format 1 -Ts -3 -Tc -3'), + mock.call('ls::config $test_.ReportOptions -PerInterval false'), + ], + any_order=True) def test___configure_ts_group(self, *args): _ts_group = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]) @@ -1545,7 +1676,8 @@ class TestLandslideTclClient(unittest.TestCase): self.ls_tcl_client.resolve_test_server_name = mock.Mock( return_value='2') self.ls_tcl_client._configure_ts_group(_ts_group, 0) - self.mock_tcl_handler.execute.assert_called_once() + self.mock_tcl_handler.execute.assert_called_once_with( + 'set tss_ [ls::create TsGroup -under $test_ -tsId 2 ]') def test___configure_ts_group_resolve_ts_fail(self, *args): _ts_group = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]) @@ -1579,6 +1711,7 @@ class TestLandslideTclClient(unittest.TestCase): self.assertRaises(RuntimeError, self.ls_tcl_client._configure_tc_type, _tc, 0) + self.mock_tcl_handler.assert_not_called() def test__configure_tc_type_not_found_basic_lib(self): _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0]) @@ -1599,18 +1732,28 @@ class TestLandslideTclClient(unittest.TestCase): "array": ["0"]} self.ls_tcl_client._configure_array_param('name', _array) self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::create -Array-name -under $p_ ;'), + mock.call('ls::create ArrayItem -under $p_.name -Value "0"'), + ]) def test__configure_test_node_param(self): _params = copy.deepcopy( SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters']) self.ls_tcl_client._configure_test_node_param('SgwUserAddr', _params['SgwUserAddr']) - self.mock_tcl_handler.execute.assert_called_once() + cmd = ('ls::create -TestNode-SgwUserAddr -under $p_ -Type "eth" ' + '-Phy "eth1" -Ip "SGW_USER_IP" -NumLinksOrNodes 1 ' + '-NextHop "SGW_CONTROL_NEXT_HOP" -Mac "" -MTU 1500 ' + '-ForcedEthInterface "" -EthStatsEnabled false -VlanId 0 ' + '-VlanUserPriority 0 -NumVlan 1 -UniqueVlanAddr false;') + self.mock_tcl_handler.execute.assert_called_once_with(cmd) def test__configure_sut_param(self): _params = {'name': 'name'} self.ls_tcl_client._configure_sut_param('name', _params) - self.mock_tcl_handler.execute.assert_called_once() + self.mock_tcl_handler.execute.assert_called_once_with( + 'ls::create -Sut-name -under $p_ -Name "name";') def test__configure_dmf_param(self): _params = {"mainflows": [{"library": '111', @@ -1633,6 +1776,16 @@ class TestLandslideTclClient(unittest.TestCase): res = self.ls_tcl_client._configure_dmf_param('name', _params) self.assertEqual(5, self.mock_tcl_handler.execute.call_count) self.assertIsNone(res) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::create -Dmf-name -under $p_ ;'), + mock.call('ls::perform AddDmfMainflow $p_.Dmf 111 "Basic UDP"'), + mock.call('ls::config $p_.Dmf.InstanceGroup(0) -mixType '), + mock.call('ls::config $p_.Dmf.InstanceGroup(0) -rate 0.0'), + mock.call('ls::config $p_.Dmf.InstanceGroup(0).Row(0) -Node 0 ' + '-OverridePort false -ClientPort 0 -Context 0 -Role 0 ' + '-PreferredTransport Any -RatingGroup 0 ' + '-ServiceID 0'), + ]) def test__configure_dmf_param_no_instance_groups(self): _params = {"mainflows": [{"library": '111', @@ -1641,14 +1794,26 @@ class TestLandslideTclClient(unittest.TestCase): res = self.ls_tcl_client._configure_dmf_param('name', _params) self.assertEqual(2, self.mock_tcl_handler.execute.call_count) self.assertIsNone(res) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::create -Dmf-name -under $p_ ;'), + mock.call('ls::perform AddDmfMainflow $p_.Dmf 111 "Basic UDP"'), + ]) def test__configure_reservation(self): _reservation = copy.deepcopy(RESERVATIONS[0]) self.ls_tcl_client.resolve_test_server_name = mock.Mock( - return_value='2') + return_value='4') res = self.ls_tcl_client._configure_reservation(_reservation) self.assertIsNone(res) self.assertEqual(4, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('set reservation_ [ls::create Reservation -under $test_]'), + mock.call('ls::config $reservation_ -TsIndex 0 -TsId 4 ' + \ + '-TsName "TestServer_1"'), + mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'), + mock.call('ls::config $physubnet_ -Name "eth1" ' + \ + '-Base "10.42.32.100" -Mask "/24" -NumIps 20'), + ]) def test__configure_preresolved_arp(self): _arp = [{'StartingAddress': '10.81.1.10', @@ -1656,6 +1821,9 @@ class TestLandslideTclClient(unittest.TestCase): res = self.ls_tcl_client._configure_preresolved_arp(_arp) self.mock_tcl_handler.execute.assert_called_once() self.assertIsNone(res) + self.mock_tcl_handler.execute.assert_called_once_with( + 'ls::create PreResolvedArpAddress -under $tss_ ' + \ + '-StartingAddress "10.81.1.10" -NumNodes 1') def test__configure_preresolved_arp_none(self): res = self.ls_tcl_client._configure_preresolved_arp(None) @@ -1672,24 +1840,40 @@ class TestLandslideTclClient(unittest.TestCase): res = self.ls_tcl_client._save_test_session() self.assertEqual(2, self.mock_tcl_handler.execute.call_count) self.assertIsNone(res) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::perform Validate -TestSession $test_'), + mock.call('ls::save $test_ -overwrite'), + ]) def test__save_test_session_invalid(self): self.mock_tcl_handler.execute.side_effect = ['Invalid', 'Errors'] self.assertRaises(exceptions.LandslideTclException, self.ls_tcl_client._save_test_session) self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call('ls::perform Validate -TestSession $test_'), + mock.call('ls::get $test_ -ErrorsAndWarnings'), + ]) def test__get_library_id_system_lib(self): self.mock_tcl_handler.execute.return_value = '111' res = self.ls_tcl_client._get_library_id('name') self.mock_tcl_handler.execute.assert_called_once() self.assertEqual('111', res) + self.mock_tcl_handler.execute.assert_called_with( + 'ls::get [ls::query LibraryInfo -systemLibraryName name] -Id') def test__get_library_id_user_lib(self): self.mock_tcl_handler.execute.side_effect = ['Not found', '222'] res = self.ls_tcl_client._get_library_id('name') self.assertEqual(2, self.mock_tcl_handler.execute.call_count) self.assertEqual('222', res) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call( + 'ls::get [ls::query LibraryInfo -systemLibraryName name] -Id'), + mock.call( + 'ls::get [ls::query LibraryInfo -userLibraryName name] -Id'), + ]) def test__get_library_id_exception(self): self.mock_tcl_handler.execute.side_effect = ['Not found', 'Not found'] @@ -1697,6 +1881,12 @@ class TestLandslideTclClient(unittest.TestCase): self.ls_tcl_client._get_library_id, 'name') self.assertEqual(2, self.mock_tcl_handler.execute.call_count) + self.mock_tcl_handler.execute.assert_has_calls([ + mock.call( + 'ls::get [ls::query LibraryInfo -systemLibraryName name] -Id'), + mock.call( + 'ls::get [ls::query LibraryInfo -userLibraryName name] -Id'), + ]) class TestLsTclHandler(unittest.TestCase): -- cgit 1.2.3-korg From 8ef31dc4d4b263b975a5b8d0ee72b06597454455 Mon Sep 17 00:00:00 2001 From: Orest Voznyy Date: Sat, 28 Jul 2018 20:39:56 +0300 Subject: Add Spirent Landslide traffic profile templates These files are templates of Spirent Landslide data message flow (DMF) representing traffic profile of one or multiple traffic flows. Template files should not be edited directly. Instead, their parameters could be overriden in test case YAML file, in section "dmf". JIRA: YARDSTICK-1359 Change-Id: I4980a784a78ca870c18457227248e6e2ac0b8eda Signed-off-by: Orest Voznyy --- .../landslide/landslide_dmf_fb_udp.yaml | 79 ++++++++++++ .../landslide/landslide_dmf_fb_udp_tcp.yaml | 136 +++++++++++++++++++++ .../landslide/landslide_dmf_udp.yaml | 79 ++++++++++++ .../landslide/landslide_dmf_udp_tcp.yaml | 136 +++++++++++++++++++++ 4 files changed, 430 insertions(+) create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_fb_udp.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_fb_udp_tcp.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_udp.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_udp_tcp.yaml diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_fb_udp.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_fb_udp.yaml new file mode 100644 index 000000000..f25239f57 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_fb_udp.yaml @@ -0,0 +1,79 @@ +# 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. + +schema: "nsb:traffic_profile:0.1" + +name: LandslideProfile +description: Spirent Landslide traffic profile (Data Message Flow) + +traffic_profile: + traffic_type: LandslideProfile + +dmf_config: + dmf: + library: test + name: Fireball UDP + description: "Basic data flow using UDP/IP (Fireball DMF)" + keywords: 'UDP ' + dataProtocol: fb_udp + burstCount: 1 # Applies only to Basic UDP DMF, DataProtocol == (udp or fb_udp) + clientPort: + clientPort: 2002 + isClientPortRange: 'false' + serverPort: 2003 + connection: + initiatingSide: Client + disconnectSide: Client + underlyingProtocol: none + persistentConnection: 'false' + protocolId: 0 + persistentConnection: 'false' + transactionRate: 8.0 + transactions: + totalTransactions: 0 + retries: 0 + dataResponseTime: 60000 + packetSize: 64 + segment: + segmentSize: 64000 + maxSegmentSize: 0 + size: + sizeDistribution: Fixed + sizeDeviation: 10 + interval: + intervalDistribution: Fixed + intervalDeviation: 10 + ipHeader: + typeOfService: 0 + timeToLive: 64 + tcpConnection: + force3Way: 'false' + fixedRetryTime: 0 + maxPacketsToForceAck: 0 + tcp: + windowSize: 32768 + windowScaling: -1 + disableFinAckWait: 'false' + disconnectType: FIN + slowStart: 'false' + connectOnly: 'false' + vtag: + VTagMask: '0x0' + VTagValue: '0x0' + sctpPayloadProtocolId: 0 + billingIncludeSyn: true + billingIncludeSubflow: true + billingRecordPerTransaction: 'false' + tcpPush: 'false' + hostDataExpansionRatio: 1 diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_fb_udp_tcp.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_fb_udp_tcp.yaml new file mode 100644 index 000000000..e613f1769 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_fb_udp_tcp.yaml @@ -0,0 +1,136 @@ +# 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. + +schema: "nsb:traffic_profile:0.1" + +name: LandslideProfile +description: Spirent Landslide traffic profile (Data Message Flow) + +traffic_profile: + traffic_type: LandslideProfile + +dmf_config: + - + dmf: + library: test + name: Fireball UDP + description: "Basic data flow using UDP/IP" + keywords: 'UDP ' + dataProtocol: fb_udp + burstCount: 1 # Applies only to Basic UDP DMF, DataProtocol==(udp or fb_udp) + clientPort: + clientPort: 2012 + isClientPortRange: 'false' + serverPort: 2013 + connection: + initiatingSide: Client + disconnectSide: Client + underlyingProtocol: none + persistentConnection: 'false' + protocolId: 0 + persistentConnection: 'false' + transactionRate: 8.0 + transactions: + totalTransactions: 0 + retries: 0 + dataResponseTime: 60000 + packetSize: 64 + segment: + segmentSize: 64000 + maxSegmentSize: 0 + size: + sizeDistribution: Fixed + sizeDeviation: 10 + interval: + intervalDistribution: Fixed + intervalDeviation: 10 + ipHeader: + typeOfService: 0 + timeToLive: 64 + tcpConnection: + force3Way: 'false' + fixedRetryTime: 0 + maxPacketsToForceAck: 0 + tcp: + windowSize: 32768 + windowScaling: -1 + disableFinAckWait: 'false' + disconnectType: FIN + slowStart: 'false' + connectOnly: 'false' + vtag: + VTagMask: '0x0' + VTagValue: '0x0' + sctpPayloadProtocolId: 0 + billingIncludeSyn: true + billingIncludeSubflow: true + billingRecordPerTransaction: 'false' + tcpPush: 'false' + hostDataExpansionRatio: 1 + - + dmf: + library: test + name: Fireball TCP + description: "Basic data flow using TCP/IP" + keywords: 'TCP ' + dataProtocol: fb_tcp + clientPort: + clientPort: 2002 + isClientPortRange: 'false' + serverPort: 2003 + connection: + initiatingSide: Client + disconnectSide: Client + underlyingProtocol: none + persistentConnection: 'false' + protocolId: 0 + persistentConnection: 'false' + transactionRate: 8.0 + transactions: + totalTransactions: 0 + retries: 0 + dataResponseTime: 60000 + packetSize: 64 + segment: + segmentSize: 64000 + maxSegmentSize: 0 + size: + sizeDistribution: Fixed + sizeDeviation: 10 + interval: + intervalDistribution: Fixed + intervalDeviation: 10 + ipHeader: + typeOfService: 0 + timeToLive: 64 + tcpConnection: + force3Way: 'false' + fixedRetryTime: 0 + maxPacketsToForceAck: 0 + tcp: + windowSize: 32768 + windowScaling: -1 + disableFinAckWait: 'false' + disconnectType: FIN + slowStart: 'false' + connectOnly: 'false' + vtag: + VTagMask: '0x0' + VTagValue: '0x0' + sctpPayloadProtocolId: 0 + billingIncludeSyn: true + billingIncludeSubflow: true + billingRecordPerTransaction: 'false' + tcpPush: 'false' + hostDataExpansionRatio: 1 diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_udp.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_udp.yaml new file mode 100644 index 000000000..c7fabd182 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_udp.yaml @@ -0,0 +1,79 @@ +# 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. + +schema: "nsb:traffic_profile:0.1" + +name: LandslideProfile +description: Spirent Landslide traffic profile (Data Message Flow) + +traffic_profile: + traffic_type: LandslideProfile + +dmf_config: + dmf: + library: test + name: Basic UDP + description: "Basic data flow using UDP/IP" + keywords: 'UDP ' + dataProtocol: udp + burstCount: 1 # Applies only to Basic UDP DMF, DataProtocol==udp. + clientPort: + clientPort: 2002 + isClientPortRange: 'false' + serverPort: 2003 + connection: + initiatingSide: Client + disconnectSide: Client + underlyingProtocol: none + persistentConnection: 'false' + protocolId: 0 + persistentConnection: 'false' + transactionRate: 8.0 + transactions: + totalTransactions: 0 + retries: 0 + dataResponseTime: 60000 + packetSize: 64 + segment: + segmentSize: 64000 + maxSegmentSize: 0 + size: + sizeDistribution: Fixed + sizeDeviation: 10 + interval: + intervalDistribution: Fixed + intervalDeviation: 10 + ipHeader: + typeOfService: 0 + timeToLive: 64 + tcpConnection: + force3Way: 'false' + fixedRetryTime: 0 + maxPacketsToForceAck: 0 + tcp: + windowSize: 32768 + windowScaling: -1 + disableFinAckWait: 'false' + disconnectType: FIN + slowStart: 'false' + connectOnly: 'false' + vtag: + VTagMask: '0x0' + VTagValue: '0x0' + sctpPayloadProtocolId: 0 + billingIncludeSyn: true + billingIncludeSubflow: true + billingRecordPerTransaction: 'false' + tcpPush: 'false' + hostDataExpansionRatio: 1 diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_udp_tcp.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_udp_tcp.yaml new file mode 100644 index 000000000..80c0db0d0 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_dmf_udp_tcp.yaml @@ -0,0 +1,136 @@ +# 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. + +schema: "nsb:traffic_profile:0.1" + +name: LandslideProfile +description: Spirent Landslide traffic profile (Data Message Flow) + +traffic_profile: + traffic_type: LandslideProfile + +dmf_config: + - + dmf: + library: test + name: Basic UDP + description: "Basic data flow using UDP/IP" + keywords: 'UDP ' + dataProtocol: udp + burstCount: 1 # Applies only to Basic UDP DMF, DataProtocol==(udp or fb_udp) + clientPort: + clientPort: 2012 + isClientPortRange: 'false' + serverPort: 2013 + connection: + initiatingSide: Client + disconnectSide: Client + underlyingProtocol: none + persistentConnection: 'false' + protocolId: 0 + persistentConnection: 'false' + transactionRate: 8.0 + transactions: + totalTransactions: 0 + retries: 0 + dataResponseTime: 60000 + packetSize: 64 + segment: + segmentSize: 64000 + maxSegmentSize: 0 + size: + sizeDistribution: Fixed + sizeDeviation: 10 + interval: + intervalDistribution: Fixed + intervalDeviation: 10 + ipHeader: + typeOfService: 0 + timeToLive: 64 + tcpConnection: + force3Way: 'false' + fixedRetryTime: 0 + maxPacketsToForceAck: 0 + tcp: + windowSize: 32768 + windowScaling: -1 + disableFinAckWait: 'false' + disconnectType: FIN + slowStart: 'false' + connectOnly: 'false' + vtag: + VTagMask: '0x0' + VTagValue: '0x0' + sctpPayloadProtocolId: 0 + billingIncludeSyn: 'true' + billingIncludeSubflow: 'true' + billingRecordPerTransaction: 'false' + tcpPush: 'false' + hostDataExpansionRatio: 1 + - + dmf: + library: test + name: Basic TCP + description: "Basic data flow using TCP/IP" + keywords: 'TCP ' + dataProtocol: tcp + clientPort: + clientPort: 2002 + isClientPortRange: 'false' + serverPort: 2003 + connection: + initiatingSide: Client + disconnectSide: Client + underlyingProtocol: none + persistentConnection: 'false' + protocolId: 0 + persistentConnection: 'false' + transactionRate: 8.0 + transactions: + totalTransactions: 0 + retries: 0 + dataResponseTime: 60000 + packetSize: 64 + segment: + segmentSize: 64000 + maxSegmentSize: 0 + size: + sizeDistribution: Fixed + sizeDeviation: 10 + interval: + intervalDistribution: Fixed + intervalDeviation: 10 + ipHeader: + typeOfService: 0 + timeToLive: 64 + tcpConnection: + force3Way: 'false' + fixedRetryTime: 0 + maxPacketsToForceAck: 0 + tcp: + windowSize: 32768 + windowScaling: -1 + disableFinAckWait: 'false' + disconnectType: FIN + slowStart: 'false' + connectOnly: 'false' + vtag: + VTagMask: '0x0' + VTagValue: '0x0' + sctpPayloadProtocolId: 0 + billingIncludeSyn: 'true' + billingIncludeSubflow: 'true' + billingRecordPerTransaction: 'false' + tcpPush: 'false' + hostDataExpansionRatio: 1 -- cgit 1.2.3-korg From 600059b928156d807ca1712736609a23f15dc1c3 Mon Sep 17 00:00:00 2001 From: Orest Voznyy Date: Sat, 28 Jul 2018 16:25:02 +0300 Subject: Add vEPC default bearers create/delete test case This test case runs on Spirent Landslide TG. All vEPC entities are emulated on Landslide test server. Test run configuration is performed in following files: 1. test case file 2. pod file 3. session profile file (landslide_session_default_bearer*.yaml) The structure of these files represents configuration of different parts of test cases in this test session. The order of test cases should always match. Spirent Landslide test types involved: "SGW_Node", "SGW_Nodal". Test case actions sequence: - create default bearers (as per value of "Sessions" key) with specified rate (session profile key "StartRate") - send traffic flow(s) (pre-configured in traffic profile) for a number of seconds (specified in session profile key "duration") - remove N default bearers with specified rate (session profile key "DisconnectRate") Parameters with ALL_CAPS values are placeholders. User should replace them with their own condifuration. Session profile file placeholders do not need to be replaced as long as these parameters are overriden in other files (e.g. pod, test case). Test results are dispatched according to runner configuration options. For fully emulated test runs like this one, best suited runner is "Search" type. In case of testing against real EPC VNFs, user could prefer different runner type. JIRA: YARDSTICK-1348 Change-Id: I5caf4878fb212b38d4148a297c5dba03b8ab98a8 Signed-off-by: Orest Voznyy --- etc/yardstick/nodes/standalone/pod_landslide.yaml | 130 ++++++++++++++++++ .../tc_epc_default_bearer_create_landslide.yaml | 57 ++++++++ ..._default_bearer_create_landslide_multi_dmf.yaml | 57 ++++++++ .../landslide_session_default_bearer.yaml | 147 ++++++++++++++++++++ ...landslide_session_default_bearer_multi_dmf.yaml | 150 +++++++++++++++++++++ 5 files changed, 541 insertions(+) create mode 100644 etc/yardstick/nodes/standalone/pod_landslide.yaml create mode 100644 samples/vnf_samples/nsut/vepc/tc_epc_default_bearer_create_landslide.yaml create mode 100644 samples/vnf_samples/nsut/vepc/tc_epc_default_bearer_create_landslide_multi_dmf.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_session_default_bearer.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_session_default_bearer_multi_dmf.yaml diff --git a/etc/yardstick/nodes/standalone/pod_landslide.yaml b/etc/yardstick/nodes/standalone/pod_landslide.yaml new file mode 100644 index 000000000..c84aed142 --- /dev/null +++ b/etc/yardstick/nodes/standalone/pod_landslide.yaml @@ -0,0 +1,130 @@ +# 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. + + +nodes: +- + name: "tg__0" + role: tg__0 + tas_manager: + ip: 192.168.122.100 + super_user: SUPER_USER + super_user_password: SUPER_USER_PASSWORD + cfguser_password: CFGUSER_PASSWORD + test_user: TEST_USER + test_user_password: TEST_USER_PASSWORD + proto: http + license: LICENSE_NUMBER + interfaces: # dummy values + xe0: + vpci: "0000:05:00.0" + local_mac: "68:05:ca:30:3d:50" + driver: "i40e" + local_ip: "152.16.100.19" + netmask: "255.255.255.0" + xe1: + vpci: "0000:05:00.1" + local_mac: "68:05:ca:30:3d:51" + driver: "i40e" + local_ip: "152.16.40.19" + netmask: "255.255.255.0" + config: + - test_server: + name: TestServer_1 + role: SGW_Node + ip: 192.168.122.101 + thread_model: Fireball + # override port-subnet and static route reservation information for this + # test server within the test session. + phySubnets: + - base: 10.42.32.100 + mask: "/24" + name: &ts1_port1 eth5 + numIps: 20 + - base: 10.42.33.100 + mask: "/24" + name: &ts1_port2 eth6 + numIps: 20 + preResolvedArpAddress: # required for testcases with enabled Fireball mode + - StartingAddress: 10.42.33.10 + NumNodes: 1 + suts: + - name: SGW-C TestNode + role: SgwControlAddr + managementIp: 12.0.1.1 + phy: *ts1_port1 + ip: 10.42.32.100 + # nextHop: '' + - name: SGW-U TestNode + role: SgwUserAddr + managementIp: 12.0.1.2 + phy: *ts1_port1 + ip: 10.42.32.101 + # nextHop: '' + + - test_server: + name: TestServer_2 + role: SGW_Nodal + ip: 192.168.122.102 + thread_model: Fireball + # override port-subnet and static route reservation information for this + # test server within the test session. + phySubnets: + - base: 10.42.32.1 + mask: "/24" + name: &ts2_port1 eth5 + numIps: 100 + - base: 10.42.33.1 + mask: "/24" + name: &ts2_port2 eth6 + numIps: 100 + suts: + - name: eNodeB TestNode + role: EnbUserAddr + managementIp: 12.0.2.1 + phy: *ts2_port1 + ip: 10.42.32.2 + # nextHop: '' + - name: Target eNodeB + role: MobEnbUserAddr + managementIp: 12.0.2.2 + phy: *ts2_port1 + ip: 10.42.32.3 + # nextHop: '' + - name: MME TestNode + role: MmeControlAddr + managementIp: 12.0.3.1 + phy: *ts2_port1 + ip: 10.42.32.1 + # nextHop: '' + - name: NetHost TestNode + role: NetworkHostAddrLocal + managementIp: 12.0.4.1 + phy: *ts2_port2 + ip: 10.42.33.10 + # nextHop: '' + - name: PGW SUT + role: PgwV4Sut + managementIp: 12.0.5.1 + phy: *ts1_port1 + ip: 10.42.32.105 + # nextHop: '' + - name: SGW-C SUT + role: SgwSut + managementIp: 12.0.6.1 + ip: 10.42.32.100 + - name: SGW-U SUT + role: SgwUserSut + managementIp: 12.0.6.2 + ip: 10.42.32.101 diff --git a/samples/vnf_samples/nsut/vepc/tc_epc_default_bearer_create_landslide.yaml b/samples/vnf_samples/nsut/vepc/tc_epc_default_bearer_create_landslide.yaml new file mode 100644 index 000000000..0b94d313f --- /dev/null +++ b/samples/vnf_samples/nsut/vepc/tc_epc_default_bearer_create_landslide.yaml @@ -0,0 +1,57 @@ +# 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. + +--- +schema: yardstick:task:0.1 +description: > + UE default bearer creation test case. Measure successful default bearer + creation rate, total number of active bearer per server. + +scenarios: +- type: NSPerf + traffic_profile: "../../traffic_profiles/landslide/landslide_dmf_udp.yaml" + session_profile: "../../traffic_profiles/landslide/landslide_session_default_bearer.yaml" + topology: "vepc_vnf_topology_landslide.yaml" + nodes: + tg__0: tg__0.traffic_gen + vnf__0: vnf__0.vnf_epc + options: + dmf: + transactionRate: 5 + packetSize: 512 + test_cases: # test case parameters to apply on session profile + - type: SGW_Node # test type from test session profile + AssociatedPhys: 'eth6' # interface(s) in Node test type to loop traffic back from NetHost + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + FireballEn: 'false' + Sessions: '20000' + - type: SGW_Nodal # test type from test session profile + StartRate: '1000.0' + DisconnectRate: '1000.0' + FireballEn: 'false' + Sessions: '20000' + + runner: + type: Duration + duration: 200 + interval: 5 + +contexts: +- name: traffic_gen + type: Node + file: /etc/yardstick/nodes/pod_landslide.yaml +- name: vnf_epc + type: Node + file: /etc/yardstick/nodes/pod_vepc_sut.yaml diff --git a/samples/vnf_samples/nsut/vepc/tc_epc_default_bearer_create_landslide_multi_dmf.yaml b/samples/vnf_samples/nsut/vepc/tc_epc_default_bearer_create_landslide_multi_dmf.yaml new file mode 100644 index 000000000..76567062a --- /dev/null +++ b/samples/vnf_samples/nsut/vepc/tc_epc_default_bearer_create_landslide_multi_dmf.yaml @@ -0,0 +1,57 @@ +# 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. + +--- +schema: yardstick:task:0.1 +description: > + UE default bearer creation test case. Measure successful default bearer + creation rate, total number of active bearer per server. + +scenarios: +- type: NSPerf + traffic_profile: "../../traffic_profiles/landslide/landslide_dmf_udp_tcp.yaml" + session_profile: "../../traffic_profiles/landslide/landslide_session_default_bearer_multi_dmf.yaml" + topology: "vepc_vnf_topology_landslide.yaml" + nodes: + tg__0: tg__0.traffic_gen + vnf__0: vnf__0.vnf_epc + options: + dmf: + - transactionRate: 5 + packetSize: 512 + - transactionRate: 5 + packetSize: 1518 + test_cases: # test case parameters to apply on session profile + - type: SGW_Node # test type from test session profile + AssociatedPhys: 'eth6' # interface(s) in Node test type to loop traffic back from NetHost + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + Sessions: '20000' + - type: SGW_Nodal # test type from test session profile + StartRate: '1000.0' + DisconnectRate: '1000.0' + Sessions: '20000' + + runner: + type: Duration + duration: 300 + interval: 5 + +contexts: +- name: traffic_gen + type: Node + file: /etc/yardstick/nodes/pod_landslide.yaml +- name: vnf_epc + type: Node + file: /etc/yardstick/nodes/pod_vepc_sut.yaml diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_session_default_bearer.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_default_bearer.yaml new file mode 100644 index 000000000..a90d8a189 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_default_bearer.yaml @@ -0,0 +1,147 @@ +# 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. + +--- +description: 'UE default bearer creation test case' +name: default_bearer_capacity +keywords: '' +duration: 60 +tsGroups: +- tsId: SGW_NODE_TS_NAME # SGW-Node test server name placeholder + testCases: + - name: '' + type: SGW_Node + AssociatedPhys: '' + parameters: + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + DedicatedsPerDefaultBearer: '0' + DefaultBearers: '1' + FireballEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2Version: 13.6.0 + PgwNodeEn: 'true' + S5Protocol: GTPv2 + Sessions: '100000' + SgiPtpTunnelEn: 'false' + SgwControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: SGW_CONTROL_IP # SGW-C TestNode IP address placeholder + mtu: 1500 + numLinksOrNodes: 1 + phy: SGW_CONTROL_PHY + SgwUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: SGW_USER_IP # SGW-U TestNode IP address placeholder + mtu: 1500 + numLinksOrNodes: 1 + phy: SGW_USER_PHY + TestType: SGW-NODE + TrafficMtu: '1500' +- tsId: SGW_NODAL_TS_NAME # SGW-Nodal test server name placeholder + testCases: + - name: '' + type: SGW_Nodal + parameters: + DataTraffic: Continuous + DataUserCfgFileEn: 'false' + DedicatedsPerDefaultBearer: '0' + DefaultBearers: '1' + DisconnectRate: '1000.0' + Dmf: + class: Dmf + mainflows: + - library: TEST_USER + name: Basic UDP + instanceGroups: + - mainflowIdx: 0 + mixType: '' + rate: 0 + startPaused: 'false' + EnbUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: ENB_USER_IP # eNodeB TestNode IP address placeholder + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: ENB_USER_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanUserPriority: 0 + vlanTagType: 0 + FireballEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2Version: 13.6.0 + MmeControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: MME_CONTROL_IP # MME TestNode IP address placeholder + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: MME_CONTROL_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanUserPriority: 0 + vlanTagType: 0 + NetworkHost: Local + NetworkHostAddrLocal: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: NET_HOST_IP # NetHost TestNode IP address placeholder + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: NET_HOST_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanUserPriority: 0 + vlanTagType: 0 + PgwNodeEn: 'false' + PgwUserSutEn: 'false' + PgwV4Sut: + class: Sut + name: PGW_SUT_NAME # PGW TestNode name placeholder + S5Protocol: GTPv2 + Sessions: '100000' + SgwSut: + class: Sut + name: SGW_CONTROL_NAME # SGW-C SUT name placeholder + SgwUserSut: + class: Sut + name: SGW_USER_NAME # SGW-U SUT name placeholder + StartRate: '1000.0' + TestActivity: Capacity Test + TestType: SGW-NODAL + TrafficMtu: '1500' + TrafficStartType: When All Sessions Established diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_session_default_bearer_multi_dmf.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_default_bearer_multi_dmf.yaml new file mode 100644 index 000000000..7b1f50160 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_default_bearer_multi_dmf.yaml @@ -0,0 +1,150 @@ +# 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. + +--- +description: 'UE default bearer creation test case' +name: default_bearer_capacity +keywords: '' +duration: 60 +tsGroups: +- tsId: SGW_NODE_TS_NAME # SGW-Node test server name placeholder + testCases: + - name: '' + type: SGW_Node + parameters: + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + DedicatedsPerDefaultBearer: '0' + DefaultBearers: '1' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2Version: 13.6.0 + PgwNodeEn: 'true' + S5Protocol: GTPv2 + Sessions: '100000' + SgiPtpTunnelEn: 'false' + SgwControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: SGW_CONTROL_IP # SGW-C TestNode IP address placeholder + mtu: 1500 + numLinksOrNodes: 1 + phy: SGW_CONTROL_PHY + SgwUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: SGW_USER_IP # SGW-U TestNode IP address placeholder + mtu: 1500 + numLinksOrNodes: 1 + phy: SGW_USER_PHY + TestType: SGW-NODE + TrafficMtu: '1500' +- tsId: SGW_NODAL_TS_NAME # SGW-Nodal test server name placeholder + testCases: + - name: '' + type: SGW_Nodal + parameters: + DataTraffic: Continuous + DataUserCfgFileEn: 'false' + DedicatedsPerDefaultBearer: '0' + DefaultBearers: '1' + DisconnectRate: '1000.0' + Dmf: + class: Dmf + mainflows: + - library: test + name: Basic UDP + - library: test + name: Basic TCP + instanceGroups: + - mainflowIdx: 0 + mixType: '' + rate: 0 + startPaused: 'false' + - mainflowIdx: 1 + mixType: '' + rate: 0 + startPaused: 'false' + EnbUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: ENB_USER_IP # eNodeB TestNode IP address placeholder + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: ENB_USER_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanUserPriority: 0 + vlanTagType: 0 + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2Version: 13.6.0 + MmeControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: MME_CONTROL_IP # MME TestNode IP address placeholder + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: MME_CONTROL_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanUserPriority: 0 + vlanTagType: 0 + NetworkHost: Local + NetworkHostAddrLocal: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: NET_HOST_IP # NetHost TestNode IP address placeholder + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: NET_HOST_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanUserPriority: 0 + vlanTagType: 0 + PgwNodeEn: 'false' + PgwUserSutEn: 'false' + PgwV4Sut: + class: Sut + name: PGW_SUT_NAME # PGW TestNode name placeholder + S5Protocol: GTPv2 + Sessions: '100000' + SgwSut: + class: Sut + name: SGW_CONTROL_NAME # SGW-C SUT name placeholder + SgwUserSut: + class: Sut + name: SGW_USER_NAME # SGW-U SUT name placeholder + StartRate: '1000.0' + TestActivity: Capacity Test + TestType: SGW-NODAL + TrafficMtu: '1500' + TrafficStartType: When All Sessions Established -- cgit 1.2.3-korg From 04429fcdfc3f0efea9b3055e8d1f1e3c0b6f06e2 Mon Sep 17 00:00:00 2001 From: Orest Voznyy Date: Sat, 28 Jul 2018 22:25:05 +0300 Subject: Add vEPC default bearers relocation test case This test case runs on Spirent Landslide TG. All vEPC entities are emulated on Landslide test servers. Test case actions sequence: - create default bearers - start sending traffic - partial/full bearers relocation between two ENodeB's, Intra-MME - disconnect all bearers JIRA: YARDSTICK-1354 Change-Id: I95c7b0001ddb363402013d83ae8617b88b2a4bd9 Signed-off-by: Orest Voznyy --- .../tc_epc_saegw_tput_relocation_landslide.yaml | 62 ++++++++ .../landslide_session_saegw_relocation.yaml | 177 +++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 samples/vnf_samples/nsut/vepc/tc_epc_saegw_tput_relocation_landslide.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_session_saegw_relocation.yaml diff --git a/samples/vnf_samples/nsut/vepc/tc_epc_saegw_tput_relocation_landslide.yaml b/samples/vnf_samples/nsut/vepc/tc_epc_saegw_tput_relocation_landslide.yaml new file mode 100644 index 000000000..cece2a747 --- /dev/null +++ b/samples/vnf_samples/nsut/vepc/tc_epc_saegw_tput_relocation_landslide.yaml @@ -0,0 +1,62 @@ +# 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. + +--- +schema: yardstick:task:0.1 +description: > + SAEGW throughput with relocation test case + +scenarios: +- type: NSPerf + traffic_profile: "../../traffic_profiles/landslide/landslide_dmf_udp.yaml" + session_profile: "../../traffic_profiles/landslide/landslide_session_saegw_relocation.yaml" + topology: "vepc_vnf_topology_landslide.yaml" + nodes: + tg__0: tg__0.traffic_gen + vnf__0: vnf__0.vnf_epc + options: + dmf: + transactionRate: 5 + packetSize: 512 + test_cases: # test case parameters to apply on session profile + - type: SGW_Node # test type from test session profile + AssociatedPhys: 'eth6' # interface(s) in Node test type to loop traffic back from NetHost + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + Sessions: '20000' + - type: SGW_Nodal # test type from test session profile + StartRate: '1000.0' + DisconnectRate: '1000.0' + Sessions: '20000' + # Relocation settings + HandoffType: '0' # 0 - X2, 1 - S1, 2 - TAU/RAU + MobilityTimeMs: '10000' # Mobility Delay Time (ms) + StartType: When All Sessions Started # When All Sessions Started or When Session Started + SessionRetries: 'true' # Enable/disable Session Start Retries + MobilityRate: '120.0' # Mobility Rate + MobilityMode: Single Handoff # Handoff Mode: Single Handoff or Continuous Handoff + MobilityIntervalShape: Fixed # Mobility Rate Interval Distribution + + runner: + type: Duration + duration: 300 + interval: 5 + +contexts: +- name: traffic_gen + type: Node + file: /etc/yardstick/nodes/pod_landslide.yaml +- name: vnf_epc + type: Node + file: /etc/yardstick/nodes/pod_vepc_sut.yaml diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_session_saegw_relocation.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_saegw_relocation.yaml new file mode 100644 index 000000000..f6daeee40 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_saegw_relocation.yaml @@ -0,0 +1,177 @@ +# 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. + +--- +description: SAEGW throughput with relocation test case +keywords: '' +duration: 60 +library: test +name: saegw_relocation +tsGroups: +- testCases: + - name: '' + type: SGW_Node + AssociatedPhys: '' + parameters: + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + BillingEn: 'false' + DedicatedsPerDefaultBearer: '0' + DefaultBearers: '1' + FireballEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2Version: 15.2.0 + PgwNodeEn: 'true' + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + Sessions: '20000' + SgiPtpTunnelEn: 'false' + SgwControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: SGW_CONTROL_IP + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + phy: SGW_CONTROL_PHY + SgwControlAddrErrInj: '0' + SgwUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + ip: SGW_USER_IP + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + phy: SGW_USER_PHY + SgwUserAddrErrInj: '0' + SgwUserDualStackEn: 'false' + TestType: SGW-NODE + TrafficMtu: '1400' + UeDhcpV4En: 'false' + tsId: SGW_NODE_TS_NAME +- testCases: + - name: '' + type: SGW_Nodal + parameters: + ApnDnsEn: 'false' + ApnToPgwMappingEn: 'false' + AutoStopControlLayer: 'false' + ContinuousWithVerification: 'false' + CtlBearerToDscpEn: 'false' + DataHostCfgFileEn: 'false' + DataResumeRate: '3000' + DataTraffic: Continuous + DataUserCfgFileEn: 'false' + DedicatedsPerDefaultBearer: '0' + DefaultBearers: '1' + DisconnectRate: '1000.0' + Dmf: + class: Dmf + instanceGroups: + - mainflowIdx: 0 + mixType: '' + rate: 0.0 + mainflows: + - library: test + name: Basic UDP + DualStackEn: 'false' + EnbUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: ENB_USER_IP + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + phy: ENB_USER_PHY + FireballEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2Version: 15.2.0 + HandoffType: '0' + HomeAddrType: '1' + HomeAddrTypePerBearerEn: 'false' + HssIfEn: 'false' + MmeControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: MME_CONTROL_IP + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + phy: MME_CONTROL_PHY + MmeControlAddrErrInj: '0' + MobEnbUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: TARGET_ENB_USER_IP + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + phy: TARGET_ENB_USER_PHY + MobEnbUserAddrErrInj: '0' + MobilityIntervalShape: Fixed + MobilityMode: Single Handoff + MobilityRate: '1.0' + MobilityTimeMs: '10000' + MultipathTcpEn: 'false' + NetworkHost: Local + NetworkHostAddrLocal: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: NET_HOST_IP + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + phy: NET_HOST_PHY + NetworkHostAddrLocalErrInj: '0' + NetworkHostNatedTrafficEn: 'false' + PgwNodeEn: 'false' + PgwUserSutEn: 'false' + PgwV4Sut: + class: Sut + name: PGW_SUT_NAME + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + SecPgwV4SutEn: 'false' + SessionIntervalShape: Fixed + SessionRetries: 'true' + Sessions: '20000' + SgwNumSutsEn: 'false' + SgwRelocationEn: 'false' + SgwSut: + class: Sut + name: SGW_CONTROL_NAME + SgwUserSut: + class: Sut + name: SGW_USER_NAME + StartRate: '1000.0' + StartType: When All Sessions Started + TestActivity: Intra-MME Mobility + TestType: SGW-NODAL + TrafficMtu: '1400' + TrafficStartDelay: '1000' + TrafficStartType: When Session Established + tsId: SGW_NODAL_TS_NAME -- cgit 1.2.3-korg From c5841cf2694247dd9f63df362d742f0902439ecc Mon Sep 17 00:00:00 2001 From: Orest Voznyy Date: Thu, 13 Sep 2018 13:30:08 +0300 Subject: Add vEPC infrastructure for Landslide TG 1. Add yardstick topology and model for fully emulated environment. 2. Add support for black-box testing of real vEPC VNF vs Spirent Landslide traffic generator: - vEPC VNF pod file - topology and model files aware of vEPC VNF connection to Spirent Landslide TG - stub class for vEPC VNF, and related unit tests JIRA: YARDSTICK-1424 Change-Id: If7b6d19919679347c4360f4a0f2e420716e7fd2d Signed-off-by: Orest Voznyy --- etc/yardstick/nodes/standalone/pod_vepc_sut.yaml | 37 +++++++++ .../nsut/vepc/landslide_tg_topology.yaml | 50 ++++++++++++ .../nsut/vepc/vepc_vnf_topology_landslide.yaml | 50 ++++++++++++ .../vnf_descriptors/tg_landslide_tpl.yaml | 38 +++++++++ samples/vnf_samples/vnf_descriptors/vepc_vnf.yaml | 38 +++++++++ .../network_services/vnf_generic/vnf/epc_vnf.py | 53 ++++++++++++ .../vnf_generic/vnf/test_epc_vnf.py | 94 ++++++++++++++++++++++ 7 files changed, 360 insertions(+) create mode 100644 etc/yardstick/nodes/standalone/pod_vepc_sut.yaml create mode 100644 samples/vnf_samples/nsut/vepc/landslide_tg_topology.yaml create mode 100644 samples/vnf_samples/nsut/vepc/vepc_vnf_topology_landslide.yaml create mode 100644 samples/vnf_samples/vnf_descriptors/tg_landslide_tpl.yaml create mode 100644 samples/vnf_samples/vnf_descriptors/vepc_vnf.yaml create mode 100644 yardstick/network_services/vnf_generic/vnf/epc_vnf.py create mode 100644 yardstick/tests/unit/network_services/vnf_generic/vnf/test_epc_vnf.py diff --git a/etc/yardstick/nodes/standalone/pod_vepc_sut.yaml b/etc/yardstick/nodes/standalone/pod_vepc_sut.yaml new file mode 100644 index 000000000..8467303e9 --- /dev/null +++ b/etc/yardstick/nodes/standalone/pod_vepc_sut.yaml @@ -0,0 +1,37 @@ +# 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. +--- +# Sample config file for fully emulated EPC environment + + +nodes: +- + name: "vnf__0" + role: vnf__0 + ip: 192.168.122.200 + user: user + password: password + interfaces: # dummy config + xe0: + vpci: "0000:05:00.0" + local_mac: "68:05:ca:30:3d:50" + driver: "i40e" + local_ip: "152.16.100.19" + netmask: "255.255.255.0" + xe1: + vpci: "0000:05:00.1" + local_mac: "68:05:ca:30:3d:51" + driver: "i40e" + local_ip: "152.16.40.19" + netmask: "255.255.255.0" diff --git a/samples/vnf_samples/nsut/vepc/landslide_tg_topology.yaml b/samples/vnf_samples/nsut/vepc/landslide_tg_topology.yaml new file mode 100644 index 000000000..ccf496bf9 --- /dev/null +++ b/samples/vnf_samples/nsut/vepc/landslide_tg_topology.yaml @@ -0,0 +1,50 @@ +# 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. + +nsd:nsd-catalog: + nsd: + - id: landslide-tg-topology + name: landslide-tg-topology + short-name: landslide-tg-topology + description: landslide-tg-topology + constituent-vnfd: + - member-vnf-index: '1' + vnfd-id-ref: tg__0 + VNF model: ../../vnf_descriptors/tg_landslide_tpl.yaml #TG type + - member-vnf-index: '2' + vnfd-id-ref: vnf__0 + VNF model: ../../vnf_descriptors/tg_landslide_tpl.yaml #VNF type: Emulated vEPC + + vld: + - id: uplink_0 + name: tg__0 to vnf__0 link 1 + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: tg__0 + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: vnf__0 + + - id: downlink_0 + name: vnf__0 to tg__0 link 2 + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: xe1 + vnfd-id-ref: vnf__0 + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: xe1 + vnfd-id-ref: tg__0 diff --git a/samples/vnf_samples/nsut/vepc/vepc_vnf_topology_landslide.yaml b/samples/vnf_samples/nsut/vepc/vepc_vnf_topology_landslide.yaml new file mode 100644 index 000000000..f54cdaf81 --- /dev/null +++ b/samples/vnf_samples/nsut/vepc/vepc_vnf_topology_landslide.yaml @@ -0,0 +1,50 @@ +# 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. + +nsd:nsd-catalog: + nsd: + - id: vEPC + name: vEPC + short-name: vEPC + description: vEPC VNF with Spirent landslide TG + constituent-vnfd: + - member-vnf-index: '1' + vnfd-id-ref: tg__0 + VNF model: ../../vnf_descriptors/tg_landslide_tpl.yaml #TG type + - member-vnf-index: '2' + vnfd-id-ref: vnf__0 + VNF model: ../../vnf_descriptors/vepc_vnf.yaml #VNF type + + vld: + - id: uplink_0 + name: tg__0 to vnf__0 link 1 + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: tg__0 + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: vnf__0 + + - id: downlink_0 + name: vnf__0 to tg__0 link 2 + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: xe1 + vnfd-id-ref: vnf__0 + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: xe1 + vnfd-id-ref: tg__0 diff --git a/samples/vnf_samples/vnf_descriptors/tg_landslide_tpl.yaml b/samples/vnf_samples/vnf_descriptors/tg_landslide_tpl.yaml new file mode 100644 index 000000000..48963f0a9 --- /dev/null +++ b/samples/vnf_samples/vnf_descriptors/tg_landslide_tpl.yaml @@ -0,0 +1,38 @@ +# 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. + +vnfd:vnfd-catalog: + vnfd: + - id: LandslideTrafficGen # NSB python class mapping + name: LandslideTrafficGen + short-name: landslide + description: Spirent Landslide traffic generator + mgmt-interface: + vdu-id: landslide-tas + super-user: '{{tas_manager.super_user}}' + super-user-password: '{{tas_manager.super_user_password}}' + user: '{{tas_manager.test_user}}' + password: '{{tas_manager.test_user_password}}' + cfguser_password: '{{tas_manager.cfguser_password}}' + ip: '{{tas_manager.ip}}' + proto: '{{tas_manager.proto}}' # protocol used for REST API- http + license: '{{tas_manager.license}}' # Landslide license + config: {{config}} + vdu: + - id: abclient-baremetal + name: abclient-baremetal + description: AB client interface details + benchmark: + kpi: [] + diff --git a/samples/vnf_samples/vnf_descriptors/vepc_vnf.yaml b/samples/vnf_samples/vnf_descriptors/vepc_vnf.yaml new file mode 100644 index 000000000..73d3468bf --- /dev/null +++ b/samples/vnf_samples/vnf_descriptors/vepc_vnf.yaml @@ -0,0 +1,38 @@ +# 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. + +vnfd:vnfd-catalog: + vnfd: + - id: EPCVnf # NSB python class mapping + name: EPCVnf + short-name: EPCVnf + description: EPCVnf + mgmt-interface: + vdu-id: vepcvnf-baremetal + {% if user is defined %} + user: '{{user}}' # Value filled by vnfdgen + {% endif %} + {% if password is defined %} + password: '{{password}}' # Value filled by vnfdgen + {% endif %} + {% if ip is defined %} + ip: '{{ip}}' # Value filled by vnfdgen + {% endif %} + vdu: + - id: vepcvnf-baremetal + name: vepc-vnf-baremetal + description: vEPCVnf workload + external-interface: [] + benchmark: + kpi: [] diff --git a/yardstick/network_services/vnf_generic/vnf/epc_vnf.py b/yardstick/network_services/vnf_generic/vnf/epc_vnf.py new file mode 100644 index 000000000..66d16d07f --- /dev/null +++ b/yardstick/network_services/vnf_generic/vnf/epc_vnf.py @@ -0,0 +1,53 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from yardstick.network_services.vnf_generic.vnf import base + +LOG = logging.getLogger(__name__) + + +class EPCVnf(base.GenericVNF): + + def __init__(self, name, vnfd, task_id): + super(EPCVnf, self).__init__(name, vnfd, task_id) + + def instantiate(self, scenario_cfg, context_cfg): + """Prepare VNF for operation and start the VNF process/VM + + :param scenario_cfg: Scenario config + :param context_cfg: Context config + """ + pass + + def wait_for_instantiate(self): + """Wait for VNF to start""" + pass + + def terminate(self): + """Kill all VNF processes""" + pass + + def scale(self, flavor=""): + pass + + def collect_kpi(self): + pass + + def start_collect(self): + pass + + def stop_collect(self): + pass diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_epc_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_epc_vnf.py new file mode 100644 index 000000000..6d14ddb54 --- /dev/null +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_epc_vnf.py @@ -0,0 +1,94 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import copy +import unittest +import uuid + +from yardstick.network_services.vnf_generic.vnf import epc_vnf + +NAME = 'vnf__0' + +VNFD = { + 'vnfd:vnfd-catalog': { + 'vnfd': [{ + 'id': 'EPCVnf', # NSB python class mapping + 'name': 'EPCVnf', + 'short-name': 'EPCVnf', + 'description': 'EPCVnf', + 'mgmt-interface': { + 'vdu-id': 'vepcvnf-baremetal', + 'user': 'user', # Value filled by vnfdgen + 'password': 'password', # Value filled by vnfdgen + 'ip': 'ip' # Value filled by vnfdgen + }, + 'vdu': [{ + 'id': 'vepcvnf-baremetal', + 'name': 'vepc-vnf-baremetal', + 'description': 'vEPCVnf workload', + 'external-interface': []}], + 'benchmark': { + 'kpi': []}}]}} + + +class TestEPCVnf(unittest.TestCase): + + def setUp(self): + self._id = uuid.uuid1().int + self.vnfd = VNFD['vnfd:vnfd-catalog']['vnfd'][0] + self.epc_vnf = epc_vnf.EPCVnf(NAME, self.vnfd, self._id) + + def test___init__(self, *args): + _epc_vnf = epc_vnf.EPCVnf(NAME, self.vnfd, self._id) + for x in {'user', 'password', 'ip'}: + self.assertEqual(self.vnfd['mgmt-interface'][x], + _epc_vnf.vnfd_helper.mgmt_interface[x]) + self.assertEqual(NAME, _epc_vnf.name) + self.assertEqual([], _epc_vnf.kpi) + self.assertEqual({}, _epc_vnf.config) + self.assertFalse(_epc_vnf.runs_traffic) + + def test___init__missing_ip(self, *args): + _vnfd = copy.deepcopy(self.vnfd) + _vnfd['mgmt-interface'].pop('ip') + _epc_vnf = epc_vnf.EPCVnf(NAME, _vnfd, self._id) + for x in {'user', 'password'}: + self.assertEqual(_vnfd['mgmt-interface'][x], + _epc_vnf.vnfd_helper.mgmt_interface[x]) + self.assertNotIn('ip', _epc_vnf.vnfd_helper.mgmt_interface) + self.assertEqual(NAME, _epc_vnf.name) + self.assertEqual([], _epc_vnf.kpi) + self.assertEqual({}, _epc_vnf.config) + self.assertFalse(_epc_vnf.runs_traffic) + + def test_instantiate(self): + self.assertIsNone(self.epc_vnf.instantiate({}, {})) + + def test_wait_for_instantiate(self): + self.assertIsNone(self.epc_vnf.wait_for_instantiate()) + + def test_terminate(self): + self.assertIsNone(self.epc_vnf.terminate()) + + def test_scale(self): + self.assertIsNone(self.epc_vnf.scale()) + + def test_collect_kpi(self): + self.assertIsNone(self.epc_vnf.collect_kpi()) + + def test_start_collect(self): + self.assertIsNone(self.epc_vnf.start_collect()) + + def test_stop_collect(self): + self.assertIsNone(self.epc_vnf.stop_collect()) -- cgit 1.2.3-korg From e75c8b0e022795f00846b1f460022f12f0d52b3e Mon Sep 17 00:00:00 2001 From: Orest Voznyy Date: Fri, 14 Sep 2018 21:49:47 +0300 Subject: Add UE initiated dedicated bearer creation test Adding session profile and test case file. JIRA: YARDSTICK-1353 Change-Id: Iaa98fd8cb3ed243f9ac157089de32fa23ec0e6b4 Signed-off-by: Orest Voznyy --- ...c_epc_ue_dedicated_bearer_create_landslide.yaml | 74 +++++ .../landslide_session_ue_dedicated_bearer.yaml | 353 +++++++++++++++++++++ 2 files changed, 427 insertions(+) create mode 100644 samples/vnf_samples/nsut/vepc/tc_epc_ue_dedicated_bearer_create_landslide.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_session_ue_dedicated_bearer.yaml diff --git a/samples/vnf_samples/nsut/vepc/tc_epc_ue_dedicated_bearer_create_landslide.yaml b/samples/vnf_samples/nsut/vepc/tc_epc_ue_dedicated_bearer_create_landslide.yaml new file mode 100644 index 000000000..81a4149f8 --- /dev/null +++ b/samples/vnf_samples/nsut/vepc/tc_epc_ue_dedicated_bearer_create_landslide.yaml @@ -0,0 +1,74 @@ +# 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. + +--- +schema: yardstick:task:0.1 +description: > + UE triggered dedicated bearer creation test case. Measure successful dedicated bearers + creation rate, total number of active bearer per server. + +scenarios: +- type: NSPerf + traffic_profile: "../../traffic_profiles/landslide/landslide_dmf_udp.yaml" + session_profile: "../../traffic_profiles/landslide/landslide_session_ue_dedicated_bearer.yaml" + topology: "vepc_vnf_topology_landslide.yaml" + nodes: + tg__0: tg__0.traffic_gen + vnf__0: vnf__0.vnf_epc + options: + dmf: + transactionRate: 5 + packetSize: 512 + burstCount: 1 # Applies only to Basic UDP DMF, DataProtocol==udp + test_cases: # test case parameters to apply on session profile + - type: SGW_Node # test type from test session profile + AssociatedPhys: 'eth6' # interface(s) in Node test type to loop traffic back from NetHost + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + Sessions: '20000' + UeInitBearerEn: 'true' + DedicatedsPerDefaultBearer: 1 # number of dedicated bearers per default + DefaultBearers: 1 # number of default bearers + + # Fireball settings + FireballEn: 'false' + + - type: SGW_Nodal # test type from test session profile + StartRate: '1000.0' + DisconnectRate: '1000.0' + Sessions: '20000' + UeInitBearerEn: 'true' + DedicatedsPerDefaultBearer: '1' # number of dedicated bearers per default + DefaultBearers: '1' # number of default bearers + + # Connection delay individually for each dedicated bearer + ConnectBearerDelay: + class: Array + array: ['5'] + + # Fireball settings + FireballEn: 'false' + + runner: + type: Duration + duration: 300 + interval: 5 + +contexts: +- name: traffic_gen + type: Node + file: /etc/yardstick/nodes/pod_landslide.yaml +- name: vnf_epc + type: Node + file: /etc/yardstick/nodes/pod_vepc_sut.yaml diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_session_ue_dedicated_bearer.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_ue_dedicated_bearer.yaml new file mode 100644 index 000000000..ace6e0258 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_ue_dedicated_bearer.yaml @@ -0,0 +1,353 @@ +# 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. + +--- +description: 'UE initiated dedicated bearer creation test case' +duration: 60 +keywords: '' +library: test +name: capacity_dedicated_bearer_creation +tsGroups: +- testCases: + - name: '' + AssociatedPhys: '' + parameters: + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + BillingEn: 'false' + DedicatedsPerDefaultBearer: '1' + DefaultBearers: '1' + FireballEn: 'false' + Gtp2AmbrDownlink: '1' + Gtp2AmbrUplink: '1' + Gtp2ApnNumSpecifiedApns_0: '0' + Gtp2ApnRestriction: '0' + Gtp2ApnRetries_0: '0' + Gtp2ApnSelectMode: '0' + Gtp2ApnSpecified_0: + array: [] + class: Array + Gtp2ApnTotalApns_0: '1' + Gtp2Apn_0: ssenoauth146 + Gtp2CfgFileEn: 'false' + Gtp2Ecgi: '0' + Gtp2EcgiSize: '28' + Gtp2EchoTimeSec: '0' + Gtp2ExtEn: 'false' + Gtp2GtpcTunnelEndptId: '1000000' + Gtp2GtpuIncludeSeqEn: 'true' + Gtp2GtpuTunnelEndptId: '2000000' + Gtp2IgnoreRestartCtrEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2IncCgiEn: 'false' + Gtp2IncEcgiEn: 'true' + Gtp2IncRaiEn: 'false' + Gtp2IncSaiEn: 'false' + Gtp2IncTaiEn: 'true' + Gtp2MacroEnbEn: 'false' + Gtp2Mcc: '000' + Gtp2Mnc: '000' + Gtp2MobGtpuForwardingEndptId: '5000000' + Gtp2MsIsdnEn: 'false' + Gtp2N3Attempts: '5' + Gtp2PagingTimeMs: '0' + Gtp2PersistentImsiEn: 'false' + Gtp2PiggybackEn_sgw: '0' + Gtp2QosArpPreemptCapEn_1: 'false' + Gtp2QosArpPreemptVulnEn_1: 'false' + Gtp2QosArpValue_1: '1' + Gtp2QosClassId_1: '1' + Gtp2QosDetail: Summary + Gtp2QosGuarDownlink_1: '1' + Gtp2QosGuarUplink_1: '1' + Gtp2QosMaxDownlink_1: '1' + Gtp2QosMaxUplink_1: '1' + Gtp2RadioAccessType: '6' + Gtp2ResponseDelayEn: 'false' + Gtp2RestartCnt: '1' + Gtp2RouterAdDelay: '1' + Gtp2S5GtpcTunnelEndptId: '3000000' + Gtp2S5GtpuTunnelEndptId: '4000000' + Gtp2SupportMabrEn: 'false' + Gtp2T3Time: '20' + Gtp2Tac: '0' + Gtp2Version: 15.2.0 + PgwNodeEn: 'true' + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + Sessions: '1000' + SgiPtpTunnelEn: 'false' + SgwControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: SGW_CONTROL_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: eth5 + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + SgwControlAddrErrInj: '0' + SgwUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: SGW_USER_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: eth5 + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + SgwUserAddrErrInj: '0' + SgwUserDualStackEn: 'false' + SxaControlNodeAddrXPort: '8805' + SxaUserNodeAddrXPort: '8805' + TestType: SGW-NODE + TrafficMtu: '1400' + TrafficNumTftsForContext0: '1' + UeDhcpV4En: 'false' + UeInitBearerEn: 'false' + type: SGW_Node + tsId: SGW_NODE_TS_NAME +- testCases: + - name: '' + parameters: + ApnDnsEn: 'false' + ApnToPgwMappingEn: 'false' + AutoStopControlLayer: 'false' + ContinuousWithVerification: 'false' + CpCiotEpsOptimizationEn: 'false' + CtlBearerToDscpEn: 'false' + DataHostCfgFileEn: 'false' + DataResumeRate: '3000' + DataTraffic: Continuous + DataUserCfgFileEn: 'false' + DedBearerConnectDelay: '0' + DedBearerDisconnectDelay: '0' + DedicatedBearerConnectRateEn: 'false' + DedicatedBearerDisconnectRateEn: 'false' + DedicatedsPerDefaultBearer: '1' + DefaultBearers: '1' + DisconnectDedicatedBearerEn: 'false' + DisconnectRate: '1000.0' + Dmf: + class: Dmf + instanceGroups: + - mainflowIdx: 0 + mixType: '' + rate: 0.0 + rows: + - clientPort: 0 + context: 0 + node: 0 + overridePort: 'false' + ratingGroup: 0 + role: 0 + serviceId: 0 + transport: Any + mainflows: + - library: test + name: Basic UDP + DualStackEn: 'false' + EDrxValueEn: 'false' + EirIfEn: 'false' + EmergencyAttachWithImeiEn: 'false' + EmergencyAttachWoAuthEn: 'false' + EmergencyPdnIndexEn: 'false' + EnableExternalData: '0' + EnbUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: ENB_USER_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: eth5 + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + EnbUserAddrErrInj: '0' + FireballEn: 'false' + Gtp2ActivationDelay: '0' + Gtp2AmbrDownlink: '1' + Gtp2AmbrUplink: '1' + Gtp2ApnNumSpecifiedApns_0: '0' + Gtp2ApnNumSpecifiedApns_1: '0' + Gtp2ApnRestriction: '0' + Gtp2ApnRetries_0: '0' + Gtp2ApnRetries_1: '0' + Gtp2ApnSelectMode: '0' + Gtp2ApnSpecified_0: + array: [] + class: Array + Gtp2ApnSpecified_1: + array: [] + class: Array + Gtp2ApnTotalApns_0: '1' + Gtp2ApnTotalApns_1: '1' + Gtp2Apn_0: ssenoauth146 + Gtp2Apn_1: ssenoauth146 + Gtp2BearerModEn: 'false' + Gtp2CfgFileEn: 'false' + Gtp2ChargingChars: '0x0' + Gtp2DelayDlPacketNotifReq: '1' + Gtp2Ecgi: '0' + Gtp2EcgiSize: '28' + Gtp2EchoTimeSec: '0' + Gtp2EnbUliEn: 'false' + Gtp2ExtEn: 'false' + Gtp2FwdUplinkDataEcmIdle: 'false' + Gtp2GtpcTunnelEndptId: '1000000' + Gtp2GtpuIncludeSeqEn: 'true' + Gtp2GtpuTunnelEndptId: '2000000' + Gtp2IdleEntryTime: '0' + Gtp2IgnoreRestartCtrEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2IncCgiEn: 'false' + Gtp2IncEcgiEn: 'true' + Gtp2IncPcoOpt: none + Gtp2IncRaiEn: 'false' + Gtp2IncSaiEn: 'false' + Gtp2IncTaiEn: 'true' + Gtp2MacroEnbEn: 'false' + Gtp2MaxWaitTimeEn: 'false' + Gtp2Mcc: '000' + Gtp2Mnc: '000' + Gtp2ModBearerDlDataDelay: '0' + Gtp2MsIsdnEn: 'false' + Gtp2N3Attempts: '5' + Gtp2PagingTimeMs: '0' + Gtp2PcoAddEn: 'false' + Gtp2PcoIpcpEn: 'false' + Gtp2QosArpPreemptCapEn_1: 'false' + Gtp2QosArpPreemptVulnEn_1: 'false' + Gtp2QosArpValue_1: '1' + Gtp2QosClassId_1: '1' + Gtp2QosDetail: Summary + Gtp2QosGuarDownlink_1: '1' + Gtp2QosGuarUplink_1: '1' + Gtp2QosMaxDownlink_1: '1' + Gtp2QosMaxUplink_1: '1' + Gtp2RadioAccessType: '6' + Gtp2RejectDedEn: 'false' + Gtp2RemoteUeReportTime: '0' + Gtp2RestartCnt: '1' + Gtp2SupportMabrEn: 'false' + Gtp2SwVersionEn: 'false' + Gtp2T3Time: '20' + Gtp2Tac: '0' + Gtp2UeDaySaveTime: '0' + Gtp2UeMultPdnConnReqSameApnEn_0: 'false' + Gtp2UeTimeZone: '0' + Gtp2UliDbCmdCbRspEn: 'true' + Gtp2Version: 15.2.0 + HomeAddrType: '1' + HomeAddrTypePerBearerEn: 'false' + HssIfEn: 'false' + MmeControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: MME_CONTROL_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: eth5 + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + MmeControlAddrErrInj: '0' + MultipathTcpEn: 'false' + NetworkHost: Local + NetworkHostAddrLocal: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: NET_HOST_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: eth5 + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + NetworkHostAddrLocalErrInj: '0' + NetworkHostNatedTrafficEn: 'false' + PgwNodeEn: 'false' + PgwUserSutEn: 'false' + PgwV4Sut: + class: Sut + name: PGW_SUT_NAME + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + SecPgwV4SutEn: 'false' + SessionIntervalShape: Fixed + SessionRetries: 'true' + Sessions: '1000' + SgwNumSutsEn: 'false' + SgwSut: + class: Sut + name: SGW_CONTROL_NAME + SgwUserSut: + class: Sut + name: SGW_USER_NAME + StartRate: '1000.0' + T3324PwrSavingValueEn: 'false' + T3412ExValueEn: 'false' + TestActivity: Capacity Test + TestType: SGW-NODAL + TrafficDontFragIp: '0' + TrafficErrorInject: '0' + TrafficHostIdleTimeEnabler: 'false' + TrafficMtu: '1400' + TrafficNumTftsForContext0: '1' + TrafficStartDelay: '1000' + TrafficStartType: When All Sessions Established + UeDhcpV4En: 'false' + UeInitBearerEn: 'true' + UseStaticBearerIp: 'false' + type: SGW_Nodal + tsId: SGW_NODAL_TS_NAME -- cgit 1.2.3-korg From bca0f482bf50c3bd04a96751de837c537b46c259 Mon Sep 17 00:00:00 2001 From: Orest Voznyy Date: Fri, 14 Sep 2018 21:27:41 +0300 Subject: Add network initiated dedicated bearers creation Adding related pod file, session profile and testcase file. JIRA: YARDSTICK-1355 Change-Id: Ic97d59ef3a36ac05c6c369c36f917ae95d18d863 Signed-off-by: Orest Voznyy --- .../pod_landslide_network_dedicated.yaml | 164 +++++ ..._network_dedicated_bearer_create_landslide.yaml | 164 +++++ ...landslide_session_network_dedicated_bearer.yaml | 681 +++++++++++++++++++++ 3 files changed, 1009 insertions(+) create mode 100644 etc/yardstick/nodes/standalone/pod_landslide_network_dedicated.yaml create mode 100644 samples/vnf_samples/nsut/vepc/tc_epc_network_dedicated_bearer_create_landslide.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_session_network_dedicated_bearer.yaml diff --git a/etc/yardstick/nodes/standalone/pod_landslide_network_dedicated.yaml b/etc/yardstick/nodes/standalone/pod_landslide_network_dedicated.yaml new file mode 100644 index 000000000..6b8db54c2 --- /dev/null +++ b/etc/yardstick/nodes/standalone/pod_landslide_network_dedicated.yaml @@ -0,0 +1,164 @@ +# 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. + + +nodes: +- + name: "tg__0" + role: tg__0 + tas_manager: + ip: 192.168.122.100 + super_user: sms + super_user_password: a1b2c3d4 + cfguser_password: cfguser + test_user: demoaff + test_user_password: demo123 + proto: http + license: 49 + interfaces: # dummy config + xe0: + vpci: "0000:05:00.0" + local_mac: "68:05:ca:30:3d:50" + driver: "i40e" + local_ip: "152.16.100.19" + netmask: "255.255.255.0" + xe1: + vpci: "0000:05:00.1" + local_mac: "68:05:ca:30:3d:51" + driver: "i40e" + local_ip: "152.16.40.19" + netmask: "255.255.255.0" + config: + - test_server: + name: TestServer_1 + role: SGW_Node + ip: 192.168.122.101 + # override port-subnet and static route reservation information for this + # test server within the test session. + thread_model: Fireball + phySubnets: + - base: 10.42.32.100 + mask: "/24" + name: &ts1_port1 eth5 + numIps: 20 + - base: 10.42.33.100 + mask: "/24" + name: &ts1_port2 eth6 + numIps: 20 + suts: + - name: SGW-C TestNode + role: SgwControlAddr + managementIp: 12.0.1.1 + phy: *ts1_port1 + ip: 10.42.32.100 + # nextHop: '' + - name: SGW-U TestNode + role: SgwUserAddr + managementIp: 12.0.1.2 + phy: *ts1_port1 + ip: 10.42.32.101 + # nextHop: '' + - name: PGW-C SUT + role: PgwSut + managementIp: 12.0.5.2 + phy: *ts1_port1 + ip: 10.42.32.108 + # nextHop: '' + + - test_server: + name: TestServer_1 + role: PGW_Node + ip: 192.168.122.101 + # override port-subnet and static route reservation information for this + # test server within the test session. + suts: + - name: PDN GW TestNode + role: PdnGwAddr + managementIp: 12.0.5.1 + phy: *ts1_port1 + ip: 10.42.32.103 + nextHop: '' + - name: AGW TestNode + role: AgwNodeAddr + managementIp: 12.0.7.2 + phy: *ts1_port1 + ip: 10.42.32.107 + nextHop: '' + - name: PCRF SUT + role: TyCcClnSutPrimarySrv + managementIp: 12.0.7.1 + ip: 10.42.32.95 + + - test_server: + name: TestServer_2 + role: SGW_Nodal + ip: 192.168.122.102 + # override port-subnet and static route reservation information for this + # test server within the test session. + thread_model: Fireball + phySubnets: + - base: 10.42.32.1 + mask: "/24" + name: &ts2_port1 eth5 + numIps: 100 + - base: 10.42.33.1 + mask: "/24" + name: &ts2_port2 eth6 + numIps: 50 + suts: + - name: eNodeB TestNode + role: EnbUserAddr + managementIp: 12.0.2.1 + phy: *ts2_port1 + ip: 10.42.32.2 + nextHop: '' + - name: MME TestNode + role: MmeControlAddr + managementIp: 12.0.3.1 + phy: *ts2_port1 + ip: 10.42.32.1 + nextHop: '' + - name: NetHost TestNode + role: NetworkHostAddrLocal + managementIp: 12.0.4.1 + phy: *ts2_port2 + ip: 10.42.33.1 + nextHop: '' + - name: PGW-C SUT + role: PgwV4Sut + managementIp: 12.0.5.1 + ip: 10.42.32.103 + - name: SGW-C SUT + role: SgwSut + managementIp: 12.0.1.1 + ip: 10.42.32.100 + - name: SGW-U SUT + role: SgwUserSut + managementIp: 12.0.1.2 + ip: 10.42.32.101 + + - test_server: + name: TestServer_2 + role: PCRF_Node + ip: 192.168.122.102 + # override port-subnet and static route reservation information for this + # test server within the test session. + suts: + - name: AgwSrvNode TestNode + role: AgwSrvNode + managementIp: 12.0.7.1 + phy: *ts2_port1 + ip: 10.42.32.95 + nextHop: '' + diff --git a/samples/vnf_samples/nsut/vepc/tc_epc_network_dedicated_bearer_create_landslide.yaml b/samples/vnf_samples/nsut/vepc/tc_epc_network_dedicated_bearer_create_landslide.yaml new file mode 100644 index 000000000..65f58bd0d --- /dev/null +++ b/samples/vnf_samples/nsut/vepc/tc_epc_network_dedicated_bearer_create_landslide.yaml @@ -0,0 +1,164 @@ +# 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. + +--- +schema: yardstick:task:0.1 +description: > + NW triggered dedicated bearer creation test case. Measure successful dedicated bearers + creation rate, total number of active bearer per server. + +scenarios: +- type: NSPerf + traffic_profile: "../../traffic_profiles/landslide/landslide_dmf_udp.yaml" + session_profile: "../../traffic_profiles/landslide/landslide_session_network_dedicated_bearer.yaml" + topology: "vepc_vnf_topology_landslide.yaml" + nodes: + tg__0: tg__0.traffic_gen + vnf__0: vnf__0.vnf_epc + options: + dmf: + transactionRate: 5 + packetSize: 512 + burstCount: 1 # Applies only to Basic UDP DMF, DataProtocol==udp + test_cases: # test case parameters to apply on session profile + - type: SGW_Node # test type from test session profile + AssociatedPhys: 'eth6' # interface(s) in Node test type to loop traffic back from NetHost + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + Sessions: 50000 + UeInitBearerEn: 'false' + DedicatedsPerDefaultBearer: 1 # number of dedicated bearers per default + DefaultBearers: 1 # number of default bearers + FireballEn: 'false' # Fireball settings + + # APN settings (number of APNs and APN's names) + Gtp2ApnNumSpecifiedApns_0: '1' + Gtp2ApnSpecified_0: + array: [dummy.an] + class: Array + + - type: PGW_Node # test type from test session profile + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + Sessions: 50000 + DedicatedsPerDefaultBearer: 1 # number of dedicated bearers per default + DefaultBearers: 1 # number of default bearers + FireballEn: 'false' # Fireball settings + + # APN settings (number of APNs and APN's names) + Gtp2ApnNumSpecifiedApns_0: '1' + Gtp2ApnSpecified_0: + class: Array + array: [dummy.an] + + - type: SGW_Nodal # test type from test session profile + StartRate: '1000.0' + DisconnectRate: '1000.0' + Sessions: 50000 + UeInitBearerEn: 'false' + DedicatedsPerDefaultBearer: 1 # number of dedicated bearers per default + DefaultBearers: 1 # number of default bearers + PgwNodeEn: 'false' # Emulate PGW Node + FireballEn: 'false' # Fireball settings + + # APN settings (number of APNs and APN's names) + Gtp2ApnNumSpecifiedApns_0: '1' + Gtp2ApnSpecified_0: + class: Array + array: [dummy.an] + + # Creation delay individually for each dedicated bearer + # Array items specifies timeout between default and dedicated bearers creation + # Array items corresponds to specific dedicated bearer + ConnectBearerDelay: + class: Array + array: ['1'] + + - type: PCRF_Node # test type from test session profile + Sessions: 50000 + DisconnectRate: '1000' + + # Starting IP address + StartingMsIpAddr: 1.0.0.1 + + # APN settings (APN's Names) + TyCcSrvApns: + class: Array + array: [dummy.an] + + # Timer column (in seconds) + # Value specifies timeout after which dedicated bearer will be created + # None-zero timeout corresponds to dedicated bearer, zero timeout - to default bearer + TyCcV4SrvRuleInterval_1: '10' # APN1 dedicated bearer + TyCcV4SrvRuleInterval_2: '0' # APN1 default bearer + + # QoS Class ID + # Name Pattern: TyCcV4SrvCrQci___ + TyCcV4SrvCrQci_1_1_1: '1' # QCI of dedicated bearer + + # Dedicated bearer Uplink/Downlink Bandwidth settings + # Name Pattern: TyCcV4SrvPrMaxUL___ + # Name Pattern: TyCcV4SrvPrGuaranteedUplink___ + TyCcV4SrvPrMaxUL_1_1_1: '300' # Uplink Max Bandwidth + TyCcV4SrvPrMaxDL_1_1_1: '300' # Downlink Max Bandwidth + TyCcV4SrvPrGuaranteedUplink_1_1_1: '300' # Uplink Guaranteed Bandwidth + TyCcV4SrvPrGuaranteedDownlink_1_1_1: '300' # Downlink Guaranteed Bandwidth + + # Dedicated bearer ARP Rules + # Name Pattern: TyCcV4SrvPrArpEn___ + # Name Pattern: TyCcV4SrvPrArpValue___ + TyCcV4SrvPrArpEn_1_1_1: 'true' # Enable ARP Rules + TyCcV4SrvPrArpValue_1_1_1: '1' # ARP Value + TyCcV4SrvPrArpPreemptCapEn_1_1_1: 'true' # Enable Pre-emption Capability + TyCcV4SrvPrArpPreemptVulnEn_1_1_1: 'true' # Enable Pre-emption Vulnerability + + # Packet Filter Description + # Name Pattern: + # TyCcV4SrvCrFilter____ + # To explicitly specify protocol number with decimal number, use following naming pattern: + # permit in from + TyCcV4SrvCrFilter_1_1_1_1: permit in 17 from + + # Packet Filter Destination IP + # Name Pattern: + # TyCcV4SrvCrFilterDestIp____ + # Parameter's value specifies filter's destination IP address and remote port range + TyCcV4SrvCrFilterDestIp_1_1_1_1: 0.0.0.0 0-65535 + + # Packet Filter IP Ext + # Name Pattern: + # TyCcV4SrvCrUserIpExt____ + # Parameter's value specifies filter's local port range + TyCcV4SrvCrUserIpExt_1_1_1_1: 0-65535 + + # Packet Filter Flow Direction + # Name Pattern: + # TyCcV4SrvCrFilterDirection____ + TyCcV4SrvCrFilterDirection_1_1_1_1: '3' # Bi-Directional + + # Diameter Transmission Protocol + TyCcSrvTcpProtocol: '1' # 0 - TCP, 1 - SCTP + + runner: + type: Duration + duration: 600 + interval: 5 + +contexts: +- name: traffic_gen + type: Node + file: /etc/yardstick/nodes/pod_landslide_network_dedicated.yaml +- name: vnf_epc + type: Node + file: /etc/yardstick/nodes/pod_vepc_sut.yaml diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_session_network_dedicated_bearer.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_network_dedicated_bearer.yaml new file mode 100644 index 000000000..2e79d8d51 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_network_dedicated_bearer.yaml @@ -0,0 +1,681 @@ +# 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. + +--- +description: Network initiated dedicated bearer creation test case +duration: 60 +keywords: '' +library: test +name: network_dedicated_bearer_creation +tsGroups: +- testCases: + - name: '' + AssociatedPhys: '' + parameters: + BillingEn: 'false' + DedicatedsPerDefaultBearer: '1' + DefaultBearers: '1' + FireballEn: 'false' + Gtp2AmbrDownlink: '1' + Gtp2AmbrUplink: '1' + Gtp2ApnNumSpecifiedApns_0: '0' + Gtp2ApnRestriction: '0' + Gtp2ApnRetries_0: '0' + Gtp2ApnSelectMode: '0' + Gtp2ApnSpecified_0: + array: [] + class: Array + Gtp2ApnTotalApns_0: '1' + Gtp2Apn_0: ssenoauth146 + Gtp2CfgFileEn: 'false' + Gtp2Ecgi: '0' + Gtp2EcgiSize: '28' + Gtp2EchoTimeSec: '0' + Gtp2ExtEn: 'false' + Gtp2GtpcTunnelEndptId: '1000000' + Gtp2GtpuIncludeSeqEn: 'true' + Gtp2GtpuTunnelEndptId: '2000000' + Gtp2IgnoreRestartCtrEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2IncCgiEn: 'false' + Gtp2IncEcgiEn: 'true' + Gtp2IncRaiEn: 'false' + Gtp2IncSaiEn: 'false' + Gtp2IncTaiEn: 'true' + Gtp2MacroEnbEn: 'false' + Gtp2Mcc: '000' + Gtp2Mnc: '000' + Gtp2MobGtpuForwardingEndptId: '5000000' + Gtp2MsIsdnEn: 'false' + Gtp2N3Attempts: '5' + Gtp2PagingTimeMs: '0' + Gtp2PersistentImsiEn: 'false' + Gtp2PiggybackEn_sgw: '0' + Gtp2QosArpPreemptCapEn_1: 'false' + Gtp2QosArpPreemptVulnEn_1: 'false' + Gtp2QosArpValue_1: '1' + Gtp2QosClassId_1: '1' + Gtp2QosDetail: Summary + Gtp2QosGuarDownlink_1: '1' + Gtp2QosGuarUplink_1: '1' + Gtp2QosMaxDownlink_1: '1' + Gtp2QosMaxUplink_1: '1' + Gtp2RadioAccessType: '6' + Gtp2RestartCnt: '1' + Gtp2S5GtpcTunnelEndptId: '3000000' + Gtp2S5GtpuTunnelEndptId: '4000000' + Gtp2SupportMabrEn: 'false' + Gtp2T3Time: '20' + Gtp2Tac: '0' + Gtp2Version: 15.2.0 + PgwNodeEn: 'false' + PgwNumSutsEn: 'false' + PgwSut: + class: Sut + name: PGW_SUT_NAME + PgwUserSutEn: 'false' + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + SeparateS5InterfacesEn: 'false' + Sessions: '1' + SgwControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: SGW_CONTROL_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: SGW_CONTROL_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + SgwControlAddrErrInj: '0' + SgwUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: SGW_USER_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: SGW_USER_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + SgwUserAddrErrInj: '0' + SgwUserDualStackEn: 'false' + SxaControlNodeAddrXPort: '8805' + SxaUserNodeAddrXPort: '8805' + TestType: SGW-NODE + TrafficMtu: '1400' + type: SGW_Node + - name: '' + parameters: + AgwNodeAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: AGW_NODE_NAME + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: AGW_NODE_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + AgwNodeAddrErrInj: '0' + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + BillingEn: 'false' + ConnectBearerDelay: + array: [] + class: Array + DataTraffic: Disabled + DedicatedsPerDefaultBearer: '1' + DefaultBearers: '1' + DisconnectDedicatedBearerEn: 'false' + FireballEn: 'false' + ForwardSessionVLanTag: '0' + Gtp2AmbrDownlink: '1' + Gtp2AmbrUplink: '1' + Gtp2ApnNumSpecifiedApns_0: '0' + Gtp2ApnRestriction: '0' + Gtp2ApnRetries_0: '0' + Gtp2ApnSelectMode: '0' + Gtp2ApnSpecified_0: + array: [] + class: Array + Gtp2ApnTotalApns_0: '1' + Gtp2Apn_0: ssenoauth146 + Gtp2Ecgi: '0' + Gtp2EcgiSize: '28' + Gtp2EchoTimeSec: '0' + Gtp2ExtEn: 'false' + Gtp2GtpcTunnelEndptId: '1000000' + Gtp2GtpuIncludeSeqEn: 'true' + Gtp2GtpuTunnelEndptId: '2000000' + Gtp2IgnoreRestartCtrEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2IncCgiEn: 'false' + Gtp2IncEcgiEn: 'true' + Gtp2IncRaiEn: 'false' + Gtp2IncSaiEn: 'false' + Gtp2IncTaiEn: 'true' + Gtp2MacroEnbEn: 'false' + Gtp2Mcc: '000' + Gtp2Mnc: '000' + Gtp2MsIsdnEn: 'false' + Gtp2MultDedsPerMsgEn: 'false' + Gtp2PcoAddEn: 'false' + Gtp2PcoIpcpEn: 'false' + Gtp2PersistentImsiEn: 'false' + Gtp2PiggybackEn_pgw: '0' + Gtp2QosArpPreemptCapEn_1: 'false' + Gtp2QosArpPreemptVulnEn_1: 'false' + Gtp2QosArpValue_1: '1' + Gtp2QosClassId_1: '1' + Gtp2QosDetail: Summary + Gtp2QosGuarDownlink_1: '1' + Gtp2QosGuarUplink_1: '1' + Gtp2QosMaxDownlink_1: '1' + Gtp2QosMaxUplink_1: '1' + Gtp2RadioAccessType: '6' + Gtp2ResponseDelayEn: 'false' + Gtp2RestartCnt: '1' + Gtp2RouterAdDelay: '1' + Gtp2Tac: '0' + Gtp2Version: 15.2.0 + MobilityType: None + OverloadCtlEn: 'false' + PcrfClnAgwIf: Gx + PdnGwAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: PGW_CONTROL_NAME + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: PGW_CONTROL_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + PdnGwAddrErrInj: '0' + PdnGwUsrAddrEn: 'false' + PgwDualStackEn: 'false' + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + S6bIfEn: 'false' + Sessions: '1' + SgiNasIfEn: 'false' + SgiNodeEn: 'false' + SgiPtpTunnelEn: 'false' + TestType: PGW-NODE + TrafficMtu: '1400' + TrafficNumTftsForContext0: '1' + TyCcClnAddFailedAvpEn: 'false' + TyCcClnApplicationId: '16777238' + TyCcClnAvpCfgFileEn: 'false' + TyCcClnConfiguration: Primary Server Only + TyCcClnDistributionMode: Dedicated + TyCcClnDoNotInitiateDprEn: 'false' + TyCcClnDprCause: '2' + TyCcClnHostAvpEn: 'true' + TyCcClnOriginHost: AGW.Spirent.com + TyCcClnOriginRealm: Spirent.com + TyCcClnProductName: 'Landslide PCRF' + TyCcClnRetryTime: '5000' + TyCcClnSctp3SackRuleEn: 'false' + TyCcClnSctpAckDelay: '100' + TyCcClnSctpSackThreshold: '2' + TyCcClnSutPort: '3868' + TyCcClnSutPrimaryHost: AGWServer.Spirent.com + TyCcClnSutPrimaryRealm: Spirent.com + TyCcClnSutPrimarySrv: + class: Sut + name: PCRF_TESTNODE_NAME + TyCcClnTcpProtocol: '1' + TyCcClnTcpWinSize: '32768' + TyCcClnVendorId: '10415' + TyCcClnVsa: + attrInfos: [] + class: Vsa + isCriteria: 'false' + isGeneric: 'false' + protocol: '301' + TyCcClnWatchDogTime: '30' + UeDhcpV4En: 'false' + UeInitBearerEn: 'false' + type: PGW_Node + tsId: SGW_PGW_NODE_TC_NAME +- testCases: + - name: '' + parameters: + ApnDnsEn: 'false' + ApnToPgwMappingEn: 'false' + AutoStopControlLayer: 'false' + ConnectBearerDelay: + array: [] + class: Array + ContinuousWithVerification: 'false' + CpCiotEpsOptimizationEn: 'false' + CtlBearerToDscpEn: 'false' + DataHostCfgFileEn: 'false' + DataResumeRate: '3000' + DataTraffic: Continuous + DataUserCfgFileEn: 'false' + DedicatedBearerConnectRateEn: 'false' + DedicatedBearerDisconnectRateEn: 'false' + DedicatedsPerDefaultBearer: '1' + DefaultBearers: '1' + DisconnectDedicatedBearerEn: 'false' + DisconnectRate: '1000.0' + Dmf: + class: Dmf + instanceGroups: + - mainflowIdx: 0 + mixType: '' + rate: 0.0 + rows: + - clientPort: 0 + context: 0 + node: 0 + overridePort: 'false' + ratingGroup: 0 + role: 0 + serviceId: 0 + transport: Any + mainflows: + - library: test + name: Basic UDP + DualStackEn: 'false' + EDrxValueEn: 'false' + EirIfEn: 'false' + EmergencyAttachWithImeiEn: 'false' + EmergencyAttachWoAuthEn: 'false' + EmergencyPdnIndexEn: 'false' + EnableExternalData: '0' + EnbUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: ENB_USER_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: ENB_USER_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + EnbUserAddrErrInj: '0' + FireballEn: 'false' + Gtp2ActivationDelay: '0' + Gtp2AmbrDownlink: '1' + Gtp2AmbrUplink: '1' + Gtp2ApnNumSpecifiedApns_0: '0' + Gtp2ApnNumSpecifiedApns_1: '0' + Gtp2ApnRestriction: '0' + Gtp2ApnRetries_0: '0' + Gtp2ApnRetries_1: '0' + Gtp2ApnSelectMode: '0' + Gtp2ApnSpecified_0: + array: [] + class: Array + Gtp2ApnSpecified_1: + array: [] + class: Array + Gtp2ApnTotalApns_0: '1' + Gtp2ApnTotalApns_1: '1' + Gtp2Apn_0: ssenoauth146 + Gtp2Apn_1: ssenoauth146 + Gtp2BearerModEn: 'false' + Gtp2CfgFileEn: 'false' + Gtp2ChargingChars: '0x0' + Gtp2DelayDlPacketNotifReq: '1' + Gtp2Ecgi: '0' + Gtp2EcgiSize: '28' + Gtp2EchoTimeSec: '0' + Gtp2EnbUliEn: 'false' + Gtp2ExtEn: 'false' + Gtp2FwdUplinkDataEcmIdle: 'false' + Gtp2GtpcTunnelEndptId: '1000000' + Gtp2GtpuIncludeSeqEn: 'true' + Gtp2GtpuTunnelEndptId: '2000000' + Gtp2IdleEntryTime: '0' + Gtp2IgnoreRestartCtrEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2IncCgiEn: 'false' + Gtp2IncEcgiEn: 'true' + Gtp2IncPcoOpt: none + Gtp2IncRaiEn: 'false' + Gtp2IncSaiEn: 'false' + Gtp2IncTaiEn: 'true' + Gtp2MacroEnbEn: 'false' + Gtp2MaxWaitTimeEn: 'false' + Gtp2Mcc: '000' + Gtp2Mnc: '000' + Gtp2ModBearerDlDataDelay: '0' + Gtp2MsIsdnEn: 'false' + Gtp2N3Attempts: '5' + Gtp2PagingTimeMs: '0' + Gtp2PcoAddEn: 'false' + Gtp2PcoIpcpEn: 'false' + Gtp2QosArpPreemptCapEn_1: 'false' + Gtp2QosArpPreemptVulnEn_1: 'false' + Gtp2QosArpValue_1: '1' + Gtp2QosClassId_1: '1' + Gtp2QosDetail: Summary + Gtp2QosGuarDownlink_1: '1' + Gtp2QosGuarUplink_1: '1' + Gtp2QosMaxDownlink_1: '1' + Gtp2QosMaxUplink_1: '1' + Gtp2RadioAccessType: '6' + Gtp2RejectDedEn: 'false' + Gtp2RemoteUeReportTime: '0' + Gtp2RestartCnt: '1' + Gtp2SupportMabrEn: 'false' + Gtp2SwVersionEn: 'false' + Gtp2T3Time: '20' + Gtp2Tac: '0' + Gtp2UeDaySaveTime: '0' + Gtp2UeMultPdnConnReqSameApnEn_0: 'false' + Gtp2UeTimeZone: '0' + Gtp2UliDbCmdCbRspEn: 'true' + Gtp2Version: 15.2.0 + HomeAddrType: '1' + HomeAddrTypePerBearerEn: 'false' + HssIfEn: 'false' + MmeControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: MME_CONTROL_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: MME_CONTROL_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + MmeControlAddrErrInj: '0' + MultipathTcpEn: 'false' + NetworkHost: Local + NetworkHostAddrLocal: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: NET_HOST_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: NET_HOST_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + NetworkHostAddrLocalErrInj: '0' + NetworkHostNatedTrafficEn: 'false' + PgwNodeEn: 'false' + PgwUserSutEn: 'false' + PgwV4Sut: + class: Sut + name: PGW_TESTNODE_NAME + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + SecPgwV4SutEn: 'false' + SessionIntervalShape: Fixed + SessionRetries: 'true' + Sessions: '1' + SgwNumSutsEn: 'false' + SgwSut: + class: Sut + name: SGW_CONTROL_NAME + SgwUserSut: + class: Sut + name: SGW_USER_NAME + StartRate: '1000.0' + T3324PwrSavingValueEn: 'false' + T3412ExValueEn: 'false' + TestActivity: Capacity Test + TestType: SGW-NODAL + TrafficDontFragIp: '0' + TrafficErrorInject: '0' + TrafficHostIdleTimeEnabler: 'false' + TrafficMtu: '1400' + TrafficStartDelay: '1000' + TrafficStartType: When All Sessions Established + UeDhcpV4En: 'false' + UeInitBearerEn: 'false' + UseStaticBearerIp: 'false' + type: SGW_Nodal + - name: '' + parameters: + AffinityModeEn: 'false' + AgwSrvNode: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: PRIMARY_AGW_NAME + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: PRIMARY_AGW_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + AgwSrvNodeErrInj: '0' + CommandMode: 'Off' + DiaAvpDataSize: '200' + DisconnectRate: '1000.0' + HomeAddrType: '1' + LteVersion: 9.6.0 + PcrfProtocol: pcrf_gx_srv + RoamingEn: 'false' + Sessions: '1' + StartingMsIpAddr: 1.0.0.1 + TestType: PCRF-NODE + TyCcDsSrvNumRuleSet: '0' + TyCcSrvAddFailedAvpEn: 'false' + TyCcSrvApnCaseInsensitiveEn: 'true' + TyCcSrvApnMapEn: 'true' + TyCcSrvApnProfilesEn: 'false' + TyCcSrvApns: + array: [] + class: Array + TyCcSrvApplicationId: '16777238' + TyCcSrvAuthKey: '505024101215074' + TyCcSrvAuthKeyType: IMSI + TyCcSrvAvpCfgFileEn: 'false' + TyCcSrvCcaIDelayEn: 'false' + TyCcSrvCcaTDelayEn: 'false' + TyCcSrvCcaUDelayEn: 'false' + TyCcSrvChargingAvpEn: 'false' + TyCcSrvCopyFilterFromRxEn: 'false' + TyCcSrvDoNotInitiateDprEn: 'false' + TyCcSrvDprCause: '2' + TyCcSrvExcludeFlowDirEn: 'false' + TyCcSrvImeiSvKeyEn: 'false' + TyCcSrvMobSupportEn: 'false' + TyCcSrvNumPeers: '1' + TyCcSrvOfflineAvpEn: 'false' + TyCcSrvOnlineAvpEn: 'false' + TyCcSrvOriginHost: AGWServer.Spirent.com + TyCcSrvOriginRealm: Spirent.com + TyCcSrvPktFltIdAlwaysEn: 'false' + TyCcSrvProductName: 'Landslide PCRF' + TyCcSrvRetryTime: '5000' + TyCcSrvSctp3SackRuleEn: 'false' + TyCcSrvSctpAckDelay: '100' + TyCcSrvSctpAckEn: 'true' + TyCcSrvSctpHeartbeatInterval: '30' + TyCcSrvSctpMaxRetransAssoc: '5' + TyCcSrvSctpMultiHomedMultiSrcEn: 'false' + TyCcSrvSctpSackThreshold: '2' + TyCcSrvSecondaryPcrfEn: 'false' + TyCcSrvTcpProtocol: '1' + TyCcSrvTcpWinSize: '32768' + TyCcSrvVendorId: '10415' + TyCcSrvVsaDbList: '30' + TyCcSrvWatchDogTime: '30' + TyCcV41Vsa: + attrInfos: [] + class: Vsa + isCriteria: 'false' + isGeneric: 'false' + protocol: '603' + TyCcV42Vsa: + attrInfos: [] + class: Vsa + isCriteria: 'false' + isGeneric: 'false' + protocol: '603' + TyCcV4AvpDataSize1: '200' + TyCcV4AvpDataSize2: '0' + TyCcV4SrvApn_1: '0' + TyCcV4SrvApn_2: '0' + TyCcV4SrvCrAction_1_1: Install + TyCcV4SrvCrAction_2_1: Install + TyCcV4SrvCrActivationTimeEn_1_1: 'false' + TyCcV4SrvCrActivationTimeEn_2_1: 'false' + TyCcV4SrvCrBearerIdEn_1_1: 'false' + TyCcV4SrvCrBearerIdEn_2_1: 'false' + TyCcV4SrvCrDeactivationTimeEn_1_1: 'false' + TyCcV4SrvCrDeactivationTimeEn_2_1: 'false' + TyCcV4SrvCrFilterDestIp_1_1_1_1: any + TyCcV4SrvCrFilterDirection_1_1_1_1: '3' + TyCcV4SrvCrFilterFlowLabel_1_1_1_1: '' + TyCcV4SrvCrFilterId_1_1_1_1: Fltr_V4_1_1_1_1 + TyCcV4SrvCrFilterSpi_1_1_1_1: '' + TyCcV4SrvCrFilterTos_1_1_1_1: '' + TyCcV4SrvCrFilter_1_1_1_1: permit in ip from + TyCcV4SrvCrIpType_1_1_1_1: '0' + TyCcV4SrvCrNumBaseName_1_1: '0' + TyCcV4SrvCrNumBaseName_2_1: '0' + TyCcV4SrvCrNumFilters_1_1_1: '1' + TyCcV4SrvCrNumFilters_2_1_1: '0' + TyCcV4SrvCrNumRuleDef_1_1: '1' + TyCcV4SrvCrNumRuleDef_2_1: '1' + TyCcV4SrvCrNumRuleName_1_1: '1' + TyCcV4SrvCrNumRuleName_2_1: '1' + TyCcV4SrvCrOverwriteSrcIpEn_1_1_1_1: 'false' + TyCcV4SrvCrPolRuleEn_1_1_1: 'true' + TyCcV4SrvCrPolRuleEn_2_1_1: 'true' + TyCcV4SrvCrQciEn_1_1_1: 'true' + TyCcV4SrvCrQciEn_2_1_1: 'true' + TyCcV4SrvCrQci_1_1_1: '1' + TyCcV4SrvCrQci_2_1_1: '1' + TyCcV4SrvCrResourceAllocEn_1_1: 'false' + TyCcV4SrvCrResourceAllocEn_2_1: 'false' + TyCcV4SrvCrRuleDefAfChargIdEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefAfChargIdEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefAppSvcProvIdEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefAppSvcProvIdEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefFlowStatusEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefFlowStatusEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefMcdNumEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefMcdNumEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefMetMethodEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefMetMethodEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefName_1_1_1: dedicated_rule_definition + TyCcV4SrvCrRuleDefName_2_1_1: default_rule_definition + TyCcV4SrvCrRuleDefOfflineAvpEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefOfflineAvpEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefOnlineAvpEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefOnlineAvpEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefPrecEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefPrecEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefRatGrpEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefRatGrpEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefSponsorIdEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefSponsorIdEn_2_1_1: 'false' + TyCcV4SrvCrRuleDefSrvIDEn_1_1_1: 'false' + TyCcV4SrvCrRuleDefSrvIDEn_2_1_1: 'false' + TyCcV4SrvCrRuleName_1_1_1: dedicated_charging_rule + TyCcV4SrvCrRuleName_2_1_1: default_charging_rule + TyCcV4SrvCrUserIpExt_1_1_1_1: '' + TyCcV4SrvNumCr_1: '1' + TyCcV4SrvNumCr_2: '1' + TyCcV4SrvNumRuleSet: '2' + TyCcV4SrvPrArpEn_1_1_1: 'false' + TyCcV4SrvPrArpEn_2_1_1: 'false' + TyCcV4SrvPrBearerIdEn_1_1_1: 'false' + TyCcV4SrvPrBearerIdEn_2_1_1: 'false' + TyCcV4SrvPrGuaranteedBwEn_1_1_1: 'true' + TyCcV4SrvPrGuaranteedBwEn_2_1_1: 'false' + TyCcV4SrvPrGuaranteedDownlink_1_1_1: '100' + TyCcV4SrvPrGuaranteedUplink_1_1_1: '100' + TyCcV4SrvPrIncPacketFilterUsage_1_1_1: 'false' + TyCcV4SrvPrIncPacketFilterUsage_2_1_1: 'false' + TyCcV4SrvPrMaxBwEn_1_1_1: 'true' + TyCcV4SrvPrMaxBwEn_2_1_1: 'false' + TyCcV4SrvPrMaxDL_1_1_1: '100' + TyCcV4SrvPrMaxUL_1_1_1: '100' + TyCcV4SrvPrUseAssignedEn_1_1_1: 'false' + TyCcV4SrvPrUseAssignedEn_2_1_1: 'false' + TyCcV4SrvRevalidateEn_1: 'false' + TyCcV4SrvRevalidateEn_2: 'false' + TyCcV4SrvRuleInterval_1: '10' + TyCcV4SrvRuleInterval_2: '0' + TyCcV6SrvNumRuleSet: '0' + TyCcVsa: + attrInfos: [] + class: Vsa + isCriteria: 'false' + isGeneric: 'false' + protocol: '303' + type: PCRF_Node + tsId: SGW_NODAL_PCRF_NODE_TS_NAME -- cgit 1.2.3-korg From c32cfdf59d67d15053e5c843684fe7093de50650 Mon Sep 17 00:00:00 2001 From: Orest Voznyy Date: Fri, 14 Sep 2018 22:21:46 +0300 Subject: Add vEPC service request test cases Add UE and network initiated testcase and related session profiles. JIRA: YARDSTICK-1429 Change-Id: I16d6c065cf346db31e235ac5add57509cfbc8009 Signed-off-by: Orest Voznyy --- .../tc_epc_network_service_request_landslide.yaml | 67 ++++ .../vepc/tc_epc_ue_service_request_landslide.yaml | 228 +++++++++++++ .../landslide_session_network_service_request.yaml | 341 +++++++++++++++++++ .../landslide_session_ue_service_request.yaml | 378 +++++++++++++++++++++ 4 files changed, 1014 insertions(+) create mode 100644 samples/vnf_samples/nsut/vepc/tc_epc_network_service_request_landslide.yaml create mode 100644 samples/vnf_samples/nsut/vepc/tc_epc_ue_service_request_landslide.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_session_network_service_request.yaml create mode 100644 samples/vnf_samples/traffic_profiles/landslide/landslide_session_ue_service_request.yaml diff --git a/samples/vnf_samples/nsut/vepc/tc_epc_network_service_request_landslide.yaml b/samples/vnf_samples/nsut/vepc/tc_epc_network_service_request_landslide.yaml new file mode 100644 index 000000000..55a96f4e4 --- /dev/null +++ b/samples/vnf_samples/nsut/vepc/tc_epc_network_service_request_landslide.yaml @@ -0,0 +1,67 @@ +# 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. + +--- +schema: yardstick:task:0.1 +description: > + Downlink Data Notification from Network to UE that are in Idle state. + +scenarios: +- type: NSPerf + traffic_profile: "../../traffic_profiles/landslide/landslide_dmf_udp.yaml" + session_profile: "../../traffic_profiles/landslide/landslide_session_network_service_request.yaml" + topology: "vepc_vnf_topology_landslide.yaml" + nodes: + tg__0: tg__0.traffic_gen + vnf__0: vnf__0.vnf_epc + options: + dmf: + transactionRate: 0.1 + packetSize: 512 + burstCount: 1 # Applies only to Basic UDP DMF, DataProtocol==udp + test_cases: # test case parameters to apply on session profile + - type: SGW_Node # test type from test session profile + AssociatedPhys: 'eth6' + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + Sessions: '20000' + - type: SGW_Nodal # test type from test session profile + StartRate: '1000.0' + DisconnectRate: '1000.0' + Sessions: '20000' + + # Configurations: + # 1. Specify continuous periodical events: UE goes to Idle state -> DL Data Notification + # E.g. Set Gtp2IdleEntryTime = 5 - UE goes to idle state after 5 seconds + # Set transactionRate = 0.1 - Send traffic periodically every 10 seconds + # 2. Set traffic run start delay + # E.g. Set Gtp2IdleEntryTime = 5 - UE goes to idle state after 5 seconds + # Set TrafficStartDelay with value greater that Gtp2IdleEntryTime + Gtp2IdleEntryTime: '5' # Idle Entry Time (s) + + # Downlink Data Notification settings + TrafficStartDelay: 1000 # Data Start Delay (ms) + + runner: + type: Duration + duration: 300 + interval: 5 + +contexts: +- name: traffic_gen + type: Node + file: /etc/yardstick/nodes/pod_landslide.yaml +- name: vnf_epc + type: Node + file: /etc/yardstick/nodes/pod_vepc_sut.yaml diff --git a/samples/vnf_samples/nsut/vepc/tc_epc_ue_service_request_landslide.yaml b/samples/vnf_samples/nsut/vepc/tc_epc_ue_service_request_landslide.yaml new file mode 100644 index 000000000..eaf4ae99f --- /dev/null +++ b/samples/vnf_samples/nsut/vepc/tc_epc_ue_service_request_landslide.yaml @@ -0,0 +1,228 @@ +# 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. + +--- +schema: yardstick:task:0.1 +description: > + UE triggered bearer modification request with new QoS and TFT settings + +scenarios: +- type: NSPerf + traffic_profile: "../../traffic_profiles/landslide/landslide_dmf_udp.yaml" + session_profile: "../../traffic_profiles/landslide/landslide_session_ue_service_request.yaml" + topology: "vepc_vnf_topology_landslide.yaml" + nodes: + tg__0: tg__0.traffic_gen + vnf__0: vnf__0.vnf_epc + options: + dmf: + transactionRate: 5 + packetSize: 512 + burstCount: 1 # Applies only to Basic UDP DMF, DataProtocol==udp + test_cases: # test case parameters to apply on session profile + - type: SGW_Node # test type from test session profile + AssociatedPhys: 'eth6' + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + Sessions: '20000' + UeInitBearerEn: 'true' + DedicatedsPerDefaultBearer: 1 # number of dedicated bearers per default + DefaultBearers: 1 # number of default bearers + FireballEn: 'false' # Fireball settings + + # Number of TFTs + # Parameter name pattern: TrafficNumTftsForContext + TrafficNumTftsForContext0: '1' + + # TFT Settings + # Parameter name(s) depends on number of dedicated bearers and number of TFTs per bearer. + # Parameter naming pattern: "TrafficTftForContext_" + # E.g.: + # "TrafficTftForContext0_0" - dedicated bearer 1, 1st TFT + # "TrafficTftForContext0_1" - dedicated bearer 1, 2nd TFT + # "TrafficTftForContext1_0" - dedicated bearer 2, 1st TFT + TrafficTftForContext0_0: + array: + - '255' # Packet Evaluation Precedence + - '6' # Protocol Number + - '' + - '' # Starting Remote Port + - '' # Ending Remote Port + - '' # Remote Address + - '' # Starting Local Port + - '' # Ending Local Port + - '' # Type of Service + - '' # Mask + - '' # Security Parameter Index + - '' # Flow Label + - '' + - '' # Include In Bearer Modification Request + - '3' # Direction: 0 - Pre Rel 7, 1 - Downlink, 2 - Uplink, 3 - Bi-Directional + - '' + - '' + - '' + - '' + class: Array + + - type: SGW_Nodal # test type from test session profile + StartRate: '1000.0' + DisconnectRate: '1000.0' + Sessions: '20000' + UeInitBearerEn: 'true' + DedicatedsPerDefaultBearer: '1' # number of dedicated bearers per default + DefaultBearers: '1' # number of default bearers + FireballEn: 'false' # Fireball settings + + # Creation delay individually for each dedicated bearer + # Array items specifies timeout between default and dedicated bearers creation + # Array items corresponds to specific dedicated bearer: + # E.g. 1st item - 1st dedicated bearer, 2nd item - 2nd dedicated bearer, etc. + ConnectBearerDelay: + class: Array + array: ['1'] + + # Data start delay (ms) + TrafficStartDelay: 1000 + + # Number of TFTs + # Parameter name pattern: TrafficNumTftsForContext + TrafficNumTftsForContext0: '1' + + # TFT settings + # Parameter name(s) depends on number of dedicated bearers and number of TFTs per bearer. + # Parameter naming pattern: "TrafficTftForContext_" + # E.g.: + # "TrafficTftForContext0_0" - dedicated bearer 1, 1st TFT + # "TrafficTftForContext0_1" - dedicated bearer 1, 2nd TFT + # "TrafficTftForContext1_0" - dedicated bearer 2, 1st TFT + TrafficTftForContext0_0: + array: + - '255' # Packet Evaluation Precedence + - '6' # Protocol Number + - '' + - '' # Starting Remote Port + - '' # Ending Remote Port + - '' # Remote Address + - '' # Starting Local Port + - '' # Ending Local Port + - '' # Type of Service + - '' # Mask + - '' # Security Parameter Index + - '' # Flow Label + - '' + - '' # Include In Bearer Modification Request + - '3' # Direction: 0 - Pre Rel 7, 1 - Downlink, 2 - Uplink, 3 - Bi-Directional + - '' + - '' + - '' + - '' + class: Array + + # Bearers modification settings + # Dedicated bearers modification settings and TFT filters + Gtp2BearerModEn: 'true' # Enable/Disable bearer modification + Gtp2BearerModInit: 'UE' # Bearer modification initiator + Gtp2BearerDelayTime: '5' # Delay time (s) + Gtp2IncModQos_2: 'true' # Include QoS IE + Gtp2BearerContinuousMod: 'false' # Continuous modifications + # Operation code in TFT settings: + # Parameter name(s) depends on number of dedicated bearers + # Parameter naming pattern: "TrafficOpCodeForContext_2" + # E.g.: + # TrafficOpCodeForContext0_2 - operation code for 1st dedicated bearer's TFT + # TrafficOpCodeForContext1_2 - operation code for 2st dedicated bearer's TFT + # 1 - create new TFT + # 2 - delete existing TFT + # 3 - add packet filters to existing TFT + # 4 - replace packet filters in existing TFT + # 5 - delete packet filters from existing TFT + TrafficOpCodeForContext0_2: '1' + + # Number of TFTs + # Parameter name pattern: TrafficNumTftsForContext_2 + TrafficNumTftsForContext0_2: '1' + + # TFT settings + # Parameter name(s) depends on number of dedicated bearers and number of TFTs per bearer. + # Parameter naming pattern: "TrafficTftForContext__2" + # E.g.: + # "TrafficTftForContext0_0" - dedicated bearer 1, 1st TFT + # "TrafficTftForContext0_1" - dedicated bearer 1, 2nd TFT + # "TrafficTftForContext1_0" - dedicated bearer 2, 1st TFT + TrafficTftForContext0_0_2: + class: Array + array: + - '255' # Packet Evaluation Precedence + - '17' # Protocol Number + - '' + - '2003' # Starting Remote Port + - '2003' # Ending Remote Port + - '' # Remote Address + - '2002' # Starting Local Port + - '2002' # Ending Local Port + - '' # Type of Service + - '' # Mask + - '' # Security Parameter Index + - '' # Flow Label + - '' + - 'true' # Include In Bearer Modification Request + - '3' # Direction: 0 - Pre Rel 7, 1 - Downlink, 2 - Uplink, 3 - Bi-Directional + - '' + - '' + - '' + - '' + + # Modified bearers QoS settings + Gtp2QosDetail_2: Individual # bearers QoS details (Summary, Individual, Per Bearer) + + # Parameter name(s) depends on number of dedicated bearers + # Parameter(s) naming pattern: "Gtp2QosClassId_2_" + # E.g.: + # Gtp2QosClassId_2_1 - default bearer class identifier + # Gtp2QosClassId_2_2 - 1st dedicated bearer class identifier + # Gtp2QosClassId_2_3 - 2st dedicated bearer class identifier + # Modified default bearer settings + Gtp2QosClassId_2_1: '1' # Bearer class identifier + Gtp2QosArpValue_2_1: '1' # Bearer ARP priority level + Gtp2QosArpPreemptCapEn_2_1: 'false' # Pre-emption capability + Gtp2QosArpPreemptVulnEn_2_1: 'false' # Pre-emption vulnerability + Gtp2QosMaxUplink_2_1: '1000' # Uplink maximum bit rates (kb/s) + Gtp2QosMaxDownlink_2_1: '1000' # Downlink maximum bit rates (kb/s) + Gtp2QosGuarUplink_2_1: '1000' # Uplink guaranteed bit rates (kb/s) + Gtp2QosGuarDownlink_2_1: '1000' # Downlink guaranteed bit rates (kb/s) + + # Modified dedicated bearer settings + Gtp2QosClassId_2_2: '5' # Bearer class identifier + Gtp2QosArpValue_2_2: '1' # Bearer ARP priority level + Gtp2QosArpPreemptCapEn_2_2: 'false' # Pre-emption capability + Gtp2QosArpPreemptVulnEn_2_2: 'false' # Pre-emption vulnerability + + # Uncomment this settings in case Gtp2QosClassId_2_2 is equal to 1 + # Gtp2QosMaxUplink_2_2: '1000' # Uplink maximum bit rates (kb/s) + # Gtp2QosMaxDownlink_2_2: '1000' # Downlink maximum bit rates (kb/s) + # Gtp2QosGuarUplink_2_2: '1000' # Uplink guaranteed bit rates (kb/s) + # Gtp2QosGuarDownlink_2_2: '1000' # Downlink guaranteed bit rates (kb/s) + + runner: + type: Duration + duration: 300 + interval: 5 + +contexts: +- name: traffic_gen + type: Node + file: /etc/yardstick/nodes/pod_landslide.yaml +- name: vnf_epc + type: Node + file: /etc/yardstick/nodes/pod_vepc_sut.yaml diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_session_network_service_request.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_network_service_request.yaml new file mode 100644 index 000000000..2589a6b47 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_network_service_request.yaml @@ -0,0 +1,341 @@ +# 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. + +--- +description: Network triggered service request +keywords: '' +duration: 60 +library: test +name: network_initiated_service_request +tsGroups: +- testCases: + - name: '' + AssociatedPhys: '' + parameters: + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + BillingEn: 'false' + DedicatedsPerDefaultBearer: '0' + DefaultBearers: '1' + FireballEn: 'false' + Gtp2AmbrDownlink: '1' + Gtp2AmbrUplink: '1' + Gtp2ApnNumSpecifiedApns_0: '0' + Gtp2ApnRestriction: '0' + Gtp2ApnRetries_0: '0' + Gtp2ApnSelectMode: '0' + Gtp2ApnSpecified_0: + array: [] + class: Array + Gtp2ApnTotalApns_0: '1' + Gtp2Apn_0: ssenoauth146 + Gtp2CfgFileEn: 'false' + Gtp2Ecgi: '0' + Gtp2EcgiSize: '28' + Gtp2EchoTimeSec: '0' + Gtp2ExtEn: 'false' + Gtp2GtpcTunnelEndptId: '1000000' + Gtp2GtpuIncludeSeqEn: 'true' + Gtp2GtpuTunnelEndptId: '2000000' + Gtp2IgnoreRestartCtrEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2IncCgiEn: 'false' + Gtp2IncEcgiEn: 'true' + Gtp2IncRaiEn: 'false' + Gtp2IncSaiEn: 'false' + Gtp2IncTaiEn: 'true' + Gtp2MacroEnbEn: 'false' + Gtp2Mcc: '000' + Gtp2Mnc: '000' + Gtp2MobGtpuForwardingEndptId: '5000000' + Gtp2MsIsdnEn: 'false' + Gtp2N3Attempts: '5' + Gtp2PagingTimeMs: '0' + Gtp2PersistentImsiEn: 'false' + Gtp2QosArpPreemptCapEn_1: 'false' + Gtp2QosArpPreemptVulnEn_1: 'false' + Gtp2QosArpValue_1: '1' + Gtp2QosClassId_1: '1' + Gtp2QosDetail: Summary + Gtp2QosGuarDownlink_1: '1' + Gtp2QosGuarUplink_1: '1' + Gtp2QosMaxDownlink_1: '1' + Gtp2QosMaxUplink_1: '1' + Gtp2RadioAccessType: '6' + Gtp2ResponseDelayEn: 'false' + Gtp2RestartCnt: '1' + Gtp2RouterAdDelay: '1' + Gtp2S5GtpcTunnelEndptId: '3000000' + Gtp2S5GtpuTunnelEndptId: '4000000' + Gtp2SupportMabrEn: 'false' + Gtp2T3Time: '20' + Gtp2Tac: '0' + Gtp2Version: 15.2.0 + PgwNodeEn: 'true' + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + Sessions: '1000' + SgiPtpTunnelEn: 'false' + SgwControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: SGW_CONTROL_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: SGW_CONTROL_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + SgwControlAddrErrInj: '0' + SgwUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: SGW_USER_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: SGW_USER_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + SgwUserAddrErrInj: '0' + SgwUserDualStackEn: 'false' + TestType: SGW-NODE + TrafficMtu: '1400' + UeDhcpV4En: 'false' + type: SGW_Node + tsId: SGW_NODE_TS_NAME +- testCases: + - name: '' + parameters: + ApnDnsEn: 'false' + ApnToPgwMappingEn: 'false' + AutoStopControlLayer: 'false' + ContinuousWithVerification: 'false' + CpCiotEpsOptimizationEn: 'false' + CtlBearerToDscpEn: 'false' + DataHostCfgFileEn: 'false' + DataResumeRate: '3000' + DataTraffic: Continuous + DataUserCfgFileEn: 'false' + DedicatedsPerDefaultBearer: '0' + DefaultBearers: '1' + DisconnectRate: '1000.0' + Dmf: + class: Dmf + instanceGroups: + - mainflowIdx: 0 + mixType: '' + rate: 0.0 + rows: + - clientPort: 0 + context: 0 + node: 0 + overridePort: 'false' + ratingGroup: 0 + role: Server + serviceId: 0 + transport: Any + mainflows: + - library: test + name: Basic UDP + DualStackEn: 'false' + EDrxValueEn: 'false' + EirIfEn: 'false' + EmergencyAttachWithImeiEn: 'false' + EmergencyAttachWoAuthEn: 'false' + EmergencyPdnIndexEn: 'false' + EnableExternalData: '0' + EnbUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: ENB_USER_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: ENB_USER_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + EnbUserAddrErrInj: '0' + FireballEn: 'false' + Gtp2ActivationDelay: '0' + Gtp2AmbrDownlink: '1' + Gtp2AmbrUplink: '1' + Gtp2ApnNumSpecifiedApns_0: '0' + Gtp2ApnNumSpecifiedApns_1: '0' + Gtp2ApnRestriction: '0' + Gtp2ApnRetries_0: '0' + Gtp2ApnRetries_1: '0' + Gtp2ApnSelectMode: '0' + Gtp2ApnSpecified_0: + array: [] + class: Array + Gtp2ApnSpecified_1: + array: [] + class: Array + Gtp2ApnTotalApns_0: '1' + Gtp2ApnTotalApns_1: '1' + Gtp2Apn_0: ssenoauth146 + Gtp2Apn_1: ssenoauth146 + Gtp2BearerModEn: 'false' + Gtp2CfgFileEn: 'false' + Gtp2ChargingChars: '0x0' + Gtp2DelayDlPacketNotifReq: '1' + Gtp2Ecgi: '0' + Gtp2EcgiSize: '28' + Gtp2EchoTimeSec: '0' + Gtp2EnbUliEn: 'false' + Gtp2ExtEn: 'false' + Gtp2FwdUplinkDataEcmIdle: 'false' + Gtp2GtpcTunnelEndptId: '1000000' + Gtp2GtpuIncludeSeqEn: 'true' + Gtp2GtpuTunnelEndptId: '2000000' + Gtp2IdleEntryTime: '0' + Gtp2IgnoreRestartCtrEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2IncCgiEn: 'false' + Gtp2IncEcgiEn: 'true' + Gtp2IncPcoOpt: none + Gtp2IncRaiEn: 'false' + Gtp2IncSaiEn: 'false' + Gtp2IncTaiEn: 'true' + Gtp2MacroEnbEn: 'false' + Gtp2MaxWaitTimeEn: 'false' + Gtp2Mcc: '000' + Gtp2Mnc: '000' + Gtp2ModBearerDlDataDelay: '0' + Gtp2MsIsdnEn: 'false' + Gtp2N3Attempts: '5' + Gtp2PagingTimeMs: '0' + Gtp2PcoAddEn: 'false' + Gtp2PcoIpcpEn: 'false' + Gtp2QosArpPreemptCapEn_1: 'false' + Gtp2QosArpPreemptVulnEn_1: 'false' + Gtp2QosArpValue_1: '1' + Gtp2QosClassId_1: '1' + Gtp2QosDetail: Summary + Gtp2QosGuarDownlink_1: '1' + Gtp2QosGuarUplink_1: '1' + Gtp2QosMaxDownlink_1: '1' + Gtp2QosMaxUplink_1: '1' + Gtp2RadioAccessType: '6' + Gtp2RejectDedEn: 'false' + Gtp2RemoteUeReportTime: '0' + Gtp2RestartCnt: '1' + Gtp2SupportMabrEn: 'false' + Gtp2SwVersionEn: 'false' + Gtp2T3Time: '20' + Gtp2Tac: '0' + Gtp2UeDaySaveTime: '0' + Gtp2UeMultPdnConnReqSameApnEn_0: 'false' + Gtp2UeTimeZone: '0' + Gtp2UliDbCmdCbRspEn: 'true' + Gtp2Version: 15.2.0 + HomeAddrType: '1' + HomeAddrTypePerBearerEn: 'false' + HssIfEn: 'false' + MmeControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: MME_CONTROL_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: MME_CONTROL_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + MmeControlAddrErrInj: '0' + MultipathTcpEn: 'false' + NetworkHost: Local + NetworkHostAddrLocal: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: NET_HOST_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: NET_HOST_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + NetworkHostAddrLocalErrInj: '0' + NetworkHostNatedTrafficEn: 'false' + PgwNodeEn: 'false' + PgwUserSutEn: 'false' + PgwV4Sut: + class: Sut + name: PGW_SUT_NAME + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + SecPgwV4SutEn: 'false' + SessionIntervalShape: Fixed + SessionRetries: 'true' + Sessions: '1000' + SgwNumSutsEn: 'false' + SgwSut: + class: Sut + name: PGW_SUT_NAME + SgwUserSut: + class: Sut + name: SGW_USER_NAME + StartRate: '1000.0' + T3324PwrSavingValueEn: 'false' + T3412ExValueEn: 'false' + TestActivity: Capacity Test + TestType: SGW-NODAL + TrafficDontFragIp: '0' + TrafficErrorInject: '0' + TrafficHostIdleTimeEnabler: 'false' + TrafficMtu: '1400' + TrafficStartDelay: '10000' + TrafficStartType: When All Sessions Established + UeDhcpV4En: 'false' + UseStaticBearerIp: 'false' + type: SGW_Nodal + tsId: SGW_NODAL_TS_NAME diff --git a/samples/vnf_samples/traffic_profiles/landslide/landslide_session_ue_service_request.yaml b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_ue_service_request.yaml new file mode 100644 index 000000000..c4b178558 --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/landslide/landslide_session_ue_service_request.yaml @@ -0,0 +1,378 @@ +# 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. + +--- +description: ue initiates service request test case +keywords: '' +duration: 60 +library: test +name: ue_initiates_service_request +tsGroups: +- testCases: + - name: '' + AssociatedPhys: '' + parameters: + BearerAddrPool: 2001::1 + BearerV4AddrPool: 1.0.0.1 + BillingEn: 'false' + DedicatedsPerDefaultBearer: '1' + DefaultBearers: '1' + FireballEn: 'false' + Gtp2AmbrDownlink: '1' + Gtp2AmbrUplink: '1' + Gtp2ApnNumSpecifiedApns_0: '0' + Gtp2ApnRestriction: '0' + Gtp2ApnRetries_0: '0' + Gtp2ApnSelectMode: '0' + Gtp2ApnSpecified_0: + array: [] + class: Array + Gtp2ApnTotalApns_0: '1' + Gtp2Apn_0: ssenoauth146 + Gtp2CfgFileEn: 'false' + Gtp2Ecgi: '0' + Gtp2EcgiSize: '28' + Gtp2EchoTimeSec: '0' + Gtp2ExtEn: 'false' + Gtp2GtpcTunnelEndptId: '1000000' + Gtp2GtpuIncludeSeqEn: 'true' + Gtp2GtpuTunnelEndptId: '2000000' + Gtp2IgnoreRestartCtrEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2IncCgiEn: 'false' + Gtp2IncEcgiEn: 'true' + Gtp2IncRaiEn: 'false' + Gtp2IncSaiEn: 'false' + Gtp2IncTaiEn: 'true' + Gtp2MacroEnbEn: 'false' + Gtp2Mcc: '000' + Gtp2Mnc: '000' + Gtp2MobGtpuForwardingEndptId: '5000000' + Gtp2MsIsdnEn: 'false' + Gtp2N3Attempts: '5' + Gtp2PagingTimeMs: '0' + Gtp2PersistentImsiEn: 'false' + Gtp2QosArpPreemptCapEn_1: 'false' + Gtp2QosArpPreemptVulnEn_1: 'false' + Gtp2QosArpValue_1: '1' + Gtp2QosClassId_1: '1' + Gtp2QosDetail: Summary + Gtp2QosGuarDownlink_1: '150' + Gtp2QosGuarUplink_1: '150' + Gtp2QosMaxDownlink_1: '200' + Gtp2QosMaxUplink_1: '200' + Gtp2RadioAccessType: '6' + Gtp2ResponseDelayEn: 'false' + Gtp2RestartCnt: '1' + Gtp2RouterAdDelay: '1' + Gtp2S5GtpcTunnelEndptId: '3000000' + Gtp2S5GtpuTunnelEndptId: '4000000' + Gtp2SupportMabrEn: 'false' + Gtp2T3Time: '20' + Gtp2Tac: '0' + Gtp2Version: 15.2.0 + PgwNodeEn: 'true' + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + Sessions: '1' + SgiPtpTunnelEn: 'false' + SgwControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: SGW_CONTROL_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: SGW_CONTROL_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + SgwControlAddrErrInj: '0' + SgwUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: SGW_USER_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: SGW_USER_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + SgwUserAddrErrInj: '0' + SgwUserDualStackEn: 'false' + TestType: SGW-NODE + TrafficMtu: '1400' + TrafficNumTftsForContext0: '0' + UeDhcpV4En: 'false' + UeInitBearerEn: 'true' + type: SGW_Node + tsId: SGW_NODE_TS_NAME +- testCases: + - name: '' + parameters: + ApnDnsEn: 'false' + ApnToPgwMappingEn: 'false' + AutoStopControlLayer: 'false' + ContinuousWithVerification: 'false' + CpCiotEpsOptimizationEn: 'false' + CtlBearerToDscpEn: 'false' + DataHostCfgFileEn: 'false' + DataResumeRate: '3000' + DataTraffic: Continuous + DataUserCfgFileEn: 'false' + DedBearerConnectDelay: '0' + DedBearerDisconnectDelay: '0' + DedicatedBearerConnectRateEn: 'false' + DedicatedBearerDisconnectRateEn: 'false' + DedicatedsPerDefaultBearer: '1' + DefaultBearers: '1' + DisconnectRate: '1000.0' + Dmf: + class: Dmf + instanceGroups: + - mainflowIdx: 0 + mixType: '' + rate: 0.0 + rows: + - clientPort: 0 + context: 0 + node: 0 + overridePort: 'false' + ratingGroup: 0 + role: 0 + serviceId: 0 + transport: Any + mainflows: + - library: test + name: Basic UDP + DualStackEn: 'false' + EDrxValueEn: 'false' + EirIfEn: 'false' + EmergencyAttachWithImeiEn: 'false' + EmergencyAttachWoAuthEn: 'false' + EmergencyPdnIndexEn: 'false' + EnableExternalData: '0' + EnbUserAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: ENB_USER_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: ENB_USER_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + EnbUserAddrErrInj: '0' + FireballEn: 'false' + Gtp2ActivationDelay: '0' + Gtp2AmbrDownlink: '1' + Gtp2AmbrUplink: '1' + Gtp2ApnNumSpecifiedApns_0: '0' + Gtp2ApnNumSpecifiedApns_1: '0' + Gtp2ApnRestriction: '0' + Gtp2ApnRetries_0: '0' + Gtp2ApnRetries_1: '0' + Gtp2ApnSelectMode: '0' + Gtp2ApnSpecified_0: + array: [] + class: Array + Gtp2ApnSpecified_1: + array: [] + class: Array + Gtp2ApnTotalApns_0: '1' + Gtp2ApnTotalApns_1: '1' + Gtp2Apn_0: ssenoauth146 + Gtp2Apn_1: ssenoauth146 + Gtp2BearerContinuousMod: 'false' + Gtp2BearerDelayTime: '10' + Gtp2BearerModEn: 'true' + Gtp2BearerModInit: UE + Gtp2CfgFileEn: 'false' + Gtp2ChargingChars: '0x0' + Gtp2DelayDlPacketNotifReq: '1' + Gtp2Ecgi: '0' + Gtp2EcgiSize: '28' + Gtp2EchoTimeSec: '0' + Gtp2EnbUliEn: 'false' + Gtp2ExtEn: 'false' + Gtp2FwdUplinkDataEcmIdle: 'false' + Gtp2GtpcTunnelEndptId: '1000000' + Gtp2GtpuIncludeSeqEn: 'true' + Gtp2GtpuTunnelEndptId: '2000000' + Gtp2IdleEntryTime: '0' + Gtp2IgnoreRestartCtrEn: 'false' + Gtp2Imei: '50502410121507' + Gtp2Imsi: '505024101215074' + Gtp2IncCgiEn: 'false' + Gtp2IncEcgiEn: 'true' + Gtp2IncModQos_2: 'true' + Gtp2IncPcoOpt: none + Gtp2IncRaiEn: 'false' + Gtp2IncSaiEn: 'false' + Gtp2IncTaiEn: 'true' + Gtp2MacroEnbEn: 'false' + Gtp2MaxWaitTimeEn: 'false' + Gtp2Mcc: '000' + Gtp2Mnc: '000' + Gtp2ModBearerDlDataDelay: '0' + Gtp2MsIsdnEn: 'false' + Gtp2N3Attempts: '5' + Gtp2PagingTimeMs: '0' + Gtp2PcoAddEn: 'false' + Gtp2PcoIpcpEn: 'false' + Gtp2QosArpPreemptCapEn_1: 'false' + Gtp2QosArpPreemptCapEn_2: 'false' + Gtp2QosArpPreemptCapEn_2_1: 'false' + Gtp2QosArpPreemptCapEn_2_2: 'false' + Gtp2QosArpPreemptVulnEn_1: 'false' + Gtp2QosArpPreemptVulnEn_2: 'false' + Gtp2QosArpPreemptVulnEn_2_1: 'false' + Gtp2QosArpPreemptVulnEn_2_2: 'false' + Gtp2QosArpValue_1: '1' + Gtp2QosArpValue_2: '1' + Gtp2QosArpValue_2_1: '1' + Gtp2QosArpValue_2_2: '1' + Gtp2QosClassId_1: '1' + Gtp2QosClassId_2: '1' + Gtp2QosClassId_2_1: '1' + Gtp2QosClassId_2_2: '5' + Gtp2QosDetail: Individual + Gtp2QosDetail_2: Individual + Gtp2QosGuarDownlink_1: '150' + Gtp2QosGuarDownlink_2: '1000' + Gtp2QosGuarDownlink_2_1: '150' + Gtp2QosGuarUplink_1: '150' + Gtp2QosGuarUplink_2: '1000' + Gtp2QosGuarUplink_2_1: '150' + Gtp2QosMaxDownlink_1: '200' + Gtp2QosMaxDownlink_2: '2000' + Gtp2QosMaxDownlink_2_1: '250' + Gtp2QosMaxUplink_1: '200' + Gtp2QosMaxUplink_2: '2000' + Gtp2QosMaxUplink_2_1: '250' + Gtp2RadioAccessType: '6' + Gtp2RejectDedEn: 'false' + Gtp2RemoteUeReportTime: '0' + Gtp2RestartCnt: '1' + Gtp2SupportMabrEn: 'false' + Gtp2SwVersionEn: 'false' + Gtp2T3Time: '20' + Gtp2Tac: '0' + Gtp2UeDaySaveTime: '0' + Gtp2UeMultPdnConnReqSameApnEn_0: 'false' + Gtp2UeTimeZone: '0' + Gtp2UliDbCmdCbRspEn: 'true' + Gtp2Version: 15.2.0 + HomeAddrType: '1' + HomeAddrTypePerBearerEn: 'false' + HssIfEn: 'false' + MmeControlAddr: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: MME_CONTROL_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: MME_CONTROL_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + MmeControlAddrErrInj: '0' + MultipathTcpEn: 'false' + NetworkHost: Local + NetworkHostAddrLocal: + class: TestNode + ethStatsEnabled: 'false' + forcedEthInterface: '' + innerVlanId: 0 + ip: NET_HOST_IP + mac: '' + mtu: 1500 + nextHop: '' + numLinksOrNodes: 1 + numVlan: 1 + phy: NET_HOST_PHY + uniqueVlanAddr: 'false' + vlanDynamic: 0 + vlanId: 0 + vlanTagType: 0 + vlanUserPriority: 0 + NetworkHostAddrLocalErrInj: '0' + NetworkHostNatedTrafficEn: 'false' + PgwNodeEn: 'false' + PgwUserSutEn: 'false' + PgwV4Sut: + class: Sut + name: PGW_SUT_NAME + QciToDscpMarkingsEn: 'false' + S5Protocol: GTPv2 + SecPgwV4SutEn: 'false' + SessionIntervalShape: Fixed + SessionRetries: 'true' + Sessions: '1' + SgwNumSutsEn: 'false' + SgwSut: + class: Sut + name: SGW_CONTROL_NAME + SgwUserSut: + class: Sut + name: SGW_USER_NAME + StartRate: '1000.0' + T3324PwrSavingValueEn: 'false' + T3412ExValueEn: 'false' + TestActivity: Capacity Test + TestType: SGW-NODAL + TrafficAutoStartingDestPort: 'false' + TrafficAutoStartingDestPort_2: 'false' + TrafficDontFragIp: '0' + TrafficErrorInject: '0' + TrafficHostIdleTimeEnabler: 'false' + TrafficMtu: '1400' + TrafficNumTftsForContext0: '0' + TrafficNumTftsForContext0_2: '0' + TrafficOpCodeForContext0_2: '0' + TrafficStartDelay: '1000' + TrafficStartType: When All Sessions Established + UeDhcpV4En: 'false' + UeInitBearerEn: 'true' + UseStaticBearerIp: 'false' + type: SGW_Nodal + tsId: SGW_NODAL_TS_NAME -- cgit 1.2.3-korg