def xmlFlush(self, fRetry=False, fForce=False): """ Flushes the XML back log. Called with the lock held, may leave it while communicating with the server. """ if not self._fXmlFlushing: asXml = self._asXml self._asXml = [] if len(asXml) > 0 or fForce is True: self._fXmlFlushing = True g_oLock.release() (asXml, fIncErrors) = self._xmlDoFlush(asXml, fRetry=fRetry) g_oLock.acquire() if fIncErrors: self.testIncErrors() self._fXmlFlushing = False if asXml is None: self._secTsXmlFlush = utils.timestampSecond() else: self._asXml = asXml + self._asXml return True self._secTsXmlFlush = utils.timestampSecond() return False
def _waitForTestManagerConnectivity(self, cSecTimeout): """ Check and wait for network connectivity to the test manager. This is used with the windows installation and uninstallation since these usually disrupts network connectivity when installing the filter driver. If we proceed to quickly, we might finish the test at a time when we cannot report to the test manager and thus end up with an abandonded test error. """ cSecElapsed = 0 secStart = utils.timestampSecond() while reporter.checkTestManagerConnection() is False: cSecElapsed = utils.timestampSecond() - secStart if cSecElapsed >= cSecTimeout: reporter.log( '_waitForTestManagerConnectivity: Giving up after %u secs.' % (cSecTimeout, )) return False time.sleep(2) if cSecElapsed > 0: reporter.log('_waitForTestManagerConnectivity: Waited %s secs.' % (cSecTimeout, )) return True
def xmlFlush(self, fRetry = False, fForce = False): """ Flushes the XML back log. Called with the lock held, may leave it while communicating with the server. """ if not self._fXmlFlushing: asXml = self._asXml; self._asXml = []; if len(asXml) > 0 or fForce is True: self._fXmlFlushing = True; g_oLock.release(); (asXml, fIncErrors) = self._xmlDoFlush(asXml, fRetry = fRetry); g_oLock.acquire(); if fIncErrors: self.testIncErrors(); self._fXmlFlushing = False; if asXml is None: self._secTsXmlFlush = utils.timestampSecond(); else: self._asXml = asXml + self._asXml; return True; self._secTsXmlFlush = utils.timestampSecond(); return False;
def _doUploadFile(self, oSrcFile, sSrcFilename, sDescription, sKind, sMime): """ Uploads the given file to the test manager. """ # Prepare header and url. dHeader = dict(self._dHttpHeader) dHeader['Content-Type'] = 'application/octet-stream' self._writeOutput('%s: _doUploadFile: sHeader=%s' % ( utils.getTimePrefix(), dHeader, )) oSrcFile.seek(0, 2) self._writeOutput('%s: _doUploadFile: size=%d' % ( utils.getTimePrefix(), oSrcFile.tell(), )) oSrcFile.seek(0) from common import constants sUrl = self._sTmServerPath + '&' \ + self._fnUrlEncode({ constants.tbreq.UPLOAD_PARAM_NAME: os.path.basename(sSrcFilename), constants.tbreq.UPLOAD_PARAM_DESC: sDescription, constants.tbreq.UPLOAD_PARAM_KIND: sKind, constants.tbreq.UPLOAD_PARAM_MIME: sMime, constants.tbreq.ALL_PARAM_ACTION: constants.tbreq.UPLOAD, }) # Retry loop. secStart = utils.timestampSecond() while True: try: oConn = self._fnTmConnect() oConn.request('POST', sUrl, oSrcFile.read(), dHeader) fRc = self._processTmStatusResponse(oConn, '_doUploadFile', fClose=True) oConn.close() if fRc is not None: return fRc except: logXcpt('warning: exception during UPLOAD request') if utils.timestampSecond( ) - secStart >= self.kcSecTestManagerRetryTimeout: self._writeOutput('%s: _doUploadFile: Timed out.' % (utils.getTimePrefix(), )) break try: oSrcFile.seek(0) except: logXcpt() break self._writeOutput('%s: _doUploadFile: Retrying...' % (utils.getTimePrefix(), )) time.sleep(2) return False
def _reportDone(self, sResult): """ Report EXEC job done to the test manager. sResult is a value from constants.result. """ ## @todo optimize this to use one server connection. # # Log it. # assert sResult in constants.result.g_kasValidResults self._log('Done %s' % (sResult, )) # # Report it. # fRc = True secStart = utils.timestampSecond() while True: self._logFlush() ## @todo Combine this with EXEC_COMPLETED. oConnection = None try: oConnection = self._oTestBoxScript.openTestManagerConnection() oConnection.postRequest( constants.tbreq.EXEC_COMPLETED, {constants.tbreq.EXEC_COMPLETED_PARAM_RESULT: sResult}) oConnection.close() except Exception as oXcpt: if utils.timestampSecond( ) - secStart < self.ksecTestManagerTimeout: self._log('_reportDone exception (%s) - retrying...' % (oXcpt, )) time.sleep(2) continue self._log('_reportDone error: %s' % (oXcpt, )) if oConnection is not None: # Be kind to apache. try: oConnection.close() except: pass fRc = False break # # Mark the task as completed. # self._complete() return fRc
def _logInternal(self, sMessage, fPrefix = True, fFlushCheck = False): """ Internal logging. Won't flush the backlog, returns a flush indicator so the caller can do it instead. """ if fPrefix: try: oNow = datetime.utcnow(); sTs = '%02u:%02u:%02u.%06u ' % (oNow.hour, oNow.minute, oNow.second, oNow.microsecond); except Exception as oXcpt: sTs = 'oXcpt=%s ' % (oXcpt); sFullMsg = sTs + sMessage; else: sFullMsg = sMessage; self._oBackLogLock.acquire(); self._asBackLog.append(sFullMsg); cchBackLog = self._cchBackLog + len(sFullMsg) + 1; self._cchBackLog = cchBackLog; secTsBackLogFlush = self._secTsBackLogFlush; self._oBackLogLock.release(); testboxcommons.log(sFullMsg); return fFlushCheck \ and ( cchBackLog >= self.kcchMaxBackLog \ or utils.timestampSecond() - secTsBackLogFlush >= self.kcSecBackLogFlush);
def __init__(self): ReporterBase.__init__(self) self.sTestManagerUrl = os.environ.get('TESTBOX_MANAGER_URL') self.sTestBoxUuid = os.environ.get('TESTBOX_UUID') self.idTestBox = int(os.environ.get('TESTBOX_ID')) self.idTestSet = int(os.environ.get('TESTBOX_TEST_SET_ID')) self._asXml = [] self._secTsXmlFlush = utils.timestampSecond() self._secTsXmlLast = self._secTsXmlFlush self._fXmlFlushing = False self.oOutput = sys.stdout # Hack for __del__ output. self.fFlushEachLine = True self.fDebugXml = 'TESTDRIVER_REPORTER_DEBUG_XML' in os.environ # Prepare the TM connecting. import urlparse import httplib import urllib from common import constants self._fnUrlEncode = urllib.urlencode self._fnUrlParseQs = urlparse.parse_qs self._oParsedTmUrl = urlparse.urlparse(self.sTestManagerUrl) if sys.version_info[0] >= 3 \ or (sys.version_info[0] == 2 and sys.version_info[1] >= 6): if self._oParsedTmUrl.scheme == 'https': # pylint: disable=E1101 self._fnTmConnect = lambda: httplib.HTTPSConnection( self._oParsedTmUrl.hostname, timeout=self.kcSecTestManagerRequestTimeout) else: self._fnTmConnect = lambda: httplib.HTTPConnection( self._oParsedTmUrl.hostname, timeout=self.kcSecTestManagerRequestTimeout) else: if self._oParsedTmUrl.scheme == 'https': # pylint: disable=E1101 self._fnTmConnect = lambda: httplib.HTTPSConnection( self._oParsedTmUrl.hostname) else: self._fnTmConnect = lambda: httplib.HTTPConnection( self._oParsedTmUrl.hostname) self._dHttpHeader = \ { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'User-Agent': 'TestDriverReporter/%s.0 (%s, %s)' % (__version__, utils.getHostOs(), utils.getHostArch(),), 'Accept': 'text/plain,application/x-www-form-urlencoded', 'Accept-Encoding': 'identity', 'Cache-Control': 'max-age=0', #'Connection': 'keep-alive', } dParams = { constants.tbreq.ALL_PARAM_TESTBOX_UUID: self.sTestBoxUuid, constants.tbreq.ALL_PARAM_TESTBOX_ID: self.idTestBox, constants.tbreq.RESULT_PARAM_TEST_SET_ID: self.idTestSet, } self._sTmServerPath = '/%s/testboxdisp.py?%s' \ % ( self._oParsedTmUrl.path.strip('/'), # pylint: disable=E1101 urllib.urlencode(dParams), )
def _xmlDoFlush(self, asXml, fRetry=False, fDtor=False): """ The code that does the actual talking to the server. Used by both xmlFlush and __del__. """ secStart = utils.timestampSecond() while True: fRc = None try: # Post. from common import constants sPostBody = self._fnUrlEncode({ constants.tbreq.XML_RESULT_PARAM_BODY: '\n'.join(asXml), }) oConn = self._fnTmConnect() oConn.request( 'POST', self._sTmServerPath + ('&%s=%s' % (constants.tbreq.ALL_PARAM_ACTION, constants.tbreq.XML_RESULTS)), sPostBody, self._dHttpHeader) fRc = self._processTmStatusResponse(oConn, '_xmlDoFlush', fClose=True) if fRc is True: if self.fDebugXml: self._writeOutput('_xmlDoFlush:\n%s' % ('\n'.join(asXml), )) return (None, False) if fRc is False: self._writeOutput( '_xmlDoFlush: Failed - we should abort the test, really.' ) return (None, True) except Exception, oXcpt: if not fDtor: logXcpt('warning: exception during XML_RESULTS request') else: self._writeOutput( 'warning: exception during XML_RESULTS request: %s' % (oXcpt, )) if fRetry is not True \ or utils.timestampSecond() - secStart >= self.kcSecTestManagerRetryTimeout: break time.sleep(2)
def _assembleArguments(self, sAction, fWithInterpreter=True): """ Creates an argument array for subprocess.Popen, splitting the sScriptCmdLine like bourne shell would. fWithInterpreter is used (False) when checking that the script exists. Returns None on bad input. """ # # This is a good place to export the test set id to the environment. # os.environ['TESTBOX_TEST_SET_ID'] = str(self._idResult) cTimeoutLeft = utils.timestampSecond() - self._tsSecStarted cTimeoutLeft = 0 if cTimeoutLeft >= self._cSecTimeout else self._cSecTimeout - cTimeoutLeft os.environ['TESTBOX_TIMEOUT'] = str(cTimeoutLeft) os.environ['TESTBOX_TIMEOUT_ABS'] = str(self._tsSecStarted + self._cSecTimeout) # # Do replacements and split the command line into arguments. # if self._sScriptCmdLine.find('@ACTION@') >= 0: sCmdLine = self._sScriptCmdLine.replace('@ACTION@', sAction) else: sCmdLine = self._sScriptCmdLine + ' ' + sAction for sVar in [ 'TESTBOX_PATH_BUILDS', 'TESTBOX_PATH_RESOURCES', 'TESTBOX_PATH_SCRATCH', 'TESTBOX_PATH_SCRIPTS', 'TESTBOX_PATH_UPLOAD', 'TESTBOX_UUID', 'TESTBOX_REPORTER', 'TESTBOX_ID', 'TESTBOX_TEST_SET_ID', 'TESTBOX_TIMEOUT', 'TESTBOX_TIMEOUT_ABS' ]: if sCmdLine.find('${' + sVar + '}') >= 0: sCmdLine = sCmdLine.replace('${' + sVar + '}', os.environ[sVar]) asArgs = utils.argsSplit(sCmdLine) # # Massage argv[0]: # - Convert portable slashes ('/') to the flavor preferred by the # OS we're currently running on. # - Run python script thru the current python interpreter (important # on systems that doesn't sport native hash-bang script execution). # asArgs[0] = asArgs[0].replace('/', os.path.sep) if not os.path.isabs(asArgs[0]): asArgs[0] = os.path.join(self._oTestBoxScript.getPathScripts(), asArgs[0]) if asArgs[0].endswith('.py') and fWithInterpreter: if sys.executable is not None and len(sys.executable) > 0: asArgs.insert(0, sys.executable) else: asArgs.insert(0, 'python') return asArgs
def _doUploadFile(self, oSrcFile, sSrcFilename, sDescription, sKind, sMime): """ Uploads the given file to the test manager. """ # Prepare header and url. dHeader = dict(self._dHttpHeader); dHeader['Content-Type'] = 'application/octet-stream'; self._writeOutput('%s: _doUploadFile: sHeader=%s' % (utils.getTimePrefix(), dHeader,)); oSrcFile.seek(0, 2); self._writeOutput('%s: _doUploadFile: size=%d' % (utils.getTimePrefix(), oSrcFile.tell(),)); oSrcFile.seek(0); from common import constants; sUrl = self._sTmServerPath + '&' \ + self._fnUrlEncode({ constants.tbreq.UPLOAD_PARAM_NAME: os.path.basename(sSrcFilename), constants.tbreq.UPLOAD_PARAM_DESC: sDescription, constants.tbreq.UPLOAD_PARAM_KIND: sKind, constants.tbreq.UPLOAD_PARAM_MIME: sMime, constants.tbreq.ALL_PARAM_ACTION: constants.tbreq.UPLOAD, }); # Retry loop. secStart = utils.timestampSecond(); while True: try: oConn = self._fnTmConnect(); oConn.request('POST', sUrl, oSrcFile.read(), dHeader); fRc = self._processTmStatusResponse(oConn, '_doUploadFile', fClose = True); oConn.close(); if fRc is not None: return fRc; except: logXcpt('warning: exception during UPLOAD request'); if utils.timestampSecond() - secStart >= self.kcSecTestManagerRetryTimeout: self._writeOutput('%s: _doUploadFile: Timed out.' % (utils.getTimePrefix(),)); break; try: oSrcFile.seek(0); except: logXcpt(); break; self._writeOutput('%s: _doUploadFile: Retrying...' % (utils.getTimePrefix(), )); time.sleep(2); return False;
def _reportDone(self, sResult): """ Report EXEC job done to the test manager. sResult is a value from constants.result. """ ## @todo optimize this to use one server connection. # # Log it. # assert sResult in constants.result.g_kasValidResults; self._log('Done %s' % (sResult,)); # # Report it. # fRc = True; secStart = utils.timestampSecond(); while True: self._logFlush(); ## @todo Combine this with EXEC_COMPLETED. oConnection = None; try: oConnection = self._oTestBoxScript.openTestManagerConnection(); oConnection.postRequest(constants.tbreq.EXEC_COMPLETED, {constants.tbreq.EXEC_COMPLETED_PARAM_RESULT: sResult}); oConnection.close(); except Exception as oXcpt: if utils.timestampSecond() - secStart < self.ksecTestManagerTimeout: self._log('_reportDone exception (%s) - retrying...' % (oXcpt,)); time.sleep(2); continue; self._log('_reportDone error: %s' % (oXcpt,)); if oConnection is not None: # Be kind to apache. try: oConnection.close(); except: pass; fRc = False; break; # # Mark the task as completed. # self._complete(); return fRc;
def __init__(self): ReporterBase.__init__(self); self.sTestManagerUrl = os.environ.get('TESTBOX_MANAGER_URL'); self.sTestBoxUuid = os.environ.get('TESTBOX_UUID'); self.idTestBox = int(os.environ.get('TESTBOX_ID')); self.idTestSet = int(os.environ.get('TESTBOX_TEST_SET_ID')); self._asXml = []; self._secTsXmlFlush = utils.timestampSecond(); self._secTsXmlLast = self._secTsXmlFlush; self._fXmlFlushing = False; self.oOutput = sys.stdout; # Hack for __del__ output. self.fFlushEachLine = True; self.fDebugXml = 'TESTDRIVER_REPORTER_DEBUG_XML' in os.environ; # Prepare the TM connecting. import urlparse; import httplib; import urllib; from common import constants; self._fnUrlEncode = urllib.urlencode; self._fnUrlParseQs = urlparse.parse_qs; self._oParsedTmUrl = urlparse.urlparse(self.sTestManagerUrl); if sys.version_info[0] >= 3 \ or (sys.version_info[0] == 2 and sys.version_info[1] >= 6): if self._oParsedTmUrl.scheme == 'https': # pylint: disable=E1101 self._fnTmConnect = lambda: httplib.HTTPSConnection(self._oParsedTmUrl.hostname, timeout = self.kcSecTestManagerRequestTimeout); else: self._fnTmConnect = lambda: httplib.HTTPConnection( self._oParsedTmUrl.hostname, timeout = self.kcSecTestManagerRequestTimeout); else: if self._oParsedTmUrl.scheme == 'https': # pylint: disable=E1101 self._fnTmConnect = lambda: httplib.HTTPSConnection(self._oParsedTmUrl.hostname); else: self._fnTmConnect = lambda: httplib.HTTPConnection( self._oParsedTmUrl.hostname); self._dHttpHeader = \ { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'User-Agent': 'TestDriverReporter/%s.0 (%s, %s)' % (__version__, utils.getHostOs(), utils.getHostArch(),), 'Accept': 'text/plain,application/x-www-form-urlencoded', 'Accept-Encoding': 'identity', 'Cache-Control': 'max-age=0', #'Connection': 'keep-alive', }; dParams = { constants.tbreq.ALL_PARAM_TESTBOX_UUID: self.sTestBoxUuid, constants.tbreq.ALL_PARAM_TESTBOX_ID: self.idTestBox, constants.tbreq.RESULT_PARAM_TEST_SET_ID: self.idTestSet, }; self._sTmServerPath = '/%s/testboxdisp.py?%s' \ % ( self._oParsedTmUrl.path.strip('/'), # pylint: disable=E1101 urllib.urlencode(dParams), );
def _logFlush(self, oGivenConnection=None): """ Flushes the log to the test manager. No exceptions. """ fRc = True self._oBackLogFlushLock.acquire() # Grab the current back log. self._oBackLogLock.acquire() asBackLog = self._asBackLog self._asBackLog = [] self._cchBackLog = 0 self._secTsBackLogFlush = utils.timestampSecond() self._oBackLogLock.release() # If there is anything to flush, flush it. if asBackLog: sBody = '' for sLine in asBackLog: sBody += sLine + '\n' oConnection = None try: if oGivenConnection is None: oConnection = self._oTestBoxScript.openTestManagerConnection( ) oConnection.postRequest( constants.tbreq.LOG_MAIN, {constants.tbreq.LOG_PARAM_BODY: sBody}) oConnection.close() else: oGivenConnection.postRequest( constants.tbreq.LOG_MAIN, {constants.tbreq.LOG_PARAM_BODY: sBody}) except Exception as oXcpt: testboxcommons.log('_logFlush error: %s' % (oXcpt, )) if len(sBody) < self.kcchMaxBackLog * 4: self._oBackLogLock.acquire() asBackLog.extend(self._asBackLog) self._asBackLog = asBackLog # Don't restore _cchBackLog as there is no point in retrying immediately. self._oBackLogLock.release() if oConnection is not None: # Be kind to apache. try: oConnection.close() except: pass fRc = False self._oBackLogFlushLock.release() return fRc
def _waitForTestManagerConnectivity(self, cSecTimeout): """ Check and wait for network connectivity to the test manager. This is used with the windows installation and uninstallation since these usually disrupts network connectivity when installing the filter driver. If we proceed to quickly, we might finish the test at a time when we cannot report to the test manager and thus end up with an abandonded test error. """ cSecElapsed = 0; secStart = utils.timestampSecond(); while reporter.checkTestManagerConnection() is False: cSecElapsed = utils.timestampSecond() - secStart; if cSecElapsed >= cSecTimeout: reporter.log('_waitForTestManagerConnectivity: Giving up after %u secs.' % (cSecTimeout,)); return False; time.sleep(2); if cSecElapsed > 0: reporter.log('_waitForTestManagerConnectivity: Waited %s secs.' % (cSecTimeout,)); return True;
def __init__(self, oTestBoxScript, cSecTimeout, fnThreadProc): self._oTestBoxScript = oTestBoxScript; self._cSecTimeout = cSecTimeout; self._tsSecStarted = utils.timestampSecond(); self.__oRLock = threading.RLock(); self._oCv = threading.Condition(self.__oRLock); self._fRunning = True; # Protected by lock. self._fShouldTerminate = False; # Protected by lock. # Spawn the worker thread. self._oThread = threading.Thread(target=fnThreadProc); self._oThread.daemon = True; self._oThread.start();
def _assembleArguments(self, sAction, fWithInterpreter = True): """ Creates an argument array for subprocess.Popen, splitting the sScriptCmdLine like bourne shell would. fWithInterpreter is used (False) when checking that the script exists. Returns None on bad input. """ # # This is a good place to export the test set id to the environment. # os.environ['TESTBOX_TEST_SET_ID'] = str(self._idResult); cTimeoutLeft = utils.timestampSecond() - self._tsSecStarted; cTimeoutLeft = 0 if cTimeoutLeft >= self._cSecTimeout else self._cSecTimeout - cTimeoutLeft; os.environ['TESTBOX_TIMEOUT'] = str(cTimeoutLeft); os.environ['TESTBOX_TIMEOUT_ABS'] = str(self._tsSecStarted + self._cSecTimeout); # # Do replacements and split the command line into arguments. # if self._sScriptCmdLine.find('@ACTION@') >= 0: sCmdLine = self._sScriptCmdLine.replace('@ACTION@', sAction); else: sCmdLine = self._sScriptCmdLine + ' ' + sAction; for sVar in [ 'TESTBOX_PATH_BUILDS', 'TESTBOX_PATH_RESOURCES', 'TESTBOX_PATH_SCRATCH', 'TESTBOX_PATH_SCRIPTS', 'TESTBOX_PATH_UPLOAD', 'TESTBOX_UUID', 'TESTBOX_REPORTER', 'TESTBOX_ID', 'TESTBOX_TEST_SET_ID', 'TESTBOX_TIMEOUT', 'TESTBOX_TIMEOUT_ABS' ]: if sCmdLine.find('${' + sVar + '}') >= 0: sCmdLine = sCmdLine.replace('${' + sVar + '}', os.environ[sVar]); asArgs = utils.argsSplit(sCmdLine); # # Massage argv[0]: # - Convert portable slashes ('/') to the flavor preferred by the # OS we're currently running on. # - Run python script thru the current python interpreter (important # on systems that doesn't sport native hash-bang script execution). # asArgs[0] = asArgs[0].replace('/', os.path.sep); if not os.path.isabs(asArgs[0]): asArgs[0] = os.path.join(self._oTestBoxScript.getPathScripts(), asArgs[0]); if asArgs[0].endswith('.py') and fWithInterpreter: if sys.executable: asArgs.insert(0, sys.executable); else: asArgs.insert(0, 'python'); return asArgs;
def _xmlDoFlush(self, asXml, fRetry = False, fDtor = False): """ The code that does the actual talking to the server. Used by both xmlFlush and __del__. """ secStart = utils.timestampSecond(); while True: fRc = None; try: # Post. from common import constants; sPostBody = self._fnUrlEncode({constants.tbreq.XML_RESULT_PARAM_BODY: '\n'.join(asXml),}); oConn = self._fnTmConnect(); oConn.request('POST', self._sTmServerPath + ('&%s=%s' % (constants.tbreq.ALL_PARAM_ACTION, constants.tbreq.XML_RESULTS)), sPostBody, self._dHttpHeader); fRc = self._processTmStatusResponse(oConn, '_xmlDoFlush', fClose = True); if fRc is True: if self.fDebugXml: self._writeOutput('_xmlDoFlush:\n%s' % ('\n'.join(asXml),)); return (None, False); if fRc is False: self._writeOutput('_xmlDoFlush: Failed - we should abort the test, really.'); return (None, True); except Exception, oXcpt: if not fDtor: logXcpt('warning: exception during XML_RESULTS request'); else: self._writeOutput('warning: exception during XML_RESULTS request: %s' % (oXcpt,)); if fRetry is not True \ or utils.timestampSecond() - secStart >= self.kcSecTestManagerRetryTimeout: break; time.sleep(2);
def __init__(self, oTestBoxScript, fnThreadProc, cSecTimeout, idResult, sScriptCmdLine): """ Class instance init """ # Init our instance data. self._idResult = idResult; self._sScriptCmdLine = sScriptCmdLine; self._oChild = None; self._oBackLogLock = threading.RLock(); self._oBackLogFlushLock = threading.RLock(); self._asBackLog = []; self._cchBackLog = 0; self._secTsBackLogFlush = utils.timestampSecond(); # Init super. TestBoxBaseTask.__init__(self, oTestBoxScript, cSecTimeout, fnThreadProc);
def _logFlush(self, oGivenConnection = None): """ Flushes the log to the test manager. No exceptions. """ fRc = True; self._oBackLogFlushLock.acquire(); # Grab the current back log. self._oBackLogLock.acquire(); asBackLog = self._asBackLog; self._asBackLog = []; self._cchBackLog = 0; self._secTsBackLogFlush = utils.timestampSecond(); self._oBackLogLock.release(); # If there is anything to flush, flush it. if asBackLog: sBody = ''; for sLine in asBackLog: sBody += sLine + '\n'; oConnection = None; try: if oGivenConnection is None: oConnection = self._oTestBoxScript.openTestManagerConnection(); oConnection.postRequest(constants.tbreq.LOG_MAIN, {constants.tbreq.LOG_PARAM_BODY: sBody}); oConnection.close(); else: oGivenConnection.postRequest(constants.tbreq.LOG_MAIN, {constants.tbreq.LOG_PARAM_BODY: sBody}); except Exception as oXcpt: testboxcommons.log('_logFlush error: %s' % (oXcpt,)); if len(sBody) < self.kcchMaxBackLog * 4: self._oBackLogLock.acquire(); asBackLog.extend(self._asBackLog); self._asBackLog = asBackLog; # Don't restore _cchBackLog as there is no point in retrying immediately. self._oBackLogLock.release(); if oConnection is not None: # Be kind to apache. try: oConnection.close(); except: pass; fRc = False; self._oBackLogFlushLock.release(); return fRc;
def _xmlFlushIfNecessary(self): """Flushes the XML back log if necessary.""" tsNow = utils.timestampSecond(); cSecs = tsNow - self._secTsXmlFlush; cSecsLast = tsNow - self._secTsXmlLast; self._secTsXmlLast = tsNow; # Absolute flush thresholds. if cSecs >= self.kcSecXmlFlushMax: return self.xmlFlush(); if len(self._asXml) >= self.kcLinesXmlFlush: return self.xmlFlush(); # Flush if idle long enough. if cSecs >= self.kcSecXmlFlushMin \ and cSecsLast >= self.kcSecXmlFlushIdle: return self.xmlFlush(); return False;
def _xmlFlushIfNecessary(self): """Flushes the XML back log if necessary.""" tsNow = utils.timestampSecond() cSecs = tsNow - self._secTsXmlFlush cSecsLast = tsNow - self._secTsXmlLast self._secTsXmlLast = tsNow # Absolute flush thresholds. if cSecs >= self.kcSecXmlFlushMax: return self.xmlFlush() if len(self._asXml) >= self.kcLinesXmlFlush: return self.xmlFlush() # Flush if idle long enough. if cSecs >= self.kcSecXmlFlushMin \ and cSecsLast >= self.kcSecXmlFlushIdle: return self.xmlFlush() return False
def _monitorChild(self, cSecTimeout, fTryKillCommand = True, oChild = None): """ Monitors the child process. If the child executes longer that cSecTimeout allows, we'll terminate it. Returns Success indicator and constants.result value. """ if oChild is None: oChild = self._oChild; iProcGroup = oChild.pid; if utils.getHostOs() in ['win', 'os2'] or iProcGroup <= 0: iProcGroup = -2; # # Do timeout processing and check the health of the child. # sResult = constants.result.PASSED; seStarted = utils.timestampSecond(); while True: # Check status. iRc = oChild.poll(); if iRc is not None: self._log('Child doing "%s" completed with exit code %d' % (oChild.sTestBoxScriptAction, iRc)); oChild.oOutputThread.join(self.kcSecFinalOutputTimeout); if oChild is self._oChild: self._oChild = None; if iRc == constants.rtexitcode.SKIPPED: return (True, constants.result.SKIPPED); if iRc != constants.rtexitcode.SUCCESS: return (False, constants.result.FAILED); return (True, constants.result.PASSED); # Check for abort first, since that has less of a stigma. if self._shouldTerminate() is True: sResult = constants.result.ABORTED; break; # Check timeout. cSecElapsed = utils.timestampSecond() - seStarted; if cSecElapsed > cSecTimeout: self._log('Timeout: %u secs (limit %u secs)' % (cSecElapsed, cSecTimeout)); sResult = constants.result.TIMED_OUT; break; # Wait. cSecLeft = cSecTimeout - cSecElapsed; oChild.oOutputThread.join(15 if cSecLeft > 15 else (cSecLeft + 1)); # # If the child is still alive, try use the abort command to stop it # very gently. This let's the testdriver clean up daemon processes # and such that our code below won't catch. # if fTryKillCommand and oChild.poll() is None: self._log('Attempting to abort child...'); (fRc2, oAbortChild) = self._spawnChild('abort'); if oAbortChild is not None and fRc2 is True: self._monitorChild(self.kcSecAbortTimeout, False, oAbortChild); oAbortChild = None; # # If the child is still alive, try the polite way. # if oChild.poll() is None: self._log('Attempting to terminate child doing "%s"...' % (oChild.sTestBoxScriptAction,)); if iProcGroup > 0: try: os.killpg(iProcGroup, signal.SIGTERM); # pylint: disable=E1101 except Exception, oXcpt: self._log('killpg() failed: %s' % (oXcpt,)); try: self._oChild.terminate(); oChild.oOutputThread.join(self.kcSecTerminateOutputTimeout); except Exception, oXcpt: self._log('terminate() failed: %s' % (oXcpt,));
sTs = 'oXcpt=%s ' % (oXcpt); sFullMsg = sTs + sMessage; else: sFullMsg = sMessage; self._oBackLogLock.acquire(); self._asBackLog.append(sFullMsg); cchBackLog = self._cchBackLog + len(sFullMsg) + 1; self._cchBackLog = cchBackLog; secTsBackLogFlush = self._secTsBackLogFlush; self._oBackLogLock.release(); testboxcommons.log(sFullMsg); return fFlushCheck \ and ( cchBackLog >= self.kcchMaxBackLog \ or utils.timestampSecond() - secTsBackLogFlush >= self.kcSecBackLogFlush); def _log(self, sMessage): """ General logging function, will flush. """ if self._logInternal(sMessage, fFlushCheck = True): self._logFlush(); return True; def _reportDone(self, sResult): """ Report EXEC job done to the test manager. sResult is a value from constants.result. """
def _monitorChild(self, cSecTimeout, fTryKillCommand = True, oChild = None): """ Monitors the child process. If the child executes longer that cSecTimeout allows, we'll terminate it. Returns Success indicator and constants.result value. """ if oChild is None: oChild = self._oChild; iProcGroup = oChild.pid; if utils.getHostOs() in ['win', 'os2'] or iProcGroup <= 0: iProcGroup = -2; # # Do timeout processing and check the health of the child. # sResult = constants.result.PASSED; seStarted = utils.timestampSecond(); while True: # Check status. iRc = oChild.poll(); if iRc is not None: self._log('Child doing "%s" completed with exit code %d' % (oChild.sTestBoxScriptAction, iRc)); oChild.oOutputThread.join(self.kcSecFinalOutputTimeout); if oChild is self._oChild: self._oChild = None; if iRc == constants.rtexitcode.SKIPPED: return (True, constants.result.SKIPPED); if iRc != constants.rtexitcode.SUCCESS: return (False, constants.result.FAILED); return (True, constants.result.PASSED); # Check for abort first, since that has less of a stigma. if self._shouldTerminate() is True: sResult = constants.result.ABORTED; break; # Check timeout. cSecElapsed = utils.timestampSecond() - seStarted; if cSecElapsed > cSecTimeout: self._log('Timeout: %u secs (limit %u secs)' % (cSecElapsed, cSecTimeout)); sResult = constants.result.TIMED_OUT; break; # Wait. cSecLeft = cSecTimeout - cSecElapsed; oChild.oOutputThread.join(15 if cSecLeft > 15 else (cSecLeft + 1)); # # If the child is still alive, try use the abort command to stop it # very gently. This let's the testdriver clean up daemon processes # and such that our code below won't catch. # if fTryKillCommand and oChild.poll() is None: self._log('Attempting to abort child...'); (fRc2, oAbortChild) = self._spawnChild('abort'); if oAbortChild is not None and fRc2 is True: self._monitorChild(self.kcSecAbortTimeout, False, oAbortChild); oAbortChild = None; # # If the child is still alive, try the polite way. # if oChild.poll() is None: self._log('Attempting to terminate child doing "%s"...' % (oChild.sTestBoxScriptAction,)); if iProcGroup > 0: try: os.killpg(iProcGroup, signal.SIGTERM); # pylint: disable=E1101 except Exception as oXcpt: self._log('killpg() failed: %s' % (oXcpt,)); try: self._oChild.terminate(); oChild.oOutputThread.join(self.kcSecTerminateOutputTimeout); except Exception as oXcpt: self._log('terminate() failed: %s' % (oXcpt,)); # # If the child doesn't respond to polite, kill it. Always do a killpg # should there be any processes left in the group. # if iProcGroup > 0: try: os.killpg(iProcGroup, signal.SIGKILL); # pylint: disable=E1101 except Exception as oXcpt: self._log('killpg() failed: %s' % (oXcpt,)); if oChild.poll() is None: self._log('Attemting to kill child doing "%s"...' % (oChild.sTestBoxScriptAction,)); try: self._oChild.kill(); oChild.oOutputThread.join(self.kcSecKillOutputTimeout); except Exception as oXcpt: self._log('kill() failed: %s' % (oXcpt,)); # # Give the whole mess a couple of more seconds to respond in case the # output thread exitted prematurely for some weird reason. # if oChild.poll() is None: time.sleep(2); time.sleep(2); time.sleep(2); iRc = oChild.poll(); if iRc is not None: self._log('Child doing "%s" aborted with exit code %d' % (oChild.sTestBoxScriptAction, iRc)); else: self._log('Child doing "%s" is still running, giving up...' % (oChild.sTestBoxScriptAction,)); ## @todo in this case we should probably try reboot the testbox... oChild.oOutputThread.fPleaseQuit = True; if oChild is self._oChild: self._oChild = None; return (False, sResult);
def _monitorChild(self, cSecTimeout, fTryKillCommand=True, oChild=None): """ Monitors the child process. If the child executes longer that cSecTimeout allows, we'll terminate it. Returns Success indicator and constants.result value. """ if oChild is None: oChild = self._oChild iProcGroup = oChild.pid if utils.getHostOs() in ['win', 'os2'] or iProcGroup <= 0: iProcGroup = -2 # # Do timeout processing and check the health of the child. # sResult = constants.result.PASSED seStarted = utils.timestampSecond() while True: # Check status. iRc = oChild.poll() if iRc is not None: self._log('Child doing "%s" completed with exit code %d' % (oChild.sTestBoxScriptAction, iRc)) oChild.oOutputThread.join(self.kcSecFinalOutputTimeout) if oChild is self._oChild: self._oChild = None if iRc == constants.rtexitcode.SKIPPED: return (True, constants.result.SKIPPED) if iRc != constants.rtexitcode.SUCCESS: return (False, constants.result.FAILED) return (True, constants.result.PASSED) # Check for abort first, since that has less of a stigma. if self._shouldTerminate() is True: sResult = constants.result.ABORTED break # Check timeout. cSecElapsed = utils.timestampSecond() - seStarted if cSecElapsed > cSecTimeout: self._log('Timeout: %u secs (limit %u secs)' % (cSecElapsed, cSecTimeout)) sResult = constants.result.TIMED_OUT break # Wait. cSecLeft = cSecTimeout - cSecElapsed oChild.oOutputThread.join(15 if cSecLeft > 15 else (cSecLeft + 1)) # # If the child is still alive, try use the abort command to stop it # very gently. This let's the testdriver clean up daemon processes # and such that our code below won't catch. # if fTryKillCommand and oChild.poll() is None: self._log('Attempting to abort child...') (fRc2, oAbortChild) = self._spawnChild('abort') if oAbortChild is not None and fRc2 is True: self._monitorChild(self.kcSecAbortTimeout, False, oAbortChild) oAbortChild = None # # If the child is still alive, try the polite way. # if oChild.poll() is None: self._log('Attempting to terminate child doing "%s"...' % (oChild.sTestBoxScriptAction, )) if iProcGroup > 0: try: os.killpg(iProcGroup, signal.SIGTERM) # pylint: disable=E1101 except Exception as oXcpt: self._log('killpg() failed: %s' % (oXcpt, )) try: self._oChild.terminate() oChild.oOutputThread.join(self.kcSecTerminateOutputTimeout) except Exception as oXcpt: self._log('terminate() failed: %s' % (oXcpt, )) # # If the child doesn't respond to polite, kill it. Always do a killpg # should there be any processes left in the group. # if iProcGroup > 0: try: os.killpg(iProcGroup, signal.SIGKILL) # pylint: disable=E1101 except Exception as oXcpt: self._log('killpg() failed: %s' % (oXcpt, )) if oChild.poll() is None: self._log('Attemting to kill child doing "%s"...' % (oChild.sTestBoxScriptAction, )) try: self._oChild.kill() oChild.oOutputThread.join(self.kcSecKillOutputTimeout) except Exception as oXcpt: self._log('kill() failed: %s' % (oXcpt, )) # # Give the whole mess a couple of more seconds to respond in case the # output thread exitted prematurely for some weird reason. # if oChild.poll() is None: time.sleep(2) time.sleep(2) time.sleep(2) iRc = oChild.poll() if iRc is not None: self._log('Child doing "%s" aborted with exit code %d' % (oChild.sTestBoxScriptAction, iRc)) else: self._log('Child doing "%s" is still running, giving up...' % (oChild.sTestBoxScriptAction, )) ## @todo in this case we should probably try reboot the testbox... oChild.oOutputThread.fPleaseQuit = True if oChild is self._oChild: self._oChild = None return (False, sResult)