def pollStatsAndCheckStatResults(self, statsDict=None, pollStatInterval=2, csvFile=False, csvEnableFileTimestamp=True, csvFilePrependName=None, exitAfterPollingIteration=None): ''' Get run time stats and evaluate the stats with an operator and the expected value. Due to stats going through ramp up and ramp down, stats will fluctuate. Once the stat hits and maintains the expected threshold value, the stat is marked as passed. If evaluating stats at run time is not what you need, use PollStats() instead shown. statsDict = This API will poll stats based on the dictionary statsDict that you passed in. Example how statsDict should look like: Example: # operator options: <, >, <=, >= statsDict = { 'HTTPClient': [{'caption': 'TCP Connections Established', 'operator': '>', 'expect': 60}, {'caption': 'HTTP Simulated Users', 'operator': None, 'expect': None}, {'caption': 'HTTP Connections', 'operator': '>=', 'expect': 300}, {'caption': 'HTTP Transactions', 'operator': '>', 'expect': 190}, {'caption': 'HTTP Connection Attempts', 'operator': '>', 'expect': 300} ], 'HTTPServer': [{'caption': 'TCP Connections Established', 'operator': '>', 'expect': 1000}, {'caption': 'TCP Connection Requests Failed', 'operator': '<', 'expect': 1} ] } The exact name of the above stats could be found in the API browser or by doing a ScriptGen on the GUI. If doing by ScriptGen, do a wordsearch for "statlist". Copy and Paste the stats that you want. csvFile: To enable or disable recording stats on csv file: True or False csvEnableFileTimestamp: To append a timestamp on the csv file so they don't overwrite each other: True or False csvFilePrependName: To prepend a name of your choice to the csv file for visual identification and if you need to restart the test, a new csv file will be created. Prepending a name will group the csv files. exitAfterPollingIteration: Stop polling for stats after the specified iteration. Default = None, which polls for stats until the test is done. An iteration means a cycle of all the stats. ''' self.testResults = dict() # Make all stats as failed. If stat hits the expected value, # then result is changed to passed. self.testResults['result'] = 'Failed' for statType in statsDict.keys(): self.testResults[statType] = dict() for captionMetas in statsDict[statType]: # CAPTION: {'caption': 'TCP Connections Established', 'operator': '>', 'expect': 60} self.testResults[statType].update({captionMetas['caption']: 'Failed'}) import operator # Not going to handle = and != because the intention is to handle hitting and maintaining the expected threshold only operators = {'>': operator.gt, '<': operator.lt, #'=': operator.eq, #'!=': operator.ne, '<=': operator.le, '>=': operator.ge } versionMatch = re.match('([0-9]+\.[0-9]+)', self.ixLoadVersion) if float(versionMatch.group(1)) < float(8.5): # If ixLoad version is < 8.50, there is no rest api to download stats. # Default to creating csv stats from real time stats. csvFile = True if csvFile: import csv csvFilesDict = {} for key in statsDict.keys(): fileName = key fileName = fileName.replace("(", '_') fileName = fileName.replace(")", '_') if csvFilePrependName: fileName = csvFilePrependName+'_'+fileName csvFilesDict[key] = {} if csvEnableFileTimestamp: import datetime timestamp = datetime.datetime.now().strftime('%H%M%S') fileName = '{}_{}'.format(fileName, timestamp) fileName = fileName+'.csv' csvFilesDict[key]['filename'] = fileName csvFilesDict[key]['columnNameList'] = [] csvFilesDict[key]['fileObj'] = open(fileName, 'w') csvFilesDict[key]['csvObj'] = csv.writer(csvFilesDict[key]['fileObj']) # Create the csv top row column name list for statType in statsDict.keys(): for captionMetas in statsDict[statType]: csvFilesDict[statType]['columnNameList'].append(captionMetas['caption']) csvFilesDict[statType]['csvObj'].writerow(csvFilesDict[statType]['columnNameList']) waitForRunningStatusCounter = 0 waitForRunningStatusCounterExit = 120 pollStatCounter = 0 while True: currentState = self.getActiveTestCurrentState(silentMode=True) self.logInfo('ActiveTest current status: %s. ' % currentState) if currentState == 'Running': if statsDict == None: time.sleep(1) continue # statType: HTTPClient or HTTPServer (Just a example using HTTP.) # statNameList: transaction success, transaction failures, ... for statType in statsDict.keys(): self.logInfo('\n%s:' % statType, timestamp=False) statUrl = self.sessionIdUrl+'/ixLoad/stats/'+statType+'/values' response = self.getStats(statUrl) highestTimestamp = 0 # Each timestamp & statnames: values for eachTimestamp,valueList in response.json().items(): if eachTimestamp == 'error': raise IxLoadRestApiException('pollStats error: Probable cause: Misconfigured stat names to retrieve.') if int(eachTimestamp) > highestTimestamp: highestTimestamp = int(eachTimestamp) if highestTimestamp == 0: time.sleep(3) continue if csvFile: csvFilesDict[statType]['rowValueList'] = [] # Get the interested stat names only for captionMetas in statsDict[statType]: # HTTPServer: [{'caption': 'TCP Connections Established', 'operator': '>', 'expect': 1000}, # {'caption': 'TCP Connection Requests Failed', 'operator': '=', 'expect': 0}] statName = captionMetas['caption'] if statName in response.json()[str(highestTimestamp)]: statValue = response.json()[str(highestTimestamp)][statName] if statValue == "N/A" or statValue == "": continue self.logInfo('\t%s: %s' % (statName, statValue), timestamp=False) if csvFile: csvFilesDict[statType]['rowValueList'].append(statValue) # Verify passed/failed objectives if captionMetas['operator'] is not None or captionMetas['expect'] is not None: op = operators.get(captionMetas['operator']) # Check user defined operator for expectation # Example: operator.ge(3,3) if op(int(statValue), int(captionMetas['expect'])) == False: if self.testResults[statType][statName] == 'Failed': self.logInfo('\t\tThreshold not reached: Expecting: {}{}\n'.format(captionMetas['operator'], int(captionMetas['expect'])), timestamp=False) if self.testResults[statType][statName] == 'Passed': self.logInfo('\t\tThreshold reached and sustaining: Expecting: {}{}\n'.format(captionMetas['operator'], int(captionMetas['expect'])), timestamp=False) if op(int(statValue), int(captionMetas['expect'])) == True: if self.testResults[statType][statName] == 'Failed': self.logInfo('\t\tThreshold reached: Expecting: {}{}\n'.format(captionMetas['operator'], int(captionMetas['expect'])), timestamp=False) if self.testResults[statType][statName] == 'Passed': self.logInfo('\t\tThreshold reached and sustaining: Expecting: {}{}\n'.format(captionMetas['operator'], int(captionMetas['expect'])), timestamp=False) self.testResults[statType].update({statName: 'Passed'}) else: self.logInfo('\t\tNo expectation defined\n', timestamp=False) else: self.logError('\tStat name not found. Check spelling and case sensitivity: %s' % statName) if csvFile: if csvFilesDict[statType]['rowValueList'] != []: csvFilesDict[statType]['csvObj'].writerow(csvFilesDict[statType]['rowValueList']) time.sleep(pollStatInterval) if exitAfterPollingIteration and pollStatCounter >= exitAfterPollingIteration: self.logInfo('pollStats exitAfterPollingIteration is set to {} iterations. Current runtime iteration is {}. Exiting PollStats'.format(exitAfterPollingIteration, pollStatCounter)) return pollStatCounter += 1 elif currentState == "Unconfigured": break else: # If currentState is "Stopping Run" or Cleaning if waitForRunningStatusCounter < waitForRunningStatusCounterExit: waitForRunningStatusCounter += 1 self.logInfo('\tWaiting {0}/{1} seconds'.format(waitForRunningStatusCounter, waitForRunningStatusCounterExit), timestamp=False) time.sleep(self.pollStatusInterval) waitForRunningStatusCounter += self.pollStatusInterval continue if waitForRunningStatusCounter == waitForRunningStatusCounterExit: return 1 if csvFile: for key in statsDict.keys(): csvFilesDict[key]['fileObj'].close()