def __init__(self, logger, server, port=80, user_name=getpass.getuser(), session_name=None): """ Init STC REST client. :param server: STC REST API server address. :param port: STC REST API HTTP port. :param user_name: user name, part of session ID. :param session_name: session, name part of session ID. Add logger to log STC REST commands only. This creates a clean REST script that can be used later for debug. """ super(self.__class__, self).__init__() debug_print = True if logger.level == 10 else False self.ls = stchttp.StcHttp(server, port, debug_print=debug_print) if session_name: self.session_id = self.ls.join_session(session_name) else: session_name = 'session' + str(randint(0, 99)) self.session_id = self.ls.new_session(user_name, session_name, kill_existing=True)
def connect(self): addr, port = self._config['stc_server_addr'], self._config[ 'stc_server_port'] log.info('Connecting to: {}:{}'.format(addr, port)) self._stc = stchttp.StcHttp(addr, port=port, debug_print=self._verbose) if self._state['sid']: log.info('Joining existing session {}'.format(self._state['sid'])) self._stc.join_session(self._state['sid']) else: sid = ''.join([choice(lowercase) for i in range(10)]) log.info('Creating new session, "{}" for user {}.'.format( sid, self._state['user'])) self._state['sid'] = self._stc.new_session(self._state['user'], sid) self._stc.apply() chas_addr = self._state['chassis_addr'] log.info('Connecting to chassis at {}'.format(chas_addr)) # stc.connect wants a list of addresses for some reason. self._stc.connect([chas_addr]) log.info('Connected.') # If not configured with an existing project, create a new one. if not self.project_handle: log.info('creating new project.') data = self._stc.createx('project') log.info('created project: {}'.format( json.dumps(data, indent=4, sort_keys=True))) self._state['project_handle'] = data['handle']
def __init__(self, labserver_addr, user_name, session_name): self.logger = logging.getLogger(__name__) # create connection obj self.stc = stchttp.StcHttp(labserver_addr) self.user_name = user_name self.session_name = session_name # create session on labserver self.session_id = self.stc.new_session(self.user_name, self.session_name) self.stc.join_session(self.session_id) return
def __init__(self, labserver_ip, user_name, stcv_west_mgmt_ip, stcv_west_test_port_ip, stcv_east_mgmt_ip, stcv_east_test_port_ip, dut_left_ip, dut_right_ip): self.labserver_ip = labserver_ip self.user_name = user_name self.result1 = None self.result2 = None self.testpass = None self.west_stcv = { "mgmt_ip": stcv_west_mgmt_ip, "test_port_ip": stcv_west_test_port_ip, "gw_ip": dut_left_ip, "port_location": "//" + stcv_west_mgmt_ip + "/1/1", "port": None, "gen": None, "ana": None, "result": None } self.east_stcv = { "mgmt_ip": stcv_east_mgmt_ip, "test_port_ip": stcv_east_test_port_ip, "gw_ip": dut_right_ip, "port_location": "//" + stcv_east_mgmt_ip + "/1/1", "port": None, "gen": None, "ana": None, "result": None } self.stc = stchttp.StcHttp(labserver_ip, port=80) #self.user_name = "csu_user" time_str = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") test_name = "simpletraffic - " + time_str sess_id = self.user_name + " - " + test_name sess_list = self.stc.sessions() logger.debug("sess_list: %s", sess_list) if sess_id not in sess_list: sess_id = self.stc.new_session(self.user_name, test_name) self.stc.join_session(sess_id) self.sys = "system1" self.project = self.stc.get(self.sys, "children-project") return
def __init__(self, logger: logging.Logger, server, port=80, user_name=getpass.getuser(), session_name=None): """Init STC REST client. :TODO: Add logger to log STC REST commands only. This creates a clean REST script that can be used later for debug. :param logger: Package logger. :param server: STC REST API server address. :param port: STC REST API HTTP port. :param user_name: user name, part of session ID. :param session_name: session, name part of session ID. """ debug_print = logger.level == 10 self.client = stchttp.StcHttp(server, port, debug_print=debug_print) if session_name: self.session_id = self.client.join_session(session_name) else: session_name = "session" + str(randint(0, 99)) self.session_id = self.client.new_session(user_name, session_name, kill_existing=True) self.command_rc = None
def __init__(self, lab_server_addr, lab_server_port=80): try: self.stc = stchttp.StcHttp(lab_server_addr, port=lab_server_port) except Exception as e: LOG.exception(e) raise StcTrafficAdapterError('Unable to create adapter - %s' % e) self.session = None self.project = None self.tx_results = None self.rx_results = None self.tx_port = None self.rx_port = None self.stream_block = None self.arp_needed = None self._attempt_to_start_traffic = False self._traffic_attempt_lock = Lock() self._emission_started = False self._emission_lock = Lock() self._service_disruption_length = None self._service_disruption_lock = Lock()
from __future__ import print_function import sys from stcrestclient import stchttp if len(sys.argv) < 2: print('usage: python', sys.argv[0], 'server_addr', file=sys.stderr) sys.exit(1) try: stc = stchttp.StcHttp(sys.argv[1]) # List all current STC sessions. sessions = stc.sessions() for session in sessions: print(' ' * 4, session) except Exception as e: print(e, file=sys.stderr) sys.exit(1)
def main(): """ Read the arguments, Invoke Test and Return the results""" parser = argparse.ArgumentParser() # Required parameters required_named = parser.add_argument_group("required named arguments") required_named.add_argument("--lab_server_addr", required=True, help=("The IP address of the" "Spirent Lab Server"), dest="lab_server_addr") required_named.add_argument("--license_server_addr", required=True, help=("The IP address of the Spirent" "License Server"), dest="license_server_addr") required_named.add_argument("--east_chassis_addr", required=True, help=("The TestCenter chassis IP address to" "use for the east test port"), dest="east_chassis_addr") required_named.add_argument("--east_slot_num", type=positive_int, required=True, help=("The TestCenter slot number to" "use for the east test port"), dest="east_slot_num") required_named.add_argument("--east_port_num", type=positive_int, required=True, help=("The TestCenter port number to use" "for the east test port"), dest="east_port_num") required_named.add_argument("--west_chassis_addr", required=True, help=("The TestCenter chassis IP address" "to use for the west test port"), dest="west_chassis_addr") required_named.add_argument("--west_slot_num", type=positive_int, required=True, help=("The TestCenter slot number to use" "for the west test port"), dest="west_slot_num") required_named.add_argument("--west_port_num", type=positive_int, required=True, help=("The TestCenter port number to" "use for the west test port"), dest="west_port_num") # Optional parameters optional_named = parser.add_argument_group("optional named arguments") optional_named.add_argument( "--metric", required=False, help=("One among - throughput, latency,\ backtoback and frameloss"), choices=["throughput", "latency", "backtoback", "frameloss"], default="throughput", dest="metric") optional_named.add_argument("--test_session_name", required=False, default="RFC2544 East-West Throughput", help=("The friendly name to identify" "the Spirent Lab Server test session"), dest="test_session_name") optional_named.add_argument("--test_user_name", required=False, default="RFC2544 East-West User", help=("The friendly name to identify the" "Spirent Lab Server test user"), dest="test_user_name") optional_named.add_argument("--results_dir", required=False, default="./Results", help="The directory to copy results to", dest="results_dir") optional_named.add_argument("--vsperf_results_dir", required=False, default="./Results", help="The directory to copy results to", dest="vsperf_results_dir") optional_named.add_argument("--csv_results_file_prefix", required=False, default="Rfc2544Tput", help="The prefix for the CSV results files", dest="csv_results_file_prefix") optional_named.add_argument("--num_trials", type=positive_int, required=False, default=1, help=("The number of trials to execute during" "the test"), dest="num_trials") optional_named.add_argument("--trial_duration_sec", type=positive_int, required=False, default=60, help=("The duration of each trial executed" "during the test"), dest="trial_duration_sec") optional_named.add_argument("--traffic_pattern", required=False, choices=["BACKBONE", "MESH", "PAIR"], default="PAIR", help="The traffic pattern between endpoints", dest="traffic_pattern") optional_named.add_argument("--traffic_custom", required=False, default=None, help="The traffic pattern between endpoints", dest="traffic_custom") optional_named.add_argument("--search_mode", required=False, choices=["COMBO", "STEP", "BINARY"], default="BINARY", help=("The search mode used to find the" "throughput rate"), dest="search_mode") optional_named.add_argument( "--learning_mode", required=False, choices=["AUTO", "L2_LEARNING", "L3_LEARNING", "NONE"], default="AUTO", help=("The learning mode used during the test," "default is 'NONE'"), dest="learning_mode") optional_named.add_argument("--rate_lower_limit_pct", type=percent_float, required=False, default=1.0, help=("The minimum percent line rate that" "will be used during the test"), dest="rate_lower_limit_pct") optional_named.add_argument("--rate_upper_limit_pct", type=percent_float, required=False, default=99.0, help=("The maximum percent line rate that" "will be used during the test"), dest="rate_upper_limit_pct") optional_named.add_argument("--rate_initial_pct", type=percent_float, required=False, default=99.0, help=("If Search Mode is BINARY, the percent" "line rate that will be used at the" "start of the test"), dest="rate_initial_pct") optional_named.add_argument("--rate_step_pct", type=percent_float, required=False, default=10.0, help=("If SearchMode is STEP, the percent" "load increase per step"), dest="rate_step_pct") optional_named.add_argument("--resolution_pct", type=percent_float, required=False, default=1.0, help=("The minimum percentage of load" "adjustment between iterations"), dest="resolution_pct") optional_named.add_argument( "--frame_size_list", type=lambda s: [int(item) for item in s.split(',')], required=False, default=[256], help="A comma-delimited list of frame sizes", dest="frame_size_list") optional_named.add_argument("--acceptable_frame_loss_pct", type=percent_float, required=False, default=0.0, help=("The maximum acceptable frame loss" "percent in any iteration"), dest="acceptable_frame_loss_pct") optional_named.add_argument("--east_intf_addr", required=False, default="192.85.1.3", help=("The address to assign to the first" "emulated device interface on the first" "east port"), dest="east_intf_addr") optional_named.add_argument("--east_intf_gateway_addr", required=False, default="192.85.1.53", help=("The gateway address to assign to the" "first emulated device interface on the" "first east port"), dest="east_intf_gateway_addr") optional_named.add_argument("--west_intf_addr", required=False, default="192.85.1.53", help=("The address to assign to the first" "emulated device interface on the" "first west port"), dest="west_intf_addr") optional_named.add_argument("--west_intf_gateway_addr", required=False, default="192.85.1.53", help=("The gateway address to assign to" "the first emulated device interface" "on the first west port"), dest="west_intf_gateway_addr") optional_named.add_argument( "--latency_histogram", required=False, action="store_true", help="latency histogram is required in output?", dest="latency_histogram") optional_named.add_argument("--imix", required=False, default="", help=("IMIX specification as genome" "Encoding - RFC 6985"), dest="imix") optional_named.add_argument("--live_results", required=False, action="store_true", help="Live Results required?", dest="live_results") optional_named.add_argument("--logfile", required=False, default="./traffic_gen.log", help="Log file to log live results", dest="logfile") parser.add_argument("-v", "--verbose", required=False, default=True, help="More output during operation when present", action="store_true", dest="verbose") args = parser.parse_args() if args.verbose: _LOGGER.debug("Creating results directory") create_dir(args.results_dir) session_name = args.test_session_name user_name = args.test_user_name # pylint: disable=import-error try: # Load Spirent REST Library from stcrestclient import stchttp stc = stchttp.StcHttp(args.lab_server_addr) session_id = stc.new_session(user_name, session_name) stc.join_session(session_id) except RuntimeError as err: _LOGGER.error(err) raise # Get STC system info. tx_port_loc = "//%s/%s/%s" % (args.east_chassis_addr, args.east_slot_num, args.east_port_num) rx_port_loc = "//%s/%s/%s" % (args.west_chassis_addr, args.west_slot_num, args.west_port_num) # Retrieve and display the server information if args.verbose: _LOGGER.debug("SpirentTestCenter system version: %s", stc.get("system1", "version")) # pylint: disable=too-many-nested-blocks try: device_list = [] port_list = [] if args.verbose: _LOGGER.debug("Bring up license server") license_mgr = stc.get("system1", "children-licenseservermanager") if args.verbose: _LOGGER.debug("license_mgr = %s", license_mgr) stc.create("LicenseServer", under=license_mgr, attributes={"server": args.license_server_addr}) # Create the root project object if args.verbose: _LOGGER.debug("Creating project ...") project = stc.get("System1", "children-Project") # Configure the Result view resultopts = stc.get('project1', 'children-resultoptions') stc.config(resultopts, {'ResultViewMode': 'BASIC'}) # Configure any custom traffic parameters if args.traffic_custom == "cont": if args.verbose: _LOGGER.debug("Configure Continuous Traffic") stc.create("ContinuousTestConfig", under=project) # Create ports if args.verbose: _LOGGER.debug("Creating ports ...") east_chassis_port = stc.create('port', project) if args.verbose: _LOGGER.debug("Configuring TX port ...") stc.config(east_chassis_port, {'location': tx_port_loc}) port_list.append(east_chassis_port) west_chassis_port = stc.create('port', project) if args.verbose: _LOGGER.debug("Configuring RX port ...") stc.config(west_chassis_port, {'location': rx_port_loc}) port_list.append(west_chassis_port) # Create emulated genparam for east port east_device_gen_params = stc.create( "EmulatedDeviceGenParams", under=project, attributes={"Port": east_chassis_port}) # Create the DeviceGenEthIIIfParams object stc.create("DeviceGenEthIIIfParams", under=east_device_gen_params, attributes={'UseDefaultPhyMac': True}) # Configuring Ipv4 interfaces stc.create("DeviceGenIpv4IfParams", under=east_device_gen_params, attributes={ "Addr": args.east_intf_addr, "Gateway": args.east_intf_gateway_addr }) # Create Devices using the Device Wizard device_gen_config = stc.perform("DeviceGenConfigExpand", params={ "DeleteExisting": "No", "GenParams": east_device_gen_params }) # Append to the device list device_list.append(device_gen_config['ReturnList']) # Create emulated genparam for west port west_device_gen_params = stc.create( "EmulatedDeviceGenParams", under=project, attributes={"Port": west_chassis_port}) # Create the DeviceGenEthIIIfParams object stc.create("DeviceGenEthIIIfParams", under=west_device_gen_params, attributes={'UseDefaultPhyMac': True}) # Configuring Ipv4 interfaces stc.create("DeviceGenIpv4IfParams", under=west_device_gen_params, attributes={ "Addr": args.west_intf_addr, "Gateway": args.west_intf_gateway_addr }) # Create Devices using the Device Wizard device_gen_config = stc.perform("DeviceGenConfigExpand", params={ "DeleteExisting": "No", "GenParams": west_device_gen_params }) # Append to the device list device_list.append(device_gen_config['ReturnList']) if args.verbose: _LOGGER.debug(device_list) # Configure Histogram if args.latency_histogram: # Generic Configuration histResOptions = stc.get("project1", 'children-ResultOptions') stc.config(histResOptions, {'ResultViewMode': 'HISTOGRAM'}) # East Port Configuration histAnaEast = stc.get(east_chassis_port, 'children-Analyzer') histAnaEastConfig = stc.get(histAnaEast, 'children-AnalyzerConfig') stc.config(histAnaEastConfig, {'HistogramMode': 'LATENCY'}) eLatHist = stc.get(histAnaEastConfig, 'children-LatencyHistogram') stc.config( eLatHist, { 'ConfigMode': 'CONFIG_LIMIT_MODE', 'BucketSizeUnit': 'ten_nanoseconds', 'Active': 'TRUE', 'DistributionMode': 'CENTERED_MODE' }) # West Port Configuration histAnaWest = stc.get(west_chassis_port, 'children-Analyzer') histAnaWestConfig = stc.get(histAnaWest, 'children-AnalyzerConfig') stc.config(histAnaWestConfig, {'HistogramMode': 'LATENCY'}) wLatHist = stc.get(histAnaWestConfig, 'children-LatencyHistogram') stc.config( wLatHist, { 'ConfigMode': 'CONFIG_LIMIT_MODE', 'BucketSizeUnit': 'ten_nanoseconds', 'Active': 'TRUE', 'DistributionMode': 'CENTERED_MODE' }) gBucketSizeList = stc.get(wLatHist, 'BucketSizeList') # gLimitSizeList = stc.get(wLatHist, 'LimitList') # IMIX configuration fld = None if args.imix: args.frame_size_list = [] weights = genome2weights(args.imix) fld = stc.create('FrameLengthDistribution', under=project) def_slots = stc.get(fld, "children-framelengthdistributionslot") stc.perform("Delete", params={"ConfigList": def_slots}) for fsize in weights: stc.create('framelengthdistributionslot', under=fld, attributes={ 'FixedFrameLength': fsize, 'Weight': weights[fsize] }) # Create the RFC 2544 'metric test if args.metric == "throughput": if args.verbose: _LOGGER.debug("Set up the RFC2544 throughput test...") stc.perform("Rfc2544SetupThroughputTestCommand", params={ "AcceptableFrameLoss": args.acceptable_frame_loss_pct, "Duration": args.trial_duration_sec, "FrameSizeList": args.frame_size_list, "LearningMode": args.learning_mode, "NumOfTrials": args.num_trials, "RateInitial": args.rate_initial_pct, "RateLowerLimit": args.rate_lower_limit_pct, "RateStep": args.rate_step_pct, "RateUpperLimit": args.rate_upper_limit_pct, "Resolution": args.resolution_pct, "SearchMode": args.search_mode, "TrafficPattern": args.traffic_pattern, "FrameSizeDistributionList": fld }) elif args.metric == "backtoback": stc.perform("Rfc2544SetupBackToBackTestCommand", params={ "AcceptableFrameLoss": args.acceptable_frame_loss_pct, "Duration": args.trial_duration_sec, "FrameSizeList": args.frame_size_list, "LearningMode": args.learning_mode, "LatencyType": args.latency_type, "NumOfTrials": args.num_trials, "RateInitial": args.rate_initial_pct, "RateLowerLimit": args.rate_lower_limit_pct, "RateStep": args.rate_step_pct, "RateUpperLimit": args.rate_upper_limit_pct, "Resolution": args.resolution_pct, "SearchMode": args.search_mode, "TrafficPattern": args.traffic_pattern }) elif args.metric == "frameloss": stc.perform("Rfc2544SetupFrameLossTestCommand", params={ "AcceptableFrameLoss": args.acceptable_frame_loss_pct, "Duration": args.trial_duration_sec, "FrameSizeList": args.frame_size_list, "LearningMode": args.learning_mode, "LatencyType": args.latency_type, "NumOfTrials": args.num_trials, "RateInitial": args.rate_initial_pct, "RateLowerLimit": args.rate_lower_limit_pct, "RateStep": args.rate_step_pct, "RateUpperLimit": args.rate_upper_limit_pct, "Resolution": args.resolution_pct, "SearchMode": args.search_mode, "TrafficPattern": args.traffic_pattern }) elif args.metric == "latency": stc.perform("Rfc2544SetupLatencyTestCommand", params={ "AcceptableFrameLoss": args.acceptable_frame_loss_pct, "Duration": args.trial_duration_sec, "FrameSizeList": args.frame_size_list, "LearningMode": args.learning_mode, "LatencyType": args.latency_type, "NumOfTrials": args.num_trials, "RateInitial": args.rate_initial_pct, "RateLowerLimit": args.rate_lower_limit_pct, "RateStep": args.rate_step_pct, "RateUpperLimit": args.rate_upper_limit_pct, "Resolution": args.resolution_pct, "SearchMode": args.search_mode, "TrafficPattern": args.traffic_pattern }) # Save the configuration stc.perform("SaveToTcc", params={"Filename": "2544.tcc"}) # Connect to the hardware... stc.perform("AttachPorts", params={ "portList": stc.get("system1.project", "children-port"), "autoConnect": "TRUE" }) # Apply configuration. if args.verbose: _LOGGER.debug("Apply configuration...") stc.apply() # Register for the results hResDataRx = stc.create('ResultDataSet', under='project1') strmBlockList = stc.get('project1', 'children-streamblock') stc.create('ResultQuery', under=hResDataRx, attributes={ 'ResultRootList': strmBlockList, 'ConfigClassId': 'StreamBlock', 'ResultClassId': 'RxStreamSummaryResults', 'PropertyIdArray': "RxStreamSummaryResults.RxPort \ RxStreamSummaryResults.AvgLatency \ RxStreamSummaryResults.BitCount \ RxStreamSummaryResults.BitRate \ RxStreamSummaryResults.DroppedFrameCount\ RxStreamSummaryResults.DroppedFrameRate \ RxStreamSummaryResults.FrameCount \ RxStreamSummaryResults.FrameRate \ RxStreamSummaryResults.MaxLatency \ RxStreamSummaryResults.MinLatency \ RxStreamSummaryResults.OctetCount \ RxStreamSummaryResults.OctetRate \ RxStreamSummaryResults.SeqRunLength" }) hResDataTx = stc.create('ResultDataSet', under='project1') strmBlockList = stc.get('project1', 'children-streamblock') stc.create('ResultQuery', under=hResDataTx, attributes={ 'ResultRootList': strmBlockList, 'ConfigClassId': 'StreamBlock', 'ResultClassId': 'TxStreamResults', 'PropertyIdArray': "TxStreamResults.BlockId \ TxStreamResults.BitCount \ TxStreamResults.BitRate \ TxStreamResults.FrameCount \ TxStreamResults.FrameRate \ TxStreamResults.OctetCount \ TxStreamResults.OctetRate" }) stc.perform('ResultDataSetSubscribe', params={'ResultDataSet': hResDataRx}) stc.perform('ResultDataSetSubscribe', params={'ResultDataSet': hResDataTx}) time.sleep(3) stc.perform('RefreshResultView', params={'ResultDataSet': hResDataTx}) hndListRx = stc.get(hResDataRx, 'ResultHandleList') hndListTx = stc.get(hResDataTx, 'ResultHandleList') if args.verbose: _LOGGER.debug("Starting the sequencer...") stc.perform("SequencerStart") sequencer = stc.get("system1", "children-sequencer") state = stc.get(sequencer, 'State') # If Live-results are required, we don't wait for the test to complete if args.live_results: write_headers(args.vsperf_results_dir, args.logfile, '.rx') write_headers(args.vsperf_results_dir, args.logfile, '.tx') while state != 'IDLE': state = stc.get(sequencer, 'State') hndListTx = stc.get(hResDataTx, 'ResultHandleList') if hndListTx: handles = hndListTx.split(' ') for handle in handles: tx_values = stc.get(handle) write_tx_live_results_to_file(args.vsperf_results_dir, args.logfile, tx_values) if hndListRx: handles = hndListRx.split(' ') for handle in handles: rx_values = stc.get(handle) write_rx_live_results_to_file(args.vsperf_results_dir, args.logfile, rx_values) time.sleep(1) # Live results not needed, so just wait! else: # Wait for sequencer to finish _LOGGER.info( "Starting test... Please wait for the test to complete...") stc.wait_until_complete() _LOGGER.info("The test has completed... Saving results...") # Determine what the results database filename is... lab_server_resultsdb = stc.get("system1.project.TestResultSetting", "CurrentResultFileName") if not lab_server_resultsdb or 'Results' not in lab_server_resultsdb: _LOGGER.info("Failed to find results.") stc.end_session() return if args.verbose: _LOGGER.debug("The lab server results database is %s", lab_server_resultsdb) # Create Latency Histogram CSV file() if args.latency_histogram: hist_dict_counts = {} for file_url in stc.files(): if '-FrameSize-' in file_url: stc.download(file_url) filename = file_url.split('/')[-1] if os.path.exists(os.getcwd() + '/' + filename): conn = sqlite3.connect(os.getcwd() + '/' + filename) # cursor = conn.execute( # 'select * from RxEotStreamResults') # names = [desc[0] for desc in cursor.description] counts = conn.execute("SELECT \ HistBin1Count, HistBin2Count,\ HistBin3Count, HistBin4Count,\ HistBin5Count, HistBin6Count,\ HistBin7Count, HistBin8Count,\ HistBin9Count, HistBin10Count,\ HistBin11Count, HistBin12Count,\ HistBin13Count, HistBin14Count, \ HistBin15Count, HistBin16Count \ from RxEotStreamResults") strs = filename.split('-') key = strs[strs.index('FrameSize') + 1] if key in hist_dict_counts: hist_dict_counts[key] = [ a + b for a, b in zip(counts.fetchone(), hist_dict_counts[key]) ] else: hist_dict_counts[key] = counts.fetchone() conn.close() write_histogram_to_csv(args.vsperf_results_dir, 'Histogram', hist_dict_counts, gBucketSizeList) stc.perform("CSSynchronizeFiles", params={"DefaultDownloadDir": args.results_dir}) resultsdb = args.results_dir + \ lab_server_resultsdb.split("/Results")[1] if not os.path.exists(resultsdb): resultsdb = lab_server_resultsdb _LOGGER.info("Failed to create the local summary DB File, using" " the remote DB file instead.") else: _LOGGER.info("The local summary DB file has been saved to %s", resultsdb) # The returns the "RFC2544ThroughputTestResultDetailedSummaryView" # table view from the results database. # There are other views available. if args.metric == "throughput": resultsdict = (stc.perform( "QueryResult", params={ "DatabaseConnectionString": resultsdb, "ResultPath": ("RFC2544ThroughputTestResultDetailed" "SummaryView") })) # The returns the "RFC2544BacktoBackTestResultDetailedSummaryView" # table view from the results database. # There are other views available. elif args.metric == "backtoback": resultsdict = (stc.perform( "QueryResult", params={ "DatabaseConnectionString": resultsdb, "ResultPath": ("RFC2544Back2BackTestResultDetailed" "SummaryView") })) # The returns the "RFC2544LatencyTestResultDetailedSummaryView" # table view from the results database. # There are other views available. elif args.metric == "latency": resultsdict = (stc.perform("QueryResult", params={ "DatabaseConnectionString": resultsdb, "ResultPath": ("RFC2544LatencyTestResultDetailed" "SummaryView") })) # The returns the "RFC2544FrameLossTestResultDetailedSummaryView" # table view from the results database. # There are other views available. elif args.metric == "frameloss": resultsdict = (stc.perform( "QueryResult", params={ "DatabaseConnectionString": resultsdb, "ResultPath": ("RFC2544FrameLossTestResultDetailed" "SummaryView") })) if args.verbose: _LOGGER.debug("resultsdict[\"Columns\"]: %s", resultsdict["Columns"]) _LOGGER.debug("resultsdict[\"Output\"]: %s", resultsdict["Output"]) _LOGGER.debug("Result paths: %s", stc.perform("GetTestResultSettingPaths")) # Write results to csv _LOGGER.debug("Writing CSV file to results directory %s", args.results_dir) write_query_results_to_csv(args.results_dir, args.csv_results_file_prefix, resultsdict) except RuntimeError as e: stc.end_session() _LOGGER.error(e) if args.verbose: _LOGGER.debug("Destroy session on lab server") stc.end_session() _LOGGER.info("Test complete!")
def main(): """ Read the arguments, Invoke Test and Return the results""" parser = argparse.ArgumentParser() # Required parameters required_named = parser.add_argument_group("required named arguments") required_named.add_argument("--lab_server_addr", required=True, help=("The IP address of the" "Spirent Lab Server"), dest="lab_server_addr") required_named.add_argument("--license_server_addr", required=True, help=("The IP address of the Spirent" "License Server"), dest="license_server_addr") required_named.add_argument("--east_chassis_addr", required=True, help=("The TestCenter chassis IP address to" "use for the east test port"), dest="east_chassis_addr") required_named.add_argument("--east_slot_num", type=positive_int, required=True, help=("The TestCenter slot number to" "use for the east test port"), dest="east_slot_num") required_named.add_argument("--east_port_num", type=positive_int, required=True, help=("The TestCenter port number to use" "for the east test port"), dest="east_port_num") required_named.add_argument("--west_chassis_addr", required=True, help=("The TestCenter chassis IP address" "to use for the west test port"), dest="west_chassis_addr") required_named.add_argument("--west_slot_num", type=positive_int, required=True, help=("The TestCenter slot number to use" "for the west test port"), dest="west_slot_num") required_named.add_argument("--west_port_num", type=positive_int, required=True, help=("The TestCenter port number to" "use for the west test port"), dest="west_port_num") # Optional parameters optional_named = parser.add_argument_group("optional named arguments") optional_named.add_argument("--metric", required=False, help=("One among - throughput, latency,\ backtoback and frameloss"), choices=["throughput", "latency", "backtoback", "frameloss"], default="throughput", dest="metric") optional_named.add_argument("--test_session_name", required=False, default="RFC2544 East-West Throughput", help=("The friendly name to identify" "the Spirent Lab Server test session"), dest="test_session_name") optional_named.add_argument("--test_user_name", required=False, default="RFC2544 East-West User", help=("The friendly name to identify the" "Spirent Lab Server test user"), dest="test_user_name") optional_named.add_argument("--results_dir", required=False, default="./Results", help="The directory to copy results to", dest="results_dir") optional_named.add_argument("--csv_results_file_prefix", required=False, default="Rfc2544Tput", help="The prefix for the CSV results files", dest="csv_results_file_prefix") optional_named.add_argument("--num_trials", type=positive_int, required=False, default=1, help=("The number of trials to execute during" "the test"), dest="num_trials") optional_named.add_argument("--trial_duration_sec", type=positive_int, required=False, default=60, help=("The duration of each trial executed" "during the test"), dest="trial_duration_sec") optional_named.add_argument("--traffic_pattern", required=False, choices=["BACKBONE", "MESH", "PAIR"], default="PAIR", help="The traffic pattern between endpoints", dest="traffic_pattern") optional_named.add_argument("--traffic_custom", required=False, default=None, help="The traffic pattern between endpoints", dest="traffic_custom") optional_named.add_argument("--search_mode", required=False, choices=["COMBO", "STEP", "BINARY"], default="BINARY", help=("The search mode used to find the" "throughput rate"), dest="search_mode") optional_named.add_argument("--learning_mode", required=False, choices=["AUTO", "L2_LEARNING", "L3_LEARNING", "NONE"], default="AUTO", help=("The learning mode used during the test," "default is 'NONE'"), dest="learning_mode") optional_named.add_argument("--rate_lower_limit_pct", type=percent_float, required=False, default=1.0, help=("The minimum percent line rate that" "will be used during the test"), dest="rate_lower_limit_pct") optional_named.add_argument("--rate_upper_limit_pct", type=percent_float, required=False, default=99.0, help=("The maximum percent line rate that" "will be used during the test"), dest="rate_upper_limit_pct") optional_named.add_argument("--rate_initial_pct", type=percent_float, required=False, default=99.0, help=("If Search Mode is BINARY, the percent" "line rate that will be used at the" "start of the test"), dest="rate_initial_pct") optional_named.add_argument("--rate_step_pct", type=percent_float, required=False, default=10.0, help=("If SearchMode is STEP, the percent" "load increase per step"), dest="rate_step_pct") optional_named.add_argument("--resolution_pct", type=percent_float, required=False, default=1.0, help=("The minimum percentage of load" "adjustment between iterations"), dest="resolution_pct") optional_named.add_argument("--frame_size_list", type=lambda s: [int(item) for item in s.split(',')], required=False, default=[256], help="A comma-delimited list of frame sizes", dest="frame_size_list") optional_named.add_argument("--acceptable_frame_loss_pct", type=percent_float, required=False, default=0.0, help=("The maximum acceptable frame loss" "percent in any iteration"), dest="acceptable_frame_loss_pct") optional_named.add_argument("--east_intf_addr", required=False, default="192.85.1.3", help=("The address to assign to the first" "emulated device interface on the first" "east port"), dest="east_intf_addr") optional_named.add_argument("--east_intf_gateway_addr", required=False, default="192.85.1.53", help=("The gateway address to assign to the" "first emulated device interface on the" "first east port"), dest="east_intf_gateway_addr") optional_named.add_argument("--west_intf_addr", required=False, default="192.85.1.53", help=("The address to assign to the first" "emulated device interface on the" "first west port"), dest="west_intf_addr") optional_named.add_argument("--west_intf_gateway_addr", required=False, default="192.85.1.53", help=("The gateway address to assign to" "the first emulated device interface" "on the first west port"), dest="west_intf_gateway_addr") parser.add_argument("-v", "--verbose", required=False, default=True, help="More output during operation when present", action="store_true", dest="verbose") args = parser.parse_args() if args.verbose: _LOGGER.debug("Creating results directory") create_dir(args.results_dir) session_name = args.test_session_name user_name = args.test_user_name # pylint: disable=import-error try: # Load Spirent REST Library from stcrestclient import stchttp stc = stchttp.StcHttp(args.lab_server_addr) session_id = stc.new_session(user_name, session_name) stc.join_session(session_id) except RuntimeError as err: _LOGGER.error(err) raise # Get STC system info. tx_port_loc = "//%s/%s/%s" % (args.east_chassis_addr, args.east_slot_num, args.east_port_num) rx_port_loc = "//%s/%s/%s" % (args.west_chassis_addr, args.west_slot_num, args.west_port_num) # Retrieve and display the server information if args.verbose: _LOGGER.debug("SpirentTestCenter system version: %s", stc.get("system1", "version")) try: device_list = [] port_list = [] if args.verbose: _LOGGER.debug("Bring up license server") license_mgr = stc.get("system1", "children-licenseservermanager") if args.verbose: _LOGGER.debug("license_mgr = %s", license_mgr) stc.create("LicenseServer", under=license_mgr, attributes={ "server": args.license_server_addr}) # Create the root project object if args.verbose: _LOGGER.debug("Creating project ...") project = stc.get("System1", "children-Project") # Configure any custom traffic parameters if args.traffic_custom == "cont": if args.verbose: _LOGGER.debug("Configure Continuous Traffic") stc.create("ContinuousTestConfig", under=project) # Create ports if args.verbose: _LOGGER.debug("Creating ports ...") east_chassis_port = stc.create('port', project) if args.verbose: _LOGGER.debug("Configuring TX port ...") stc.config(east_chassis_port, {'location': tx_port_loc}) port_list.append(east_chassis_port) west_chassis_port = stc.create('port', project) if args.verbose: _LOGGER.debug("Configuring RX port ...") stc.config(west_chassis_port, {'location': rx_port_loc}) port_list.append(west_chassis_port) # Create emulated genparam for east port east_device_gen_params = stc.create("EmulatedDeviceGenParams", under=project, attributes={"Port": east_chassis_port}) # Create the DeviceGenEthIIIfParams object stc.create("DeviceGenEthIIIfParams", under=east_device_gen_params) # Configuring Ipv4 interfaces stc.create("DeviceGenIpv4IfParams", under=east_device_gen_params, attributes={"Addr": args.east_intf_addr, "Gateway": args.east_intf_gateway_addr}) # Create Devices using the Device Wizard device_gen_config = stc.perform("DeviceGenConfigExpand", params={"DeleteExisting": "No", "GenParams": east_device_gen_params}) # Append to the device list device_list.append(device_gen_config['ReturnList']) # Create emulated genparam for west port west_device_gen_params = stc.create("EmulatedDeviceGenParams", under=project, attributes={"Port": west_chassis_port}) # Create the DeviceGenEthIIIfParams object stc.create("DeviceGenEthIIIfParams", under=west_device_gen_params) # Configuring Ipv4 interfaces stc.create("DeviceGenIpv4IfParams", under=west_device_gen_params, attributes={"Addr": args.west_intf_addr, "Gateway": args.west_intf_gateway_addr}) # Create Devices using the Device Wizard device_gen_config = stc.perform("DeviceGenConfigExpand", params={"DeleteExisting": "No", "GenParams": west_device_gen_params}) # Append to the device list device_list.append(device_gen_config['ReturnList']) if args.verbose: _LOGGER.debug(device_list) # Create the RFC 2544 'metric test if args.metric == "throughput": if args.verbose: _LOGGER.debug("Set up the RFC2544 throughput test...") stc.perform("Rfc2544SetupThroughputTestCommand", params={"AcceptableFrameLoss": args.acceptable_frame_loss_pct, "Duration": args.trial_duration_sec, "FrameSizeList": args.frame_size_list, "LearningMode": args.learning_mode, "NumOfTrials": args.num_trials, "RateInitial": args.rate_initial_pct, "RateLowerLimit": args.rate_lower_limit_pct, "RateStep": args.rate_step_pct, "RateUpperLimit": args.rate_upper_limit_pct, "Resolution": args.resolution_pct, "SearchMode": args.search_mode, "TrafficPattern": args.traffic_pattern}) elif args.metric == "backtoback": stc.perform("Rfc2544SetupBackToBackTestCommand", params={"AcceptableFrameLoss": args.acceptable_frame_loss_pct, "Duration": args.trial_duration_sec, "FrameSizeList": args.frame_size_list, "LearningMode": args.learning_mode, "LatencyType": args.latency_type, "NumOfTrials": args.num_trials, "RateInitial": args.rate_initial_pct, "RateLowerLimit": args.rate_lower_limit_pct, "RateStep": args.rate_step_pct, "RateUpperLimit": args.rate_upper_limit_pct, "Resolution": args.resolution_pct, "SearchMode": args.search_mode, "TrafficPattern": args.traffic_pattern}) elif args.metric == "frameloss": stc.perform("Rfc2544SetupFrameLossTestCommand", params={"AcceptableFrameLoss": args.acceptable_frame_loss_pct, "Duration": args.trial_duration_sec, "FrameSizeList": args.frame_size_list, "LearningMode": args.learning_mode, "LatencyType": args.latency_type, "NumOfTrials": args.num_trials, "RateInitial": args.rate_initial_pct, "RateLowerLimit": args.rate_lower_limit_pct, "RateStep": args.rate_step_pct, "RateUpperLimit": args.rate_upper_limit_pct, "Resolution": args.resolution_pct, "SearchMode": args.search_mode, "TrafficPattern": args.traffic_pattern}) elif args.metric == "latency": stc.perform("Rfc2544SetupLatencyTestCommand", params={"AcceptableFrameLoss": args.acceptable_frame_loss_pct, "Duration": args.trial_duration_sec, "FrameSizeList": args.frame_size_list, "LearningMode": args.learning_mode, "LatencyType": args.latency_type, "NumOfTrials": args.num_trials, "RateInitial": args.rate_initial_pct, "RateLowerLimit": args.rate_lower_limit_pct, "RateStep": args.rate_step_pct, "RateUpperLimit": args.rate_upper_limit_pct, "Resolution": args.resolution_pct, "SearchMode": args.search_mode, "TrafficPattern": args.traffic_pattern}) # Save the configuration stc.perform("SaveToTcc", params={"Filename": "2544.tcc"}) # Connect to the hardware... stc.perform("AttachPorts", params={"portList": stc.get( "system1.project", "children-port"), "autoConnect": "TRUE"}) # Apply configuration. if args.verbose: _LOGGER.debug("Apply configuration...") stc.apply() if args.verbose: _LOGGER.debug("Starting the sequencer...") stc.perform("SequencerStart") # Wait for sequencer to finish _LOGGER.info( "Starting test... Please wait for the test to complete...") stc.wait_until_complete() _LOGGER.info("The test has completed... Saving results...") # Determine what the results database filename is... lab_server_resultsdb = stc.get( "system1.project.TestResultSetting", "CurrentResultFileName") if args.verbose: _LOGGER.debug("The lab server results database is %s", lab_server_resultsdb) stc.perform("CSSynchronizeFiles", params={"DefaultDownloadDir": args.results_dir}) resultsdb = args.results_dir + \ lab_server_resultsdb.split("/Results")[1] if not os.path.exists(resultsdb): resultsdb = lab_server_resultsdb _LOGGER.info("Failed to create the local summary DB File, using" " the remote DB file instead.") else: _LOGGER.info( "The local summary DB file has been saved to %s", resultsdb) # The returns the "RFC2544ThroughputTestResultDetailedSummaryView" # table view from the results database. # There are other views available. if args.metric == "throughput": resultsdict = ( stc.perform("QueryResult", params={ "DatabaseConnectionString": resultsdb, "ResultPath": ("RFC2544ThroughputTestResultDetailed" "SummaryView")})) # The returns the "RFC2544BacktoBackTestResultDetailedSummaryView" # table view from the results database. # There are other views available. elif args.metric == "backtoback": resultsdict = ( stc.perform("QueryResult", params={ "DatabaseConnectionString": resultsdb, "ResultPath": ("RFC2544Back2BackTestResultDetailed" "SummaryView")})) # The returns the "RFC2544LatencyTestResultDetailedSummaryView" # table view from the results database. # There are other views available. elif args.metric == "latency": resultsdict = ( stc.perform("QueryResult", params={ "DatabaseConnectionString": resultsdb, "ResultPath": ("RFC2544LatencyTestResultDetailed" "SummaryView")})) # The returns the "RFC2544FrameLossTestResultDetailedSummaryView" # table view from the results database. # There are other views available. elif args.metric == "frameloss": resultsdict = ( stc.perform("QueryResult", params={ "DatabaseConnectionString": resultsdb, "ResultPath": ("RFC2544FrameLossTestResultDetailed" "SummaryView")})) if args.verbose: _LOGGER.debug("resultsdict[\"Columns\"]: %s", resultsdict["Columns"]) _LOGGER.debug("resultsdict[\"Output\"]: %s", resultsdict["Output"]) _LOGGER.debug("Result paths: %s", stc.perform("GetTestResultSettingPaths")) # Write results to csv _LOGGER.debug("Writing CSV file to results directory %s", args.results_dir) write_query_results_to_csv( args.results_dir, args.csv_results_file_prefix, resultsdict) except RuntimeError as e: _LOGGER.error(e) if args.verbose: _LOGGER.debug("Destroy session on lab server") stc.end_session() _LOGGER.info("Test complete!")
#!/usr/bin/env python3 import logging from stcrestclient import stchttp from stc_session import StcSession log = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) try: addr = StcSession.default_config['stc_server_addr'] port = StcSession.default_config['stc_server_port'] stc = stchttp.StcHttp(addr, port) sessions = stc.sessions() for session in sessions: log.info('Joining session {}'.format(session)) stc.join_session(session) log.info('Ending session {}'.format(session)) stc.end_session(session) except Exception as e: print(e) exit(1)
def main(): """ Read the arguments, Invoke Test and Return the results""" parser = argparse.ArgumentParser() # Required parameters required_named = parser.add_argument_group("required named arguments") required_named.add_argument("--lab_server_addr", required=True, help=("The IP address of the " "Spirent Lab Server"), dest="lab_server_addr") required_named.add_argument("--license_server_addr", required=True, help=("The IP address of the Spirent " "License Server"), dest="license_server_addr") required_named.add_argument("--location_list", required=True, help=("A comma-delimited list of test port " "locations"), dest="location_list") # Optional parameters optional_named = parser.add_argument_group("optional named arguments") optional_named.add_argument("--metric", required=False, help=("One among - Forwarding,\ Address Caching and Learning"), choices=["forwarding", "caching", "learning"], default="forwarding", dest="metric") optional_named.add_argument("--test_session_name", required=False, default="Rfc2889Ses", help=("The friendly name to identify " "the Spirent Lab Server test session"), dest="test_session_name") optional_named.add_argument("--test_user_name", required=False, default="Rfc2889Usr", help=("The friendly name to identify the " "Spirent Lab Server test user"), dest="test_user_name") optional_named.add_argument("--results_dir", required=False, default="./Results", help="The directory to copy results to", dest="results_dir") optional_named.add_argument("--csv_results_file_prefix", required=False, default="Rfc2889MaxFor", help="The prefix for the CSV results files", dest="csv_results_file_prefix") optional_named.add_argument("--num_trials", type=positive_int, required=False, default=1, help=("The number of trials to execute during " "the test"), dest="num_trials") optional_named.add_argument("--trial_duration_sec", type=positive_int, required=False, default=60, help=("The duration of each trial executed " "during the test"), dest="trial_duration_sec") optional_named.add_argument("--traffic_pattern", required=False, choices=["BACKBONE", "MESH", "PAIR"], default="MESH", help="The traffic pattern between endpoints", dest="traffic_pattern") optional_named.add_argument("--frame_size_list", type=lambda s: [int(item) for item in s.split(',')], required=False, default=[256], help="A comma-delimited list of frame sizes", dest="frame_size_list") optional_named.add_argument("--min_learning_rate", type=positive_int, required=False, default=1488, help="Lowest learning rate for test", dest="min_learning_rate") optional_named.add_argument("--max_learning_rate", type=positive_int, required=False, default=14880, help="Highest learning rate for test", dest="max_learning_rate") optional_named.add_argument("--min_num_addrs", type=positive_int, required=False, default=1, help="lowest number of addrs sent to DUT", dest="min_num_addrs") optional_named.add_argument("--max_num_addrs", type=positive_int, required=False, default=1000, help="Highest number of addrs sent to DUT", dest="max_num_addrs") optional_named.add_argument("--ac_learning_rate", type=positive_int, required=False, default=1000, help="Number of learning frames per sec", dest="ac_learning_rate") optional_named.add_argument("--frame_size", type=positive_int, required=False, default=64, help="Frame size for address test", dest="frame_size") parser.add_argument("-v", "--verbose", required=False, default=True, help="More output during operation when present", action="store_true", dest="verbose") args = parser.parse_args() if args.verbose: logger.debug("Creating results directory") create_dir(args.results_dir) locationList = [str(item) for item in args.location_list.split(',')] session_name = args.test_session_name user_name = args.test_user_name # pylint: disable=import-error try: # Load Spirent REST Library from stcrestclient import stchttp stc = stchttp.StcHttp(args.lab_server_addr) session_id = stc.new_session(user_name, session_name) stc.join_session(session_id) except RuntimeError as e: logger.error(e) raise # Retrieve and display the server information if args.verbose: logger.debug("SpirentTestCenter system version: %s", stc.get("system1", "version")) try: if args.verbose: logger.debug("Bring up license server") license_mgr = stc.get("system1", "children-licenseservermanager") if args.verbose: logger.debug("license_mgr = %s", license_mgr) stc.create("LicenseServer", under=license_mgr, attributes={ "server": args.license_server_addr}) # Create the root project object if args.verbose: logger.debug("Creating project ...") project = stc.get("System1", "children-Project") # Create ports if args.verbose: logger.debug("Creating ports ...") for location in locationList: stc.perform("CreateAndReservePorts", params={"locationList": location, "RevokeOwner": "FALSE"}) port_list_get = stc.get("System1.project", "children-port") if args.verbose: logger.debug("Adding Host Gen PArams") gen_params = stc.create("EmulatedDeviceGenParams", under=project, attributes={"Port": port_list_get}) # Create the DeviceGenEthIIIfParams object stc.create("DeviceGenEthIIIfParams", under=gen_params) # Configuring Ipv4 interfaces stc.create("DeviceGenIpv4IfParams", under=gen_params) stc.perform("DeviceGenConfigExpand", params={"DeleteExisting": "No", "GenParams": gen_params}) if args.verbose: logger.debug("Set up the RFC2889 test...") if args.metric == "learning": stc.perform("Rfc2889SetupAddressLearningRateTestCommand", params={"FrameSize": args.frame_size, "MinLearningRate": args.min_learning_rate, "MaxLearningRate": args.max_learning_rate, "NumOfTrials": args.num_trials}) elif args.metric == "caching": stc.perform("Rfc2889SetupAddressCachingCapacityTestCommand", params={"FrameSize": args.frame_size, "MinNumAddrs": args.min_num_addrs, "MaxNumAddrs": args.max_num_addrs, "LearningRate": args.ac_learning_rate, "NumOfTrials": args.num_trials}) else: stc.perform("Rfc2889SetupMaxForwardingRateTestCommand", params={"Duration": args.trial_duration_sec, "FrameSizeList": args.frame_size_list, "NumOfTrials": args.num_trials, "TrafficPattern": args.traffic_pattern}) # Save the configuration stc.perform("SaveToTcc", params={"Filename": "2889.tcc"}) # Connect to the hardware... stc.perform("AttachPorts", params={"portList": stc.get( "system1.project", "children-port"), "autoConnect": "TRUE"}) # Apply configuration. if args.verbose: logger.debug("Apply configuration...") stc.apply() if args.verbose: logger.debug("Starting the sequencer...") stc.perform("SequencerStart") # Wait for sequencer to finish logger.info( "Starting test... Please wait for the test to complete...") stc.wait_until_complete() logger.info("The test has completed... Saving results...") # Determine what the results database filename is... lab_server_resultsdb = stc.get( "system1.project.TestResultSetting", "CurrentResultFileName") if args.verbose: logger.debug("The lab server results database is %s", lab_server_resultsdb) if args.metric == "learning": resultsdict = ( stc.perform("QueryResult", params={ "DatabaseConnectionString": lab_server_resultsdb, "ResultPath": ("RFC2889AddressLearningRateTestResultDetailed" "SummaryView")})) elif args.metric == "caching": resultsdict = ( stc.perform("QueryResult", params={ "DatabaseConnectionString": lab_server_resultsdb, "ResultPath": ("RFC2889AddressCachingCapacityTestResult" "DetailedSummaryView")})) else: resultsdict = ( stc.perform("QueryResult", params={ "DatabaseConnectionString": lab_server_resultsdb, "ResultPath": ("RFC2889MaxForwardingRateTestResultDetailed" "SummaryView")})) if args.verbose: logger.debug("resultsdict[\"Columns\"]: %s", resultsdict["Columns"]) logger.debug("resultsdict[\"Output\"]: %s", resultsdict["Output"]) logger.debug("Result paths: %s", stc.perform("GetTestResultSettingPaths")) # Write results to csv if args.verbose: logger.debug("Writing CSV file to results directory %s", args.results_dir) write_query_results_to_csv( args.results_dir, args.csv_results_file_prefix, resultsdict) except RuntimeError as err: logger.error(err) if args.verbose: logger.debug("Destroy session on lab server") stc.end_session() logger.info("Test complete!")